Merge branches 'release' and 'menlo' into release
Conflicts:
drivers/acpi/video.c
Signed-off-by: Len Brown <len.brown@intel.com>
diff --git a/CREDITS b/CREDITS
index edff310..da0a56e 100644
--- a/CREDITS
+++ b/CREDITS
@@ -508,12 +508,8 @@
S: Germany
N: Adrian Bunk
-E: bunk@stusta.de
P: 1024D/4F12B400 B29C E71E FE19 6755 5C8A 84D4 99FC EA98 4F12 B400
D: misc kernel hacking and testing
-S: Grasmeierstrasse 11
-S: 80805 Muenchen
-S: Germany
N: Ray Burr
E: ryb@nightmare.com
@@ -1124,6 +1120,9 @@
S: San Jose, California 95131
S: USA
+N: Adam Fritzler
+E: mid@zigamorph.net
+
N: Fernando Fuganti
E: fuganti@conectiva.com.br
E: fuganti@netbank.com.br
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index c3014df..33f5591 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -14,6 +14,7 @@
- this file.
ABI/
- info on kernel <-> userspace ABI and relative interface stability.
+
BUG-HUNTING
- brute force method of doing binary search of patches to find bug.
Changes
@@ -66,6 +67,8 @@
- how to change your VGA cursor from a blinking underscore.
accounting/
- documentation on accounting and taskstats.
+acpi/
+ - info on ACPI-specific hooks in the kernel.
aoe/
- description of AoE (ATA over Ethernet) along with config examples.
applying-patches.txt
@@ -154,7 +157,7 @@
- request_firmware() hotplug interface info.
floppy.txt
- notes and driver options for the floppy disk driver.
-fujitsu/
+frv/
- Fujitsu FR-V Linux documentation.
gpio.txt
- overview of GPIO (General Purpose Input/Output) access conventions.
@@ -364,8 +367,6 @@
- a description of shared subtrees for namespaces.
smart-config.txt
- description of the Smart Config makefile feature.
-smp.txt
- - a few notes on symmetric multi-processing.
sony-laptop.txt
- Sony Notebook Control Driver (SNC) Readme.
sonypi.txt
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 9734577..11a3c16 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -52,3 +52,36 @@
facility is inherently dangerous, it is disabled by default
for all devices except hubs. For more information, see
Documentation/usb/persist.txt.
+
+What: /sys/bus/usb/device/.../power/connected_duration
+Date: January 2008
+KernelVersion: 2.6.25
+Contact: Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+ If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+ is present. When read, it returns the total time (in msec)
+ that the USB device has been connected to the machine. This
+ file is read-only.
+Users:
+ PowerTOP <power@bughost.org>
+ http://www.lesswatts.org/projects/powertop/
+
+What: /sys/bus/usb/device/.../power/active_duration
+Date: January 2008
+KernelVersion: 2.6.25
+Contact: Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+ If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+ is present. When read, it returns the total time (in msec)
+ that the USB device has been active, i.e. not in a suspended
+ state. This file is read-only.
+
+ Tools can use this file and the connected_duration file to
+ compute the percentage of time that a device has been active.
+ For example,
+ echo $((100 * `cat active_duration` / `cat connected_duration`))
+ will give an integer percentage. Note that this does not
+ account for counter wrap.
+Users:
+ PowerTOP <power@bughost.org>
+ http://www.lesswatts.org/projects/powertop/
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
new file mode 100644
index 0000000..9470ed9
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -0,0 +1,99 @@
+What: /sys/firmware/acpi/interrupts/
+Date: February 2008
+Contact: Len Brown <lenb@kernel.org>
+Description:
+ All ACPI interrupts are handled via a single IRQ,
+ the System Control Interrupt (SCI), which appears
+ as "acpi" in /proc/interrupts.
+
+ However, one of the main functions of ACPI is to make
+ the platform understand random hardware without
+ special driver support. So while the SCI handles a few
+ well known (fixed feature) interrupts sources, such
+ as the power button, it can also handle a variable
+ number of a "General Purpose Events" (GPE).
+
+ A GPE vectors to a specified handler in AML, which
+ can do a anything the BIOS writer wants from
+ OS context. GPE 0x12, for example, would vector
+ to a level or edge handler called _L12 or _E12.
+ The handler may do its business and return.
+ Or the handler may send send a Notify event
+ to a Linux device driver registered on an ACPI device,
+ such as a battery, or a processor.
+
+ To figure out where all the SCI's are coming from,
+ /sys/firmware/acpi/interrupts contains a file listing
+ every possible source, and the count of how many
+ times it has triggered.
+
+ $ cd /sys/firmware/acpi/interrupts
+ $ grep . *
+ error:0
+ ff_gbl_lock:0
+ ff_pmtimer:0
+ ff_pwr_btn:0
+ ff_rt_clk:0
+ ff_slp_btn:0
+ gpe00:0
+ gpe01:0
+ gpe02:0
+ gpe03:0
+ gpe04:0
+ gpe05:0
+ gpe06:0
+ gpe07:0
+ gpe08:0
+ gpe09:174
+ gpe0A:0
+ gpe0B:0
+ gpe0C:0
+ gpe0D:0
+ gpe0E:0
+ gpe0F:0
+ gpe10:0
+ gpe11:60
+ gpe12:0
+ gpe13:0
+ gpe14:0
+ gpe15:0
+ gpe16:0
+ gpe17:0
+ gpe18:0
+ gpe19:7
+ gpe1A:0
+ gpe1B:0
+ gpe1C:0
+ gpe1D:0
+ gpe1E:0
+ gpe1F:0
+ gpe_all:241
+ sci:241
+
+ sci - The total number of times the ACPI SCI
+ has claimed an interrupt.
+
+ gpe_all - count of SCI caused by GPEs.
+
+ gpeXX - count for individual GPE source
+
+ ff_gbl_lock - Global Lock
+
+ ff_pmtimer - PM Timer
+
+ ff_pwr_btn - Power Button
+
+ ff_rt_clk - Real Time Clock
+
+ ff_slp_btn - Sleep Button
+
+ error - an interrupt that can't be accounted for above.
+
+ Root has permission to clear any of these counters. Eg.
+ # echo 0 > gpe11
+
+ All counters can be cleared by clearing the total "sci":
+ # echo 0 > sci
+
+ None of these counters has an effect on the function
+ of the system, they are simply statistics.
diff --git a/Documentation/BUG-HUNTING b/Documentation/BUG-HUNTING
index 35f5bd2..65022a8 100644
--- a/Documentation/BUG-HUNTING
+++ b/Documentation/BUG-HUNTING
@@ -53,7 +53,7 @@
[Sat Mar 2 10:32:33 PST 1996 KERNEL_BUG-HOWTO lm@sgi.com (Larry McVoy)]
-This is how to track down a bug if you know nothing about kernel hacking.
+This is how to track down a bug if you know nothing about kernel hacking.
It's a brute force approach but it works pretty well.
You need:
@@ -66,12 +66,12 @@
. Rebuild a revision that you believe works, install, and verify that.
. Do a binary search over the kernels to figure out which one
- introduced the bug. I.e., suppose 1.3.28 didn't have the bug, but
+ introduced the bug. I.e., suppose 1.3.28 didn't have the bug, but
you know that 1.3.69 does. Pick a kernel in the middle and build
that, like 1.3.50. Build & test; if it works, pick the mid point
between .50 and .69, else the mid point between .28 and .50.
. You'll narrow it down to the kernel that introduced the bug. You
- can probably do better than this but it gets tricky.
+ can probably do better than this but it gets tricky.
. Narrow it down to a subdirectory
@@ -81,27 +81,27 @@
directories:
Copy the non-working directory next to the working directory
- as "dir.63".
+ as "dir.63".
One directory at time, try moving the working directory to
- "dir.62" and mv dir.63 dir"time, try
+ "dir.62" and mv dir.63 dir"time, try
mv dir dir.62
mv dir.63 dir
find dir -name '*.[oa]' -print | xargs rm -f
And then rebuild and retest. Assuming that all related
- changes were contained in the sub directory, this should
- isolate the change to a directory.
+ changes were contained in the sub directory, this should
+ isolate the change to a directory.
Problems: changes in header files may have occurred; I've
- found in my case that they were self explanatory - you may
+ found in my case that they were self explanatory - you may
or may not want to give up when that happens.
. Narrow it down to a file
- You can apply the same technique to each file in the directory,
- hoping that the changes in that file are self contained.
-
+ hoping that the changes in that file are self contained.
+
. Narrow it down to a routine
- You can take the old file and the new file and manually create
@@ -130,7 +130,7 @@
that makes the difference.
Finally, you take all the info that you have, kernel revisions, bug
-description, the extent to which you have narrowed it down, and pass
+description, the extent to which you have narrowed it down, and pass
that off to whomever you believe is the maintainer of that section.
A post to linux.dev.kernel isn't such a bad idea if you've done some
work to narrow it down.
@@ -214,6 +214,23 @@
gdb vmlinux
(gdb) p vt_ioctl
(gdb) l *(0x<address of vt_ioctl> + 0xda8)
+or, as one command
+ (gdb) l *(vt_ioctl + 0xda8)
+
+If you have a call trace, such as :-
+>Call Trace:
+> [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
+> [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
+> [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
+> ...
+this shows the problem in the :jbd: module. You can load that module in gdb
+and list the relevant code.
+ gdb fs/jbd/jbd.ko
+ (gdb) p log_wait_commit
+ (gdb) l *(0x<address> + 0xa3)
+or
+ (gdb) l *(log_wait_commit + 0xa3)
+
Another very useful option of the Kernel Hacking section in menuconfig is
Debug memory allocations. This will help you see whether data has been
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 77436d73..059aaf2 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -165,6 +165,7 @@
!Emm/vmalloc.c
!Imm/page_alloc.c
!Emm/mempool.c
+!Emm/dmapool.c
!Emm/page-writeback.c
!Emm/truncate.c
</sect1>
@@ -371,7 +372,6 @@
!Edrivers/base/class.c
!Edrivers/base/firmware_class.c
!Edrivers/base/transport_class.c
-!Edrivers/base/dmapool.c
<!-- Cannot be included, because
attribute_container_add_class_device_adapter
and attribute_container_classdev_to_container
diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
index 01825ee..2e9d6b4 100644
--- a/Documentation/DocBook/kernel-locking.tmpl
+++ b/Documentation/DocBook/kernel-locking.tmpl
@@ -717,7 +717,7 @@
<para>
For our first example, we assume that all operations are in user
context (ie. from system calls), so we can sleep. This means we can
-use a semaphore to protect the cache and all the objects within
+use a mutex to protect the cache and all the objects within
it. Here's the code:
</para>
@@ -725,7 +725,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/errno.h>
struct object
@@ -737,7 +737,7 @@
};
/* Protects the cache, cache_num, and the objects within it */
-static DECLARE_MUTEX(cache_lock);
+static DEFINE_MUTEX(cache_lock);
static LIST_HEAD(cache);
static unsigned int cache_num = 0;
#define MAX_CACHE_SIZE 10
@@ -789,17 +789,17 @@
obj->id = id;
obj->popularity = 0;
- down(&cache_lock);
+ mutex_lock(&cache_lock);
__cache_add(obj);
- up(&cache_lock);
+ mutex_unlock(&cache_lock);
return 0;
}
void cache_delete(int id)
{
- down(&cache_lock);
+ mutex_lock(&cache_lock);
__cache_delete(__cache_find(id));
- up(&cache_lock);
+ mutex_unlock(&cache_lock);
}
int cache_find(int id, char *name)
@@ -807,13 +807,13 @@
struct object *obj;
int ret = -ENOENT;
- down(&cache_lock);
+ mutex_lock(&cache_lock);
obj = __cache_find(id);
if (obj) {
ret = 0;
strcpy(name, obj->name);
}
- up(&cache_lock);
+ mutex_unlock(&cache_lock);
return ret;
}
</programlisting>
@@ -853,7 +853,7 @@
int popularity;
};
--static DECLARE_MUTEX(cache_lock);
+-static DEFINE_MUTEX(cache_lock);
+static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(cache);
static unsigned int cache_num = 0;
@@ -870,22 +870,22 @@
obj->id = id;
obj->popularity = 0;
-- down(&cache_lock);
+- mutex_lock(&cache_lock);
+ spin_lock_irqsave(&cache_lock, flags);
__cache_add(obj);
-- up(&cache_lock);
+- mutex_unlock(&cache_lock);
+ spin_unlock_irqrestore(&cache_lock, flags);
return 0;
}
void cache_delete(int id)
{
-- down(&cache_lock);
+- mutex_lock(&cache_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&cache_lock, flags);
__cache_delete(__cache_find(id));
-- up(&cache_lock);
+- mutex_unlock(&cache_lock);
+ spin_unlock_irqrestore(&cache_lock, flags);
}
@@ -895,14 +895,14 @@
int ret = -ENOENT;
+ unsigned long flags;
-- down(&cache_lock);
+- mutex_lock(&cache_lock);
+ spin_lock_irqsave(&cache_lock, flags);
obj = __cache_find(id);
if (obj) {
ret = 0;
strcpy(name, obj->name);
}
-- up(&cache_lock);
+- mutex_unlock(&cache_lock);
+ spin_unlock_irqrestore(&cache_lock, flags);
return ret;
}
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
index 3d2f31b..4acc732 100644
--- a/Documentation/DocBook/s390-drivers.tmpl
+++ b/Documentation/DocBook/s390-drivers.tmpl
@@ -59,7 +59,7 @@
<title>Introduction</title>
<para>
This document describes the interfaces available for device drivers that
- drive s390 based channel attached devices. This includes interfaces for
+ drive s390 based channel attached I/O devices. This includes interfaces for
interaction with the hardware and interfaces for interacting with the
common driver core. Those interfaces are provided by the s390 common I/O
layer.
@@ -86,9 +86,10 @@
The ccw bus typically contains the majority of devices available to
a s390 system. Named after the channel command word (ccw), the basic
command structure used to address its devices, the ccw bus contains
- so-called channel attached devices. They are addressed via subchannels,
- visible on the css bus. A device driver, however, will never interact
- with the subchannel directly, but only via the device on the ccw bus,
+ so-called channel attached devices. They are addressed via I/O
+ subchannels, visible on the css bus. A device driver for
+ channel-attached devices, however, will never interact with the
+ subchannel directly, but only via the I/O device on the ccw bus,
the ccw device.
</para>
<sect1 id="channelIO">
@@ -116,7 +117,6 @@
!Iinclude/asm-s390/ccwdev.h
!Edrivers/s390/cio/device.c
!Edrivers/s390/cio/device_ops.c
-!Edrivers/s390/cio/airq.c
</sect1>
<sect1 id="cmf">
<title>The channel-measurement facility</title>
@@ -147,4 +147,15 @@
</sect1>
</chapter>
+ <chapter id="genericinterfaces">
+ <title>Generic interfaces</title>
+ <para>
+ Some interfaces are available to other drivers that do not necessarily
+ have anything to do with the busses described above, but still are
+ indirectly using basic infrastructure in the common I/O layer.
+ One example is the support for adapter interrupts.
+ </para>
+!Edrivers/s390/cio/airq.c
+ </chapter>
+
</book>
diff --git a/Documentation/Smack.txt b/Documentation/Smack.txt
new file mode 100644
index 0000000..989c2fc
--- /dev/null
+++ b/Documentation/Smack.txt
@@ -0,0 +1,493 @@
+
+
+ "Good for you, you've decided to clean the elevator!"
+ - The Elevator, from Dark Star
+
+Smack is the the Simplified Mandatory Access Control Kernel.
+Smack is a kernel based implementation of mandatory access
+control that includes simplicity in its primary design goals.
+
+Smack is not the only Mandatory Access Control scheme
+available for Linux. Those new to Mandatory Access Control
+are encouraged to compare Smack with the other mechanisms
+available to determine which is best suited to the problem
+at hand.
+
+Smack consists of three major components:
+ - The kernel
+ - A start-up script and a few modified applications
+ - Configuration data
+
+The kernel component of Smack is implemented as a Linux
+Security Modules (LSM) module. It requires netlabel and
+works best with file systems that support extended attributes,
+although xattr support is not strictly required.
+It is safe to run a Smack kernel under a "vanilla" distribution.
+Smack kernels use the CIPSO IP option. Some network
+configurations are intolerant of IP options and can impede
+access to systems that use them as Smack does.
+
+The startup script etc-init.d-smack should be installed
+in /etc/init.d/smack and should be invoked early in the
+start-up process. On Fedora rc5.d/S02smack is recommended.
+This script ensures that certain devices have the correct
+Smack attributes and loads the Smack configuration if
+any is defined. This script invokes two programs that
+ensure configuration data is properly formatted. These
+programs are /usr/sbin/smackload and /usr/sin/smackcipso.
+The system will run just fine without these programs,
+but it will be difficult to set access rules properly.
+
+A version of "ls" that provides a "-M" option to display
+Smack labels on long listing is available.
+
+A hacked version of sshd that allows network logins by users
+with specific Smack labels is available. This version does
+not work for scp. You must set the /etc/ssh/sshd_config
+line:
+ UsePrivilegeSeparation no
+
+The format of /etc/smack/usr is:
+
+ username smack
+
+In keeping with the intent of Smack, configuration data is
+minimal and not strictly required. The most important
+configuration step is mounting the smackfs pseudo filesystem.
+
+Add this line to /etc/fstab:
+
+ smackfs /smack smackfs smackfsdef=* 0 0
+
+and create the /smack directory for mounting.
+
+Smack uses extended attributes (xattrs) to store file labels.
+The command to set a Smack label on a file is:
+
+ # attr -S -s SMACK64 -V "value" path
+
+NOTE: Smack labels are limited to 23 characters. The attr command
+ does not enforce this restriction and can be used to set
+ invalid Smack labels on files.
+
+If you don't do anything special all users will get the floor ("_")
+label when they log in. If you do want to log in via the hacked ssh
+at other labels use the attr command to set the smack value on the
+home directory and it's contents.
+
+You can add access rules in /etc/smack/accesses. They take the form:
+
+ subjectlabel objectlabel access
+
+access is a combination of the letters rwxa which specify the
+kind of access permitted a subject with subjectlabel on an
+object with objectlabel. If there is no rule no access is allowed.
+
+A process can see the smack label it is running with by
+reading /proc/self/attr/current. A privileged process can
+set the process smack by writing there.
+
+Look for additional programs on http://schaufler-ca.com
+
+From the Smack Whitepaper:
+
+The Simplified Mandatory Access Control Kernel
+
+Casey Schaufler
+casey@schaufler-ca.com
+
+Mandatory Access Control
+
+Computer systems employ a variety of schemes to constrain how information is
+shared among the people and services using the machine. Some of these schemes
+allow the program or user to decide what other programs or users are allowed
+access to pieces of data. These schemes are called discretionary access
+control mechanisms because the access control is specified at the discretion
+of the user. Other schemes do not leave the decision regarding what a user or
+program can access up to users or programs. These schemes are called mandatory
+access control mechanisms because you don't have a choice regarding the users
+or programs that have access to pieces of data.
+
+Bell & LaPadula
+
+From the middle of the 1980's until the turn of the century Mandatory Access
+Control (MAC) was very closely associated with the Bell & LaPadula security
+model, a mathematical description of the United States Department of Defense
+policy for marking paper documents. MAC in this form enjoyed a following
+within the Capital Beltway and Scandinavian supercomputer centers but was
+often sited as failing to address general needs.
+
+Domain Type Enforcement
+
+Around the turn of the century Domain Type Enforcement (DTE) became popular.
+This scheme organizes users, programs, and data into domains that are
+protected from each other. This scheme has been widely deployed as a component
+of popular Linux distributions. The administrative overhead required to
+maintain this scheme and the detailed understanding of the whole system
+necessary to provide a secure domain mapping leads to the scheme being
+disabled or used in limited ways in the majority of cases.
+
+Smack
+
+Smack is a Mandatory Access Control mechanism designed to provide useful MAC
+while avoiding the pitfalls of its predecessors. The limitations of Bell &
+LaPadula are addressed by providing a scheme whereby access can be controlled
+according to the requirements of the system and its purpose rather than those
+imposed by an arcane government policy. The complexity of Domain Type
+Enforcement and avoided by defining access controls in terms of the access
+modes already in use.
+
+Smack Terminology
+
+The jargon used to talk about Smack will be familiar to those who have dealt
+with other MAC systems and shouldn't be too difficult for the uninitiated to
+pick up. There are four terms that are used in a specific way and that are
+especially important:
+
+ Subject: A subject is an active entity on the computer system.
+ On Smack a subject is a task, which is in turn the basic unit
+ of execution.
+
+ Object: An object is a passive entity on the computer system.
+ On Smack files of all types, IPC, and tasks can be objects.
+
+ Access: Any attempt by a subject to put information into or get
+ information from an object is an access.
+
+ Label: Data that identifies the Mandatory Access Control
+ characteristics of a subject or an object.
+
+These definitions are consistent with the traditional use in the security
+community. There are also some terms from Linux that are likely to crop up:
+
+ Capability: A task that possesses a capability has permission to
+ violate an aspect of the system security policy, as identified by
+ the specific capability. A task that possesses one or more
+ capabilities is a privileged task, whereas a task with no
+ capabilities is an unprivileged task.
+
+ Privilege: A task that is allowed to violate the system security
+ policy is said to have privilege. As of this writing a task can
+ have privilege either by possessing capabilities or by having an
+ effective user of root.
+
+Smack Basics
+
+Smack is an extension to a Linux system. It enforces additional restrictions
+on what subjects can access which objects, based on the labels attached to
+each of the subject and the object.
+
+Labels
+
+Smack labels are ASCII character strings, one to twenty-three characters in
+length. Single character labels using special characters, that being anything
+other than a letter or digit, are reserved for use by the Smack development
+team. Smack labels are unstructured, case sensitive, and the only operation
+ever performed on them is comparison for equality. Smack labels cannot
+contain unprintable characters or the "/" (slash) character.
+
+There are some predefined labels:
+
+ _ Pronounced "floor", a single underscore character.
+ ^ Pronounced "hat", a single circumflex character.
+ * Pronounced "star", a single asterisk character.
+ ? Pronounced "huh", a single question mark character.
+
+Every task on a Smack system is assigned a label. System tasks, such as
+init(8) and systems daemons, are run with the floor ("_") label. User tasks
+are assigned labels according to the specification found in the
+/etc/smack/user configuration file.
+
+Access Rules
+
+Smack uses the traditional access modes of Linux. These modes are read,
+execute, write, and occasionally append. There are a few cases where the
+access mode may not be obvious. These include:
+
+ Signals: A signal is a write operation from the subject task to
+ the object task.
+ Internet Domain IPC: Transmission of a packet is considered a
+ write operation from the source task to the destination task.
+
+Smack restricts access based on the label attached to a subject and the label
+attached to the object it is trying to access. The rules enforced are, in
+order:
+
+ 1. Any access requested by a task labeled "*" is denied.
+ 2. A read or execute access requested by a task labeled "^"
+ is permitted.
+ 3. A read or execute access requested on an object labeled "_"
+ is permitted.
+ 4. Any access requested on an object labeled "*" is permitted.
+ 5. Any access requested by a task on an object with the same
+ label is permitted.
+ 6. Any access requested that is explicitly defined in the loaded
+ rule set is permitted.
+ 7. Any other access is denied.
+
+Smack Access Rules
+
+With the isolation provided by Smack access separation is simple. There are
+many interesting cases where limited access by subjects to objects with
+different labels is desired. One example is the familiar spy model of
+sensitivity, where a scientist working on a highly classified project would be
+able to read documents of lower classifications and anything she writes will
+be "born" highly classified. To accommodate such schemes Smack includes a
+mechanism for specifying rules allowing access between labels.
+
+Access Rule Format
+
+The format of an access rule is:
+
+ subject-label object-label access
+
+Where subject-label is the Smack label of the task, object-label is the Smack
+label of the thing being accessed, and access is a string specifying the sort
+of access allowed. The Smack labels are limited to 23 characters. The access
+specification is searched for letters that describe access modes:
+
+ a: indicates that append access should be granted.
+ r: indicates that read access should be granted.
+ w: indicates that write access should be granted.
+ x: indicates that execute access should be granted.
+
+Uppercase values for the specification letters are allowed as well.
+Access mode specifications can be in any order. Examples of acceptable rules
+are:
+
+ TopSecret Secret rx
+ Secret Unclass R
+ Manager Game x
+ User HR w
+ New Old rRrRr
+ Closed Off -
+
+Examples of unacceptable rules are:
+
+ Top Secret Secret rx
+ Ace Ace r
+ Odd spells waxbeans
+
+Spaces are not allowed in labels. Since a subject always has access to files
+with the same label specifying a rule for that case is pointless. Only
+valid letters (rwxaRWXA) and the dash ('-') character are allowed in
+access specifications. The dash is a placeholder, so "a-r" is the same
+as "ar". A lone dash is used to specify that no access should be allowed.
+
+Applying Access Rules
+
+The developers of Linux rarely define new sorts of things, usually importing
+schemes and concepts from other systems. Most often, the other systems are
+variants of Unix. Unix has many endearing properties, but consistency of
+access control models is not one of them. Smack strives to treat accesses as
+uniformly as is sensible while keeping with the spirit of the underlying
+mechanism.
+
+File system objects including files, directories, named pipes, symbolic links,
+and devices require access permissions that closely match those used by mode
+bit access. To open a file for reading read access is required on the file. To
+search a directory requires execute access. Creating a file with write access
+requires both read and write access on the containing directory. Deleting a
+file requires read and write access to the file and to the containing
+directory. It is possible that a user may be able to see that a file exists
+but not any of its attributes by the circumstance of having read access to the
+containing directory but not to the differently labeled file. This is an
+artifact of the file name being data in the directory, not a part of the file.
+
+IPC objects, message queues, semaphore sets, and memory segments exist in flat
+namespaces and access requests are only required to match the object in
+question.
+
+Process objects reflect tasks on the system and the Smack label used to access
+them is the same Smack label that the task would use for its own access
+attempts. Sending a signal via the kill() system call is a write operation
+from the signaler to the recipient. Debugging a process requires both reading
+and writing. Creating a new task is an internal operation that results in two
+tasks with identical Smack labels and requires no access checks.
+
+Sockets are data structures attached to processes and sending a packet from
+one process to another requires that the sender have write access to the
+receiver. The receiver is not required to have read access to the sender.
+
+Setting Access Rules
+
+The configuration file /etc/smack/accesses contains the rules to be set at
+system startup. The contents are written to the special file /smack/load.
+Rules can be written to /smack/load at any time and take effect immediately.
+For any pair of subject and object labels there can be only one rule, with the
+most recently specified overriding any earlier specification.
+
+The program smackload is provided to ensure data is formatted
+properly when written to /smack/load. This program reads lines
+of the form
+
+ subjectlabel objectlabel mode.
+
+Task Attribute
+
+The Smack label of a process can be read from /proc/<pid>/attr/current. A
+process can read its own Smack label from /proc/self/attr/current. A
+privileged process can change its own Smack label by writing to
+/proc/self/attr/current but not the label of another process.
+
+File Attribute
+
+The Smack label of a filesystem object is stored as an extended attribute
+named SMACK64 on the file. This attribute is in the security namespace. It can
+only be changed by a process with privilege.
+
+Privilege
+
+A process with CAP_MAC_OVERRIDE is privileged.
+
+Smack Networking
+
+As mentioned before, Smack enforces access control on network protocol
+transmissions. Every packet sent by a Smack process is tagged with its Smack
+label. This is done by adding a CIPSO tag to the header of the IP packet. Each
+packet received is expected to have a CIPSO tag that identifies the label and
+if it lacks such a tag the network ambient label is assumed. Before the packet
+is delivered a check is made to determine that a subject with the label on the
+packet has write access to the receiving process and if that is not the case
+the packet is dropped.
+
+CIPSO Configuration
+
+It is normally unnecessary to specify the CIPSO configuration. The default
+values used by the system handle all internal cases. Smack will compose CIPSO
+label values to match the Smack labels being used without administrative
+intervention. Unlabeled packets that come into the system will be given the
+ambient label.
+
+Smack requires configuration in the case where packets from a system that is
+not smack that speaks CIPSO may be encountered. Usually this will be a Trusted
+Solaris system, but there are other, less widely deployed systems out there.
+CIPSO provides 3 important values, a Domain Of Interpretation (DOI), a level,
+and a category set with each packet. The DOI is intended to identify a group
+of systems that use compatible labeling schemes, and the DOI specified on the
+smack system must match that of the remote system or packets will be
+discarded. The DOI is 3 by default. The value can be read from /smack/doi and
+can be changed by writing to /smack/doi.
+
+The label and category set are mapped to a Smack label as defined in
+/etc/smack/cipso.
+
+A Smack/CIPSO mapping has the form:
+
+ smack level [category [category]*]
+
+Smack does not expect the level or category sets to be related in any
+particular way and does not assume or assign accesses based on them. Some
+examples of mappings:
+
+ TopSecret 7
+ TS:A,B 7 1 2
+ SecBDE 5 2 4 6
+ RAFTERS 7 12 26
+
+The ":" and "," characters are permitted in a Smack label but have no special
+meaning.
+
+The mapping of Smack labels to CIPSO values is defined by writing to
+/smack/cipso. Again, the format of data written to this special file
+is highly restrictive, so the program smackcipso is provided to
+ensure the writes are done properly. This program takes mappings
+on the standard input and sends them to /smack/cipso properly.
+
+In addition to explicit mappings Smack supports direct CIPSO mappings. One
+CIPSO level is used to indicate that the category set passed in the packet is
+in fact an encoding of the Smack label. The level used is 250 by default. The
+value can be read from /smack/direct and changed by writing to /smack/direct.
+
+Socket Attributes
+
+There are two attributes that are associated with sockets. These attributes
+can only be set by privileged tasks, but any task can read them for their own
+sockets.
+
+ SMACK64IPIN: The Smack label of the task object. A privileged
+ program that will enforce policy may set this to the star label.
+
+ SMACK64IPOUT: The Smack label transmitted with outgoing packets.
+ A privileged program may set this to match the label of another
+ task with which it hopes to communicate.
+
+Writing Applications for Smack
+
+There are three sorts of applications that will run on a Smack system. How an
+application interacts with Smack will determine what it will have to do to
+work properly under Smack.
+
+Smack Ignorant Applications
+
+By far the majority of applications have no reason whatever to care about the
+unique properties of Smack. Since invoking a program has no impact on the
+Smack label associated with the process the only concern likely to arise is
+whether the process has execute access to the program.
+
+Smack Relevant Applications
+
+Some programs can be improved by teaching them about Smack, but do not make
+any security decisions themselves. The utility ls(1) is one example of such a
+program.
+
+Smack Enforcing Applications
+
+These are special programs that not only know about Smack, but participate in
+the enforcement of system policy. In most cases these are the programs that
+set up user sessions. There are also network services that provide information
+to processes running with various labels.
+
+File System Interfaces
+
+Smack maintains labels on file system objects using extended attributes. The
+Smack label of a file, directory, or other file system object can be obtained
+using getxattr(2).
+
+ len = getxattr("/", "security.SMACK64", value, sizeof (value));
+
+will put the Smack label of the root directory into value. A privileged
+process can set the Smack label of a file system object with setxattr(2).
+
+ len = strlen("Rubble");
+ rc = setxattr("/foo", "security.SMACK64", "Rubble", len, 0);
+
+will set the Smack label of /foo to "Rubble" if the program has appropriate
+privilege.
+
+Socket Interfaces
+
+The socket attributes can be read using fgetxattr(2).
+
+A privileged process can set the Smack label of outgoing packets with
+fsetxattr(2).
+
+ len = strlen("Rubble");
+ rc = fsetxattr(fd, "security.SMACK64IPOUT", "Rubble", len, 0);
+
+will set the Smack label "Rubble" on packets going out from the socket if the
+program has appropriate privilege.
+
+ rc = fsetxattr(fd, "security.SMACK64IPIN, "*", strlen("*"), 0);
+
+will set the Smack label "*" as the object label against which incoming
+packets will be checked if the program has appropriate privilege.
+
+Administration
+
+Smack supports some mount options:
+
+ smackfsdef=label: specifies the label to give files that lack
+ the Smack label extended attribute.
+
+ smackfsroot=label: specifies the label to assign the root of the
+ file system if it lacks the Smack extended attribute.
+
+ smackfshat=label: specifies a label that must have read access to
+ all labels set on the filesystem. Not yet enforced.
+
+ smackfsfloor=label: specifies a label to which all labels set on the
+ filesystem must have read access. Not yet enforced.
+
+These mount options apply to all file system types.
+
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 681e2b3..08a1ed1 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -220,20 +220,8 @@
Exception: If your mailer is mangling patches then someone may ask
you to re-send them using MIME.
-
-WARNING: Some mailers like Mozilla send your messages with
----- message header ----
-Content-Type: text/plain; charset=us-ascii; format=flowed
----- message header ----
-The problem is that "format=flowed" makes some of the mailers
-on receiving side to replace TABs with spaces and do similar
-changes. Thus the patches from you can look corrupted.
-
-To fix this just make your mozilla defaults/pref/mailnews.js file to look like:
-pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
-pref("mailnews.display.disable_format_flowed_support", true);
-
-
+See Documentation/email-clients.txt for hints about configuring
+your e-mail client so that it sends your patches untouched.
8) E-mail size.
diff --git a/Documentation/acpi/method-tracing.txt b/Documentation/acpi/method-tracing.txt
new file mode 100644
index 0000000..f6efb1e
--- /dev/null
+++ b/Documentation/acpi/method-tracing.txt
@@ -0,0 +1,26 @@
+/sys/module/acpi/parameters/:
+
+trace_method_name
+ The AML method name that the user wants to trace
+
+trace_debug_layer
+ The temporary debug_layer used when tracing the method.
+ Using 0xffffffff by default if it is 0.
+
+trace_debug_level
+ The temporary debug_level used when tracing the method.
+ Using 0x00ffffff by default if it is 0.
+
+trace_state
+ The status of the tracing feature.
+
+ "enabled" means this feature is enabled
+ and the AML method is traced every time it's executed.
+
+ "1" means this feature is enabled and the AML method
+ will only be traced during the next execution.
+
+ "disabled" means this feature is disabled.
+ Users can enable/disable this debug tracing feature by
+ "echo string > /sys/module/acpi/parameters/trace_state".
+ "string" should be one of "enable", "disable" and "1".
diff --git a/Documentation/arm/Sharp-LH/IOBarrier b/Documentation/arm/Sharp-LH/IOBarrier
index c0d8853..2e953e2 100644
--- a/Documentation/arm/Sharp-LH/IOBarrier
+++ b/Documentation/arm/Sharp-LH/IOBarrier
@@ -32,7 +32,7 @@
only needs occurs after the SMC IO write cycle. The routines that
implement this work-around make an additional concession which is to
disable interrupts during the IO sequence. Other hardware devices
-(the LogicPD CPLD) have registers in the same the physical memory
+(the LogicPD CPLD) have registers in the same physical memory
region as the SMC chip. An interrupt might allow an access to one of
those registers while SMC IO is being performed.
diff --git a/Documentation/debugging-modules.txt b/Documentation/debugging-modules.txt
index 24029f6..172ad4a 100644
--- a/Documentation/debugging-modules.txt
+++ b/Documentation/debugging-modules.txt
@@ -16,3 +16,7 @@
echo 'exec /sbin/modprobe "$@"' >> /tmp/modprobe
chmod a+x /tmp/modprobe
echo /tmp/modprobe > /proc/sys/kernel/modprobe
+
+Note that the above applies only when the *kernel* is requesting
+that the module be loaded -- it won't have any effect if that module
+is being loaded explicitly using "modprobe" from userspace.
diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt
index 2a97320..83009fdc 100644
--- a/Documentation/driver-model/platform.txt
+++ b/Documentation/driver-model/platform.txt
@@ -122,15 +122,15 @@
using these calls except with such hotplug-deficient drivers.
struct platform_device *platform_device_alloc(
- char *name, unsigned id);
+ const char *name, int id);
You can use platform_device_alloc() to dynamically allocate a device, which
you will then initialize with resources and platform_device_register().
A better solution is usually:
struct platform_device *platform_device_register_simple(
- char *name, unsigned id,
- struct resource *res, unsigned nres);
+ const char *name, int id,
+ struct resource *res, unsigned int nres);
You can use platform_device_register_simple() as a one-step call to allocate
and register a device.
diff --git a/Documentation/fb/deferred_io.txt b/Documentation/fb/deferred_io.txt
index 63883a8..7483283 100644
--- a/Documentation/fb/deferred_io.txt
+++ b/Documentation/fb/deferred_io.txt
@@ -7,10 +7,10 @@
works:
- userspace app like Xfbdev mmaps framebuffer
-- deferred IO and driver sets up nopage and page_mkwrite handlers
+- deferred IO and driver sets up fault and page_mkwrite handlers
- userspace app tries to write to mmaped vaddress
-- we get pagefault and reach nopage handler
-- nopage handler finds and returns physical page
+- we get pagefault and reach fault handler
+- fault handler finds and returns physical page
- we get page_mkwrite where we add this page to a list
- schedule a workqueue task to be run after a delay
- app continues writing to that page with no additional cost. this is
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 181bff0..68ce130 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -156,22 +156,6 @@
---------------------------
-What: USB driver API moves to EXPORT_SYMBOL_GPL
-When: February 2008
-Files: include/linux/usb.h, drivers/usb/core/driver.c
-Why: The USB subsystem has changed a lot over time, and it has been
- possible to create userspace USB drivers using usbfs/libusb/gadgetfs
- that operate as fast as the USB bus allows. Because of this, the USB
- subsystem will not be allowing closed source kernel drivers to
- register with it, after this grace period is over. If anyone needs
- any help in converting their closed source drivers over to use the
- userspace filesystems, please contact the
- linux-usb-devel@lists.sourceforge.net mailing list, and the developers
- there will be glad to help you out.
-Who: Greg Kroah-Hartman <gregkh@suse.de>
-
----------------------------
-
What: vm_ops.nopage
When: Soon, provided in-kernel callers have been converted
Why: This interface is replaced by vm_ops.fault, but it has been around
@@ -224,13 +208,6 @@
---------------------------
-What: drivers depending on OSS_OBSOLETE
-When: options in 2.6.23, code in 2.6.25
-Why: obsolete OSS drivers
-Who: Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
What: libata spindown skipping and warning
When: Dec 2008
Why: Some halt(8) implementations synchronize caches for and spin
diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index d1b9825..44c97e6 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -377,7 +377,7 @@
Rather than have a group where some items behave differently than
others, configfs provides a method whereby one or many subgroups are
automatically created inside the parent at its creation. Thus,
-mkdir("parent) results in "parent", "parent/subgroup1", up through
+mkdir("parent") results in "parent", "parent/subgroup1", up through
"parent/subgroupN". Items of type 1 can now be created in
"parent/subgroup1", and items of type N can be created in
"parent/subgroupN".
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index dac45c9..0f33c77 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -1,6 +1,6 @@
Changes since 2.5.0:
----
+---
[recommended]
New helpers: sb_bread(), sb_getblk(), sb_find_get_block(), set_bh(),
@@ -10,7 +10,7 @@
(sb_find_get_block() replaces 2.4's get_hash_table())
----
+---
[recommended]
New methods: ->alloc_inode() and ->destroy_inode().
@@ -28,7 +28,7 @@
Use FOO_I(inode) instead of &inode->u.foo_inode_i;
-Add foo_alloc_inode() and foo_destory_inode() - the former should allocate
+Add foo_alloc_inode() and foo_destroy_inode() - the former should allocate
foo_inode_info and return the address of ->vfs_inode, the latter should free
FOO_I(inode) (see in-tree filesystems for examples).
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 194c8f35..5681e2f 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -216,6 +216,7 @@
priority priority level
nice nice level
num_threads number of threads
+ it_real_value (obsolete, always 0)
start_time time the process started after system boot
vsize virtual memory size
rss resident set memory size
@@ -1028,6 +1029,14 @@
Denotes the number of inodes the system has allocated. This number will
grow and shrink dynamically.
+nr_open
+-------
+
+Denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
nr_free_inodes
--------------
@@ -1314,13 +1323,28 @@
Data which has been dirty in-memory for longer than this interval will be
written out next time a pdflush daemon wakes up.
+highmem_is_dirtyable
+--------------------
+
+Only present if CONFIG_HIGHMEM is set.
+
+This defaults to 0 (false), meaning that the ratios set above are calculated
+as a percentage of lowmem only. This protects against excessive scanning
+in page reclaim, swapping and general VM distress.
+
+Setting this to 1 can be useful on 32 bit machines where you want to make
+random changes within an MMAPed file that is larger than your available
+lowmem without causing large quantities of random IO. Is is safe if the
+behavior of all programs running on the machine is known and memory will
+not be otherwise stressed.
+
legacy_va_layout
----------------
If non-zero, this sysctl disables the new 32-bit mmap mmap layout - the kernel
will use the legacy (2.4) layout for all processes.
-lower_zone_protection
+lowmem_reserve_ratio
---------------------
For some specialised workloads on highmem machines it is dangerous for
@@ -1340,25 +1364,71 @@
mechanism will also defend that region from allocations which could use
highmem or lowmem).
-The `lower_zone_protection' tunable determines how aggressive the kernel is
-in defending these lower zones. The default value is zero - no
-protection at all.
+The `lowmem_reserve_ratio' tunable determines how aggressive the kernel is
+in defending these lower zones.
If you have a machine which uses highmem or ISA DMA and your
applications are using mlock(), or if you are running with no swap then
-you probably should increase the lower_zone_protection setting.
+you probably should change the lowmem_reserve_ratio setting.
-The units of this tunable are fairly vague. It is approximately equal
-to "megabytes," so setting lower_zone_protection=100 will protect around 100
-megabytes of the lowmem zone from user allocations. It will also make
-those 100 megabytes unavailable for use by applications and by
-pagecache, so there is a cost.
+The lowmem_reserve_ratio is an array. You can see them by reading this file.
+-
+% cat /proc/sys/vm/lowmem_reserve_ratio
+256 256 32
+-
+Note: # of this elements is one fewer than number of zones. Because the highest
+ zone's value is not necessary for following calculation.
-The effects of this tunable may be observed by monitoring
-/proc/meminfo:LowFree. Write a single huge file and observe the point
-at which LowFree ceases to fall.
+But, these values are not used directly. The kernel calculates # of protection
+pages for each zones from them. These are shown as array of protection pages
+in /proc/zoneinfo like followings. (This is an example of x86-64 box).
+Each zone has an array of protection pages like this.
-A reasonable value for lower_zone_protection is 100.
+-
+Node 0, zone DMA
+ pages free 1355
+ min 3
+ low 3
+ high 4
+ :
+ :
+ numa_other 0
+ protection: (0, 2004, 2004, 2004)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ pagesets
+ cpu: 0 pcp: 0
+ :
+-
+These protections are added to score to judge whether this zone should be used
+for page allocation or should be reclaimed.
+
+In this example, if normal pages (index=2) are required to this DMA zone and
+pages_high is used for watermark, the kernel judges this zone should not be
+used because pages_free(1355) is smaller than watermark + protection[2]
+(4 + 2004 = 2008). If this protection value is 0, this zone would be used for
+normal page requirement. If requirement is DMA zone(index=0), protection[0]
+(=0) is used.
+
+zone[i]'s protection[j] is calculated by following exprssion.
+
+(i < j):
+ zone[i]->protection[j]
+ = (total sums of present_pages from zone[i+1] to zone[j] on the node)
+ / lowmem_reserve_ratio[i];
+(i = j):
+ (should not be protected. = 0;
+(i > j):
+ (not necessary, but looks 0)
+
+The default values of lowmem_reserve_ratio[i] are
+ 256 (if zone[i] means DMA or DMA32 zone)
+ 32 (others).
+As above expression, they are reciprocal number of ratio.
+256 means 1/256. # of protection pages becomes about "0.39%" of total present
+pages of higher zones on the node.
+
+If you would like to protect more pages, smaller values are effective.
+The minimum value is 1 (1/1 -> 100%).
page-cluster
------------
diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
index 339c6a4..7be232b 100644
--- a/Documentation/filesystems/ramfs-rootfs-initramfs.txt
+++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
@@ -118,7 +118,7 @@
with the new root (cd /newmount; mount --move . /; chroot .), attach
stdin/stdout/stderr to the new /dev/console, and exec the new init.
- Since this is a remarkably persnickity process (and involves deleting
+ Since this is a remarkably persnickety process (and involves deleting
commands before you can run them), the klibc package introduced a helper
program (utils/run_init.c) to do all this for you. Most other packages
(such as busybox) have named this command "switch_root".
diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt
index 18d23f9..094f2d2 100644
--- a/Documentation/filesystems/relay.txt
+++ b/Documentation/filesystems/relay.txt
@@ -140,7 +140,7 @@
In order for a user application to make use of relay files, the
host filesystem must be mounted. For example,
- mount -t debugfs debugfs /debug
+ mount -t debugfs debugfs /sys/kernel/debug
NOTE: the host filesystem doesn't need to be mounted for kernel
clients to create or use channels - it only needs to be
diff --git a/Documentation/fujitsu/frv/README.txt b/Documentation/frv/README.txt
similarity index 100%
rename from Documentation/fujitsu/frv/README.txt
rename to Documentation/frv/README.txt
diff --git a/Documentation/fujitsu/frv/atomic-ops.txt b/Documentation/frv/atomic-ops.txt
similarity index 100%
rename from Documentation/fujitsu/frv/atomic-ops.txt
rename to Documentation/frv/atomic-ops.txt
diff --git a/Documentation/fujitsu/frv/booting.txt b/Documentation/frv/booting.txt
similarity index 98%
rename from Documentation/fujitsu/frv/booting.txt
rename to Documentation/frv/booting.txt
index 4e22905..ace200b 100644
--- a/Documentation/fujitsu/frv/booting.txt
+++ b/Documentation/frv/booting.txt
@@ -177,5 +177,5 @@
(*) vdc=...
This option configures the MB93493 companion chip visual display
- driver. Please see Documentation/fujitsu/mb93493/vdc.txt for more
+ driver. Please see Documentation/frv/mb93493/vdc.txt for more
information.
diff --git a/Documentation/fujitsu/frv/clock.txt b/Documentation/frv/clock.txt
similarity index 100%
rename from Documentation/fujitsu/frv/clock.txt
rename to Documentation/frv/clock.txt
diff --git a/Documentation/fujitsu/frv/configuring.txt b/Documentation/frv/configuring.txt
similarity index 100%
rename from Documentation/fujitsu/frv/configuring.txt
rename to Documentation/frv/configuring.txt
diff --git a/Documentation/fujitsu/frv/features.txt b/Documentation/frv/features.txt
similarity index 100%
rename from Documentation/fujitsu/frv/features.txt
rename to Documentation/frv/features.txt
diff --git a/Documentation/fujitsu/frv/gdbinit b/Documentation/frv/gdbinit
similarity index 100%
rename from Documentation/fujitsu/frv/gdbinit
rename to Documentation/frv/gdbinit
diff --git a/Documentation/fujitsu/frv/gdbstub.txt b/Documentation/frv/gdbstub.txt
similarity index 100%
rename from Documentation/fujitsu/frv/gdbstub.txt
rename to Documentation/frv/gdbstub.txt
diff --git a/Documentation/fujitsu/frv/kernel-ABI.txt b/Documentation/frv/kernel-ABI.txt
similarity index 100%
rename from Documentation/fujitsu/frv/kernel-ABI.txt
rename to Documentation/frv/kernel-ABI.txt
diff --git a/Documentation/fujitsu/frv/mmu-layout.txt b/Documentation/frv/mmu-layout.txt
similarity index 100%
rename from Documentation/fujitsu/frv/mmu-layout.txt
rename to Documentation/frv/mmu-layout.txt
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 6bc2ba2..8da724e 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -32,7 +32,7 @@
- Input values are likewise readable (1, 0). Some chips support readback
of pins configured as "output", which is very useful in such "wire-OR"
cases (to support bidirectional signaling). GPIO controllers may have
- input de-glitch logic, sometimes with software controls.
+ input de-glitch/debounce logic, sometimes with software controls.
- Inputs can often be used as IRQ signals, often edge triggered but
sometimes level triggered. Such IRQs may be configurable as system
@@ -60,10 +60,13 @@
functionality can be very portable. Other features are platform-specific,
and that can be critical for glue logic.
-Plus, this doesn't define an implementation framework, just an interface.
+Plus, this doesn't require any implementation framework, just an interface.
One platform might implement it as simple inline functions accessing chip
registers; another might implement it by delegating through abstractions
-used for several very different kinds of GPIO controller.
+used for several very different kinds of GPIO controller. (There is some
+optional code supporting such an implementation strategy, described later
+in this document, but drivers acting as clients to the GPIO interface must
+not care how it's implemented.)
That said, if the convention is supported on their platform, drivers should
use it when possible. Platforms should declare GENERIC_GPIO support in
@@ -121,6 +124,11 @@
For output GPIOs, the value provided becomes the initial output value.
This helps avoid signal glitching during system startup.
+For compatibility with legacy interfaces to GPIOs, setting the direction
+of a GPIO implicitly requests that GPIO (see below) if it has not been
+requested already. That compatibility may be removed in the future;
+explicitly requesting GPIOs is strongly preferred.
+
Setting the direction can fail if the GPIO number is invalid, or when
that particular GPIO can't be used in that mode. It's generally a bad
idea to rely on boot firmware to have set the direction correctly, since
@@ -133,6 +141,7 @@
-------------------------
Most GPIO controllers can be accessed with memory read/write instructions.
That doesn't need to sleep, and can safely be done from inside IRQ handlers.
+(That includes hardirq contexts on RT kernels.)
Use these calls to access such GPIOs:
@@ -145,7 +154,7 @@
The values are boolean, zero for low, nonzero for high. When reading the
value of an output pin, the value returned should be what's seen on the
pin ... that won't always match the specified output value, because of
-issues including wire-OR and output latencies.
+issues including open-drain signaling and output latencies.
The get/set calls have no error returns because "invalid GPIO" should have
been reported earlier from gpio_direction_*(). However, note that not all
@@ -170,7 +179,8 @@
This requires sleeping, which can't be done from inside IRQ handlers.
Platforms that support this type of GPIO distinguish them from other GPIOs
-by returning nonzero from this call:
+by returning nonzero from this call (which requires a valid GPIO number,
+either explicitly or implicitly requested):
int gpio_cansleep(unsigned gpio);
@@ -209,8 +219,11 @@
These calls serve two basic purposes. One is marking the signals which
are actually in use as GPIOs, for better diagnostics; systems may have
several hundred potential GPIOs, but often only a dozen are used on any
-given board. Another is to catch conflicts between drivers, reporting
-errors when drivers wrongly think they have exclusive use of that signal.
+given board. Another is to catch conflicts, identifying errors when
+(a) two or more drivers wrongly think they have exclusive use of that
+signal, or (b) something wrongly believes it's safe to remove drivers
+needed to manage a signal that's in active use. That is, requesting a
+GPIO can serve as a kind of lock.
These two calls are optional because not not all current Linux platforms
offer such functionality in their GPIO support; a valid implementation
@@ -223,6 +236,9 @@
way; it just marks that GPIO as in use. Separate code must handle any
pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
+Also note that it's your responsibility to have stopped using a GPIO
+before you free it.
+
GPIOs mapped to IRQs
--------------------
@@ -238,7 +254,7 @@
Those return either the corresponding number in the other namespace, or
else a negative errno code if the mapping can't be done. (For example,
-some GPIOs can't used as IRQs.) It is an unchecked error to use a GPIO
+some GPIOs can't be used as IRQs.) It is an unchecked error to use a GPIO
number that wasn't set up as an input using gpio_direction_input(), or
to use an IRQ number that didn't originally come from gpio_to_irq().
@@ -299,17 +315,110 @@
pulldowns integrated on some platforms. Not all platforms support them,
or support them in the same way; and any given board might use external
pullups (or pulldowns) so that the on-chip ones should not be used.
+(When a circuit needs 5 kOhm, on-chip 100 kOhm resistors won't do.)
There are other system-specific mechanisms that are not specified here,
like the aforementioned options for input de-glitching and wire-OR output.
Hardware may support reading or writing GPIOs in gangs, but that's usually
configuration dependent: for GPIOs sharing the same bank. (GPIOs are
commonly grouped in banks of 16 or 32, with a given SOC having several such
-banks.) Some systems can trigger IRQs from output GPIOs. Code relying on
-such mechanisms will necessarily be nonportable.
+banks.) Some systems can trigger IRQs from output GPIOs, or read values
+from pins not managed as GPIOs. Code relying on such mechanisms will
+necessarily be nonportable.
-Dynamic definition of GPIOs is not currently supported; for example, as
+Dynamic definition of GPIOs is not currently standard; for example, as
a side effect of configuring an add-on board with some GPIO expanders.
These calls are purely for kernel space, but a userspace API could be built
-on top of it.
+on top of them.
+
+
+GPIO implementor's framework (OPTIONAL)
+=======================================
+As noted earlier, there is an optional implementation framework making it
+easier for platforms to support different kinds of GPIO controller using
+the same programming interface.
+
+As a debugging aid, if debugfs is available a /sys/kernel/debug/gpio file
+will be found there. That will list all the controllers registered through
+this framework, and the state of the GPIOs currently in use.
+
+
+Controller Drivers: gpio_chip
+-----------------------------
+In this framework each GPIO controller is packaged as a "struct gpio_chip"
+with information common to each controller of that type:
+
+ - methods to establish GPIO direction
+ - methods used to access GPIO values
+ - flag saying whether calls to its methods may sleep
+ - optional debugfs dump method (showing extra state like pullup config)
+ - label for diagnostics
+
+There is also per-instance data, which may come from device.platform_data:
+the number of its first GPIO, and how many GPIOs it exposes.
+
+The code implementing a gpio_chip should support multiple instances of the
+controller, possibly using the driver model. That code will configure each
+gpio_chip and issue gpiochip_add(). Removing a GPIO controller should be
+rare; use gpiochip_remove() when it is unavoidable.
+
+Most often a gpio_chip is part of an instance-specific structure with state
+not exposed by the GPIO interfaces, such as addressing, power management,
+and more. Chips such as codecs will have complex non-GPIO state,
+
+Any debugfs dump method should normally ignore signals which haven't been
+requested as GPIOs. They can use gpiochip_is_requested(), which returns
+either NULL or the label associated with that GPIO when it was requested.
+
+
+Platform Support
+----------------
+To support this framework, a platform's Kconfig will "select HAVE_GPIO_LIB"
+and arrange that its <asm/gpio.h> includes <asm-generic/gpio.h> and defines
+three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep().
+They may also want to provide a custom value for ARCH_NR_GPIOS.
+
+Trivial implementations of those functions can directly use framework
+code, which always dispatches through the gpio_chip:
+
+ #define gpio_get_value __gpio_get_value
+ #define gpio_set_value __gpio_set_value
+ #define gpio_cansleep __gpio_cansleep
+
+Fancier implementations could instead define those as inline functions with
+logic optimizing access to specific SOC-based GPIOs. For example, if the
+referenced GPIO is the constant "12", getting or setting its value could
+cost as little as two or three instructions, never sleeping. When such an
+optimization is not possible those calls must delegate to the framework
+code, costing at least a few dozen instructions. For bitbanged I/O, such
+instruction savings can be significant.
+
+For SOCs, platform-specific code defines and registers gpio_chip instances
+for each bank of on-chip GPIOs. Those GPIOs should be numbered/labeled to
+match chip vendor documentation, and directly match board schematics. They
+may well start at zero and go up to a platform-specific limit. Such GPIOs
+are normally integrated into platform initialization to make them always be
+available, from arch_initcall() or earlier; they can often serve as IRQs.
+
+
+Board Support
+-------------
+For external GPIO controllers -- such as I2C or SPI expanders, ASICs, multi
+function devices, FPGAs or CPLDs -- most often board-specific code handles
+registering controller devices and ensures that their drivers know what GPIO
+numbers to use with gpiochip_add(). Their numbers often start right after
+platform-specific GPIOs.
+
+For example, board setup code could create structures identifying the range
+of GPIOs that chip will expose, and passes them to each GPIO expander chip
+using platform_data. Then the chip driver's probe() routine could pass that
+data to gpiochip_add().
+
+Initialization order can be important. For example, when a device relies on
+an I2C-based GPIO, its probe() routine should only be called after that GPIO
+becomes available. That may mean the device should not be registered until
+calls for that GPIO can work. One way to address such dependencies is for
+such gpio_chip controllers to provide setup() and teardown() callbacks to
+board specific code; those board specific callbacks would register devices
+once all the necessary resources are available.
diff --git a/Documentation/i2c/chips/pca9539 b/Documentation/i2c/chips/pca9539
index c4fce6a..1d81c53 100644
--- a/Documentation/i2c/chips/pca9539
+++ b/Documentation/i2c/chips/pca9539
@@ -1,6 +1,9 @@
Kernel driver pca9539
=====================
+NOTE: this driver is deprecated and will be dropped soon, use
+drivers/gpio/pca9539.c instead.
+
Supported chips:
* Philips PCA9539
Prefix: 'pca9539'
diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c
index 773a814..d23610f 100644
--- a/Documentation/ia64/aliasing-test.c
+++ b/Documentation/ia64/aliasing-test.c
@@ -16,6 +16,7 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <string.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -65,7 +66,7 @@
{
struct dirent **namelist;
char *name, *path2;
- int i, n, r, rc, result = 0;
+ int i, n, r, rc = 0, result = 0;
struct stat buf;
n = scandir(path, &namelist, 0, alphasort);
@@ -113,7 +114,7 @@
free(namelist[i]);
}
free(namelist);
- return rc;
+ return result;
}
char buf[1024];
@@ -149,7 +150,7 @@
{
struct dirent **namelist;
char *name, *path2;
- int i, n, r, rc, result = 0;
+ int i, n, r, rc = 0, result = 0;
struct stat buf;
n = scandir(path, &namelist, 0, alphasort);
@@ -180,7 +181,7 @@
* important thing is that no MCA happened.
*/
if (rc > 0)
- fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc);
+ fprintf(stderr, "PASS: %s read %d bytes\n", path2, rc);
else {
fprintf(stderr, "PASS: %s not readable\n", path2);
return rc;
@@ -201,10 +202,10 @@
free(namelist[i]);
}
free(namelist);
- return rc;
+ return result;
}
-int main()
+int main(void)
{
int rc;
@@ -256,4 +257,6 @@
scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0);
scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1);
scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0);
+
+ return rc;
}
diff --git a/Documentation/ide/ChangeLog.ide-tape.1995-2002 b/Documentation/ide/ChangeLog.ide-tape.1995-2002
new file mode 100644
index 0000000..877fac8
--- /dev/null
+++ b/Documentation/ide/ChangeLog.ide-tape.1995-2002
@@ -0,0 +1,257 @@
+/*
+ * Ver 0.1 Nov 1 95 Pre-working code :-)
+ * Ver 0.2 Nov 23 95 A short backup (few megabytes) and restore procedure
+ * was successful ! (Using tar cvf ... on the block
+ * device interface).
+ * A longer backup resulted in major swapping, bad
+ * overall Linux performance and eventually failed as
+ * we received non serial read-ahead requests from the
+ * buffer cache.
+ * Ver 0.3 Nov 28 95 Long backups are now possible, thanks to the
+ * character device interface. Linux's responsiveness
+ * and performance doesn't seem to be much affected
+ * from the background backup procedure.
+ * Some general mtio.h magnetic tape operations are
+ * now supported by our character device. As a result,
+ * popular tape utilities are starting to work with
+ * ide tapes :-)
+ * The following configurations were tested:
+ * 1. An IDE ATAPI TAPE shares the same interface
+ * and irq with an IDE ATAPI CDROM.
+ * 2. An IDE ATAPI TAPE shares the same interface
+ * and irq with a normal IDE disk.
+ * Both configurations seemed to work just fine !
+ * However, to be on the safe side, it is meanwhile
+ * recommended to give the IDE TAPE its own interface
+ * and irq.
+ * The one thing which needs to be done here is to
+ * add a "request postpone" feature to ide.c,
+ * so that we won't have to wait for the tape to finish
+ * performing a long media access (DSC) request (such
+ * as a rewind) before we can access the other device
+ * on the same interface. This effect doesn't disturb
+ * normal operation most of the time because read/write
+ * requests are relatively fast, and once we are
+ * performing one tape r/w request, a lot of requests
+ * from the other device can be queued and ide.c will
+ * service all of them after this single tape request.
+ * Ver 1.0 Dec 11 95 Integrated into Linux 1.3.46 development tree.
+ * On each read / write request, we now ask the drive
+ * if we can transfer a constant number of bytes
+ * (a parameter of the drive) only to its buffers,
+ * without causing actual media access. If we can't,
+ * we just wait until we can by polling the DSC bit.
+ * This ensures that while we are not transferring
+ * more bytes than the constant referred to above, the
+ * interrupt latency will not become too high and
+ * we won't cause an interrupt timeout, as happened
+ * occasionally in the previous version.
+ * While polling for DSC, the current request is
+ * postponed and ide.c is free to handle requests from
+ * the other device. This is handled transparently to
+ * ide.c. The hwgroup locking method which was used
+ * in the previous version was removed.
+ * Use of new general features which are provided by
+ * ide.c for use with atapi devices.
+ * (Programming done by Mark Lord)
+ * Few potential bug fixes (Again, suggested by Mark)
+ * Single character device data transfers are now
+ * not limited in size, as they were before.
+ * We are asking the tape about its recommended
+ * transfer unit and send a larger data transfer
+ * as several transfers of the above size.
+ * For best results, use an integral number of this
+ * basic unit (which is shown during driver
+ * initialization). I will soon add an ioctl to get
+ * this important parameter.
+ * Our data transfer buffer is allocated on startup,
+ * rather than before each data transfer. This should
+ * ensure that we will indeed have a data buffer.
+ * Ver 1.1 Dec 14 95 Fixed random problems which occurred when the tape
+ * shared an interface with another device.
+ * (poll_for_dsc was a complete mess).
+ * Removed some old (non-active) code which had
+ * to do with supporting buffer cache originated
+ * requests.
+ * The block device interface can now be opened, so
+ * that general ide driver features like the unmask
+ * interrupts flag can be selected with an ioctl.
+ * This is the only use of the block device interface.
+ * New fast pipelined operation mode (currently only on
+ * writes). When using the pipelined mode, the
+ * throughput can potentially reach the maximum
+ * tape supported throughput, regardless of the
+ * user backup program. On my tape drive, it sometimes
+ * boosted performance by a factor of 2. Pipelined
+ * mode is enabled by default, but since it has a few
+ * downfalls as well, you may want to disable it.
+ * A short explanation of the pipelined operation mode
+ * is available below.
+ * Ver 1.2 Jan 1 96 Eliminated pipelined mode race condition.
+ * Added pipeline read mode. As a result, restores
+ * are now as fast as backups.
+ * Optimized shared interface behavior. The new behavior
+ * typically results in better IDE bus efficiency and
+ * higher tape throughput.
+ * Pre-calculation of the expected read/write request
+ * service time, based on the tape's parameters. In
+ * the pipelined operation mode, this allows us to
+ * adjust our polling frequency to a much lower value,
+ * and thus to dramatically reduce our load on Linux,
+ * without any decrease in performance.
+ * Implemented additional mtio.h operations.
+ * The recommended user block size is returned by
+ * the MTIOCGET ioctl.
+ * Additional minor changes.
+ * Ver 1.3 Feb 9 96 Fixed pipelined read mode bug which prevented the
+ * use of some block sizes during a restore procedure.
+ * The character device interface will now present a
+ * continuous view of the media - any mix of block sizes
+ * during a backup/restore procedure is supported. The
+ * driver will buffer the requests internally and
+ * convert them to the tape's recommended transfer
+ * unit, making performance almost independent of the
+ * chosen user block size.
+ * Some improvements in error recovery.
+ * By cooperating with ide-dma.c, bus mastering DMA can
+ * now sometimes be used with IDE tape drives as well.
+ * Bus mastering DMA has the potential to dramatically
+ * reduce the CPU's overhead when accessing the device,
+ * and can be enabled by using hdparm -d1 on the tape's
+ * block device interface. For more info, read the
+ * comments in ide-dma.c.
+ * Ver 1.4 Mar 13 96 Fixed serialize support.
+ * Ver 1.5 Apr 12 96 Fixed shared interface operation, broken in 1.3.85.
+ * Fixed pipelined read mode inefficiency.
+ * Fixed nasty null dereferencing bug.
+ * Ver 1.6 Aug 16 96 Fixed FPU usage in the driver.
+ * Fixed end of media bug.
+ * Ver 1.7 Sep 10 96 Minor changes for the CONNER CTT8000-A model.
+ * Ver 1.8 Sep 26 96 Attempt to find a better balance between good
+ * interactive response and high system throughput.
+ * Ver 1.9 Nov 5 96 Automatically cross encountered filemarks rather
+ * than requiring an explicit FSF command.
+ * Abort pending requests at end of media.
+ * MTTELL was sometimes returning incorrect results.
+ * Return the real block size in the MTIOCGET ioctl.
+ * Some error recovery bug fixes.
+ * Ver 1.10 Nov 5 96 Major reorganization.
+ * Reduced CPU overhead a bit by eliminating internal
+ * bounce buffers.
+ * Added module support.
+ * Added multiple tape drives support.
+ * Added partition support.
+ * Rewrote DSC handling.
+ * Some portability fixes.
+ * Removed ide-tape.h.
+ * Additional minor changes.
+ * Ver 1.11 Dec 2 96 Bug fix in previous DSC timeout handling.
+ * Use ide_stall_queue() for DSC overlap.
+ * Use the maximum speed rather than the current speed
+ * to compute the request service time.
+ * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data
+ * corruption, which could occur if the total number
+ * of bytes written to the tape was not an integral
+ * number of tape blocks.
+ * Add support for INTERRUPT DRQ devices.
+ * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB
+ * Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives.
+ * Replace cli()/sti() with hwgroup spinlocks.
+ * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup
+ * spinlock with private per-tape spinlock.
+ * Ver 1.16 Sep 1 99 Add OnStream tape support.
+ * Abort read pipeline on EOD.
+ * Wait for the tape to become ready in case it returns
+ * "in the process of becoming ready" on open().
+ * Fix zero padding of the last written block in
+ * case the tape block size is larger than PAGE_SIZE.
+ * Decrease the default disconnection time to tn.
+ * Ver 1.16e Oct 3 99 Minor fixes.
+ * Ver 1.16e1 Oct 13 99 Patches by Arnold Niessen,
+ * niessen@iae.nl / arnold.niessen@philips.com
+ * GO-1) Undefined code in idetape_read_position
+ * according to Gadi's email
+ * AJN-1) Minor fix asc == 11 should be asc == 0x11
+ * in idetape_issue_packet_command (did effect
+ * debugging output only)
+ * AJN-2) Added more debugging output, and
+ * added ide-tape: where missing. I would also
+ * like to add tape->name where possible
+ * AJN-3) Added different debug_level's
+ * via /proc/ide/hdc/settings
+ * "debug_level" determines amount of debugging output;
+ * can be changed using /proc/ide/hdx/settings
+ * 0 : almost no debugging output
+ * 1 : 0+output errors only
+ * 2 : 1+output all sensekey/asc
+ * 3 : 2+follow all chrdev related procedures
+ * 4 : 3+follow all procedures
+ * 5 : 4+include pc_stack rq_stack info
+ * 6 : 5+USE_COUNT updates
+ * AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
+ * from 5 to 10 minutes
+ * AJN-5) Changed maximum number of blocks to skip when
+ * reading tapes with multiple consecutive write
+ * errors from 100 to 1000 in idetape_get_logical_blk
+ * Proposed changes to code:
+ * 1) output "logical_blk_num" via /proc
+ * 2) output "current_operation" via /proc
+ * 3) Either solve or document the fact that `mt rewind' is
+ * required after reading from /dev/nhtx to be
+ * able to rmmod the idetape module;
+ * Also, sometimes an application finishes but the
+ * device remains `busy' for some time. Same cause ?
+ * Proposed changes to release-notes:
+ * 4) write a simple `quickstart' section in the
+ * release notes; I volunteer if you don't want to
+ * 5) include a pointer to video4linux in the doc
+ * to stimulate video applications
+ * 6) release notes lines 331 and 362: explain what happens
+ * if the application data rate is higher than 1100 KB/s;
+ * similar approach to lower-than-500 kB/s ?
+ * 7) 6.6 Comparison; wouldn't it be better to allow different
+ * strategies for read and write ?
+ * Wouldn't it be better to control the tape buffer
+ * contents instead of the bandwidth ?
+ * 8) line 536: replace will by would (if I understand
+ * this section correctly, a hypothetical and unwanted situation
+ * is being described)
+ * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames.
+ * Ver 1.17 Nov 2000 / Jan 2001 Marcel Mol, marcel@mesa.nl
+ * - Add idetape_onstream_mode_sense_tape_parameter_page
+ * function to get tape capacity in frames: tape->capacity.
+ * - Add support for DI-50 drives( or any DI- drive).
+ * - 'workaround' for read error/blank block around block 3000.
+ * - Implement Early warning for end of media for Onstream.
+ * - Cosmetic code changes for readability.
+ * - Idetape_position_tape should not use SKIP bit during
+ * Onstream read recovery.
+ * - Add capacity, logical_blk_num and first/last_frame_position
+ * to /proc/ide/hd?/settings.
+ * - Module use count was gone in the Linux 2.4 driver.
+ * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
+ * - Get drive's actual block size from mode sense block descriptor
+ * - Limit size of pipeline
+ * Ver 1.17b Oct 2002 Alan Stern <stern@rowland.harvard.edu>
+ * Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ * it in the code!
+ * Actually removed aborted stages in idetape_abort_pipeline
+ * instead of just changing the command code.
+ * Made the transfer byte count for Request Sense equal to the
+ * actual length of the data transfer.
+ * Changed handling of partial data transfers: they do not
+ * cause DMA errors.
+ * Moved initiation of DMA transfers to the correct place.
+ * Removed reference to unallocated memory.
+ * Made __idetape_discard_read_pipeline return the number of
+ * sectors skipped, not the number of stages.
+ * Replaced errant kfree() calls with __idetape_kfree_stage().
+ * Fixed off-by-one error in testing the pipeline length.
+ * Fixed handling of filemarks in the read pipeline.
+ * Small code optimization for MTBSF and MTBSFM ioctls.
+ * Don't try to unlock the door during device close if is
+ * already unlocked!
+ * Cosmetic fixes to miscellaneous debugging output messages.
+ * Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ * "pipeline_min", and "pipeline_max" to 1.
+ */
diff --git a/Documentation/ide/ide-tape.txt b/Documentation/ide/ide-tape.txt
new file mode 100644
index 0000000..658f271
--- /dev/null
+++ b/Documentation/ide/ide-tape.txt
@@ -0,0 +1,146 @@
+/*
+ * IDE ATAPI streaming tape driver.
+ *
+ * This driver is a part of the Linux ide driver.
+ *
+ * The driver, in co-operation with ide.c, basically traverses the
+ * request-list for the block device interface. The character device
+ * interface, on the other hand, creates new requests, adds them
+ * to the request-list of the block device, and waits for their completion.
+ *
+ * Pipelined operation mode is now supported on both reads and writes.
+ *
+ * The block device major and minor numbers are determined from the
+ * tape's relative position in the ide interfaces, as explained in ide.c.
+ *
+ * The character device interface consists of the following devices:
+ *
+ * ht0 major 37, minor 0 first IDE tape, rewind on close.
+ * ht1 major 37, minor 1 second IDE tape, rewind on close.
+ * ...
+ * nht0 major 37, minor 128 first IDE tape, no rewind on close.
+ * nht1 major 37, minor 129 second IDE tape, no rewind on close.
+ * ...
+ *
+ * The general magnetic tape commands compatible interface, as defined by
+ * include/linux/mtio.h, is accessible through the character device.
+ *
+ * General ide driver configuration options, such as the interrupt-unmask
+ * flag, can be configured by issuing an ioctl to the block device interface,
+ * as any other ide device.
+ *
+ * Our own ide-tape ioctl's can be issued to either the block device or
+ * the character device interface.
+ *
+ * Maximal throughput with minimal bus load will usually be achieved in the
+ * following scenario:
+ *
+ * 1. ide-tape is operating in the pipelined operation mode.
+ * 2. No buffering is performed by the user backup program.
+ *
+ * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
+ *
+ * Here are some words from the first releases of hd.c, which are quoted
+ * in ide.c and apply here as well:
+ *
+ * | Special care is recommended. Have Fun!
+ *
+ *
+ * An overview of the pipelined operation mode.
+ *
+ * In the pipelined write mode, we will usually just add requests to our
+ * pipeline and return immediately, before we even start to service them. The
+ * user program will then have enough time to prepare the next request while
+ * we are still busy servicing previous requests. In the pipelined read mode,
+ * the situation is similar - we add read-ahead requests into the pipeline,
+ * before the user even requested them.
+ *
+ * The pipeline can be viewed as a "safety net" which will be activated when
+ * the system load is high and prevents the user backup program from keeping up
+ * with the current tape speed. At this point, the pipeline will get
+ * shorter and shorter but the tape will still be streaming at the same speed.
+ * Assuming we have enough pipeline stages, the system load will hopefully
+ * decrease before the pipeline is completely empty, and the backup program
+ * will be able to "catch up" and refill the pipeline again.
+ *
+ * When using the pipelined mode, it would be best to disable any type of
+ * buffering done by the user program, as ide-tape already provides all the
+ * benefits in the kernel, where it can be done in a more efficient way.
+ * As we will usually not block the user program on a request, the most
+ * efficient user code will then be a simple read-write-read-... cycle.
+ * Any additional logic will usually just slow down the backup process.
+ *
+ * Using the pipelined mode, I get a constant over 400 KBps throughput,
+ * which seems to be the maximum throughput supported by my tape.
+ *
+ * However, there are some downfalls:
+ *
+ * 1. We use memory (for data buffers) in proportional to the number
+ * of pipeline stages (each stage is about 26 KB with my tape).
+ * 2. In the pipelined write mode, we cheat and postpone error codes
+ * to the user task. In read mode, the actual tape position
+ * will be a bit further than the last requested block.
+ *
+ * Concerning (1):
+ *
+ * 1. We allocate stages dynamically only when we need them. When
+ * we don't need them, we don't consume additional memory. In
+ * case we can't allocate stages, we just manage without them
+ * (at the expense of decreased throughput) so when Linux is
+ * tight in memory, we will not pose additional difficulties.
+ *
+ * 2. The maximum number of stages (which is, in fact, the maximum
+ * amount of memory) which we allocate is limited by the compile
+ * time parameter IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * 3. The maximum number of stages is a controlled parameter - We
+ * don't start from the user defined maximum number of stages
+ * but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
+ * will not even allocate this amount of stages if the user
+ * program can't handle the speed). We then implement a feedback
+ * loop which checks if the pipeline is empty, and if it is, we
+ * increase the maximum number of stages as necessary until we
+ * reach the optimum value which just manages to keep the tape
+ * busy with minimum allocated memory or until we reach
+ * IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * Concerning (2):
+ *
+ * In pipelined write mode, ide-tape can not return accurate error codes
+ * to the user program since we usually just add the request to the
+ * pipeline without waiting for it to be serviced. In case an error
+ * occurs, I will report it on the next user request.
+ *
+ * In the pipelined read mode, subsequent read requests or forward
+ * filemark spacing will perform correctly, as we preserve all blocks
+ * and filemarks which we encountered during our excess read-ahead.
+ *
+ * For accurate tape positioning and error reporting, disabling
+ * pipelined mode might be the best option.
+ *
+ * You can enable/disable/tune the pipelined operation mode by adjusting
+ * the compile time parameters below.
+ *
+ *
+ * Possible improvements.
+ *
+ * 1. Support for the ATAPI overlap protocol.
+ *
+ * In order to maximize bus throughput, we currently use the DSC
+ * overlap method which enables ide.c to service requests from the
+ * other device while the tape is busy executing a command. The
+ * DSC overlap method involves polling the tape's status register
+ * for the DSC bit, and servicing the other device while the tape
+ * isn't ready.
+ *
+ * In the current QIC development standard (December 1995),
+ * it is recommended that new tape drives will *in addition*
+ * implement the ATAPI overlap protocol, which is used for the
+ * same purpose - efficient use of the IDE bus, but is interrupt
+ * driven and thus has much less CPU overhead.
+ *
+ * ATAPI overlap is likely to be supported in most new ATAPI
+ * devices, including new ATAPI cdroms, and thus provides us
+ * a method by which we can achieve higher throughput when
+ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
+ */
diff --git a/Documentation/initrd.txt b/Documentation/initrd.txt
index 74f68b3..1ba84f3 100644
--- a/Documentation/initrd.txt
+++ b/Documentation/initrd.txt
@@ -85,7 +85,7 @@
disk with the desired initrd content, cd to that directory, and run (as an
example):
-find . | cpio --quiet -c -o | gzip -9 -n > /boot/imagefile.img
+find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/imagefile.img
Examining the contents of an existing image file is just as simple:
diff --git a/Documentation/ja_JP/stable_kernel_rules.txt b/Documentation/ja_JP/stable_kernel_rules.txt
new file mode 100644
index 0000000..17d8751
--- /dev/null
+++ b/Documentation/ja_JP/stable_kernel_rules.txt
@@ -0,0 +1,79 @@
+NOTE:
+This is Japanese translated version of "Documentation/stable_kernel_rules.txt".
+This one is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
+and JF Project team <www.linux.or.jp/JF>.
+If you find difference with original file or problem in translation,
+please contact maintainer of this file or JF project.
+
+Please also note that purpose of this file is easier to read for non
+English natives and do no intended to fork. So, if you have any
+comment or update of this file, please try to update Original(English)
+file at first.
+
+==================================
+ããã¯ã
+linux-2.6.24/Documentation/stable_kernel_rules.txt
+ã®å訳ã§ãã
+
+翻訳å£ä½ï¼ JF ããã¸ã§ã¯ã < http://www.linux.or.jp/JF/ >
+翻訳æ¥ï¼ 2007/12/30
+翻訳è
ï¼ Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
+æ ¡æ£è
ï¼ æ¦äºä¼¸å
ããã<takei at webmasters dot gr dot jp>
+ ããããã (Seiji Kaneko) <skaneko at a2 dot mbn dot or dot jp>
+ å°æ é
å
¸ãã (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
+ éå£ãã (Kenji Noguchi) <tokyo246 at gmail dot com>
+ ç¥å®®ä¿¡å¤ªéãã <jin at libjingu dot jp>
+==================================
+
+ãã£ã¨ç¥ãããã£ã Linux 2.6 -stable ãªãªã¼ã¹ã®å
¨ã¦
+
+"-stable" ããªã¼ã«ã©ã®ãããªç¨®é¡ã®ããããåãå
¥ããããããã©ã®ãããª
+ãã®ãåãå
¥ããããªãããã«ã¤ãã¦ã®è¦å-
+
+ - æããã«æ£ããããã¹ãããã¦ãããã®ã§ãªããã°ãªããªãã
+ - æè(å¤æ´è¡ã®åå¾)ãå«ã㦠100 è¡ãã大ããã¦ã¯ãããªãã
+ - ãã ä¸åã®ãã¨ã ããä¿®æ£ãã¦ããã¹ãã
+ - çãæ©ã¾ãã¦ããæ¬ç©ã®ãã°ãä¿®æ£ããªããã°ãªããªãã("ããã¯ãã°ã§
+ ãããããããªãã..." ã®ãããªãã®ã§ã¯ãªã)
+ - ãã«ãã¨ã©ã¼(CONFIG_BROKENã«ãªã£ã¦ãããã®ãé¤ã), oops, ãã³ã°ããã¼
+ ã¿ç ´å£ãç¾å®ã®ã»ãã¥ãªãã£åé¡ããã®ä» "ãããããã¯ãã¡ã ã"ã¨ãã
+ ãããªãã®ãä¿®æ£ããªããã°ãªããªããçãè¨ãã°ãé大ãªåé¡ã
+ - ã©ã®ããã«ç«¶åç¶æ
ãçºçãããã®èª¬æãä¸ç·ã«æ¸ããã¦ããªãéãã
+ "çè«çã«ã¯ç«¶åç¶æ
ã«ãªã"ãããªãã®ã¯ä¸å¯ã
+ - ãããªãäºç´°ãªä¿®æ£ãå«ãããã¨ã¯ã§ããªãã(ã¹ãã«ã®ä¿®æ£ã空ç½ã®ã¯ãªã¼
+ ã³ã¢ãããªã©)
+ - 対å¿ãããµãã·ã¹ãã ã¡ã³ãããåãå
¥ãããã®ã§ãªããã°ãªããªãã
+ - Documentation/SubmittingPatches ã®è¦åã«å¾ã£ããã®ã§ãªããã°ãªããªãã
+
+-stable ããªã¼ã«ããããéä»ããæç¶ã-
+
+ - ä¸è¨ã®è¦åã«å¾ã£ã¦ãããã確èªããå¾ã«ãstable@kernel.org ã«ããã
+ ãéãã
+ - éä¿¡è
ã¯ãããããã¥ã¼ã«åãä»ããããéã«ã¯ ACK ããå´ä¸ãããå ´å
+ ã«ã¯ NAK ãåãåãããã®åå¿ã¯éçºè
ãã¡ã®ã¹ã±ã¸ã¥ã¼ã«ã«ãã£ã¦ãæ°
+ æ¥ãããå ´åãããã
+ - ããåãåããããããããã¯ä»ã®éçºè
ãã¡ã®ã¬ãã¥ã¼ã®ããã«
+ -stable ãã¥ã¼ã«è¿½å ãããã
+ - ã»ãã¥ãªãã£ãããã¯ãã®ã¨ã¤ãªã¢ã¹ (stable@kernel.org) ã«éãããã¹
+ ãã§ã¯ãªãã代ããã« security@kernel.org ã®ã¢ãã¬ã¹ã«éãããã
+
+ã¬ãã¥ã¼ãµã¤ã¯ã«-
+
+ - -stable ã¡ã³ãããã¬ãã¥ã¼ãµã¤ã¯ã«ã決ããã¨ãããããã¯ã¬ãã¥ã¼å§
+ å¡ä¼ã¨ããããå½±é¿ããé åã®ã¡ã³ãã(æä¾è
ããã®é åã®ã¡ã³ããã§ç¡
+ ãéã)ã«éãããlinux-kernel ã¡ã¼ãªã³ã°ãªã¹ãã«CCãããã
+ - ã¬ãã¥ã¼å§å¡ä¼ã¯ 48æéã®éã« ACK ã NAK ãåºãã
+ - ããããããå§å¡ä¼ã®ã¡ã³ãããå´ä¸ããããã¡ã³ããéãã¡ã³ããæ°ä»
+ ããªãã£ãåé¡ãæã¡ããããlinux-kernel ã¡ã³ãããããã«ç°è°ãå±ã
+ ãå ´åã«ã¯ããããã¯ãã¥ã¼ããåé¤ãããã
+ - ã¬ãã¥ã¼ãµã¤ã¯ã«ã®æå¾ã«ãACK ãåãããããã¯ææ°ã® -stable ãªãªã¼
+ ã¹ã«è¿½å ããããã®å¾ã«æ°ãã -stable ãªãªã¼ã¹ãè¡ãããã
+ - ã»ãã¥ãªãã£ãããã¯ãé常ã®ã¬ãã¥ã¼ãµã¤ã¯ã«ãéãããã»ãã¥ãªãã£
+ ã«ã¼ãã«ãã¼ã ããç´æ¥ -stable ããªã¼ã«åãä»ããããã
+ ãã®æç¶ãã®è©³ç´°ã«ã¤ãã¦ã¯ kernel security ãã¼ã ã«åãåããããã¨ã
+
+ã¬ãã¥ã¼å§å¡ä¼-
+
+ - ãã®å§å¡ä¼ã¯ããã®ã¿ã¹ã¯ã«ã¤ãã¦æ´»åããå¤ãã®ãã©ã³ãã£ã¢ã¨ãå°æ°ã®
+ éãã©ã³ãã£ã¢ã®ã«ã¼ãã«éçºè
éã§æ§æããã¦ããã
+
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 92c40d1..8ea41b6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -147,8 +147,10 @@
default: 0
acpi_sleep= [HW,ACPI] Sleep options
- Format: { s3_bios, s3_mode }
- See Documentation/power/video.txt
+ Format: { s3_bios, s3_mode, s3_beep }
+ See Documentation/power/video.txt for s3_bios and s3_mode.
+ s3_beep is for debugging; it makes the PC's speaker beep
+ as soon as the kernel's real-mode entry point is called.
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low }
@@ -168,6 +170,11 @@
acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
Format: <irq>,<irq>...
+ acpi_new_pts_ordering [HW,ACPI]
+ Enforce the ACPI 2.0 ordering of the _PTS control
+ method wrt putting devices into low power states
+ default: pre ACPI 2.0 ordering of _PTS
+
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
@@ -544,7 +551,7 @@
1 will print _a lot_ more information - normally
only useful to kernel developers.
- decnet= [HW,NET]
+ decnet.addr= [HW,NET]
Format: <area>[,<node>]
See also Documentation/networking/decnet.txt.
@@ -775,6 +782,9 @@
loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
as idle=poll.
+ ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
+ Claim all unknown PCI IDE storage controllers.
+
ignore_loglevel [KNL]
Ignore loglevel setting - this will print /all/
kernel messages to the console. Useful for debugging.
@@ -1556,14 +1566,17 @@
ramdisk_size= [RAM] Sizes of RAM disks in kilobytes
See Documentation/ramdisk.txt.
- rcu.blimit= [KNL,BOOT] Set maximum number of finished
- RCU callbacks to process in one batch.
+ rcupdate.blimit= [KNL,BOOT]
+ Set maximum number of finished RCU callbacks to process
+ in one batch.
- rcu.qhimark= [KNL,BOOT] Set threshold of queued
+ rcupdate.qhimark= [KNL,BOOT]
+ Set threshold of queued
RCU callbacks over which batch limiting is disabled.
- rcu.qlowmark= [KNL,BOOT] Set threshold of queued
- RCU callbacks below which batch limiting is re-enabled.
+ rcupdate.qlowmark= [KNL,BOOT]
+ Set threshold of queued RCU callbacks below which
+ batch limiting is re-enabled.
rdinit= [KNL]
Format: <full_path>
@@ -1883,9 +1896,6 @@
st= [HW,SCSI] SCSI tape parameters (buffers, etc.)
See Documentation/scsi/st.txt.
- st0x= [HW,SCSI]
- See header of drivers/scsi/seagate.c.
-
sti= [PARISC,HW]
Format: <num>
Set the STI (builtin display/keyboard on the HP-PARISC
@@ -1970,9 +1980,6 @@
tipar.delay= [HW,PPT]
Set inter-bit delay in microseconds (default 10).
- tmc8xx= [HW,SCSI]
- See header of drivers/scsi/seagate.c.
-
tmscsim= [HW,SCSI]
See comment before function dc390_setup() in
drivers/scsi/tmscsim.c.
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index 53a6389..30c1017 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -96,7 +96,9 @@
The jprobe will work in either case, so long as the handler's
prototype matches that of the probed function.
-1.3 How Does a Return Probe Work?
+1.3 Return Probes
+
+1.3.1 How Does a Return Probe Work?
When you call register_kretprobe(), Kprobes establishes a kprobe at
the entry to the function. When the probed function is called and this
@@ -107,9 +109,9 @@
When the probed function executes its return instruction, control
passes to the trampoline and that probe is hit. Kprobes' trampoline
-handler calls the user-specified handler associated with the kretprobe,
-then sets the saved instruction pointer to the saved return address,
-and that's where execution resumes upon return from the trap.
+handler calls the user-specified return handler associated with the
+kretprobe, then sets the saved instruction pointer to the saved return
+address, and that's where execution resumes upon return from the trap.
While the probed function is executing, its return address is
stored in an object of type kretprobe_instance. Before calling
@@ -131,6 +133,30 @@
time the probed function is entered but there is no kretprobe_instance
object available for establishing the return probe.
+1.3.2 Kretprobe entry-handler
+
+Kretprobes also provides an optional user-specified handler which runs
+on function entry. This handler is specified by setting the entry_handler
+field of the kretprobe struct. Whenever the kprobe placed by kretprobe at the
+function entry is hit, the user-defined entry_handler, if any, is invoked.
+If the entry_handler returns 0 (success) then a corresponding return handler
+is guaranteed to be called upon function return. If the entry_handler
+returns a non-zero error then Kprobes leaves the return address as is, and
+the kretprobe has no further effect for that particular function instance.
+
+Multiple entry and return handler invocations are matched using the unique
+kretprobe_instance object associated with them. Additionally, a user
+may also specify per return-instance private data to be part of each
+kretprobe_instance object. This is especially useful when sharing private
+data between corresponding user entry and return handlers. The size of each
+private data object can be specified at kretprobe registration time by
+setting the data_size field of the kretprobe struct. This data can be
+accessed through the data field of each kretprobe_instance object.
+
+In case probed function is entered but there is no kretprobe_instance
+object available, then in addition to incrementing the nmissed count,
+the user entry_handler invocation is also skipped.
+
2. Architectures Supported
Kprobes, jprobes, and return probes are implemented on the following
@@ -274,6 +300,8 @@
- ret_addr: the return address
- rp: points to the corresponding kretprobe object
- task: points to the corresponding task struct
+- data: points to per return-instance private data; see "Kretprobe
+ entry-handler" for details.
The regs_return_value(regs) macro provides a simple abstraction to
extract the return value from the appropriate register as defined by
@@ -556,23 +584,52 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
+#include <linux/ktime.h>
+
+/* per-instance private data */
+struct my_data {
+ ktime_t entry_stamp;
+};
static const char *probed_func = "sys_open";
-/* Return-probe handler: If the probed function fails, log the return value. */
-static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+/* Timestamp function entry. */
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+ struct my_data *data;
+
+ if(!current->mm)
+ return 1; /* skip kernel threads */
+
+ data = (struct my_data *)ri->data;
+ data->entry_stamp = ktime_get();
+ return 0;
+}
+
+/* If the probed function failed, log the return value and duration.
+ * Duration may turn out to be zero consistently, depending upon the
+ * granularity of time accounting on the platform. */
+static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
int retval = regs_return_value(regs);
+ struct my_data *data = (struct my_data *)ri->data;
+ s64 delta;
+ ktime_t now;
+
if (retval < 0) {
- printk("%s returns %d\n", probed_func, retval);
+ now = ktime_get();
+ delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
+ printk("%s: return val = %d (duration = %lld ns)\n",
+ probed_func, retval, delta);
}
return 0;
}
static struct kretprobe my_kretprobe = {
- .handler = ret_handler,
- /* Probe up to 20 instances concurrently. */
- .maxactive = 20
+ .handler = return_handler,
+ .entry_handler = entry_handler,
+ .data_size = sizeof(struct my_data),
+ .maxactive = 20, /* probe up to 20 instances concurrently */
};
static int __init kretprobe_init(void)
@@ -584,7 +641,7 @@
printk("register_kretprobe failed, returned %d\n", ret);
return -1;
}
- printk("Planted return probe at %p\n", my_kretprobe.kp.addr);
+ printk("Kretprobe active on %s\n", my_kretprobe.kp.symbol_name);
return 0;
}
@@ -594,7 +651,7 @@
printk("kretprobe unregistered\n");
/* nmissed > 0 suggests that maxactive was set too low. */
printk("Missed probing %d instances of %s\n",
- my_kretprobe.nmissed, probed_func);
+ my_kretprobe.nmissed, probed_func);
}
module_init(kretprobe_init)
diff --git a/Documentation/kref.txt b/Documentation/kref.txt
index f38b59d..130b6e8 100644
--- a/Documentation/kref.txt
+++ b/Documentation/kref.txt
@@ -141,10 +141,10 @@
instance, you have a list of items that are each kref-ed, and you wish
to get the first one. You can't just pull the first item off the list
and kref_get() it. That violates rule 3 because you are not already
-holding a valid pointer. You must add locks or semaphores. For
-instance:
+holding a valid pointer. You must add a mutex (or some other lock).
+For instance:
-static DECLARE_MUTEX(sem);
+static DEFINE_MUTEX(mutex);
static LIST_HEAD(q);
struct my_data
{
@@ -155,12 +155,12 @@
static struct my_data *get_entry()
{
struct my_data *entry = NULL;
- down(&sem);
+ mutex_lock(&mutex);
if (!list_empty(&q)) {
entry = container_of(q.next, struct my_q_entry, link);
kref_get(&entry->refcount);
}
- up(&sem);
+ mutex_unlock(&mutex);
return entry;
}
@@ -174,9 +174,9 @@
static void put_entry(struct my_data *entry)
{
- down(&sem);
+ mutex_lock(&mutex);
kref_put(&entry->refcount, release_entry);
- up(&sem);
+ mutex_unlock(&mutex);
}
The kref_put() return value is useful if you do not want to hold the
@@ -191,13 +191,13 @@
static void put_entry(struct my_data *entry)
{
- down(&sem);
+ mutex_lock(&mutex);
if (kref_put(&entry->refcount, release_entry)) {
list_del(&entry->link);
- up(&sem);
+ mutex_unlock(&mutex);
kfree(entry);
} else
- up(&sem);
+ mutex_unlock(&mutex);
}
This is really more useful if you have to call other routines as part
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 6c8a238..0f23d67f 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -34,6 +34,8 @@
#include <zlib.h>
#include <assert.h>
#include <sched.h>
+#include <limits.h>
+#include <stddef.h>
#include "linux/lguest_launcher.h"
#include "linux/virtio_config.h"
#include "linux/virtio_net.h"
@@ -99,13 +101,11 @@
/* The descriptor page for the devices. */
u8 *descpage;
- /* The tail of the last descriptor. */
- unsigned int desc_used;
-
/* A single linked list of devices. */
struct device *dev;
- /* ... And an end pointer so we can easily append new devices */
- struct device **lastdev;
+ /* And a pointer to the last device for easy append and also for
+ * configuration appending. */
+ struct device *lastdev;
};
/* The list of Guest devices, based on command line arguments. */
@@ -191,7 +191,14 @@
#define cpu_to_le64(v64) (v64)
#define le16_to_cpu(v16) (v16)
#define le32_to_cpu(v32) (v32)
-#define le64_to_cpu(v32) (v64)
+#define le64_to_cpu(v64) (v64)
+
+/* The device virtqueue descriptors are followed by feature bitmasks. */
+static u8 *get_feature_bits(struct device *dev)
+{
+ return (u8 *)(dev->desc + 1)
+ + dev->desc->num_vq * sizeof(struct lguest_vqconfig);
+}
/*L:100 The Launcher code itself takes us out into userspace, that scary place
* where pointers run wild and free! Unfortunately, like most userspace
@@ -914,21 +921,58 @@
write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
}
+/* Resetting a device is fairly easy. */
+static void reset_device(struct device *dev)
+{
+ struct virtqueue *vq;
+
+ verbose("Resetting device %s\n", dev->name);
+ /* Clear the status. */
+ dev->desc->status = 0;
+
+ /* Clear any features they've acked. */
+ memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
+ dev->desc->feature_len);
+
+ /* Zero out the virtqueues. */
+ for (vq = dev->vq; vq; vq = vq->next) {
+ memset(vq->vring.desc, 0,
+ vring_size(vq->config.num, getpagesize()));
+ vq->last_avail_idx = 0;
+ }
+}
+
/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
static void handle_output(int fd, unsigned long addr)
{
struct device *i;
struct virtqueue *vq;
- /* Check each virtqueue. */
+ /* Check each device and virtqueue. */
for (i = devices.dev; i; i = i->next) {
+ /* Notifications to device descriptors reset the device. */
+ if (from_guest_phys(addr) == i->desc) {
+ reset_device(i);
+ return;
+ }
+
+ /* Notifications to virtqueues mean output has occurred. */
for (vq = i->vq; vq; vq = vq->next) {
- if (vq->config.pfn == addr/getpagesize()
- && vq->handle_output) {
- verbose("Output to %s\n", vq->dev->name);
- vq->handle_output(fd, vq);
+ if (vq->config.pfn != addr/getpagesize())
+ continue;
+
+ /* Guest should acknowledge (and set features!) before
+ * using the device. */
+ if (i->desc->status == 0) {
+ warnx("%s gave early output", i->name);
return;
}
+
+ if (strcmp(vq->dev->name, "console") != 0)
+ verbose("Output to %s\n", vq->dev->name);
+ if (vq->handle_output)
+ vq->handle_output(fd, vq);
+ return;
}
}
@@ -986,54 +1030,44 @@
*
* All devices need a descriptor so the Guest knows it exists, and a "struct
* device" so the Launcher can keep track of it. We have common helper
- * routines to allocate them.
- *
- * This routine allocates a new "struct lguest_device_desc" from descriptor
- * table just above the Guest's normal memory. It returns a pointer to that
- * descriptor. */
+ * routines to allocate and manage them. */
+
+/* The layout of the device page is a "struct lguest_device_desc" followed by a
+ * number of virtqueue descriptors, then two sets of feature bits, then an
+ * array of configuration bytes. This routine returns the configuration
+ * pointer. */
+static u8 *device_config(const struct device *dev)
+{
+ return (void *)(dev->desc + 1)
+ + dev->desc->num_vq * sizeof(struct lguest_vqconfig)
+ + dev->desc->feature_len * 2;
+}
+
+/* This routine allocates a new "struct lguest_device_desc" from descriptor
+ * table page just above the Guest's normal memory. It returns a pointer to
+ * that descriptor. */
static struct lguest_device_desc *new_dev_desc(u16 type)
{
- struct lguest_device_desc *d;
+ struct lguest_device_desc d = { .type = type };
+ void *p;
+
+ /* Figure out where the next device config is, based on the last one. */
+ if (devices.lastdev)
+ p = device_config(devices.lastdev)
+ + devices.lastdev->desc->config_len;
+ else
+ p = devices.descpage;
/* We only have one page for all the descriptors. */
- if (devices.desc_used + sizeof(*d) > getpagesize())
+ if (p + sizeof(d) > (void *)devices.descpage + getpagesize())
errx(1, "Too many devices");
- /* We don't need to set config_len or status: page is 0 already. */
- d = (void *)devices.descpage + devices.desc_used;
- d->type = type;
- devices.desc_used += sizeof(*d);
-
- return d;
+ /* p might not be aligned, so we memcpy in. */
+ return memcpy(p, &d, sizeof(d));
}
-/* Each device descriptor is followed by some configuration information.
- * Each configuration field looks like: u8 type, u8 len, [... len bytes...].
- *
- * This routine adds a new field to an existing device's descriptor. It only
- * works for the last device, but that's OK because that's how we use it. */
-static void add_desc_field(struct device *dev, u8 type, u8 len, const void *c)
-{
- /* This is the last descriptor, right? */
- assert(devices.descpage + devices.desc_used
- == (u8 *)(dev->desc + 1) + dev->desc->config_len);
-
- /* We only have one page of device descriptions. */
- if (devices.desc_used + 2 + len > getpagesize())
- errx(1, "Too many devices");
-
- /* Copy in the new config header: type then length. */
- devices.descpage[devices.desc_used++] = type;
- devices.descpage[devices.desc_used++] = len;
- memcpy(devices.descpage + devices.desc_used, c, len);
- devices.desc_used += len;
-
- /* Update the device descriptor length: two byte head then data. */
- dev->desc->config_len += 2 + len;
-}
-
-/* This routine adds a virtqueue to a device. We specify how many descriptors
- * the virtqueue is to have. */
+/* Each device descriptor is followed by the description of its virtqueues. We
+ * specify how many descriptors the virtqueue is to have. */
static void add_virtqueue(struct device *dev, unsigned int num_descs,
void (*handle_output)(int fd, struct virtqueue *me))
{
@@ -1059,9 +1093,15 @@
/* Initialize the vring. */
vring_init(&vq->vring, num_descs, p, getpagesize());
- /* Add the configuration information to this device's descriptor. */
- add_desc_field(dev, VIRTIO_CONFIG_F_VIRTQUEUE,
- sizeof(vq->config), &vq->config);
+ /* Append virtqueue to this device's descriptor. We use
+ * device_config() to get the end of the device's current virtqueues;
+ * we check that we haven't added any config or feature information
+ * yet, otherwise we'd be overwriting them. */
+ assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
+ memcpy(device_config(dev), &vq->config, sizeof(vq->config));
+ dev->desc->num_vq++;
+
+ verbose("Virtqueue page %#lx\n", to_guest_phys(p));
/* Add to tail of list, so dev->vq is first vq, dev->vq->next is
* second. */
@@ -1072,11 +1112,41 @@
* virtqueue. */
vq->handle_output = handle_output;
- /* Set the "Don't Notify Me" flag if we don't have a handler */
+ /* As an optimization, set the advisory "Don't Notify Me" flag if we
+ * don't have a handler */
if (!handle_output)
vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
}
+/* The first half of the feature bitmask is for us to advertise features. The
+ * second half if for the Guest to accept features. */
+static void add_feature(struct device *dev, unsigned bit)
+{
+ u8 *features = get_feature_bits(dev);
+
+ /* We can't extend the feature bits once we've added config bytes */
+ if (dev->desc->feature_len <= bit / CHAR_BIT) {
+ assert(dev->desc->config_len == 0);
+ dev->desc->feature_len = (bit / CHAR_BIT) + 1;
+ }
+
+ features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
+}
+
+/* This routine sets the configuration fields for an existing device's
+ * descriptor. It only works for the last device, but that's OK because that's
+ * how we use it. */
+static void set_config(struct device *dev, unsigned len, const void *conf)
+{
+ /* Check we haven't overflowed our single page. */
+ if (device_config(dev) + len > devices.descpage + getpagesize())
+ errx(1, "Too many devices");
+
+ /* Copy in the config information, and store the length. */
+ memcpy(device_config(dev), conf, len);
+ dev->desc->config_len = len;
+}
+
/* This routine does all the creation and setup of a new device, including
* calling new_dev_desc() to allocate the descriptor and device memory. */
static struct device *new_device(const char *name, u16 type, int fd,
@@ -1084,14 +1154,6 @@
{
struct device *dev = malloc(sizeof(*dev));
- /* Append to device list. Prepending to a single-linked list is
- * easier, but the user expects the devices to be arranged on the bus
- * in command-line order. The first network device on the command line
- * is eth0, the first block device /dev/vda, etc. */
- *devices.lastdev = dev;
- dev->next = NULL;
- devices.lastdev = &dev->next;
-
/* Now we populate the fields one at a time. */
dev->fd = fd;
/* If we have an input handler for this file descriptor, then we add it
@@ -1102,6 +1164,17 @@
dev->handle_input = handle_input;
dev->name = name;
dev->vq = NULL;
+
+ /* Append to device list. Prepending to a single-linked list is
+ * easier, but the user expects the devices to be arranged on the bus
+ * in command-line order. The first network device on the command line
+ * is eth0, the first block device /dev/vda, etc. */
+ if (devices.lastdev)
+ devices.lastdev->next = dev;
+ else
+ devices.dev = dev;
+ devices.lastdev = dev;
+
return dev;
}
@@ -1226,7 +1299,7 @@
int netfd, ipfd;
u32 ip;
const char *br_name = NULL;
- u8 hwaddr[6];
+ struct virtio_net_config conf;
/* We open the /dev/net/tun device and tell it we want a tap device. A
* tap device is like a tun device, only somehow different. To tell
@@ -1265,12 +1338,13 @@
ip = str2ip(arg);
/* Set up the tun device, and get the mac address for the interface. */
- configure_device(ipfd, ifr.ifr_name, ip, hwaddr);
+ configure_device(ipfd, ifr.ifr_name, ip, conf.mac);
/* Tell Guest what MAC address to use. */
- add_desc_field(dev, VIRTIO_CONFIG_NET_MAC_F, sizeof(hwaddr), hwaddr);
+ add_feature(dev, VIRTIO_NET_F_MAC);
+ set_config(dev, sizeof(conf), &conf);
- /* We don't seed the socket any more; setup is done. */
+ /* We don't need the socket any more; setup is done. */
close(ipfd);
verbose("device %u: tun net %u.%u.%u.%u\n",
@@ -1458,8 +1532,7 @@
struct device *dev;
struct vblk_info *vblk;
void *stack;
- u64 cap;
- unsigned int val;
+ struct virtio_blk_config conf;
/* This is the pipe the I/O thread will use to tell us I/O is done. */
pipe(p);
@@ -1477,14 +1550,18 @@
vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
vblk->len = lseek64(vblk->fd, 0, SEEK_END);
+ /* We support barriers. */
+ add_feature(dev, VIRTIO_BLK_F_BARRIER);
+
/* Tell Guest how many sectors this device has. */
- cap = cpu_to_le64(vblk->len / 512);
- add_desc_field(dev, VIRTIO_CONFIG_BLK_F_CAPACITY, sizeof(cap), &cap);
+ conf.capacity = cpu_to_le64(vblk->len / 512);
/* Tell Guest not to put in too many descriptors at once: two are used
* for the in and out elements. */
- val = cpu_to_le32(VIRTQUEUE_NUM - 2);
- add_desc_field(dev, VIRTIO_CONFIG_BLK_F_SEG_MAX, sizeof(val), &val);
+ add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
+ conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);
+
+ set_config(dev, sizeof(conf), &conf);
/* The I/O thread writes to this end of the pipe when done. */
vblk->done_fd = p[1];
@@ -1505,7 +1582,7 @@
close(vblk->workpipe[0]);
verbose("device %u: virtblock %llu sectors\n",
- devices.device_num, cap);
+ devices.device_num, le64_to_cpu(conf.capacity));
}
/* That's the end of device setup. :*/
@@ -1610,12 +1687,12 @@
/* First we initialize the device list. Since console and network
* device receive input from a file descriptor, we keep an fdset
* (infds) and the maximum fd number (max_infd) with the head of the
- * list. We also keep a pointer to the last device, for easy appending
- * to the list. Finally, we keep the next interrupt number to hand out
- * (1: remember that 0 is used by the timer). */
+ * list. We also keep a pointer to the last device. Finally, we keep
+ * the next interrupt number to hand out (1: remember that 0 is used by
+ * the timer). */
FD_ZERO(&devices.infds);
devices.max_infd = -1;
- devices.lastdev = &devices.dev;
+ devices.lastdev = NULL;
devices.next_irq = 1;
cpu_id = 0;
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 5818628..396cdd9 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -416,6 +416,16 @@
sectors in total that could need to be processed. The two
numbers are separated by a '/' thus effectively showing one
value, a fraction of the process that is complete.
+ A 'select' on this attribute will return when resync completes,
+ when it reaches the current sync_max (below) and possibly at
+ other times.
+
+ sync_max
+ This is a number of sectors at which point a resync/recovery
+ process will pause. When a resync is active, the value can
+ only ever be increased, never decreased. The value of 'max'
+ effectively disables the limit.
+
sync_speed
This shows the current actual speed, in K/sec, of the current
diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
index badb748..d896895 100644
--- a/Documentation/networking/decnet.txt
+++ b/Documentation/networking/decnet.txt
@@ -60,7 +60,7 @@
The kernel command line takes options looking like the following:
- decnet=1,2
+ decnet.addr=1,2
the two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels
and early 2.3.xx kernels, you must use a comma when specifying the
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index 7754f5a..72b20c6 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -274,8 +274,6 @@
o allocate an IRQ (if BIOS did not).
NOTE: pci_enable_device() can fail! Check the return value.
-NOTE2: Also see pci_enable_device_bars() below. Drivers can
- attempt to enable only a subset of BARs they need.
[ OS BUG: we don't check resource allocations before enabling those
resources. The sequence would make more sense if we called
@@ -605,40 +603,7 @@
-10. pci_enable_device_bars() and Legacy I/O Port space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Large servers may not be able to provide I/O port resources to all PCI
-devices. I/O Port space is only 64KB on Intel Architecture[1] and is
-likely also fragmented since the I/O base register of PCI-to-PCI
-bridge will usually be aligned to a 4KB boundary[2]. On such systems,
-pci_enable_device() and pci_request_region() will fail when
-attempting to enable I/O Port regions that don't have I/O Port
-resources assigned.
-
-Fortunately, many PCI devices which request I/O Port resources also
-provide access to the same registers via MMIO BARs. These devices can
-be handled without using I/O port space and the drivers typically
-offer a CONFIG_ option to only use MMIO regions
-(e.g. CONFIG_TULIP_MMIO). PCI devices typically provide I/O port
-interface for legacy OSes and will work when I/O port resources are not
-assigned. The "PCI Local Bus Specification Revision 3.0" discusses
-this on p.44, "IMPLEMENTATION NOTE".
-
-If your PCI device driver doesn't need I/O port resources assigned to
-I/O Port BARs, you should use pci_enable_device_bars() instead of
-pci_enable_device() in order not to enable I/O port regions for the
-corresponding devices. In addition, you should use
-pci_request_selected_regions() and pci_release_selected_regions()
-instead of pci_request_regions()/pci_release_regions() in order not to
-request/release I/O port regions for the corresponding devices.
-
-[1] Some systems support 64KB I/O port space per PCI segment.
-[2] Some PCI-to-PCI bridges support optional 1KB aligned I/O base.
-
-
-
-11. MMIO Space and "Write Posting"
+10. MMIO Space and "Write Posting"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Converting a driver from using I/O Port space to using MMIO space
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
index 4739c5c..96f155e 100644
--- a/Documentation/pcmcia/driver-changes.txt
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -33,8 +33,8 @@
and can be used (e.g. for SET_NETDEV_DEV) by using
handle_to_dev(client_handle_t * handle).
-* Convert internal I/O port addresses to unsigned long (as of 2.6.11)
- ioaddr_t should be replaced by kio_addr_t in PCMCIA card drivers.
+* Convert internal I/O port addresses to unsigned int (as of 2.6.11)
+ ioaddr_t should be replaced by unsigned int in PCMCIA card drivers.
* irq_mask and irq_list parameters (as of 2.6.11)
The irq_mask and irq_list parameters should no longer be used in
diff --git a/Documentation/pm_qos_interface.txt b/Documentation/pm_qos_interface.txt
new file mode 100644
index 0000000..49adb1a
--- /dev/null
+++ b/Documentation/pm_qos_interface.txt
@@ -0,0 +1,59 @@
+PM quality of Service interface.
+
+This interface provides a kernel and user mode interface for registering
+performance expectations by drivers, subsystems and user space applications on
+one of the parameters.
+
+Currently we have {cpu_dma_latency, network_latency, network_throughput} as the
+initial set of pm_qos parameters.
+
+The infrastructure exposes multiple misc device nodes one per implemented
+parameter. The set of parameters implement is defined by pm_qos_power_init()
+and pm_qos_params.h. This is done because having the available parameters
+being runtime configurable or changeable from a driver was seen as too easy to
+abuse.
+
+For each parameter a list of performance requirements is maintained along with
+an aggregated target value. The aggregated target value is updated with
+changes to the requirement list or elements of the list. Typically the
+aggregated target value is simply the max or min of the requirement values held
+in the parameter list elements.
+
+From kernel mode the use of this interface is simple:
+pm_qos_add_requirement(param_id, name, target_value):
+Will insert a named element in the list for that identified PM_QOS parameter
+with the target value. Upon change to this list the new target is recomputed
+and any registered notifiers are called only if the target value is now
+different.
+
+pm_qos_update_requirement(param_id, name, new_target_value):
+Will search the list identified by the param_id for the named list element and
+then update its target value, calling the notification tree if the aggregated
+target is changed. with that name is already registered.
+
+pm_qos_remove_requirement(param_id, name):
+Will search the identified list for the named element and remove it, after
+removal it will update the aggregate target and call the notification tree if
+the target was changed as a result of removing the named requirement.
+
+
+From user mode:
+Only processes can register a pm_qos requirement. To provide for automatic
+cleanup for process the interface requires the process to register its
+parameter requirements in the following way:
+
+To register the default pm_qos target for the specific parameter, the process
+must open one of /dev/[cpu_dma_latency, network_latency, network_throughput]
+
+As long as the device node is held open that process has a registered
+requirement on the parameter. The name of the requirement is "process_<PID>"
+derived from the current->pid from within the open system call.
+
+To change the requested target value the process needs to write a s32 value to
+the open device node. This translates to a pm_qos_update_requirement call.
+
+To remove the user mode request for a target value simply close the device
+node.
+
+
+
diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
index 57aef2f..1555001 100644
--- a/Documentation/power/basic-pm-debugging.txt
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -1,45 +1,111 @@
-Debugging suspend and resume
+Debugging hibernation and suspend
(C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
-1. Testing suspend to disk (STD)
+1. Testing hibernation (aka suspend to disk or STD)
-To verify that the STD works, you can try to suspend in the "reboot" mode:
+To check if hibernation works, you can try to hibernate in the "reboot" mode:
# echo reboot > /sys/power/disk
# echo disk > /sys/power/state
-and the system should suspend, reboot, resume and get back to the command prompt
-where you have started the transition. If that happens, the STD is most likely
-to work correctly, but you need to repeat the test at least a couple of times in
-a row for confidence. This is necessary, because some problems only show up on
-a second attempt at suspending and resuming the system. You should also test
-the "platform" and "shutdown" modes of suspend:
+and the system should create a hibernation image, reboot, resume and get back to
+the command prompt where you have started the transition. If that happens,
+hibernation is most likely to work correctly. Still, you need to repeat the
+test at least a couple of times in a row for confidence. [This is necessary,
+because some problems only show up on a second attempt at suspending and
+resuming the system.] Moreover, hibernating in the "reboot" and "shutdown"
+modes causes the PM core to skip some platform-related callbacks which on ACPI
+systems might be necessary to make hibernation work. Thus, if you machine fails
+to hibernate or resume in the "reboot" mode, you should try the "platform" mode:
# echo platform > /sys/power/disk
# echo disk > /sys/power/state
-or
+which is the default and recommended mode of hibernation.
+
+Unfortunately, the "platform" mode of hibernation does not work on some systems
+with broken BIOSes. In such cases the "shutdown" mode of hibernation might
+work:
# echo shutdown > /sys/power/disk
# echo disk > /sys/power/state
-in which cases you will have to press the power button to make the system
-resume. If that does not work, you will need to identify what goes wrong.
+(it is similar to the "reboot" mode, but it requires you to press the power
+button to make the system resume).
-a) Test mode of STD
+If neither "platform" nor "shutdown" hibernation mode works, you will need to
+identify what goes wrong.
-To verify if there are any drivers that cause problems you can run the STD
-in the test mode:
+a) Test modes of hibernation
-# echo test > /sys/power/disk
+To find out why hibernation fails on your system, you can use a special testing
+facility available if the kernel is compiled with CONFIG_PM_DEBUG set. Then,
+there is the file /sys/power/pm_test that can be used to make the hibernation
+core run in a test mode. There are 5 test modes available:
+
+freezer
+- test the freezing of processes
+
+devices
+- test the freezing of processes and suspending of devices
+
+platform
+- test the freezing of processes, suspending of devices and platform
+ global control methods(*)
+
+processors
+- test the freezing of processes, suspending of devices, platform
+ global control methods(*) and the disabling of nonboot CPUs
+
+core
+- test the freezing of processes, suspending of devices, platform global
+ control methods(*), the disabling of nonboot CPUs and suspending of
+ platform/system devices
+
+(*) the platform global control methods are only available on ACPI systems
+ and are only tested if the hibernation mode is set to "platform"
+
+To use one of them it is necessary to write the corresponding string to
+/sys/power/pm_test (eg. "devices" to test the freezing of processes and
+suspending devices) and issue the standard hibernation commands. For example,
+to use the "devices" test mode along with the "platform" mode of hibernation,
+you should do the following:
+
+# echo devices > /sys/power/pm_test
+# echo platform > /sys/power/disk
# echo disk > /sys/power/state
-in which case the system should freeze tasks, suspend devices, disable nonboot
-CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw
-tasks and return to your command prompt. If that fails, most likely there is
-a driver that fails to either suspend or resume (in the latter case the system
-may hang or be unstable after the test, so please take that into consideration).
-To find this driver, you can carry out a binary search according to the rules:
+Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds,
+resume devices and thaw processes. If "platform" is written to
+/sys/power/pm_test , then after suspending devices the kernel will additionally
+invoke the global control methods (eg. ACPI global control methods) used to
+prepare the platform firmware for hibernation. Next, it will wait 5 seconds and
+invoke the platform (eg. ACPI) global methods used to cancel hibernation etc.
+
+Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
+hibernation/suspend operations. Also, when open for reading, /sys/power/pm_test
+contains a space-separated list of all available tests (including "none" that
+represents the normal functionality) in which the current test level is
+indicated by square brackets.
+
+Generally, as you can see, each test level is more "invasive" than the previous
+one and the "core" level tests the hardware and drivers as deeply as possible
+without creating a hibernation image. Obviously, if the "devices" test fails,
+the "platform" test will fail as well and so on. Thus, as a rule of thumb, you
+should try the test modes starting from "freezer", through "devices", "platform"
+and "processors" up to "core" (repeat the test on each level a couple of times
+to make sure that any random factors are avoided).
+
+If the "freezer" test fails, there is a task that cannot be frozen (in that case
+it usually is possible to identify the offending task by analysing the output of
+dmesg obtained after the failing test). Failure at this level usually means
+that there is a problem with the tasks freezer subsystem that should be
+reported.
+
+If the "devices" test fails, most likely there is a driver that cannot suspend
+or resume its device (in the latter case the system may hang or become unstable
+after the test, so please take that into consideration). To find this driver,
+you can carry out a binary search according to the rules:
- if the test fails, unload a half of the drivers currently loaded and repeat
(that would probably involve rebooting the system, so always note what drivers
have been loaded before the test),
@@ -47,23 +113,46 @@
recently and repeat.
Once you have found the failing driver (there can be more than just one of
-them), you have to unload it every time before the STD transition. In that case
-please make sure to report the problem with the driver.
+them), you have to unload it every time before hibernation. In that case please
+make sure to report the problem with the driver.
-It is also possible that a cycle can still fail after you have unloaded
-all modules. In that case, you would want to look in your kernel configuration
-for the drivers that can be compiled as modules (testing again with them as
-modules), and possibly also try boot time options such as "noapic" or "noacpi".
+It is also possible that the "devices" test will still fail after you have
+unloaded all modules. In that case, you may want to look in your kernel
+configuration for the drivers that can be compiled as modules (and test again
+with these drivers compiled as modules). You may also try to use some special
+kernel command line options such as "noapic", "noacpi" or even "acpi=off".
+
+If the "platform" test fails, there is a problem with the handling of the
+platform (eg. ACPI) firmware on your system. In that case the "platform" mode
+of hibernation is not likely to work. You can try the "shutdown" mode, but that
+is rather a poor man's workaround.
+
+If the "processors" test fails, the disabling/enabling of nonboot CPUs does not
+work (of course, this only may be an issue on SMP systems) and the problem
+should be reported. In that case you can also try to switch the nonboot CPUs
+off and on using the /sys/devices/system/cpu/cpu*/online sysfs attributes and
+see if that works.
+
+If the "core" test fails, which means that suspending of the system/platform
+devices has failed (these devices are suspended on one CPU with interrupts off),
+the problem is most probably hardware-related and serious, so it should be
+reported.
+
+A failure of any of the "platform", "processors" or "core" tests may cause your
+system to hang or become unstable, so please beware. Such a failure usually
+indicates a serious problem that very well may be related to the hardware, but
+please report it anyway.
b) Testing minimal configuration
-If the test mode of STD works, you can boot the system with "init=/bin/bash"
-and attempt to suspend in the "reboot", "shutdown" and "platform" modes. If
-that does not work, there probably is a problem with a driver statically
-compiled into the kernel and you can try to compile more drivers as modules,
-so that they can be tested individually. Otherwise, there is a problem with a
-modular driver and you can find it by loading a half of the modules you normally
-use and binary searching in accordance with the algorithm:
+If all of the hibernation test modes work, you can boot the system with the
+"init=/bin/bash" command line parameter and attempt to hibernate in the
+"reboot", "shutdown" and "platform" modes. If that does not work, there
+probably is a problem with a driver statically compiled into the kernel and you
+can try to compile more drivers as modules, so that they can be tested
+individually. Otherwise, there is a problem with a modular driver and you can
+find it by loading a half of the modules you normally use and binary searching
+in accordance with the algorithm:
- if there are n modules loaded and the attempt to suspend and resume fails,
unload n/2 of the modules and try again (that would probably involve rebooting
the system),
@@ -71,19 +160,19 @@
load n/2 modules more and try again.
Again, if you find the offending module(s), it(they) must be unloaded every time
-before the STD transition, and please report the problem with it(them).
+before hibernation, and please report the problem with it(them).
c) Advanced debugging
-In case the STD does not work on your system even in the minimal configuration
-and compiling more drivers as modules is not practical or some modules cannot
-be unloaded, you can use one of the more advanced debugging techniques to find
-the problem. First, if there is a serial port in your box, you can boot the
-kernel with the 'no_console_suspend' parameter and try to log kernel
-messages using the serial console. This may provide you with some information
-about the reasons of the suspend (resume) failure. Alternatively, it may be
-possible to use a FireWire port for debugging with firescope
-(ftp://ftp.firstfloor.org/pub/ak/firescope/). On i386 it is also possible to
+In case that hibernation does not work on your system even in the minimal
+configuration and compiling more drivers as modules is not practical or some
+modules cannot be unloaded, you can use one of the more advanced debugging
+techniques to find the problem. First, if there is a serial port in your box,
+you can boot the kernel with the 'no_console_suspend' parameter and try to log
+kernel messages using the serial console. This may provide you with some
+information about the reasons of the suspend (resume) failure. Alternatively,
+it may be possible to use a FireWire port for debugging with firescope
+(ftp://ftp.firstfloor.org/pub/ak/firescope/). On x86 it is also possible to
use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
2. Testing suspend to RAM (STR)
@@ -91,16 +180,25 @@
To verify that the STR works, it is generally more convenient to use the s2ram
tool available from http://suspend.sf.net and documented at
http://en.opensuse.org/s2ram . However, before doing that it is recommended to
-carry out the procedure described in section 1.
+carry out STR testing using the facility described in section 1.
-Assume you have resolved the problems with the STD and you have found some
-failing drivers. These drivers are also likely to fail during the STR or
-during the resume, so it is better to unload them every time before the STR
-transition. Now, you can follow the instructions at
-http://en.opensuse.org/s2ram to test the system, but if it does not work
-"out of the box", you may need to boot it with "init=/bin/bash" and test
-s2ram in the minimal configuration. In that case, you may be able to search
-for failing drivers by following the procedure analogous to the one described in
-1b). If you find some failing drivers, you will have to unload them every time
-before the STR transition (ie. before you run s2ram), and please report the
-problems with them.
+Namely, after writing "freezer", "devices", "platform", "processors", or "core"
+into /sys/power/pm_test (available if the kernel is compiled with
+CONFIG_PM_DEBUG set) the suspend code will work in the test mode corresponding
+to given string. The STR test modes are defined in the same way as for
+hibernation, so please refer to Section 1 for more information about them. In
+particular, the "core" test allows you to test everything except for the actual
+invocation of the platform firmware in order to put the system into the sleep
+state.
+
+Among other things, the testing with the help of /sys/power/pm_test may allow
+you to identify drivers that fail to suspend or resume their devices. They
+should be unloaded every time before an STR transition.
+
+Next, you can follow the instructions at http://en.opensuse.org/s2ram to test
+the system, but if it does not work "out of the box", you may need to boot it
+with "init=/bin/bash" and test s2ram in the minimal configuration. In that
+case, you may be able to search for failing drivers by following the procedure
+analogous to the one described in section 1. If you find some failing drivers,
+you will have to unload them every time before an STR transition (ie. before
+you run s2ram), and please report the problems with them.
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index d0e79d5..c53d263 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -502,52 +502,3 @@
to shift to lower voltage settings and reduce the power cost of executing
a given number of instructions. (Without voltage adjustment, it's rare
for cpufreq to save much power; the cost-per-instruction must go down.)
-
-
-/sys/devices/.../power/state files
-==================================
-For now you can also test some of this functionality using sysfs.
-
- DEPRECATED: USE "power/state" ONLY FOR DRIVER TESTING, AND
- AVOID USING dev->power.power_state IN DRIVERS.
-
- THESE WILL BE REMOVED. IF THE "power/state" FILE GETS REPLACED,
- IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
-
-In each device's directory, there is a 'power' directory, which contains
-at least a 'state' file. The value of this field is effectively boolean,
-PM_EVENT_ON or PM_EVENT_SUSPEND.
-
- * Reading from this file displays a value corresponding to
- the power.power_state.event field. All nonzero values are
- displayed as "2", corresponding to a low power state; zero
- is displayed as "0", corresponding to normal operation.
-
- * Writing to this file initiates a transition using the
- specified event code number; only '0', '2', and '3' are
- accepted (without a newline); '2' and '3' are both
- mapped to PM_EVENT_SUSPEND.
-
-On writes, the PM core relies on that recorded event code and the device/bus
-capabilities to determine whether it uses a partial suspend() or resume()
-sequence to change things so that the recorded event corresponds to the
-numeric parameter.
-
- - If the bus requires the irqs-disabled suspend_late()/resume_early()
- phases, writes fail because those operations are not supported here.
-
- - If the recorded value is the expected value, nothing is done.
-
- - If the recorded value is nonzero, the device is partially resumed,
- using the bus.resume() and/or class.resume() methods.
-
- - If the target value is nonzero, the device is partially suspended,
- using the class.suspend() and/or bus.suspend() methods and the
- PM_EVENT_SUSPEND message.
-
-Drivers have no way to tell whether their suspend() and resume() calls
-have come through the sysfs power/state file or as part of entering a
-system sleep state, except that when accessed through sysfs the normal
-parent/child sequencing rules are ignored. Drivers (such as bus, bridge,
-or hub drivers) which expose child devices may need to enforce those rules
-on their own.
diff --git a/Documentation/power/drivers-testing.txt b/Documentation/power/drivers-testing.txt
index e4bdcae..7f7a737 100644
--- a/Documentation/power/drivers-testing.txt
+++ b/Documentation/power/drivers-testing.txt
@@ -6,9 +6,9 @@
Unfortunately, to effectively test the support for the system-wide suspend and
resume transitions in a driver, it is necessary to suspend and resume a fully
functional system with this driver loaded. Moreover, that should be done
-several times, preferably several times in a row, and separately for the suspend
-to disk (STD) and the suspend to RAM (STR) transitions, because each of these
-cases involves different ordering of operations and different interactions with
+several times, preferably several times in a row, and separately for hibernation
+(aka suspend to disk or STD) and suspend to RAM (STR), because each of these
+cases involves slightly different operations and different interactions with
the machine's BIOS.
Of course, for this purpose the test system has to be known to suspend and
@@ -22,20 +22,24 @@
Once you have resolved the suspend/resume-related problems with your test system
without the new driver, you are ready to test it:
-a) Build the driver as a module, load it and try the STD in the test mode (see:
-Documents/power/basic-pm-debugging.txt, 1a)).
+a) Build the driver as a module, load it and try the test modes of hibernation
+ (see: Documents/power/basic-pm-debugging.txt, 1).
-b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown"
-and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and
+ "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
-c) Compile the driver directly into the kernel and try the STD in the test mode.
+c) Compile the driver directly into the kernel and try the test modes of
+ hibernation.
-d) Attempt to suspend to disk with the driver compiled directly into the kernel
-in the "reboot", "shutdown" and "platform" modes.
+d) Attempt to hibernate with the driver compiled directly into the kernel
+ in the "reboot", "shutdown" and "platform" modes.
-e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see:
-Documents/power/basic-pm-debugging.txt, 2). As far as the STR tests are
-concerned, it should not matter whether or not the driver is built as a module.
+e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt,
+ 2). [As far as the STR tests are concerned, it should not matter whether or
+ not the driver is built as a module.]
+
+f) Attempt to suspend to RAM using the s2ram tool with the driver loaded
+ (see: Documents/power/basic-pm-debugging.txt, 2).
Each of the above tests should be repeated several times and the STD tests
should be mixed with the STR tests. If any of them fails, the driver cannot be
diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
index 9293e4b..ae1b7ec0 100644
--- a/Documentation/power/notifiers.txt
+++ b/Documentation/power/notifiers.txt
@@ -28,6 +28,14 @@
hibernation. Device drivers' .resume() callbacks have
been executed and tasks have been thawed.
+PM_RESTORE_PREPARE The system is going to restore a hibernation image.
+ If all goes well the restored kernel will issue a
+ PM_POST_HIBERNATION notification.
+
+PM_POST_RESTORE An error occurred during the hibernation restore.
+ Device drivers' .resume() callbacks have been executed
+ and tasks have been thawed.
+
PM_SUSPEND_PREPARE The system is preparing for a suspend.
PM_POST_SUSPEND The system has just resumed or an error occured during
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index aea7e92..9d60ab7 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -386,6 +386,11 @@
There is a work-around for this problem. For more information, see
Documentation/usb/persist.txt.
+Q: Can I suspend-to-disk using a swap partition under LVM?
+
+A: No. You can suspend successfully, but you'll not be able to
+resume. uswsusp should be able to work with LVM. See suspend.sf.net.
+
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
compiled with the similar configuration files. Anyway I found that
suspend to disk (and resume) is much slower on 2.6.16 compared to
diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index e00c6cf..7b99636 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -14,7 +14,7 @@
The interface consists of a character device providing the open(),
release(), read(), and write() operations as well as several ioctl()
-commands defined in kernel/power/power.h. The major and minor
+commands defined in include/linux/suspend_ioctls.h . The major and minor
numbers of the device are, respectively, 10 and 231, and they can
be read from /sys/class/misc/snapshot/dev.
@@ -27,17 +27,17 @@
The ioctl() commands recognized by the device are:
SNAPSHOT_FREEZE - freeze user space processes (the current process is
- not frozen); this is required for SNAPSHOT_ATOMIC_SNAPSHOT
+ not frozen); this is required for SNAPSHOT_CREATE_IMAGE
and SNAPSHOT_ATOMIC_RESTORE to succeed
SNAPSHOT_UNFREEZE - thaw user space processes frozen by SNAPSHOT_FREEZE
-SNAPSHOT_ATOMIC_SNAPSHOT - create a snapshot of the system memory; the
+SNAPSHOT_CREATE_IMAGE - create a snapshot of the system memory; the
last argument of ioctl() should be a pointer to an int variable,
the value of which will indicate whether the call returned after
creating the snapshot (1) or after restoring the system memory state
from it (0) (after resume the system finds itself finishing the
- SNAPSHOT_ATOMIC_SNAPSHOT ioctl() again); after the snapshot
+ SNAPSHOT_CREATE_IMAGE ioctl() again); after the snapshot
has been created the read() operation can be used to transfer
it out of the kernel
@@ -49,39 +49,37 @@
SNAPSHOT_FREE - free memory allocated for the snapshot image
-SNAPSHOT_SET_IMAGE_SIZE - set the preferred maximum size of the image
+SNAPSHOT_PREF_IMAGE_SIZE - set the preferred maximum size of the image
(the kernel will do its best to ensure the image size will not exceed
this number, but if it turns out to be impossible, the kernel will
create the smallest image possible)
-SNAPSHOT_AVAIL_SWAP - return the amount of available swap in bytes (the last
- argument should be a pointer to an unsigned int variable that will
+SNAPSHOT_GET_IMAGE_SIZE - return the actual size of the hibernation image
+
+SNAPSHOT_AVAIL_SWAP_SIZE - return the amount of available swap in bytes (the
+ last argument should be a pointer to an unsigned int variable that will
contain the result if the call is successful).
-SNAPSHOT_GET_SWAP_PAGE - allocate a swap page from the resume partition
+SNAPSHOT_ALLOC_SWAP_PAGE - allocate a swap page from the resume partition
(the last argument should be a pointer to a loff_t variable that
will contain the swap page offset if the call is successful)
-SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated with
- SNAPSHOT_GET_SWAP_PAGE
-
-SNAPSHOT_SET_SWAP_FILE - set the resume partition (the last ioctl() argument
- should specify the device's major and minor numbers in the old
- two-byte format, as returned by the stat() function in the .st_rdev
- member of the stat structure)
+SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated by
+ SNAPSHOT_ALLOC_SWAP_PAGE
SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
units) from the beginning of the partition at which the swap header is
located (the last ioctl() argument should point to a struct
- resume_swap_area, as defined in kernel/power/power.h, containing the
- resume device specification, as for the SNAPSHOT_SET_SWAP_FILE ioctl(),
- and the offset); for swap partitions the offset is always 0, but it is
- different to zero for swap files (please see
- Documentation/swsusp-and-swap-files.txt for details).
- The SNAPSHOT_SET_SWAP_AREA ioctl() is considered as a replacement for
- SNAPSHOT_SET_SWAP_FILE which is regarded as obsolete. It is
- recommended to always use this call, because the code to set the resume
- partition may be removed from future kernels
+ resume_swap_area, as defined in kernel/power/suspend_ioctls.h,
+ containing the resume device specification and the offset); for swap
+ partitions the offset is always 0, but it is different from zero for
+ swap files (see Documentation/swsusp-and-swap-files.txt for details).
+
+SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
+ depending on the argument value (enable, if the argument is nonzero)
+
+SNAPSHOT_POWER_OFF - make the kernel transition the system to the hibernation
+ state (eg. ACPI S4) using the platform (eg. ACPI) driver
SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
immediately enter the suspend-to-RAM state, so this call must always
@@ -93,24 +91,6 @@
to resume the system from RAM if there's enough battery power or restore
its state on the basis of the saved suspend image otherwise)
-SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
- hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
- swsusp knows these as the "platform method") which are needed on many
- machines to (among others) speed up the resume by letting the BIOS skip
- some steps or to let the system recognise the correct state of the
- hardware after the resume (in particular on many machines this ensures
- that unplugged AC adapters get correctly detected and that kacpid does
- not run wild after the resume). The last ioctl() argument can take one
- of the three values, defined in kernel/power/power.h:
- PMOPS_PREPARE - make the kernel carry out the
- hibernation_ops->prepare() operation
- PMOPS_ENTER - make the kernel power off the system by calling
- hibernation_ops->enter()
- PMOPS_FINISH - make the kernel carry out the
- hibernation_ops->finish() operation
- Note that the actual constants are misnamed because they surface
- internal kernel implementation details that have changed.
-
The device's read() operation can be used to transfer the snapshot image from
the kernel. It has the following limitations:
- you cannot read() more than one virtual memory page at a time
@@ -122,7 +102,7 @@
into the kernel. It has the same limitations as the read() operation.
The release() operation frees all memory allocated for the snapshot image
-and all swap pages allocated with SNAPSHOT_GET_SWAP_PAGE (if any).
+and all swap pages allocated with SNAPSHOT_ALLOC_SWAP_PAGE (if any).
Thus it is not necessary to use either SNAPSHOT_FREE or
SNAPSHOT_FREE_SWAP_PAGES before closing the device (in fact it will also
unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
@@ -133,16 +113,12 @@
partition, or a swap file as storage space (if a swap file is used, the resume
partition is the partition that holds this file). However, this is not really
required, as they can use, for example, a special (blank) suspend partition or
-a file on a partition that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and
+a file on a partition that is unmounted before SNAPSHOT_CREATE_IMAGE and
mounted afterwards.
-These utilities SHOULD NOT make any assumptions regarding the ordering of
-data within the snapshot image, except for the image header that MAY be
-assumed to start with an swsusp_info structure, as specified in
-kernel/power/power.h. This structure MAY be used by the userland utilities
-to obtain some information about the snapshot image, such as the size
-of the snapshot image, including the metadata and the header itself,
-contained in the .size member of swsusp_info.
+These utilities MUST NOT make any assumptions regarding the ordering of
+data within the snapshot image. The contents of the image are entirely owned
+by the kernel and its structure may be changed in future kernel releases.
The snapshot image MUST be written to the kernel unaltered (ie. all of the image
data, metadata and header MUST be written in _exactly_ the same amount, form
@@ -159,7 +135,7 @@
The suspending and resuming utilities MUST lock themselves in memory,
preferrably using mlockall(), before calling SNAPSHOT_FREEZE.
-The suspending utility MUST check the value stored by SNAPSHOT_ATOMIC_SNAPSHOT
+The suspending utility MUST check the value stored by SNAPSHOT_CREATE_IMAGE
in the memory location pointed to by the last argument of ioctl() and proceed
in accordance with it:
1. If the value is 1 (ie. the system memory snapshot has just been
@@ -173,7 +149,7 @@
image has been saved.
(b) The suspending utility SHOULD NOT attempt to perform any
file system operations (including reads) on the file systems
- that were mounted before SNAPSHOT_ATOMIC_SNAPSHOT has been
+ that were mounted before SNAPSHOT_CREATE_IMAGE has been
called. However, it MAY mount a file system that was not
mounted at that time and perform some operations on it (eg.
use it for saving the image).
diff --git a/Documentation/power_supply_class.txt b/Documentation/power_supply_class.txt
index 9758cf4..a8686e5 100644
--- a/Documentation/power_supply_class.txt
+++ b/Documentation/power_supply_class.txt
@@ -87,6 +87,10 @@
Battery driver also can use this attribute just to inform userspace
about maximal and minimal voltage thresholds of a given battery.
+VOLTAGE_MAX, VOLTAGE_MIN - same as _DESIGN voltage values except that
+these ones should be used if hardware could only guess (measure and
+retain) the thresholds of a given power supply.
+
CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when
battery considered full/empty.
@@ -100,8 +104,6 @@
ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
CAPACITY - capacity in percents.
-CAPACITY_LEVEL - capacity level. This corresponds to
-POWER_SUPPLY_CAPACITY_LEVEL_*.
TEMP - temperature of the power supply.
TEMP_AMBIENT - ambient temperature.
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index e20b19c..8deffcd 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -182,8 +182,8 @@
since the frequency is stored in the irq_freq member of the rtc_device
structure. Your driver needs to initialize the irq_freq member during
init. Make sure you check the requested frequency is in range of your
- hardware in the irq_set_freq function. If you cannot actually change
- the frequency, just return -ENOTTY.
+ hardware in the irq_set_freq function. If it isn't, return -EINVAL. If
+ you cannot actually change the frequency, do not define irq_set_freq.
If all else fails, check out the rtc-test.c driver!
@@ -268,8 +268,8 @@
/* This read will block */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -1) {
- perror("read");
- exit(errno);
+ perror("read");
+ exit(errno);
}
fprintf(stderr, " %d",i);
fflush(stderr);
@@ -326,11 +326,11 @@
rtc_tm.tm_sec %= 60;
rtc_tm.tm_min++;
}
- if (rtc_tm.tm_min == 60) {
+ if (rtc_tm.tm_min == 60) {
rtc_tm.tm_min = 0;
rtc_tm.tm_hour++;
}
- if (rtc_tm.tm_hour == 24)
+ if (rtc_tm.tm_hour == 24)
rtc_tm.tm_hour = 0;
retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
@@ -407,8 +407,8 @@
"\n...Periodic IRQ rate is fixed\n");
goto done;
}
- perror("RTC_IRQP_SET ioctl");
- exit(errno);
+ perror("RTC_IRQP_SET ioctl");
+ exit(errno);
}
fprintf(stderr, "\n%ldHz:\t", tmp);
@@ -417,27 +417,27 @@
/* Enable periodic interrupts */
retval = ioctl(fd, RTC_PIE_ON, 0);
if (retval == -1) {
- perror("RTC_PIE_ON ioctl");
- exit(errno);
+ perror("RTC_PIE_ON ioctl");
+ exit(errno);
}
for (i=1; i<21; i++) {
- /* This blocks */
- retval = read(fd, &data, sizeof(unsigned long));
- if (retval == -1) {
- perror("read");
- exit(errno);
- }
- fprintf(stderr, " %d",i);
- fflush(stderr);
- irqcount++;
+ /* This blocks */
+ retval = read(fd, &data, sizeof(unsigned long));
+ if (retval == -1) {
+ perror("read");
+ exit(errno);
+ }
+ fprintf(stderr, " %d",i);
+ fflush(stderr);
+ irqcount++;
}
/* Disable periodic interrupts */
retval = ioctl(fd, RTC_PIE_OFF, 0);
if (retval == -1) {
- perror("RTC_PIE_OFF ioctl");
- exit(errno);
+ perror("RTC_PIE_OFF ioctl");
+ exit(errno);
}
}
diff --git a/Documentation/smp.txt b/Documentation/smp.txt
deleted file mode 100644
index 82fc50b..0000000
--- a/Documentation/smp.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-To set up SMP
-
-Configure the kernel and answer Y to CONFIG_SMP.
-
-If you are using LILO, it is handy to have both SMP and non-SMP
-kernel images on hand. Edit /etc/lilo.conf to create an entry
-for another kernel image called "linux-smp" or something.
-
-The next time you compile the kernel, when running a SMP kernel,
-edit linux/Makefile and change "MAKE=make" to "MAKE=make -jN"
-(where N = number of CPU + 1, or if you have tons of memory/swap
- you can just use "-j" without a number). Feel free to experiment
-with this one.
-
-Of course you should time how long each build takes :-)
-Example:
- make config
- time -v sh -c 'make clean install modules modules_install'
-
-If you are using some Compaq MP compliant machines you will need to set
-the operating system in the BIOS settings to "Unixware" - don't ask me
-why Compaqs don't work otherwise.
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
index aa986a3..f992543 100644
--- a/Documentation/sysctl/fs.txt
+++ b/Documentation/sysctl/fs.txt
@@ -23,6 +23,7 @@
- inode-max
- inode-nr
- inode-state
+- nr_open
- overflowuid
- overflowgid
- suid_dumpable
@@ -91,6 +92,15 @@
==============================================================
+nr_open:
+
+This denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
+==============================================================
+
inode-max, inode-nr & inode-state:
As with file handles, the kernel allocates the inode structures
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 6f31f0a..24eac1b 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -22,6 +22,7 @@
- dirty_background_ratio
- dirty_expire_centisecs
- dirty_writeback_centisecs
+- highmem_is_dirtyable (only if CONFIG_HIGHMEM set)
- max_map_count
- min_free_kbytes
- laptop_mode
@@ -40,9 +41,9 @@
==============================================================
dirty_ratio, dirty_background_ratio, dirty_expire_centisecs,
-dirty_writeback_centisecs, vfs_cache_pressure, laptop_mode,
-block_dump, swap_token_timeout, drop-caches,
-hugepages_treat_as_movable:
+dirty_writeback_centisecs, highmem_is_dirtyable,
+vfs_cache_pressure, laptop_mode, block_dump, swap_token_timeout,
+drop-caches, hugepages_treat_as_movable:
See Documentation/filesystems/proc.txt
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index 10c041c..6c24777 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,7 +1,7 @@
ThinkPad ACPI Extras Driver
- Version 0.17
- October 04th, 2007
+ Version 0.19
+ January 06th, 2008
Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -215,6 +215,11 @@
... any other 8-hex-digit mask ...
echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
+The procfs interface does not support NVRAM polling control. So as to
+maintain maximum bug-to-bug compatibility, it does not report any masks,
+nor does it allow one to manipulate the hot key mask when the firmware
+does not support masks at all, even if NVRAM polling is in use.
+
sysfs notes:
hotkey_bios_enabled:
@@ -231,17 +236,26 @@
to this value.
hotkey_enable:
- Enables/disables the hot keys feature, and reports
- current status of the hot keys feature.
+ Enables/disables the hot keys feature in the ACPI
+ firmware, and reports current status of the hot keys
+ feature. Has no effect on the NVRAM hot key polling
+ functionality.
0: disables the hot keys feature / feature disabled
1: enables the hot keys feature / feature enabled
hotkey_mask:
- bit mask to enable driver-handling and ACPI event
- generation for each hot key (see above). Returns the
- current status of the hot keys mask, and allows one to
- modify it.
+ bit mask to enable driver-handling (and depending on
+ the firmware, ACPI event generation) for each hot key
+ (see above). Returns the current status of the hot keys
+ mask, and allows one to modify it.
+
+ Note: when NVRAM polling is active, the firmware mask
+ will be different from the value returned by
+ hotkey_mask. The driver will retain enabled bits for
+ hotkeys that are under NVRAM polling even if the
+ firmware refuses them, and will not set these bits on
+ the firmware hot key mask.
hotkey_all_mask:
bit mask that should enable event reporting for all
@@ -257,12 +271,48 @@
handled by the firmware anyway. Echo it to
hotkey_mask above, to use.
+ hotkey_source_mask:
+ bit mask that selects which hot keys will the driver
+ poll the NVRAM for. This is auto-detected by the driver
+ based on the capabilities reported by the ACPI firmware,
+ but it can be overridden at runtime.
+
+ Hot keys whose bits are set in both hotkey_source_mask
+ and also on hotkey_mask are polled for in NVRAM. Only a
+ few hot keys are available through CMOS NVRAM polling.
+
+ Warning: when in NVRAM mode, the volume up/down/mute
+ keys are synthesized according to changes in the mixer,
+ so you have to use volume up or volume down to unmute,
+ as per the ThinkPad volume mixer user interface. When
+ in ACPI event mode, volume up/down/mute are reported as
+ separate events, but this behaviour may be corrected in
+ future releases of this driver, in which case the
+ ThinkPad volume mixer user interface semanthics will be
+ enforced.
+
+ hotkey_poll_freq:
+ frequency in Hz for hot key polling. It must be between
+ 0 and 25 Hz. Polling is only carried out when strictly
+ needed.
+
+ Setting hotkey_poll_freq to zero disables polling, and
+ will cause hot key presses that require NVRAM polling
+ to never be reported.
+
+ Setting hotkey_poll_freq too low will cause repeated
+ pressings of the same hot key to be misreported as a
+ single key press, or to not even be detected at all.
+ The recommended polling frequency is 10Hz.
+
hotkey_radio_sw:
if the ThinkPad has a hardware radio switch, this
attribute will read 0 if the switch is in the "radios
disabled" postition, and 1 if the switch is in the
"radios enabled" position.
+ This attribute has poll()/select() support.
+
hotkey_report_mode:
Returns the state of the procfs ACPI event report mode
filter for hot keys. If it is set to 1 (the default),
@@ -277,6 +327,25 @@
May return -EPERM (write access locked out by module
parameter) or -EACCES (read-only).
+ wakeup_reason:
+ Set to 1 if the system is waking up because the user
+ requested a bay ejection. Set to 2 if the system is
+ waking up because the user requested the system to
+ undock. Set to zero for normal wake-ups or wake-ups
+ due to unknown reasons.
+
+ This attribute has poll()/select() support.
+
+ wakeup_hotunplug_complete:
+ Set to 1 if the system was waken up because of an
+ undock or bay ejection request, and that request
+ was sucessfully completed. At this point, it might
+ be useful to send the system back to sleep, at the
+ user's choice. Refer to HKEY events 0x4003 and
+ 0x3003, below.
+
+ This attribute has poll()/select() support.
+
input layer notes:
A Hot key is mapped to a single input layer EV_KEY event, possibly
@@ -427,6 +496,23 @@
The above events are not propagated by the driver, except for legacy
compatibility purposes when hotkey_report_mode is set to 1.
+0x2304 System is waking up from suspend to undock
+0x2305 System is waking up from suspend to eject bay
+0x2404 System is waking up from hibernation to undock
+0x2405 System is waking up from hibernation to eject bay
+
+The above events are never propagated by the driver.
+
+0x3003 Bay ejection (see 0x2x05) complete, can sleep again
+0x4003 Undocked (see 0x2x04), can sleep again
+0x5009 Tablet swivel: switched to tablet mode
+0x500A Tablet swivel: switched to normal mode
+0x500B Tablet pen insterted into its storage bay
+0x500C Tablet pen removed from its storage bay
+0x5010 Brightness level changed (newer Lenovo BIOSes)
+
+The above events are propagated by the driver.
+
Compatibility notes:
ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never
@@ -1263,3 +1349,17 @@
and the hwmon class for libsensors4 (lm-sensors 3)
compatibility. Moved all hwmon attributes to this
new platform device.
+
+0x020100: Marker for thinkpad-acpi with hot key NVRAM polling
+ support. If you must, use it to know you should not
+ start an userspace NVRAM poller (allows to detect when
+ NVRAM is compiled out by the user because it is
+ unneeded/undesired in the first place).
+0x020101: Marker for thinkpad-acpi with hot key NVRAM polling
+ and proper hotkey_mask semanthics (version 8 of the
+ NVRAM polling patch). Some development snapshots of
+ 0.18 had an earlier version that did strange things
+ to hotkey_mask.
+
+0x020200: Add poll()/select() support to the following attributes:
+ hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason
diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt
new file mode 100644
index 0000000..6223eac
--- /dev/null
+++ b/Documentation/unaligned-memory-access.txt
@@ -0,0 +1,226 @@
+UNALIGNED MEMORY ACCESSES
+=========================
+
+Linux runs on a wide variety of architectures which have varying behaviour
+when it comes to memory access. This document presents some details about
+unaligned accesses, why you need to write code that doesn't cause them,
+and how to write such code!
+
+
+The definition of an unaligned access
+=====================================
+
+Unaligned memory accesses occur when you try to read N bytes of data starting
+from an address that is not evenly divisible by N (i.e. addr % N != 0).
+For example, reading 4 bytes of data from address 0x10004 is fine, but
+reading 4 bytes of data from address 0x10005 would be an unaligned memory
+access.
+
+The above may seem a little vague, as memory access can happen in different
+ways. The context here is at the machine code level: certain instructions read
+or write a number of bytes to or from memory (e.g. movb, movw, movl in x86
+assembly). As will become clear, it is relatively easy to spot C statements
+which will compile to multiple-byte memory access instructions, namely when
+dealing with types such as u16, u32 and u64.
+
+
+Natural alignment
+=================
+
+The rule mentioned above forms what we refer to as natural alignment:
+When accessing N bytes of memory, the base memory address must be evenly
+divisible by N, i.e. addr % N == 0.
+
+When writing code, assume the target architecture has natural alignment
+requirements.
+
+In reality, only a few architectures require natural alignment on all sizes
+of memory access. However, we must consider ALL supported architectures;
+writing code that satisfies natural alignment requirements is the easiest way
+to achieve full portability.
+
+
+Why unaligned access is bad
+===========================
+
+The effects of performing an unaligned memory access vary from architecture
+to architecture. It would be easy to write a whole document on the differences
+here; a summary of the common scenarios is presented below:
+
+ - Some architectures are able to perform unaligned memory accesses
+ transparently, but there is usually a significant performance cost.
+ - Some architectures raise processor exceptions when unaligned accesses
+ happen. The exception handler is able to correct the unaligned access,
+ at significant cost to performance.
+ - Some architectures raise processor exceptions when unaligned accesses
+ happen, but the exceptions do not contain enough information for the
+ unaligned access to be corrected.
+ - Some architectures are not capable of unaligned memory access, but will
+ silently perform a different memory access to the one that was requested,
+ resulting a a subtle code bug that is hard to detect!
+
+It should be obvious from the above that if your code causes unaligned
+memory accesses to happen, your code will not work correctly on certain
+platforms and will cause performance problems on others.
+
+
+Code that does not cause unaligned access
+=========================================
+
+At first, the concepts above may seem a little hard to relate to actual
+coding practice. After all, you don't have a great deal of control over
+memory addresses of certain variables, etc.
+
+Fortunately things are not too complex, as in most cases, the compiler
+ensures that things will work for you. For example, take the following
+structure:
+
+ struct foo {
+ u16 field1;
+ u32 field2;
+ u8 field3;
+ };
+
+Let us assume that an instance of the above structure resides in memory
+starting at address 0x10000. With a basic level of understanding, it would
+not be unreasonable to expect that accessing field2 would cause an unaligned
+access. You'd be expecting field2 to be located at offset 2 bytes into the
+structure, i.e. address 0x10002, but that address is not evenly divisible
+by 4 (remember, we're reading a 4 byte value here).
+
+Fortunately, the compiler understands the alignment constraints, so in the
+above case it would insert 2 bytes of padding in between field1 and field2.
+Therefore, for standard structure types you can always rely on the compiler
+to pad structures so that accesses to fields are suitably aligned (assuming
+you do not cast the field to a type of different length).
+
+Similarly, you can also rely on the compiler to align variables and function
+parameters to a naturally aligned scheme, based on the size of the type of
+the variable.
+
+At this point, it should be clear that accessing a single byte (u8 or char)
+will never cause an unaligned access, because all memory addresses are evenly
+divisible by one.
+
+On a related topic, with the above considerations in mind you may observe
+that you could reorder the fields in the structure in order to place fields
+where padding would otherwise be inserted, and hence reduce the overall
+resident memory size of structure instances. The optimal layout of the
+above example is:
+
+ struct foo {
+ u32 field2;
+ u16 field1;
+ u8 field3;
+ };
+
+For a natural alignment scheme, the compiler would only have to add a single
+byte of padding at the end of the structure. This padding is added in order
+to satisfy alignment constraints for arrays of these structures.
+
+Another point worth mentioning is the use of __attribute__((packed)) on a
+structure type. This GCC-specific attribute tells the compiler never to
+insert any padding within structures, useful when you want to use a C struct
+to represent some data that comes in a fixed arrangement 'off the wire'.
+
+You might be inclined to believe that usage of this attribute can easily
+lead to unaligned accesses when accessing fields that do not satisfy
+architectural alignment requirements. However, again, the compiler is aware
+of the alignment constraints and will generate extra instructions to perform
+the memory access in a way that does not cause unaligned access. Of course,
+the extra instructions obviously cause a loss in performance compared to the
+non-packed case, so the packed attribute should only be used when avoiding
+structure padding is of importance.
+
+
+Code that causes unaligned access
+=================================
+
+With the above in mind, let's move onto a real life example of a function
+that can cause an unaligned memory access. The following function adapted
+from include/linux/etherdevice.h is an optimized routine to compare two
+ethernet MAC addresses for equality.
+
+unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2)
+{
+ const u16 *a = (const u16 *) addr1;
+ const u16 *b = (const u16 *) addr2;
+ return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+}
+
+In the above function, the reference to a[0] causes 2 bytes (16 bits) to
+be read from memory starting at address addr1. Think about what would happen
+if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned
+access.)
+
+Despite the potential unaligned access problems with the above function, it
+is included in the kernel anyway but is understood to only work on
+16-bit-aligned addresses. It is up to the caller to ensure this alignment or
+not use this function at all. This alignment-unsafe function is still useful
+as it is a decent optimization for the cases when you can ensure alignment,
+which is true almost all of the time in ethernet networking context.
+
+
+Here is another example of some code that could cause unaligned accesses:
+ void myfunc(u8 *data, u32 value)
+ {
+ [...]
+ *((u32 *) data) = cpu_to_le32(value);
+ [...]
+ }
+
+This code will cause unaligned accesses every time the data parameter points
+to an address that is not evenly divisible by 4.
+
+In summary, the 2 main scenarios where you may run into unaligned access
+problems involve:
+ 1. Casting variables to types of different lengths
+ 2. Pointer arithmetic followed by access to at least 2 bytes of data
+
+
+Avoiding unaligned accesses
+===========================
+
+The easiest way to avoid unaligned access is to use the get_unaligned() and
+put_unaligned() macros provided by the <asm/unaligned.h> header file.
+
+Going back to an earlier example of code that potentially causes unaligned
+access:
+
+ void myfunc(u8 *data, u32 value)
+ {
+ [...]
+ *((u32 *) data) = cpu_to_le32(value);
+ [...]
+ }
+
+To avoid the unaligned memory access, you would rewrite it as follows:
+
+ void myfunc(u8 *data, u32 value)
+ {
+ [...]
+ value = cpu_to_le32(value);
+ put_unaligned(value, (u32 *) data);
+ [...]
+ }
+
+The get_unaligned() macro works similarly. Assuming 'data' is a pointer to
+memory and you wish to avoid unaligned access, its usage is as follows:
+
+ u32 value = get_unaligned((u32 *) data);
+
+These macros work work for memory accesses of any length (not just 32 bits as
+in the examples above). Be aware that when compared to standard access of
+aligned memory, using these macros to access unaligned memory can be costly in
+terms of performance.
+
+If use of such macros is not convenient, another option is to use memcpy(),
+where the source or destination (or both) are of type u8* or unsigned char*.
+Due to the byte-wise nature of this operation, unaligned accesses are avoided.
+
+--
+Author: Daniel Drake <dsd@gentoo.org>
+With help from: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt,
+Johannes Berg, Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock,
+Uli Kunitz, Vadim Lobanov
+
diff --git a/Documentation/usb/gadget_printer.txt b/Documentation/usb/gadget_printer.txt
new file mode 100644
index 0000000..ad995bf
--- /dev/null
+++ b/Documentation/usb/gadget_printer.txt
@@ -0,0 +1,510 @@
+
+ Linux USB Printer Gadget Driver
+ 06/04/2007
+
+ Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
+
+
+
+GENERAL
+=======
+
+This driver may be used if you are writing printer firmware using Linux as
+the embedded OS. This driver has nothing to do with using a printer with
+your Linux host system.
+
+You will need a USB device controller and a Linux driver for it that accepts
+a gadget / "device class" driver using the Linux USB Gadget API. After the
+USB device controller driver is loaded then load the printer gadget driver.
+This will present a printer interface to the USB Host that your USB Device
+port is connected to.
+
+This driver is structured for printer firmware that runs in user mode. The
+user mode printer firmware will read and write data from the kernel mode
+printer gadget driver using a device file. The printer returns a printer status
+byte when the USB HOST sends a device request to get the printer status. The
+user space firmware can read or write this status byte using a device file
+/dev/g_printer . Both blocking and non-blocking read/write calls are supported.
+
+
+
+
+HOWTO USE THIS DRIVER
+=====================
+
+To load the USB device controller driver and the printer gadget driver. The
+following example uses the Netchip 2280 USB device controller driver:
+
+modprobe net2280
+modprobe g_printer
+
+
+The follow command line parameter can be used when loading the printer gadget
+(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
+
+idVendor - This is the Vendor ID used in the device descriptor. The default is
+ the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
+ BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
+ already have a Vendor ID please see www.usb.org for details on how to
+ get one.
+
+idProduct - This is the Product ID used in the device descriptor. The default
+ is 0xa4a8, you should change this to an ID that's not used by any of
+ your other USB products if you have any. It would be a good idea to
+ start numbering your products starting with say 0x0001.
+
+bcdDevice - This is the version number of your product. It would be a good idea
+ to put your firmware version here.
+
+iManufacturer - A string containing the name of the Vendor.
+
+iProduct - A string containing the Product Name.
+
+iSerialNum - A string containing the Serial Number. This should be changed for
+ each unit of your product.
+
+iPNPstring - The PNP ID string used for this printer. You will want to set
+ either on the command line or hard code the PNP ID string used for
+ your printer product.
+
+qlen - The number of 8k buffers to use per endpoint. The default is 10, you
+ should tune this for your product. You may also want to tune the
+ size of each buffer for your product.
+
+
+
+
+USING THE EXAMPLE CODE
+======================
+
+This example code talks to stdout, instead of a print engine.
+
+To compile the test code below:
+
+1) save it to a file called prn_example.c
+2) compile the code with the follow command:
+ gcc prn_example.c -o prn_example
+
+
+
+To read printer data from the host to stdout:
+
+ # prn_example -read_data
+
+
+To write printer data from a file (data_file) to the host:
+
+ # cat data_file | prn_example -write_data
+
+
+To get the current printer status for the gadget driver:
+
+ # prn_example -get_status
+
+ Printer status is:
+ Printer is NOT Selected
+ Paper is Out
+ Printer OK
+
+
+To set printer to Selected/On-line:
+
+ # prn_example -selected
+
+
+To set printer to Not Selected/Off-line:
+
+ # prn_example -not_selected
+
+
+To set paper status to paper out:
+
+ # prn_example -paper_out
+
+
+To set paper status to paper loaded:
+
+ # prn_example -paper_loaded
+
+
+To set error status to printer OK:
+
+ # prn_example -no_error
+
+
+To set error status to ERROR:
+
+ # prn_example -error
+
+
+
+
+EXAMPLE CODE
+============
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <linux/poll.h>
+#include <sys/ioctl.h>
+#include <linux/usb/g_printer.h>
+
+#define PRINTER_FILE "/dev/g_printer"
+#define BUF_SIZE 512
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(const char *option) /* I - Option string or NULL */
+{
+ if (option) {
+ fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
+ option);
+ }
+
+ fputs("\n", stderr);
+ fputs("Usage: prn_example -[options]\n", stderr);
+ fputs("Options:\n", stderr);
+ fputs("\n", stderr);
+ fputs("-get_status Get the current printer status.\n", stderr);
+ fputs("-selected Set the selected status to selected.\n", stderr);
+ fputs("-not_selected Set the selected status to NOT selected.\n",
+ stderr);
+ fputs("-error Set the error status to error.\n", stderr);
+ fputs("-no_error Set the error status to NO error.\n", stderr);
+ fputs("-paper_out Set the paper status to paper out.\n", stderr);
+ fputs("-paper_loaded Set the paper status to paper loaded.\n",
+ stderr);
+ fputs("-read_data Read printer data from driver.\n", stderr);
+ fputs("-write_data Write printer sata to driver.\n", stderr);
+ fputs("-NB_read_data (Non-Blocking) Read printer data from driver.\n",
+ stderr);
+ fputs("\n\n", stderr);
+
+ exit(1);
+}
+
+
+static int
+read_printer_data()
+{
+ struct pollfd fd[1];
+
+ /* Open device file for printer gadget. */
+ fd[0].fd = open(PRINTER_FILE, O_RDWR);
+ if (fd[0].fd < 0) {
+ printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
+ close(fd[0].fd);
+ return(-1);
+ }
+
+ fd[0].events = POLLIN | POLLRDNORM;
+
+ while (1) {
+ static char buf[BUF_SIZE];
+ int bytes_read;
+ int retval;
+
+ /* Wait for up to 1 second for data. */
+ retval = poll(fd, 1, 1000);
+
+ if (retval && (fd[0].revents & POLLRDNORM)) {
+
+ /* Read data from printer gadget driver. */
+ bytes_read = read(fd[0].fd, buf, BUF_SIZE);
+
+ if (bytes_read < 0) {
+ printf("Error %d reading from %s\n",
+ fd[0].fd, PRINTER_FILE);
+ close(fd[0].fd);
+ return(-1);
+ } else if (bytes_read > 0) {
+ /* Write data to standard OUTPUT (stdout). */
+ fwrite(buf, 1, bytes_read, stdout);
+ fflush(stdout);
+ }
+
+ }
+
+ }
+
+ /* Close the device file. */
+ close(fd[0].fd);
+
+ return 0;
+}
+
+
+static int
+write_printer_data()
+{
+ struct pollfd fd[1];
+
+ /* Open device file for printer gadget. */
+ fd[0].fd = open (PRINTER_FILE, O_RDWR);
+ if (fd[0].fd < 0) {
+ printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
+ close(fd[0].fd);
+ return(-1);
+ }
+
+ fd[0].events = POLLOUT | POLLWRNORM;
+
+ while (1) {
+ int retval;
+ static char buf[BUF_SIZE];
+ /* Read data from standard INPUT (stdin). */
+ int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
+
+ if (!bytes_read) {
+ break;
+ }
+
+ while (bytes_read) {
+
+ /* Wait for up to 1 second to sent data. */
+ retval = poll(fd, 1, 1000);
+
+ /* Write data to printer gadget driver. */
+ if (retval && (fd[0].revents & POLLWRNORM)) {
+ retval = write(fd[0].fd, buf, bytes_read);
+ if (retval < 0) {
+ printf("Error %d writing to %s\n",
+ fd[0].fd,
+ PRINTER_FILE);
+ close(fd[0].fd);
+ return(-1);
+ } else {
+ bytes_read -= retval;
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Wait until the data has been sent. */
+ fsync(fd[0].fd);
+
+ /* Close the device file. */
+ close(fd[0].fd);
+
+ return 0;
+}
+
+
+static int
+read_NB_printer_data()
+{
+ int fd;
+ static char buf[BUF_SIZE];
+ int bytes_read;
+
+ /* Open device file for printer gadget. */
+ fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
+ if (fd < 0) {
+ printf("Error %d opening %s\n", fd, PRINTER_FILE);
+ close(fd);
+ return(-1);
+ }
+
+ while (1) {
+ /* Read data from printer gadget driver. */
+ bytes_read = read(fd, buf, BUF_SIZE);
+ if (bytes_read <= 0) {
+ break;
+ }
+
+ /* Write data to standard OUTPUT (stdout). */
+ fwrite(buf, 1, bytes_read, stdout);
+ fflush(stdout);
+ }
+
+ /* Close the device file. */
+ close(fd);
+
+ return 0;
+}
+
+
+static int
+get_printer_status()
+{
+ int retval;
+ int fd;
+
+ /* Open device file for printer gadget. */
+ fd = open(PRINTER_FILE, O_RDWR);
+ if (fd < 0) {
+ printf("Error %d opening %s\n", fd, PRINTER_FILE);
+ close(fd);
+ return(-1);
+ }
+
+ /* Make the IOCTL call. */
+ retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
+ if (retval < 0) {
+ fprintf(stderr, "ERROR: Failed to set printer status\n");
+ return(-1);
+ }
+
+ /* Close the device file. */
+ close(fd);
+
+ return(retval);
+}
+
+
+static int
+set_printer_status(unsigned char buf, int clear_printer_status_bit)
+{
+ int retval;
+ int fd;
+
+ retval = get_printer_status();
+ if (retval < 0) {
+ fprintf(stderr, "ERROR: Failed to get printer status\n");
+ return(-1);
+ }
+
+ /* Open device file for printer gadget. */
+ fd = open(PRINTER_FILE, O_RDWR);
+
+ if (fd < 0) {
+ printf("Error %d opening %s\n", fd, PRINTER_FILE);
+ close(fd);
+ return(-1);
+ }
+
+ if (clear_printer_status_bit) {
+ retval &= ~buf;
+ } else {
+ retval |= buf;
+ }
+
+ /* Make the IOCTL call. */
+ if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
+ fprintf(stderr, "ERROR: Failed to set printer status\n");
+ return(-1);
+ }
+
+ /* Close the device file. */
+ close(fd);
+
+ return 0;
+}
+
+
+static int
+display_printer_status()
+{
+ char printer_status;
+
+ printer_status = get_printer_status();
+ if (printer_status < 0) {
+ fprintf(stderr, "ERROR: Failed to get printer status\n");
+ return(-1);
+ }
+
+ printf("Printer status is:\n");
+ if (printer_status & PRINTER_SELECTED) {
+ printf(" Printer is Selected\n");
+ } else {
+ printf(" Printer is NOT Selected\n");
+ }
+ if (printer_status & PRINTER_PAPER_EMPTY) {
+ printf(" Paper is Out\n");
+ } else {
+ printf(" Paper is Loaded\n");
+ }
+ if (printer_status & PRINTER_NOT_ERROR) {
+ printf(" Printer OK\n");
+ } else {
+ printf(" Printer ERROR\n");
+ }
+
+ return(0);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int i; /* Looping var */
+ int retval = 0;
+
+ /* No Args */
+ if (argc == 1) {
+ usage(0);
+ exit(0);
+ }
+
+ for (i = 1; i < argc && !retval; i ++) {
+
+ if (argv[i][0] != '-') {
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-get_status")) {
+ if (display_printer_status()) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-paper_loaded")) {
+ if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-paper_out")) {
+ if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-selected")) {
+ if (set_printer_status(PRINTER_SELECTED, 0)) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-not_selected")) {
+ if (set_printer_status(PRINTER_SELECTED, 1)) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-error")) {
+ if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-no_error")) {
+ if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-read_data")) {
+ if (read_printer_data()) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-write_data")) {
+ if (write_printer_data()) {
+ retval = 1;
+ }
+
+ } else if (!strcmp(argv[i], "-NB_read_data")) {
+ if (read_NB_printer_data()) {
+ retval = 1;
+ }
+
+ } else {
+ usage(argv[i]);
+ retval = 1;
+ }
+ }
+
+ exit(retval);
+}
diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt
new file mode 100644
index 0000000..e5f0480
--- /dev/null
+++ b/Documentation/usb/iuu_phoenix.txt
@@ -0,0 +1,84 @@
+Infinity Usb Unlimited Readme
+-----------------------------
+
+Hi all,
+
+
+This module provide a serial interface to use your
+IUU unit in phoenix mode. Loading this module will
+bring a ttyUSB[0-x] interface. This driver must be
+used by your favorite application to pilot the IUU
+
+This driver is still in beta stage, so bugs can
+occur and your system may freeze. As far I now,
+I never had any problem with it, but I'm not a real
+guru, so don't blame me if your system is unstable
+
+You can plug more than one IUU. Every unit will
+have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...)
+
+
+
+How to tune the reader speed ?
+
+ A few parameters can be used at load time
+ To use parameters, just unload the module if it is
+ already loaded and use modprobe iuu_phoenix param=value.
+ In case of prebuilt module, use the command
+ insmod iuu_phoenix param=value.
+
+ Example:
+
+ modprobe iuu_phoenix clockmode=3
+
+ The parameters are:
+
+ parm: clockmode:1=3Mhz579,2=3Mhz680,3=6Mhz (int)
+ parm: boost:overclock boost percent 100 to 500 (int)
+ parm: cdmode:Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int)
+ parm: xmas:xmas color enabled or not (bool)
+ parm: debug:Debug enabled or not (bool)
+
+- clockmode will provide 3 different base settings commonly adopted by
+ different software:
+ 1. 3Mhz579
+ 2. 3Mhz680
+ 3. 6Mhz
+
+- boost provide a way to overclock the reader ( my favorite :-) )
+ For example to have best performance than a simple clockmode=3, try this:
+
+ modprobe boost=195
+
+ This will put the reader in a base of 3Mhz579 but boosted a 195 % !
+ the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase
+ the speed to a score 10 to 20% better than the simple clockmode=3 !!!
+
+
+- cdmode permit to setup the signal used to inform the userland ( ioctl answer )
+ if the card is present or not. Eight signals are possible.
+
+- xmas is completely useless except for your eyes. This is one of my friend who was
+ so sad to have a nice device like the iuu without seeing all color range available.
+ So I have added this option to permit him to see a lot of color ( each activity change the color
+ and the frequency randomly )
+
+- debug will produce a lot of debugging messages...
+
+
+ Last notes:
+
+ Don't worry about the serial settings, the serial emulation
+ is an abstraction, so use any speed or parity setting will
+ work. ( This will not change anything ).Later I will perhaps
+ use this settings to deduce de boost but is that feature
+ really necessary ?
+ The autodetect feature used is the serial CD. If that doesn't
+ work for your software, disable detection mechanism in it.
+
+
+ Have fun !
+
+ Alain Degreffe
+
+ eczema(at)ecze.com
diff --git a/Documentation/w1/masters/00-INDEX b/Documentation/w1/masters/00-INDEX
index 752613c..7b0ceaa 100644
--- a/Documentation/w1/masters/00-INDEX
+++ b/Documentation/w1/masters/00-INDEX
@@ -4,3 +4,5 @@
- The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
ds2490
- The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
+w1-gpio
+ - GPIO 1-wire bus master driver.
diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio
new file mode 100644
index 0000000..af5d3b4
--- /dev/null
+++ b/Documentation/w1/masters/w1-gpio
@@ -0,0 +1,33 @@
+Kernel driver w1-gpio
+=====================
+
+Author: Ville Syrjala <syrjala@sci.fi>
+
+
+Description
+-----------
+
+GPIO 1-wire bus master driver. The driver uses the GPIO API to control the
+wire and the GPIO pin can be specified using platform data.
+
+
+Example (mach-at91)
+-------------------
+
+#include <linux/w1-gpio.h>
+
+static struct w1_gpio_platform_data foo_w1_gpio_pdata = {
+ .pin = AT91_PIN_PB20,
+ .is_open_drain = 1,
+};
+
+static struct platform_device foo_w1_device = {
+ .name = "w1-gpio",
+ .id = -1,
+ .dev.platform_data = &foo_w1_gpio_pdata,
+};
+
+...
+ at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1);
+ at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1);
+ platform_device_register(&foo_w1_device);
diff --git a/Documentation/x86_64/00-INDEX b/Documentation/x86_64/00-INDEX
new file mode 100644
index 0000000..92fc20a
--- /dev/null
+++ b/Documentation/x86_64/00-INDEX
@@ -0,0 +1,16 @@
+00-INDEX
+ - This file
+boot-options.txt
+ - AMD64-specific boot options.
+cpu-hotplug-spec
+ - Firmware support for CPU hotplug under Linux/x86-64
+fake-numa-for-cpusets
+ - Using numa=fake and CPUSets for Resource Management
+kernel-stacks
+ - Context-specific per-processor interrupt stacks.
+machinecheck
+ - Configurable sysfs parameters for the x86-64 machine check code.
+mm.txt
+ - Memory layout of x86-64 (4 level page tables, 46 bits physical).
+uefi.txt
+ - Booting Linux via Unified Extensible Firmware Interface.
diff --git a/MAINTAINERS b/MAINTAINERS
index 91082e6..0885aa2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -84,13 +84,6 @@
it has been replaced by a better system and you
should be using that.
-3C359 NETWORK DRIVER
-P: Mike Phillips
-M: mikep@linuxtr.net
-L: netdev@vger.kernel.org
-W: http://www.linuxtr.net
-S: Maintained
-
3C505 NETWORK DRIVER
P: Philip Blundell
M: philb@gnu.org
@@ -345,13 +338,12 @@
AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
P: Thomas Dahlmann
M: thomas.dahlmann@amd.com
-L: info-linux@geode.amd.com
+L: info-linux@geode.amd.com (subscribers-only)
S: Supported
AMD GEODE PROCESSOR/CHIPSET SUPPORT
P: Jordan Crouse
-M: info-linux@geode.amd.com
-L: info-linux@geode.amd.com
+L: info-linux@geode.amd.com (subscribers-only)
W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
S: Supported
@@ -848,6 +840,12 @@
T: git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
S: Maintained
+BLOCK2MTD DRIVER
+P: Joern Engel
+M: joern@lazybastard.org
+L: linux-mtd@lists.infradead.org
+S: Maintained
+
BLUETOOTH SUBSYSTEM
P: Marcel Holtmann
M: marcel@holtmann.org
@@ -939,8 +937,6 @@
S: Maintained
BONDING DRIVER
-P: Chad Tindel
-M: ctindel@users.sourceforge.net
P: Jay Vosburgh
M: fubar@us.ibm.com
L: bonding-devel@lists.sourceforge.net
@@ -2247,7 +2243,7 @@
M: bfields@fieldses.org
P: Neil Brown
M: neilb@suse.de
-L: nfs@lists.sourceforge.net
+L: linux-nfs@vger.kernel.org
W: http://nfs.sourceforge.net/
S: Supported
@@ -2258,6 +2254,15 @@
W: kvm.sourceforge.net
S: Supported
+KERNEL VIRTUAL MACHINE For Itanium(KVM/IA64)
+P: Anthony Xu
+M: anthony.xu@intel.com
+P: Xiantao Zhang
+M: xiantao.zhang@intel.com
+L: kvm-ia64-devel@lists.sourceforge.net
+W: kvm.sourceforge.net
+S: Supported
+
KEXEC
P: Eric Biederman
M: ebiederm@xmission.com
@@ -2690,6 +2695,16 @@
L: linux-scsi@vger.kernel.org
S: Maintained
+NETEFFECT IWARP RNIC DRIVER (IW_NES)
+P: Faisal Latif
+M: flatif@neteffect.com
+P: Glenn Streiff
+M: gstreiff@neteffect.com
+L: general@lists.openfabrics.org
+W: http://www.neteffect.com
+S: Supported
+F: drivers/infiniband/hw/nes/
+
NETEM NETWORK EMULATOR
P: Stephen Hemminger
M: shemminger@linux-foundation.org
@@ -2864,15 +2879,6 @@
W: http://oss.oracle.com/projects/ocfs2/
S: Supported
-OLYMPIC NETWORK DRIVER
-P: Peter De Shrijver
-M: p2@ace.ulyssis.student.kuleuven.ac.be
-P: Mike Phillips
-M: mikep@linuxtr.net
-L: netdev@vger.kernel.org
-W: http://www.linuxtr.net
-S: Maintained
-
OMNIKEY CARDMAN 4000 DRIVER
P: Harald Welte
M: laforge@gnumonks.org
@@ -3030,8 +3036,8 @@
S: Maintained
PHRAM MTD DRIVER
-P: Jörn Engel
-M: joern@wh.fh-wedel.de
+P: Joern Engel
+M: joern@lazybastard.org
L: linux-mtd@lists.infradead.org
S: Maintained
@@ -3053,7 +3059,6 @@
P: David Woodhouse
M: dwmw2@infradead.org
L: linux-kernel@vger.kernel.org
-L: kernel-discuss@handhelds.org
T: git git.infradead.org/battery-2.6.git
S: Maintained
@@ -3196,7 +3201,7 @@
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
P: Corey Thomas
-M: corey@world.std.com
+M: coreythomas@charter.net
L: linux-wireless@vger.kernel.org
S: Maintained
@@ -3219,6 +3224,12 @@
L: linux-kernel@vger.kernel.org
S: Maintained
+RDC R-321X SoC
+P: Florian Fainelli
+M: florian.fainelli@telecomint.eu
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
RDC R6040 FAST ETHERNET DRIVER
P: Florian Fainelli
M: florian.fainelli@telecomint.eu
@@ -3789,13 +3800,6 @@
W: http://sourceforge.net/projects/tlan/
S: Maintained
-TOKEN-RING NETWORK DRIVER
-P: Mike Phillips
-M: mikep@linuxtr.net
-L: netdev@vger.kernel.org
-W: http://www.linuxtr.net
-S: Maintained
-
TOSHIBA ACPI EXTRAS DRIVER
P: John Belmonte
M: toshiba_acpi@memebeam.org
@@ -3816,18 +3820,9 @@
S: Maintained
TRIVIAL PATCHES
-P: Adrian Bunk
+P: Jesper Juhl
M: trivial@kernel.org
L: linux-kernel@vger.kernel.org
-W: http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/
-T: git kernel.org:/pub/scm/linux/kernel/git/bunk/trivial.git
-S: Maintained
-
-TMS380 TOKEN-RING NETWORK DRIVER
-P: Adam Fritzler
-M: mid@auk.cx
-L: linux-tr@linuxtr.net
-W: http://www.auk.cx/tms380tr/
S: Maintained
TULIP NETWORK DRIVER
@@ -3872,6 +3867,12 @@
L: linux-usb@vger.kernel.org
S: Maintained
+USB AUERSWALD DRIVER
+P: Wolfgang Muees
+M: wolfgang@iksw-muees.de
+L: linux-usb@vger.kernel.org
+S: Maintained
+
USB BLOCK DRIVER (UB ub)
P: Pete Zaitcev
M: zaitcev@redhat.com
@@ -4022,12 +4023,6 @@
W: http://geocities.com/i0xox0i
W: http://firstlight.net/cvs
-USB AUERSWALD DRIVER
-P: Wolfgang Muees
-M: wolfgang@iksw-muees.de
-L: linux-usb@vger.kernel.org
-S: Maintained
-
USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
P: Gary Brubaker
M: xavyer@ix.netcom.com
diff --git a/Makefile b/Makefile
index 0f84c74..89f2d8b 100644
--- a/Makefile
+++ b/Makefile
@@ -1484,7 +1484,7 @@
# Single targets
# ---------------------------------------------------------------------------
# Single targets are compatible with:
-# - build whith mixed source and output
+# - build with mixed source and output
# - build with separate output dir 'make O=...'
# - external modules
#
diff --git a/arch/Kconfig b/arch/Kconfig
new file mode 100644
index 0000000..3d72dc3
--- /dev/null
+++ b/arch/Kconfig
@@ -0,0 +1,31 @@
+#
+# General architecture dependent options
+#
+
+config OPROFILE
+ tristate "OProfile system profiling (EXPERIMENTAL)"
+ depends on PROFILING
+ depends on HAVE_OPROFILE
+ help
+ OProfile is a profiling system capable of profiling the
+ whole system, include the kernel, kernel modules, libraries,
+ and applications.
+
+ If unsure, say N.
+
+config HAVE_OPROFILE
+ def_bool n
+
+config KPROBES
+ bool "Kprobes"
+ depends on KALLSYMS && MODULES
+ depends on HAVE_KPROBES
+ help
+ Kprobes allows you to trap at almost any kernel address and
+ execute a callback function. register_kprobe() establishes
+ a probepoint and specifies the callback. Kprobes is useful
+ for kernel debugging, non-intrusive instrumentation and testing.
+ If in doubt, say "N".
+
+config HAVE_KPROBES
+ def_bool n
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 4c002ba..01b10ab 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -5,6 +5,7 @@
config ALPHA
bool
default y
+ select HAVE_OPROFILE
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
@@ -318,11 +319,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config PCI_DOMAINS
bool
default y
@@ -536,8 +532,8 @@
singleprocessor machines. On a singleprocessor machine, the kernel
will run faster if you say N here.
- See also the <file:Documentation/smp.txt>, and the SMP-HOWTO
- available at <http://www.tldp.org/docs.html#howto>.
+ See also the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -654,8 +650,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/alpha/Kconfig.debug"
# DUMMY_CONSOLE may be defined in drivers/video/console/Kconfig
diff --git a/arch/alpha/Kconfig.debug b/arch/alpha/Kconfig.debug
index f45f28c..3f6265f 100644
--- a/arch/alpha/Kconfig.debug
+++ b/arch/alpha/Kconfig.debug
@@ -7,15 +7,6 @@
depends on ALPHA_GENERIC || ALPHA_SRM
default y
-config DEBUG_RWLOCK
- bool "Read-write spinlock debugging"
- depends on DEBUG_KERNEL
- help
- If you say Y here then read-write lock processing will count how many
- times it has tried to get the lock and issue an error message after
- too many attempts. If you suspect a rwlock problem or a kernel
- hacker asks for this option then say Y. Otherwise say N.
-
config ALPHA_LEGACY_START_ADDRESS
bool "Legacy kernel start address"
depends on ALPHA_GENERIC
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index 6da9c3d..e43f68f 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -882,7 +882,6 @@
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_DEBUG_INFO=y
CONFIG_EARLY_PRINTK=y
-# CONFIG_DEBUG_RWLOCK is not set
# CONFIG_DEBUG_SEMAPHORE is not set
CONFIG_ALPHA_LEGACY_START_ADDRESS=y
CONFIG_MATHEMU=y
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 6413c5f..72f9a61 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -430,7 +430,7 @@
asmlinkage unsigned long
sys_getdtablesize(void)
{
- return NR_OPEN;
+ return sysctl_nr_open;
}
/*
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
index 468b76c..8ac0831 100644
--- a/arch/alpha/kernel/pci-noop.c
+++ b/arch/alpha/kernel/pci-noop.c
@@ -165,7 +165,7 @@
ret = (void *)__get_free_pages(gfp, get_order(size));
if (ret) {
memset(ret, 0, size);
- *dma_handle = virt_to_bus(ret);
+ *dma_handle = virt_to_phys(ret);
}
return ret;
}
@@ -184,7 +184,7 @@
BUG_ON(!sg_page(sg));
va = sg_virt(sg);
- sg_dma_address(sg) = (dma_addr_t)virt_to_bus(va);
+ sg_dma_address(sg) = (dma_addr_t)virt_to_phys(va);
sg_dma_len(sg) = sg->length;
}
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 2d00a08..26d3789 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -9,6 +9,7 @@
#include <linux/bootmem.h>
#include <linux/scatterlist.h>
#include <linux/log2.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/hwrpb.h>
@@ -470,22 +471,29 @@
#define SG_ENT_PHYS_ADDRESS(SG) __pa(SG_ENT_VIRT_ADDRESS(SG))
static void
-sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
+sg_classify(struct device *dev, struct scatterlist *sg, struct scatterlist *end,
+ int virt_ok)
{
unsigned long next_paddr;
struct scatterlist *leader;
long leader_flag, leader_length;
+ unsigned int max_seg_size;
leader = sg;
leader_flag = 0;
leader_length = leader->length;
next_paddr = SG_ENT_PHYS_ADDRESS(leader) + leader_length;
+ /* we will not marge sg without device. */
+ max_seg_size = dev ? dma_get_max_seg_size(dev) : 0;
for (++sg; sg < end; ++sg) {
unsigned long addr, len;
addr = SG_ENT_PHYS_ADDRESS(sg);
len = sg->length;
+ if (leader_length + len > max_seg_size)
+ goto new_segment;
+
if (next_paddr == addr) {
sg->dma_address = -1;
leader_length += len;
@@ -494,6 +502,7 @@
leader_flag = 1;
leader_length += len;
} else {
+new_segment:
leader->dma_address = leader_flag;
leader->dma_length = leader_length;
leader = sg;
@@ -512,7 +521,7 @@
in the blanks. */
static int
-sg_fill(struct scatterlist *leader, struct scatterlist *end,
+sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
struct scatterlist *out, struct pci_iommu_arena *arena,
dma_addr_t max_dma, int dac_allowed)
{
@@ -562,8 +571,8 @@
/* Otherwise, break up the remaining virtually contiguous
hunks into individual direct maps and retry. */
- sg_classify(leader, end, 0);
- return sg_fill(leader, end, out, arena, max_dma, dac_allowed);
+ sg_classify(dev, leader, end, 0);
+ return sg_fill(dev, leader, end, out, arena, max_dma, dac_allowed);
}
out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
@@ -619,12 +628,15 @@
struct pci_iommu_arena *arena;
dma_addr_t max_dma;
int dac_allowed;
+ struct device *dev;
if (direction == PCI_DMA_NONE)
BUG();
dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
+ dev = pdev ? &pdev->dev : NULL;
+
/* Fast path single entry scatterlists. */
if (nents == 1) {
sg->dma_length = sg->length;
@@ -638,7 +650,7 @@
end = sg + nents;
/* First, prepare information about the entries. */
- sg_classify(sg, end, alpha_mv.mv_pci_tbi != 0);
+ sg_classify(dev, sg, end, alpha_mv.mv_pci_tbi != 0);
/* Second, figure out where we're going to map things. */
if (alpha_mv.mv_pci_tbi) {
@@ -658,7 +670,7 @@
for (out = sg; sg < end; ++sg) {
if ((int) sg->dma_address < 0)
continue;
- if (sg_fill(sg, end, out, arena, max_dma, dac_allowed) < 0)
+ if (sg_fill(dev, sg, end, out, arena, max_dma, dac_allowed) < 0)
goto error;
out++;
}
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index bd5e68c..beff629 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -58,7 +58,6 @@
#include <asm/system.h>
#include <asm/hwrpb.h>
#include <asm/dma.h>
-#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/console.h>
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index f4ab233..63c2073 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -77,10 +77,6 @@
int smp_num_cpus = 1; /* Number that came online. */
EXPORT_SYMBOL(smp_num_cpus);
-extern void calibrate_delay(void);
-
-
-
/*
* Called by both boot and secondaries to move global data into
* per-processor storage.
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 79de99e3..ba914af 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -495,7 +495,7 @@
.quad sys_epoll_pwait
.quad sys_utimensat /* 475 */
.quad sys_signalfd
- .quad sys_timerfd
+ .quad sys_ni_syscall
.quad sys_eventfd
.size sys_call_table, . - sys_call_table
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 77201d3..e19e774 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -10,6 +10,8 @@
default y
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
+ select HAVE_OPROFILE
+ select HAVE_KPROBES if (!XIP_KERNEL)
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -33,6 +35,11 @@
bool
default n
+config GENERIC_CLOCKEVENTS_BROADCAST
+ bool
+ depends on GENERIC_CLOCKEVENTS
+ default y if SMP && !LOCAL_TIMERS
+
config MMU
bool
default y
@@ -135,6 +142,23 @@
config ARCH_MTD_XIP
bool
+if OPROFILE
+
+config OPROFILE_ARMV6
+ def_bool y
+ depends on CPU_V6 && !SMP
+ select OPROFILE_ARM11_CORE
+
+config OPROFILE_MPCORE
+ def_bool y
+ depends on CPU_V6 && SMP
+ select OPROFILE_ARM11_CORE
+
+config OPROFILE_ARM11_CORE
+ bool
+
+endif
+
config VECTORS_BASE
hex
default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@@ -168,6 +192,8 @@
bool "ARM Ltd. RealView family"
select ARM_AMBA
select ICST307
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
help
This enables support for ARM Ltd RealView boards.
@@ -359,6 +385,7 @@
depends on MMU
select ARCH_MTD_XIP
select GENERIC_GPIO
+ select HAVE_GPIO_LIB
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select TICK_ONESHOT
@@ -577,11 +604,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config PCI_SYSCALL
def_bool PCI
@@ -609,7 +631,7 @@
config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
- depends on EXPERIMENTAL && REALVIEW_MPCORE
+ depends on EXPERIMENTAL && REALVIEW_EB_ARM11MP
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
@@ -621,8 +643,7 @@
processor machines. On a single processor machine, the kernel will
run faster if you say N here.
- See also the <file:Documentation/smp.txt>,
- <file:Documentation/i386/IO-APIC.txt>,
+ See also <file:Documentation/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
<http://www.linuxdoc.org/docs.html#howto>.
@@ -643,7 +664,7 @@
config LOCAL_TIMERS
bool "Use local timer interrupts"
- depends on SMP && REALVIEW_MPCORE
+ depends on SMP && REALVIEW_EB_ARM11MP
default y
help
Enable support for local timers on SMP platforms, rather then the
@@ -899,6 +920,13 @@
initially work for you. It may help to enable device hotplugging
support.
+config ATAGS_PROC
+ bool "Export atags in procfs"
+ default n
+ help
+ Should the atags used to boot the kernel be exported in an "atags"
+ file in procfs. Useful with kexec.
+
endmenu
if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
@@ -1035,6 +1063,9 @@
source "kernel/power/Kconfig"
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+
endmenu
source "net/Kconfig"
@@ -1092,6 +1123,8 @@
source "drivers/spi/Kconfig"
+source "drivers/gpio/Kconfig"
+
source "drivers/w1/Kconfig"
source "drivers/power/Kconfig"
@@ -1130,8 +1163,6 @@
source "fs/Kconfig"
-source "arch/arm/Kconfig.instrumentation"
-
source "arch/arm/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/arm/Kconfig.instrumentation b/arch/arm/Kconfig.instrumentation
deleted file mode 100644
index 453ad8e..0000000
--- a/arch/arm/Kconfig.instrumentation
+++ /dev/null
@@ -1,62 +0,0 @@
-menuconfig INSTRUMENTATION
- bool "Instrumentation Support"
- default y
- ---help---
- Say Y here to get to see options related to performance measurement,
- system-wide debugging, and testing. This option alone does not add any
- kernel code.
-
- If you say N, all options in this submenu will be skipped and
- disabled. If you're trying to debug the kernel itself, go see the
- Kernel Hacking menu.
-
-if INSTRUMENTATION
-
-config PROFILING
- bool "Profiling support (EXPERIMENTAL)"
- help
- Say Y here to enable the extended profiling support mechanisms used
- by profilers such as OProfile.
-
-config OPROFILE
- tristate "OProfile system profiling (EXPERIMENTAL)"
- depends on PROFILING && !UML
- help
- OProfile is a profiling system capable of profiling the
- whole system, include the kernel, kernel modules, libraries,
- and applications.
-
- If unsure, say N.
-
-config OPROFILE_ARMV6
- bool
- depends on OPROFILE && CPU_V6 && !SMP
- default y
- select OPROFILE_ARM11_CORE
-
-config OPROFILE_MPCORE
- bool
- depends on OPROFILE && CPU_V6 && SMP
- default y
- select OPROFILE_ARM11_CORE
-
-config OPROFILE_ARM11_CORE
- bool
-
-config KPROBES
- bool "Kprobes"
- depends on KALLSYMS && MODULES && !UML && !XIP_KERNEL
- help
- Kprobes allows you to trap at almost any kernel address and
- execute a callback function. register_kprobe() establishes
- a probepoint and specifies the callback. Kprobes is useful
- for kernel debugging, non-intrusive instrumentation and testing.
- If in doubt, say "N".
-
-config MARKERS
- bool "Activate markers"
- help
- Place an empty function call at each marker site. Can be
- dynamically changed for a probe function.
-
-endif # INSTRUMENTATION
diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c
index 34038ec..d544da4 100644
--- a/arch/arm/common/time-acorn.c
+++ b/arch/arm/common/time-acorn.c
@@ -69,9 +69,7 @@
static irqreturn_t
ioc_timer_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
timer_tick();
- write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
index db850a5..efa0485 100644
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -1,69 +1,96 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15
-# Tue Jan 3 03:20:40 2006
+# Linux kernel version: 2.6.24
+# Sun Jan 27 07:33:38 2008
#
CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_MMU=y
-CONFIG_UID16=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# General setup
#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
+CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -81,28 +108,39 @@
#
# System Type
#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-CONFIG_ARCH_IXP4XX=y
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
# CONFIG_ARCH_IXP2000 is not set
+CONFIG_ARCH_IXP4XX=y
# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_AAEC2000 is not set
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
#
@@ -112,8 +150,12 @@
#
# IXP4xx Platforms
#
-CONFIG_ARCH_AVILA=y
+CONFIG_MACH_NSLU2=y
+CONFIG_MACH_AVILA=y
+CONFIG_MACH_LOFT=y
CONFIG_ARCH_ADI_COYOTE=y
+CONFIG_MACH_GATEWAY7001=y
+CONFIG_MACH_WG302V2=y
CONFIG_ARCH_IXDP425=y
CONFIG_MACH_IXDPG425=y
CONFIG_MACH_IXDP465=y
@@ -121,15 +163,27 @@
CONFIG_ARCH_IXCDP1100=y
CONFIG_ARCH_PRPMC1100=y
CONFIG_MACH_NAS100D=y
+CONFIG_MACH_DSMG600=y
CONFIG_ARCH_IXDP4XX=y
CONFIG_CPU_IXP46X=y
CONFIG_CPU_IXP43X=y
-# CONFIG_MACH_GTWX5715 is not set
+CONFIG_MACH_GTWX5715=y
#
# IXP4xx Options
#
+CONFIG_DMABOUNCE=y
# CONFIG_IXP4XX_INDIRECT_PCI is not set
+CONFIG_IXP4XX_QMGR=y
+CONFIG_IXP4XX_NPE=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
#
# Processor Type
@@ -140,33 +194,40 @@
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
#
# Processor Features
#
# CONFIG_ARM_THUMB is not set
CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+# CONFIG_IWMMXT is not set
CONFIG_XSCALE_PMU=y
-CONFIG_DMABOUNCE=y
#
# Bus support
#
-CONFIG_ISA_DMA_API=y
CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
# CONFIG_PCI_DEBUG is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
# CONFIG_PCCARD is not set
#
# Kernel Features
#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_PREEMPT is not set
-# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
@@ -175,7 +236,12 @@
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
CONFIG_ALIGNMENT_TRAP=y
#
@@ -185,6 +251,7 @@
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs"
# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
#
# Floating point emulation
@@ -203,13 +270,12 @@
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_AOUT is not set
# CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
#
# Power management options
#
# CONFIG_PM is not set
-# CONFIG_APM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
#
# Networking
@@ -219,11 +285,13 @@
#
# Networking options
#
-CONFIG_PACKET=m
+CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -232,9 +300,7 @@
# CONFIG_IP_FIB_TRIE is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_ROUTE_MULTIPATH=y
-# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
@@ -251,15 +317,18 @@
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
CONFIG_IP_VS=m
CONFIG_IP_VS_DEBUG=y
CONFIG_IP_VS_TAB_BITS=12
@@ -290,6 +359,9 @@
# IPVS application helper
#
# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
CONFIG_BRIDGE_NETFILTER=y
@@ -298,70 +370,57 @@
# Core Netfilter Configuration
#
# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
#
# IP: Netfilter Configuration
#
-CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_PPTP is not set
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
# CONFIG_IP_NF_MATCH_IPRANGE is not set
-CONFIG_IP_NF_MATCH_MAC=m
-# CONFIG_IP_NF_MATCH_PKTTYPE is not set
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
CONFIG_IP_NF_MATCH_TOS=m
# CONFIG_IP_NF_MATCH_RECENT is not set
# CONFIG_IP_NF_MATCH_ECN is not set
-# CONFIG_IP_NF_MATCH_DSCP is not set
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
+# CONFIG_IP_NF_MATCH_AH is not set
CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-# CONFIG_IP_NF_MATCH_HELPER is not set
-CONFIG_IP_NF_MATCH_STATE=m
-# CONFIG_IP_NF_MATCH_CONNTRACK is not set
CONFIG_IP_NF_MATCH_OWNER=m
-# CONFIG_IP_NF_MATCH_PHYSDEV is not set
# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-# CONFIG_IP_NF_MATCH_SCTP is not set
-# CONFIG_IP_NF_MATCH_DCCP is not set
-# CONFIG_IP_NF_MATCH_COMMENT is not set
-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
-# CONFIG_IP_NF_MATCH_STRING is not set
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_SAME is not set
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
# CONFIG_IP_NF_TARGET_ECN is not set
-# CONFIG_IP_NF_TARGET_DSCP is not set
-CONFIG_IP_NF_TARGET_MARK=m
-# CONFIG_IP_NF_TARGET_CLASSIFY is not set
# CONFIG_IP_NF_TARGET_TTL is not set
# CONFIG_IP_NF_RAW is not set
CONFIG_IP_NF_ARPTABLES=m
@@ -372,16 +431,9 @@
# Bridge: Netfilter Configuration
#
# CONFIG_BRIDGE_NF_EBTABLES is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
CONFIG_ATM=y
CONFIG_ATM_CLIP=y
# CONFIG_ATM_CLIP_NO_ICMP is not set
@@ -397,25 +449,17 @@
CONFIG_IPX=m
# CONFIG_IPX_INTERN is not set
CONFIG_ATALK=m
-CONFIG_DEV_APPLETALK=y
+CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
CONFIG_X25=m
CONFIG_LAPB=m
-# CONFIG_NET_DIVERT is not set
CONFIG_ECONET=m
CONFIG_ECONET_AUNUDP=y
CONFIG_ECONET_NATIVE=y
CONFIG_WAN_ROUTER=m
-
-#
-# QoS and/or fair queueing
-#
CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CLK_JIFFIES=y
-# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-# CONFIG_NET_SCH_CLK_CPU is not set
#
# Queueing/Scheduling
@@ -425,6 +469,7 @@
# CONFIG_NET_SCH_HFSC is not set
# CONFIG_NET_SCH_ATM is not set
CONFIG_NET_SCH_PRIO=m
+# CONFIG_NET_SCH_RR is not set
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
@@ -449,10 +494,17 @@
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
# CONFIG_NET_EMATCH is not set
-# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
CONFIG_NET_CLS_POLICE=y
# CONFIG_NET_CLS_IND is not set
-CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_SCH_FIFO=y
#
# Network testing
@@ -461,7 +513,18 @@
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -470,19 +533,14 @@
#
# Generic Driver Options
#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_CONCAT is not set
@@ -498,11 +556,14 @@
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
@@ -528,7 +589,6 @@
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
#
# Mapping drivers for chip access
@@ -538,6 +598,7 @@
# CONFIG_MTD_ARM_INTEGRATOR is not set
CONFIG_MTD_IXP4XX=y
# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
# CONFIG_MTD_PLATRAM is not set
#
@@ -547,7 +608,6 @@
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -556,33 +616,24 @@
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
CONFIG_MTD_NAND=m
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
CONFIG_MTD_NAND_IDS=m
# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
# CONFIG_MTD_NAND_NANDSIM is not set
-
-#
-# OneNAND Flash Device Drivers
-#
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
# CONFIG_MTD_ONENAND is not set
#
-# Parallel port support
+# UBI - Unsorted block images
#
+# CONFIG_MTD_UBI is not set
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -592,17 +643,20 @@
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -614,24 +668,28 @@
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
#
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_PCIBUS_ORDER=y
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_GENERIC is not set
# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_TRIFLEX is not set
# CONFIG_BLK_DEV_CY82C693 is not set
@@ -639,93 +697,163 @@
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
CONFIG_BLK_DEV_PDC202XX_NEW=y
-# CONFIG_PDC202XX_FORCE is not set
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
+CONFIG_IDE_ARCH_OBSOLETE_INIT=y
# CONFIG_BLK_DEV_HD is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
#
-# Multi-device support (RAID and LVM)
+# SCSI support type (disk, tape, CD-ROM)
#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+CONFIG_PATA_ARTOP=y
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+CONFIG_PATA_IXP4XX_CF=y
# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
+CONFIG_IXP4XX_ETH=y
+# CONFIG_AX88796 is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
-
-#
-# Tulip family network device support
-#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
CONFIG_EEPRO100=y
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
@@ -738,93 +866,76 @@
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-CONFIG_NET_RADIO=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
-# Obsolete Wireless cards support (pre-802.11)
+# USB Network Adapters
#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_AIRO is not set
-CONFIG_HERMES=y
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_NORTEL_HERMES is not set
-CONFIG_PCI_HERMES=y
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Wan interfaces
-#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
CONFIG_WAN=y
-# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
-# CONFIG_SYNCLINK_SYNCPPP is not set
CONFIG_HDLC=m
-CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW=m
# CONFIG_HDLC_RAW_ETH is not set
-CONFIG_HDLC_CISCO=y
-CONFIG_HDLC_FR=y
-CONFIG_HDLC_PPP=y
-CONFIG_HDLC_X25=y
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_HDLC_X25=m
# CONFIG_PCI200SYN is not set
# CONFIG_WANXL is not set
# CONFIG_PC300 is not set
+# CONFIG_PC300TOO is not set
# CONFIG_FARSYNC is not set
+# CONFIG_DSCC4 is not set
+# CONFIG_IXP4XX_HSS is not set
CONFIG_DLCI=m
-CONFIG_DLCI_COUNT=24
CONFIG_DLCI_MAX=8
-CONFIG_WAN_ROUTER_DRIVERS=y
+CONFIG_WAN_ROUTER_DRIVERS=m
# CONFIG_CYCLADES_SYNC is not set
# CONFIG_LAPBETHER is not set
# CONFIG_X25_ASY is not set
-
-#
-# ATM drivers
-#
+CONFIG_ATM_DRIVERS=y
# CONFIG_ATM_DUMMY is not set
CONFIG_ATM_TCP=m
# CONFIG_ATM_LANAI is not set
@@ -842,20 +953,19 @@
# CONFIG_HIPPI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
#
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -865,7 +975,6 @@
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
@@ -875,8 +984,16 @@
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_IXP4XX_BEEPER=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
#
# Hardware I/O ports
@@ -895,7 +1012,9 @@
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
# CONFIG_SERIAL_8250_EXTENDED is not set
#
@@ -907,51 +1026,17 @@
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-CONFIG_IXP4XX_WATCHDOG=y
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_IXP4XX=m
# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
#
@@ -969,57 +1054,68 @@
# CONFIG_I2C_ALI15X3 is not set
# CONFIG_I2C_AMD756 is not set
# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_IOP3XX is not set
CONFIG_I2C_IXP4XX=y
# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
#
# Miscellaneous I2C Chip support
#
# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
#
-# Hardware Monitoring support
+# SPI support
#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ADT7470 is not set
# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
@@ -1033,67 +1129,268 @@
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
#
-# Misc devices
+# Watchdog Device Drivers
#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP4XX_WATCHDOG=y
#
-# Multimedia Capabilities Port drivers
+# PCI-based Watchdog Cards
#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
#
# Graphics support
#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
#
# Sound
#
# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
#
-# USB support
+# USB Input Devices
#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+# CONFIG_USB_ATM is not set
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
#
-# MMC/SD Card support
+# LED drivers
#
-# CONFIG_MMC is not set
+# CONFIG_LEDS_IXP4XX is not set
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+CONFIG_RTC_DRV_X1205=y
+CONFIG_RTC_DRV_PCF8563=y
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
#
# File systems
@@ -1107,16 +1404,19 @@
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -1140,11 +1440,12 @@
# Pseudo filesystems
#
CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -1156,13 +1457,15 @@
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
@@ -1171,10 +1474,7 @@
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
@@ -1186,6 +1486,7 @@
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -1193,7 +1494,6 @@
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1213,37 +1513,53 @@
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
+# CONFIG_SYSV68_PARTITION is not set
# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
#
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
# CONFIG_DEBUG_USER is not set
CONFIG_DEBUG_ERRORS=y
CONFIG_DEBUG_LL=y
@@ -1254,22 +1570,22 @@
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index faa7619..00d44c6 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -20,6 +20,7 @@
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
+obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c
new file mode 100644
index 0000000..e2e934c
--- /dev/null
+++ b/arch/arm/kernel/atags.c
@@ -0,0 +1,86 @@
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/proc_fs.h>
+#include <asm/setup.h>
+#include <asm/types.h>
+#include <asm/page.h>
+
+struct buffer {
+ size_t size;
+ char *data;
+};
+static struct buffer tags_buffer;
+
+static int
+read_buffer(char* page, char** start, off_t off, int count,
+ int* eof, void* data)
+{
+ struct buffer *buffer = (struct buffer *)data;
+
+ if (off >= buffer->size) {
+ *eof = 1;
+ return 0;
+ }
+
+ count = min((int) (buffer->size - off), count);
+
+ memcpy(page, &buffer->data[off], count);
+
+ return count;
+}
+
+
+static int
+create_proc_entries(void)
+{
+ struct proc_dir_entry* tags_entry;
+
+ tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer);
+ if (!tags_entry)
+ return -ENOMEM;
+
+ return 0;
+}
+
+
+static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE];
+static char __initdata *atags_copy;
+
+void __init save_atags(const struct tag *tags)
+{
+ atags_copy = atags_copy_buf;
+ memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE);
+}
+
+
+static int __init init_atags_procfs(void)
+{
+ struct tag *tag;
+ int error;
+
+ if (!atags_copy) {
+ printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n");
+ return -EIO;
+ }
+
+ for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag))
+ ;
+
+ tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr);
+ tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL);
+ if (tags_buffer.data == NULL)
+ return -ENOMEM;
+ memcpy(tags_buffer.data, atags_copy, tags_buffer.size);
+
+ error = create_proc_entries();
+ if (error) {
+ printk(KERN_ERR "Exporting ATAGs: not enough memory\n");
+ kfree(tags_buffer.data);
+ tags_buffer.size = 0;
+ tags_buffer.data = NULL;
+ }
+
+ return error;
+}
+
+arch_initcall(init_atags_procfs);
diff --git a/arch/arm/kernel/atags.h b/arch/arm/kernel/atags.h
new file mode 100644
index 0000000..e5f028d
--- /dev/null
+++ b/arch/arm/kernel/atags.h
@@ -0,0 +1,5 @@
+#ifdef CONFIG_ATAGS_PROC
+extern void save_atags(struct tag *tags);
+#else
+static inline void save_atags(struct tag *tags) { }
+#endif
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index cecf658..283e14f 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -359,7 +359,7 @@
CALL(sys_kexec_load)
CALL(sys_utimensat)
CALL(sys_signalfd)
-/* 350 */ CALL(sys_timerfd)
+/* 350 */ CALL(sys_ni_syscall)
CALL(sys_eventfd)
CALL(sys_fallocate)
#ifndef syscalls_counted
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 863c664..db8f54a 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -21,6 +21,7 @@
extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;
extern unsigned long kexec_mach_type;
+extern unsigned long kexec_boot_atags;
/*
* Provide a dummy crash_notes definition while crash dump arrives to arm.
@@ -62,6 +63,7 @@
kexec_start_address = image->start;
kexec_indirection_page = page_list;
kexec_mach_type = machine_arch_type;
+ kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
/* copy our kernel relocation code to the control code page */
memcpy(reboot_code_buffer,
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index 062c111..61930eb0 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -7,23 +7,6 @@
.globl relocate_new_kernel
relocate_new_kernel:
- /* Move boot params back to where the kernel expects them */
-
- ldr r0,kexec_boot_params_address
- teq r0,#0
- beq 8f
-
- ldr r1,kexec_boot_params_copy
- mov r6,#KEXEC_BOOT_PARAMS_SIZE/4
-7:
- ldr r5,[r1],#4
- str r5,[r0],#4
- subs r6,r6,#1
- bne 7b
-
-8:
- /* Boot params moved, now go on with the kernel */
-
ldr r0,kexec_indirection_page
ldr r1,kexec_start_address
@@ -67,7 +50,7 @@
mov lr,r1
mov r0,#0
ldr r1,kexec_mach_type
- ldr r2,kexec_boot_params_address
+ ldr r2,kexec_boot_atags
mov pc,lr
.globl kexec_start_address
@@ -82,14 +65,9 @@
kexec_mach_type:
.long 0x0
- /* phy addr where new kernel will expect to find boot params */
- .globl kexec_boot_params_address
-kexec_boot_params_address:
- .long 0x0
-
- /* phy addr where old kernel put a copy of orig boot params */
- .globl kexec_boot_params_copy
-kexec_boot_params_copy:
+ /* phy addr of the atags for the new kernel */
+ .globl kexec_boot_atags
+kexec_boot_atags:
.long 0x0
relocate_new_kernel_end:
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index bf56eb3..d3941a7b 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/fs.h>
-#include <linux/kexec.h>
#include <asm/cpu.h>
#include <asm/elf.h>
@@ -39,6 +38,7 @@
#include <asm/mach/time.h>
#include "compat.h"
+#include "atags.h"
#ifndef MEM_SIZE
#define MEM_SIZE (16*1024*1024)
@@ -62,6 +62,7 @@
extern void _stext, _text, _etext, __data_start, _edata, _end;
unsigned int processor_id;
+EXPORT_SYMBOL(processor_id);
unsigned int __machine_arch_type;
EXPORT_SYMBOL(__machine_arch_type);
@@ -784,23 +785,6 @@
}
arch_initcall(customize_machine);
-#ifdef CONFIG_KEXEC
-
-/* Physical addr of where the boot params should be for this machine */
-extern unsigned long kexec_boot_params_address;
-
-/* Physical addr of the buffer into which the boot params are copied */
-extern unsigned long kexec_boot_params_copy;
-
-/* Pointer to the boot params buffer, for manipulation and display */
-unsigned long kexec_boot_params;
-EXPORT_SYMBOL(kexec_boot_params);
-
-/* The buffer itself - make sure it is sized correctly */
-static unsigned long kexec_boot_params_buf[(KEXEC_BOOT_PARAMS_SIZE + 3) / 4];
-
-#endif
-
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
@@ -819,18 +803,6 @@
else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
-#ifdef CONFIG_KEXEC
- kexec_boot_params_copy = virt_to_phys(kexec_boot_params_buf);
- kexec_boot_params = (unsigned long)kexec_boot_params_buf;
- if (__atags_pointer) {
- kexec_boot_params_address = __atags_pointer;
- memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
- } else if (mdesc->boot_params) {
- kexec_boot_params_address = mdesc->boot_params;
- memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
- }
-#endif
-
/*
* If we have the old style parameters, convert them to
* a tag list.
@@ -846,6 +818,7 @@
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
+ save_atags(tags);
parse_tags(tags);
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index eafbb2b..eefae1d 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -150,7 +150,7 @@
secondary_data.pgdir = 0;
*pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);
- pgd_free(pgd);
+ pgd_free(&init_mm, pgd);
if (ret) {
printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu);
@@ -290,6 +290,11 @@
local_irq_enable();
local_fiq_enable();
+ /*
+ * Setup local timer for this CPU.
+ */
+ local_timer_setup(cpu);
+
calibrate_delay();
smp_store_cpu_info(cpu);
@@ -300,11 +305,6 @@
cpu_set(cpu, cpu_online_map);
/*
- * Setup local timer for this CPU.
- */
- local_timer_setup(cpu);
-
- /*
* OK, it's off to the idle thread for us
*/
cpu_idle();
@@ -454,6 +454,27 @@
}
EXPORT_SYMBOL_GPL(smp_call_function);
+int smp_call_function_single(int cpu, void (*func)(void *info), void *info,
+ int retry, int wait)
+{
+ /* prevent preemption and reschedule on another processor */
+ int current_cpu = get_cpu();
+ int ret = 0;
+
+ if (cpu == current_cpu) {
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
+ } else
+ ret = smp_call_function_on_cpu(func, info, retry, wait,
+ cpumask_of_cpu(cpu));
+
+ put_cpu();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(smp_call_function_single);
+
void show_ipi_list(struct seq_file *p)
{
unsigned int cpu;
@@ -481,8 +502,7 @@
static void ipi_timer(void)
{
irq_enter();
- profile_tick(CPU_PROFILING);
- update_process_times(user_mode(get_irq_regs()));
+ local_timer_interrupt();
irq_exit();
}
@@ -621,6 +641,11 @@
send_ipi_message(mask, IPI_TIMER);
}
+void smp_timer_broadcast(cpumask_t mask)
+{
+ send_ipi_message(mask, IPI_TIMER);
+}
+
void smp_send_stop(void)
{
cpumask_t mask = cpu_online_map;
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 5b0422c..074dcd5 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -253,6 +253,36 @@
system clock (of at least several MHz), rounding is less of a
problem so it can be safer to use a decimal values like 100.
+choice
+ prompt "Select a UART for early kernel messages"
+
+config AT91_EARLY_DBGU
+ bool "DBGU"
+
+config AT91_EARLY_USART0
+ bool "USART0"
+
+config AT91_EARLY_USART1
+ bool "USART1"
+
+config AT91_EARLY_USART2
+ bool "USART2"
+ depends on ! ARCH_AT91X40
+
+config AT91_EARLY_USART3
+ bool "USART3"
+ depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260)
+
+config AT91_EARLY_USART4
+ bool "USART4"
+ depends on ARCH_AT91SAM9260
+
+config AT91_EARLY_USART5
+ bool "USART5"
+ depends on ARCH_AT91SAM9260
+
+endchoice
+
endmenu
endif
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
index 5c090c9..e38d237 100644
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -49,8 +49,6 @@
volatile long nr_ticks;
if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */
- write_seqlock(&xtime_lock);
-
/* Get number to ticks performed before interrupt and clear PIT interrupt */
nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR));
do {
@@ -58,7 +56,6 @@
nr_ticks--;
} while (nr_ticks);
- write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
} else
return IRQ_NONE; /* not handled */
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index aa29ea5..0ce38df 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -383,6 +383,7 @@
}
static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcdcon_is_backlight = true,
.default_bpp = 16,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9261_DEFAULT_TFT_LCDCON2,
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index f09347a8..38313ab 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -253,6 +253,7 @@
/* Driver datas */
static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcdcon_is_backlight = true,
.default_bpp = 16,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2,
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index b5daf7f..7b9ce7a 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -47,6 +47,9 @@
#define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */
struct at91_gpio_bank {
+ unsigned chipbase; /* bank's first GPIO number */
+ void __iomem *regbase; /* base of register bank */
+ struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */
unsigned short id; /* peripheral ID */
unsigned long offset; /* offset from system peripheral base */
struct clk *clock; /* associated clock */
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index 6aeddd6..f629c2b 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -33,12 +33,10 @@
static inline void __iomem *pin_to_controller(unsigned pin)
{
- void __iomem *sys_base = (void __iomem *) AT91_VA_BASE_SYS;
-
pin -= PIN_BASE;
pin /= 32;
if (likely(pin < gpio_banks))
- return sys_base + gpio[pin].offset;
+ return gpio[pin].regbase;
return NULL;
}
@@ -294,11 +292,11 @@
int i;
for (i = 0; i < gpio_banks; i++) {
- u32 pio = gpio[i].offset;
+ void __iomem *pio = gpio[i].regbase;
- backups[i] = at91_sys_read(pio + PIO_IMR);
- at91_sys_write(pio + PIO_IDR, backups[i]);
- at91_sys_write(pio + PIO_IER, wakeups[i]);
+ backups[i] = __raw_readl(pio + PIO_IMR);
+ __raw_writel(backups[i], pio + PIO_IDR);
+ __raw_writel(wakeups[i], pio + PIO_IER);
if (!wakeups[i])
clk_disable(gpio[i].clock);
@@ -315,13 +313,13 @@
int i;
for (i = 0; i < gpio_banks; i++) {
- u32 pio = gpio[i].offset;
+ void __iomem *pio = gpio[i].regbase;
if (!wakeups[i])
clk_enable(gpio[i].clock);
- at91_sys_write(pio + PIO_IDR, wakeups[i]);
- at91_sys_write(pio + PIO_IER, backups[i]);
+ __raw_writel(wakeups[i], pio + PIO_IDR);
+ __raw_writel(backups[i], pio + PIO_IER);
}
}
@@ -361,7 +359,13 @@
static int gpio_irq_type(unsigned pin, unsigned type)
{
- return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL;
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_EDGE_BOTH:
+ return 0;
+ default:
+ return -EINVAL;
+ }
}
static struct irq_chip gpio_irqchip = {
@@ -376,20 +380,30 @@
{
unsigned pin;
struct irq_desc *gpio;
+ struct at91_gpio_bank *bank;
void __iomem *pio;
u32 isr;
- pio = get_irq_chip_data(irq);
+ bank = get_irq_chip_data(irq);
+ pio = bank->regbase;
/* temporarily mask (level sensitive) parent IRQ */
desc->chip->ack(irq);
for (;;) {
- /* reading ISR acks the pending (edge triggered) GPIO interrupt */
+ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+ * When there none are pending, we're finished unless we need
+ * to process multiple banks (like ID_PIOCDE on sam9263).
+ */
isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
- if (!isr)
- break;
+ if (!isr) {
+ if (!bank->next)
+ break;
+ bank = bank->next;
+ pio = bank->regbase;
+ continue;
+ }
- pin = (unsigned) get_irq_data(irq);
+ pin = bank->chipbase;
gpio = &irq_desc[pin];
while (isr) {
@@ -481,24 +495,21 @@
*/
void __init at91_gpio_irq_setup(void)
{
- unsigned pioc, pin;
+ unsigned pioc, pin;
+ struct at91_gpio_bank *this, *prev;
- for (pioc = 0, pin = PIN_BASE;
- pioc < gpio_banks;
- pioc++) {
- void __iomem *controller;
- unsigned id = gpio[pioc].id;
+ for (pioc = 0, pin = PIN_BASE, this = gpio, prev = NULL;
+ pioc++ < gpio_banks;
+ prev = this, this++) {
+ unsigned id = this->id;
unsigned i;
- clk_enable(gpio[pioc].clock); /* enable PIO controller's clock */
+ /* enable PIO controller's clock */
+ clk_enable(this->clock);
- controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset;
- __raw_writel(~0, controller + PIO_IDR);
+ __raw_writel(~0, this->regbase + PIO_IDR);
- set_irq_data(id, (void *) pin);
- set_irq_chip_data(id, controller);
-
- for (i = 0; i < 32; i++, pin++) {
+ for (i = 0, pin = this->chipbase; i < 32; i++, pin++) {
/*
* Can use the "simple" and not "edge" handler since it's
* shorter, and the AIC handles interrupts sanely.
@@ -508,6 +519,14 @@
set_irq_flags(pin, IRQF_VALID);
}
+ /* The toplevel handler handles one bank of GPIOs, except
+ * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
+ * the list, so we only set up that handler.
+ */
+ if (prev && prev->next == this)
+ continue;
+
+ set_irq_chip_data(id, this);
set_irq_chained_handler(id, gpio_irq_handler);
}
pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
@@ -518,8 +537,20 @@
*/
void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
{
+ unsigned i;
+ struct at91_gpio_bank *last;
+
BUG_ON(nr_banks > MAX_GPIO_BANKS);
gpio = data;
gpio_banks = nr_banks;
+
+ for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) {
+ data->chipbase = PIN_BASE + i * 32;
+ data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS;
+
+ /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
+ if (last && last->id == data->id)
+ last->next = data;
+ }
}
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 4b120cc..a67defd 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -52,7 +52,7 @@
/*
* Called after processes are frozen, but before we shutdown devices.
*/
-static int at91_pm_set_target(suspend_state_t state)
+static int at91_pm_begin(suspend_state_t state)
{
target_state = state;
return 0;
@@ -202,11 +202,20 @@
return 0;
}
+/*
+ * Called right prior to thawing processes.
+ */
+static void at91_pm_end(void)
+{
+ target_state = PM_SUSPEND_ON;
+}
+
static struct platform_suspend_ops at91_pm_ops ={
- .valid = at91_pm_valid_state,
- .set_target = at91_pm_set_target,
- .enter = at91_pm_enter,
+ .valid = at91_pm_valid_state,
+ .begin = at91_pm_begin,
+ .enter = at91_pm_enter,
+ .end = at91_pm_end,
};
static int __init at91_pm_init(void)
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 61b2dfc..e774447 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -189,6 +189,20 @@
need to use the indirect method instead. If you don't know
what you need, leave this option unselected.
+config IXP4XX_QMGR
+ tristate "IXP4xx Queue Manager support"
+ help
+ This driver supports IXP4xx built-in hardware queue manager
+ and is automatically selected by Ethernet and HSS drivers.
+
+config IXP4XX_NPE
+ tristate "IXP4xx Network Processor Engine support"
+ select HOTPLUG
+ select FW_LOADER
+ help
+ This driver supports IXP4xx built-in network coprocessors
+ and is automatically selected by Ethernet and HSS drivers.
+
endmenu
endif
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index 77e00ad..c195688 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -23,10 +23,12 @@
obj-$(CONFIG_MACH_IXDPG425) += coyote-setup.o
obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o
obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o
-obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o
-obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o
-obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o
+obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o
+obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o
+obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o
obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o
obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o
obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
+obj-$(CONFIG_IXP4XX_NPE) += ixp4xx_npe.o
diff --git a/arch/arm/mach-ixp4xx/dsmg600-power.c b/arch/arm/mach-ixp4xx/dsmg600-power.c
deleted file mode 100644
index 3471787..0000000
--- a/arch/arm/mach-ixp4xx/dsmg600-power.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/dsmg600-power.c
- *
- * DSM-G600 Power/Reset driver
- * Author: Michael Westerhof <mwester@dls.net>
- *
- * Based on nslu2-power.c
- * Copyright (C) 2005 Tower Technologies
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * which was based on nslu2-io.c
- * Copyright (C) 2004 Karen Spearel
- *
- * Maintainers: http://www.nslu2-linux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-
-#include <asm/mach-types.h>
-
-extern void ctrl_alt_del(void);
-
-/* This is used to make sure the power-button pusher is serious. The button
- * must be held until the value of this counter reaches zero.
- */
-static volatile int power_button_countdown;
-
-/* Must hold the button down for at least this many counts to be processed */
-#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
-
-static void dsmg600_power_handler(unsigned long data);
-static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
-
-static void dsmg600_power_handler(unsigned long data)
-{
- /* This routine is called twice per second to check the
- * state of the power button.
- */
-
- if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) {
-
- /* IO Pin is 1 (button pushed) */
- if (power_button_countdown == 0) {
- /* Signal init to do the ctrlaltdel action, this will bypass
- * init if it hasn't started and do a kernel_restart.
- */
- ctrl_alt_del();
-
- /* Change the state of the power LED to "blink" */
- gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
- }
- power_button_countdown--;
-
- } else {
- power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
- }
-
- mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
-}
-
-static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
-{
- /* This is the paper-clip reset, it shuts the machine down directly. */
- machine_power_off();
-
- return IRQ_HANDLED;
-}
-
-static int __init dsmg600_power_init(void)
-{
- if (!(machine_is_dsmg600()))
- return 0;
-
- if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler,
- IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button",
- NULL) < 0) {
-
- printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
- DSMG600_RB_IRQ);
-
- return -EIO;
- }
-
- /* The power button on the D-Link DSM-G600 is on GPIO 15, but
- * it cannot handle interrupts on that GPIO line. So we'll
- * have to poll it with a kernel timer.
- */
-
- /* Make sure that the power button GPIO is set up as an input */
- gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
-
- /* Set the initial value for the power button IRQ handler */
- power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
-
- mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
-
- return 0;
-}
-
-static void __exit dsmg600_power_exit(void)
-{
- if (!(machine_is_dsmg600()))
- return;
-
- del_timer_sync(&dsmg600_power_timer);
-
- free_irq(DSMG600_RB_IRQ, NULL);
-}
-
-module_init(dsmg600_power_init);
-module_exit(dsmg600_power_exit);
-
-MODULE_AUTHOR("Michael Westerhof <mwester@dls.net>");
-MODULE_DESCRIPTION("DSM-G600 Power/Reset driver");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
index c473d40..6886596 100644
--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -1,25 +1,37 @@
/*
* DSM-G600 board-setup
*
+ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
* Copyright (C) 2006 Tower Technologies
- * Author: Alessandro Zummo <a.zummo@towertech.it>
*
- * based ixdp425-setup.c:
+ * based on ixdp425-setup.c:
* Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * based on nslu2-power.c:
+ * Copyright (C) 2005 Tower Technologies
+ * based on nslu2-io.c:
+ * Copyright (C) 2004 Karen Spearel
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Author: Michael Westerhof <mwester@dls.net>
+ * Author: Rod Whitby <rod@whitby.id.au>
* Maintainers: http://www.nslu2-linux.org/
*/
-#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
+#include <linux/leds.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
+#include <asm/gpio.h>
static struct flash_platform_data dsmg600_flash_data = {
.map_name = "cfi_probe",
@@ -51,29 +63,34 @@
},
};
-#ifdef CONFIG_LEDS_CLASS
-static struct resource dsmg600_led_resources[] = {
+static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
{
- .name = "power",
- .start = DSMG600_LED_PWR_GPIO,
- .end = DSMG600_LED_PWR_GPIO,
- .flags = IXP4XX_GPIO_HIGH,
- },
- {
- .name = "wlan",
- .start = DSMG600_LED_WLAN_GPIO,
- .end = DSMG600_LED_WLAN_GPIO,
- .flags = IXP4XX_GPIO_LOW,
+ I2C_BOARD_INFO("rtc-pcf8563", 0x51),
},
};
-static struct platform_device dsmg600_leds = {
- .name = "IXP4XX-GPIO-LED",
- .id = -1,
- .num_resources = ARRAY_SIZE(dsmg600_led_resources),
- .resource = dsmg600_led_resources,
+static struct gpio_led dsmg600_led_pins[] = {
+ {
+ .name = "power",
+ .gpio = DSMG600_LED_PWR_GPIO,
+ },
+ {
+ .name = "wlan",
+ .gpio = DSMG600_LED_WLAN_GPIO,
+ .active_low = true,
+ },
};
-#endif
+
+static struct gpio_led_platform_data dsmg600_led_data = {
+ .num_leds = ARRAY_SIZE(dsmg600_led_pins),
+ .leds = dsmg600_led_pins,
+};
+
+static struct platform_device dsmg600_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &dsmg600_led_data,
+};
static struct resource dsmg600_uart_resources[] = {
{
@@ -121,6 +138,7 @@
static struct platform_device *dsmg600_devices[] __initdata = {
&dsmg600_i2c_gpio,
&dsmg600_flash,
+ &dsmg600_leds,
};
static void dsmg600_power_off(void)
@@ -132,6 +150,57 @@
gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
}
+/* This is used to make sure the power-button pusher is serious. The button
+ * must be held until the value of this counter reaches zero.
+ */
+static int power_button_countdown;
+
+/* Must hold the button down for at least this many counts to be processed */
+#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
+
+static void dsmg600_power_handler(unsigned long data);
+static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
+
+static void dsmg600_power_handler(unsigned long data)
+{
+ /* This routine is called twice per second to check the
+ * state of the power button.
+ */
+
+ if (gpio_get_value(DSMG600_PB_GPIO)) {
+
+ /* IO Pin is 1 (button pushed) */
+ if (power_button_countdown > 0)
+ power_button_countdown--;
+
+ } else {
+
+ /* Done on button release, to allow for auto-power-on mods. */
+ if (power_button_countdown == 0) {
+ /* Signal init to do the ctrlaltdel action,
+ * this will bypass init if it hasn't started
+ * and do a kernel_restart.
+ */
+ ctrl_alt_del();
+
+ /* Change the state of the power LED to "blink" */
+ gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
+ } else {
+ power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+ }
+ }
+
+ mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
+{
+ /* This is the paper-clip reset, it shuts the machine down directly. */
+ machine_power_off();
+
+ return IRQ_HANDLED;
+}
+
static void __init dsmg600_timer_init(void)
{
/* The xtal on this machine is non-standard. */
@@ -156,7 +225,8 @@
dsmg600_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
- pm_power_off = dsmg600_power_off;
+ i2c_register_board_info(0, dsmg600_i2c_board_info,
+ ARRAY_SIZE(dsmg600_i2c_board_info));
/* The UART is required on the DSM-G600 (Redboot cannot use the
* NIC) -- do it here so that it does *not* get removed if
@@ -166,10 +236,28 @@
platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));
-#ifdef CONFIG_LEDS_CLASS
- /* We don't care whether or not this works. */
- (void)platform_device_register(&dsmg600_leds);
-#endif
+ pm_power_off = dsmg600_power_off;
+
+ if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_LOW,
+ "DSM-G600 reset button", NULL) < 0) {
+
+ printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+ gpio_to_irq(DSMG600_RB_GPIO));
+ }
+
+ /* The power button on the D-Link DSM-G600 is on GPIO 15, but
+ * it cannot handle interrupts on that GPIO line. So we'll
+ * have to poll it with a kernel timer.
+ */
+
+ /* Make sure that the power button GPIO is set up as an input */
+ gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
+
+ /* Set the initial value for the power button IRQ handler */
+ power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+
+ mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
}
MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index e89070d..44584af 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -177,6 +177,31 @@
.resource = ixdp425_uart_resources
};
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info ixdp425_plat_eth[] = {
+ {
+ .phy = 0,
+ .rxq = 3,
+ .txreadyq = 20,
+ }, {
+ .phy = 1,
+ .rxq = 4,
+ .txreadyq = 21,
+ }
+};
+
+static struct platform_device ixdp425_eth[] = {
+ {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = ixdp425_plat_eth,
+ }, {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEC,
+ .dev.platform_data = ixdp425_plat_eth + 1,
+ }
+};
+
static struct platform_device *ixdp425_devices[] __initdata = {
&ixdp425_i2c_gpio,
&ixdp425_flash,
@@ -184,7 +209,9 @@
defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
&ixdp425_flash_nand,
#endif
- &ixdp425_uart
+ &ixdp425_uart,
+ &ixdp425_eth[0],
+ &ixdp425_eth[1],
};
static void __init ixdp425_init(void)
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
new file mode 100644
index 0000000..83c137e
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
@@ -0,0 +1,741 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * The code is based on publicly available information:
+ * - Intel IXP4xx Developer's Manual and other e-papers
+ * - Intel IXP400 Access Library Software (BSD license)
+ * - previous works by Christian Hohnstaedt <chohnstaedt@innominate.com>
+ * Thanks, Christian.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/arch/npe.h>
+
+#define DEBUG_MSG 0
+#define DEBUG_FW 0
+
+#define NPE_COUNT 3
+#define MAX_RETRIES 1000 /* microseconds */
+#define NPE_42X_DATA_SIZE 0x800 /* in dwords */
+#define NPE_46X_DATA_SIZE 0x1000
+#define NPE_A_42X_INSTR_SIZE 0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE 0x800
+#define NPE_46X_INSTR_SIZE 0x1000
+#define REGS_SIZE 0x1000
+
+#define NPE_PHYS_REG 32
+
+#define FW_MAGIC 0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR 0x0
+#define FW_BLOCK_TYPE_DATA 0x1
+#define FW_BLOCK_TYPE_EOF 0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP 0x01
+#define CMD_NPE_START 0x02
+#define CMD_NPE_STOP 0x03
+#define CMD_NPE_CLR_PIPE 0x04
+#define CMD_CLR_PROFILE_CNT 0x0C
+#define CMD_RD_INS_MEM 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM 0x11
+#define CMD_RD_DATA_MEM 0x12 /* data memory */
+#define CMD_WR_DATA_MEM 0x13
+#define CMD_RD_ECS_REG 0x14 /* exec access register */
+#define CMD_WR_ECS_REG 0x15
+
+#define STAT_RUN 0x80000000
+#define STAT_STOP 0x40000000
+#define STAT_CLEAR 0x20000000
+#define STAT_ECS_K 0x00800000 /* pipeline clean */
+
+#define NPE_STEVT 0x1B
+#define NPE_STARTPC 0x1C
+#define NPE_REGMAP 0x1E
+#define NPE_CINDEX 0x1F
+
+#define INSTR_WR_REG_SHORT 0x0000C000
+#define INSTR_WR_REG_BYTE 0x00004000
+#define INSTR_RD_FIFO 0x0F888220
+#define INSTR_RESET_MBOX 0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0 0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1 0x01 /* Stack level */
+#define ECS_BG_CTXT_REG_2 0x02
+#define ECS_PRI_1_CTXT_REG_0 0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1 0x05 /* Stack level */
+#define ECS_PRI_1_CTXT_REG_2 0x06
+#define ECS_PRI_2_CTXT_REG_0 0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1 0x09 /* Stack level */
+#define ECS_PRI_2_CTXT_REG_2 0x0A
+#define ECS_DBG_CTXT_REG_0 0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1 0x0D /* Stack level */
+#define ECS_DBG_CTXT_REG_2 0x0E
+#define ECS_INSTRUCT_REG 0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE 0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK 0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS 8
+#define ECS_REG_0_LDUR_MASK 0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS 16
+#define ECS_REG_1_CCTXT_MASK 0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS 0
+#define ECS_REG_1_SELCTXT_MASK 0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF 0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE 0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID 0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE 0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF 0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF 0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE 0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO 0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO 0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE 0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT 0x0000F0F0
+
+const char *npe_names[] = { "NPE-A", "NPE-B", "NPE-C" };
+
+#define print_npe(pri, npe, fmt, ...) \
+ printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...) \
+ print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+ u32 reg, val;
+} ecs_reset[] = {
+ { ECS_BG_CTXT_REG_0, 0xA0000000 },
+ { ECS_BG_CTXT_REG_1, 0x01000000 },
+ { ECS_BG_CTXT_REG_2, 0x00008000 },
+ { ECS_PRI_1_CTXT_REG_0, 0x20000080 },
+ { ECS_PRI_1_CTXT_REG_1, 0x01000000 },
+ { ECS_PRI_1_CTXT_REG_2, 0x00008000 },
+ { ECS_PRI_2_CTXT_REG_0, 0x20000080 },
+ { ECS_PRI_2_CTXT_REG_1, 0x01000000 },
+ { ECS_PRI_2_CTXT_REG_2, 0x00008000 },
+ { ECS_DBG_CTXT_REG_0, 0x20000000 },
+ { ECS_DBG_CTXT_REG_1, 0x00000000 },
+ { ECS_DBG_CTXT_REG_2, 0x001E0000 },
+ { ECS_INSTRUCT_REG, 0x1003C00F },
+};
+
+static struct npe npe_tab[NPE_COUNT] = {
+ {
+ .id = 0,
+ .regs = (struct npe_regs __iomem *)IXP4XX_NPEA_BASE_VIRT,
+ .regs_phys = IXP4XX_NPEA_BASE_PHYS,
+ }, {
+ .id = 1,
+ .regs = (struct npe_regs __iomem *)IXP4XX_NPEB_BASE_VIRT,
+ .regs_phys = IXP4XX_NPEB_BASE_PHYS,
+ }, {
+ .id = 2,
+ .regs = (struct npe_regs __iomem *)IXP4XX_NPEC_BASE_VIRT,
+ .regs_phys = IXP4XX_NPEC_BASE_PHYS,
+ }
+};
+
+int npe_running(struct npe *npe)
+{
+ return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+ __raw_writel(data, &npe->regs->exec_data);
+ __raw_writel(addr, &npe->regs->exec_addr);
+ __raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+ __raw_writel(addr, &npe->regs->exec_addr);
+ __raw_writel(cmd, &npe->regs->exec_status_cmd);
+ /* Iintroduce extra read cycles after issuing read command to NPE
+ so that we read the register after the NPE has updated it.
+ This is to overcome race condition between XScale and NPE */
+ __raw_readl(&npe->regs->exec_data);
+ __raw_readl(&npe->regs->exec_data);
+ return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+ u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+ npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+ /* ensure only Background Context Stack Level is active */
+ npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+ npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+ npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+ __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+ __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx,
+ u32 ldur)
+{
+ u32 wc;
+ int i;
+
+ /* set the Active bit, and the LDUR, in the debug level */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+ ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+ /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+ the instruction, and set SELCTXT at ECS DEBUG Level to specify
+ which context store to access.
+ Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+ */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+ (ctx << ECS_REG_1_CCTXT_BITS) |
+ (ctx << ECS_REG_1_SELCTXT_BITS));
+
+ /* clear the pipeline */
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+ /* load NPE instruction into the instruction register */
+ npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+ /* we need this value later to wait for completion of NPE execution
+ step */
+ wc = __raw_readl(&npe->regs->watch_count);
+
+ /* issue a Step One command via the Execution Control register */
+ __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+ /* Watch Count register increments when NPE completes an instruction */
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (wc != __raw_readl(&npe->regs->watch_count))
+ return 0;
+ udelay(1);
+ }
+
+ print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n");
+ return -ETIMEDOUT;
+}
+
+static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,
+ u8 val, u32 ctx)
+{
+ /* here we build the NPE assembler instruction: mov8 d0, #0 */
+ u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+ addr << 9 | /* base Operand */
+ (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
+ (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,
+ u16 val, u32 ctx)
+{
+ /* here we build the NPE assembler instruction: mov16 d0, #0 */
+ u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+ addr << 9 | /* base Operand */
+ (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
+ (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,
+ u32 val, u32 ctx)
+{
+ /* write in 16 bit steps first the high and then the low value */
+ if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+ return -ETIMEDOUT;
+ return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+ u32 val, ctl, exec_count, ctx_reg2;
+ int i;
+
+ ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+ 0x3F3FFFFF;
+
+ /* disable parity interrupt */
+ __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+ /* pre exec - debug instruction */
+ /* turn off the halt bit by clearing Execution Count register. */
+ exec_count = __raw_readl(&npe->regs->exec_count);
+ __raw_writel(0, &npe->regs->exec_count);
+ /* ensure that IF and IE are on (temporarily), so that we don't end up
+ stepping forever */
+ ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+ ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+ /* clear the FIFOs */
+ while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+ ;
+ while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+ /* read from the outFIFO until empty */
+ print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",
+ __raw_readl(&npe->regs->in_out_fifo));
+
+ while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+ /* step execution of the NPE intruction to read inFIFO using
+ the Debug Executing Context stack */
+ if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+ return -ETIMEDOUT;
+
+ /* reset the mailbox reg from the XScale side */
+ __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+ /* from NPE side */
+ if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+ return -ETIMEDOUT;
+
+ /* Reset the physical registers in the NPE register file */
+ for (val = 0; val < NPE_PHYS_REG; val++) {
+ if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+ return -ETIMEDOUT;
+ /* address is either 0 or 4 */
+ if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+ return -ETIMEDOUT;
+ }
+
+ /* Reset the context store = each context's Context Store registers */
+
+ /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+ for Background ECS, to set where NPE starts executing code */
+ val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+ val &= ~ECS_REG_0_NEXTPC_MASK;
+ val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+ npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+ for (i = 0; i < 16; i++) {
+ if (i) { /* Context 0 has no STEVT nor STARTPC */
+ /* STEVT = off, 0x80 */
+ if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+ return -ETIMEDOUT;
+ if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+ return -ETIMEDOUT;
+ }
+ /* REGMAP = d0->p0, d8->p2, d16->p4 */
+ if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+ return -ETIMEDOUT;
+ if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+ return -ETIMEDOUT;
+ }
+
+ /* post exec */
+ /* clear active bit in debug level */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+ /* clear the pipeline */
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+ /* restore previous values */
+ __raw_writel(exec_count, &npe->regs->exec_count);
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+ /* write reset values to Execution Context Stack registers */
+ for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+ npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+ ecs_reset[val].val);
+
+ /* clear the profile counter */
+ __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+ __raw_writel(0, &npe->regs->exec_count);
+ __raw_writel(0, &npe->regs->action_points[0]);
+ __raw_writel(0, &npe->regs->action_points[1]);
+ __raw_writel(0, &npe->regs->action_points[2]);
+ __raw_writel(0, &npe->regs->action_points[3]);
+ __raw_writel(0, &npe->regs->watch_count);
+
+ val = ixp4xx_read_feature_bits();
+ /* reset the NPE */
+ ixp4xx_write_feature_bits(val &
+ ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (!(ixp4xx_read_feature_bits() &
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id)))
+ break; /* reset completed */
+ udelay(1);
+ }
+ if (i == MAX_RETRIES)
+ return -ETIMEDOUT;
+
+ /* deassert reset */
+ ixp4xx_write_feature_bits(val |
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (ixp4xx_read_feature_bits() &
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+ break; /* NPE is back alive */
+ udelay(1);
+ }
+ if (i == MAX_RETRIES)
+ return -ETIMEDOUT;
+
+ npe_stop(npe);
+
+ /* restore NPE configuration bus Control Register - parity settings */
+ __raw_writel(ctl, &npe->regs->messaging_control);
+ return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+ const u32 *send = msg;
+ int cycles = 0;
+
+ debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+ what, send[0], send[1]);
+
+ if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+ debug_msg(npe, "NPE input FIFO not empty\n");
+ return -EIO;
+ }
+
+ __raw_writel(send[0], &npe->regs->in_out_fifo);
+
+ if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+ debug_msg(npe, "NPE input FIFO full\n");
+ return -EIO;
+ }
+
+ __raw_writel(send[1], &npe->regs->in_out_fifo);
+
+ while ((cycles < MAX_RETRIES) &&
+ (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_RETRIES) {
+ debug_msg(npe, "Timeout sending message\n");
+ return -ETIMEDOUT;
+ }
+
+ debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+ return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+ u32 *recv = msg;
+ int cycles = 0, cnt = 0;
+
+ debug_msg(npe, "Trying to receive message %s\n", what);
+
+ while (cycles < MAX_RETRIES) {
+ if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+ recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+ if (cnt == 2)
+ break;
+ } else {
+ udelay(1);
+ cycles++;
+ }
+ }
+
+ switch(cnt) {
+ case 1:
+ debug_msg(npe, "Received [%08X]\n", recv[0]);
+ break;
+ case 2:
+ debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+ break;
+ }
+
+ if (cycles == MAX_RETRIES) {
+ debug_msg(npe, "Timeout waiting for message\n");
+ return -ETIMEDOUT;
+ }
+
+ debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+ return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+ int result;
+ u32 *send = msg, recv[2];
+
+ if ((result = npe_send_message(npe, msg, what)) != 0)
+ return result;
+ if ((result = npe_recv_message(npe, recv, what)) != 0)
+ return result;
+
+ if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+ debug_msg(npe, "Message %s: unexpected message received\n",
+ what);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
+{
+ const struct firmware *fw_entry;
+
+ struct dl_block {
+ u32 type;
+ u32 offset;
+ } *blk;
+
+ struct dl_image {
+ u32 magic;
+ u32 id;
+ u32 size;
+ union {
+ u32 data[0];
+ struct dl_block blocks[0];
+ };
+ } *image;
+
+ struct dl_codeblock {
+ u32 npe_addr;
+ u32 size;
+ u32 data[0];
+ } *cb;
+
+ int i, j, err, data_size, instr_size, blocks, table_end;
+ u32 cmd;
+
+ if ((err = request_firmware(&fw_entry, name, dev)) != 0)
+ return err;
+
+ err = -EINVAL;
+ if (fw_entry->size < sizeof(struct dl_image)) {
+ print_npe(KERN_ERR, npe, "incomplete firmware file\n");
+ goto err;
+ }
+ image = (struct dl_image*)fw_entry->data;
+
+#if DEBUG_FW
+ print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n",
+ image->magic, image->id, image->size, image->size * 4);
+#endif
+
+ if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+ image->id = swab32(image->id);
+ image->size = swab32(image->size);
+ } else if (image->magic != FW_MAGIC) {
+ print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",
+ image->magic);
+ goto err;
+ }
+ if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {
+ print_npe(KERN_ERR, npe,
+ "inconsistent size of firmware file\n");
+ goto err;
+ }
+ if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+ print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");
+ goto err;
+ }
+ if (image->magic == swab32(FW_MAGIC))
+ for (i = 0; i < image->size; i++)
+ image->data[i] = swab32(image->data[i]);
+
+ if (!cpu_is_ixp46x() && ((image->id >> 28) & 0xF /* device ID */)) {
+ print_npe(KERN_INFO, npe, "IXP46x firmware ignored on "
+ "IXP42x\n");
+ goto err;
+ }
+
+ if (npe_running(npe)) {
+ print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "
+ "already running\n");
+ err = -EBUSY;
+ goto err;
+ }
+#if 0
+ npe_stop(npe);
+ npe_reset(npe);
+#endif
+
+ print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
+ "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
+ (image->id >> 8) & 0xFF, image->id & 0xFF);
+
+ if (!cpu_is_ixp46x()) {
+ if (!npe->id)
+ instr_size = NPE_A_42X_INSTR_SIZE;
+ else
+ instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+ data_size = NPE_42X_DATA_SIZE;
+ } else {
+ instr_size = NPE_46X_INSTR_SIZE;
+ data_size = NPE_46X_DATA_SIZE;
+ }
+
+ for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+ blocks++)
+ if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+ break;
+ if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+ print_npe(KERN_INFO, npe, "firmware EOF block marker not "
+ "found\n");
+ goto err;
+ }
+
+#if DEBUG_FW
+ print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);
+#endif
+
+ table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+ for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+ if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+ || blk->offset < table_end) {
+ print_npe(KERN_INFO, npe, "invalid offset 0x%X of "
+ "firmware block #%i\n", blk->offset, i);
+ goto err;
+ }
+
+ cb = (struct dl_codeblock*)&image->data[blk->offset];
+ if (blk->type == FW_BLOCK_TYPE_INSTR) {
+ if (cb->npe_addr + cb->size > instr_size)
+ goto too_big;
+ cmd = CMD_WR_INS_MEM;
+ } else if (blk->type == FW_BLOCK_TYPE_DATA) {
+ if (cb->npe_addr + cb->size > data_size)
+ goto too_big;
+ cmd = CMD_WR_DATA_MEM;
+ } else {
+ print_npe(KERN_INFO, npe, "invalid firmware block #%i "
+ "type 0x%X\n", i, blk->type);
+ goto err;
+ }
+ if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+ print_npe(KERN_INFO, npe, "firmware block #%i doesn't "
+ "fit in firmware image: type %c, start 0x%X,"
+ " length 0x%X\n", i,
+ blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+ cb->npe_addr, cb->size);
+ goto err;
+ }
+
+ for (j = 0; j < cb->size; j++)
+ npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+ }
+
+ npe_start(npe);
+ if (!npe_running(npe))
+ print_npe(KERN_ERR, npe, "unable to start\n");
+ release_firmware(fw_entry);
+ return 0;
+
+too_big:
+ print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "
+ "memory: type %c, start 0x%X, length 0x%X\n", i,
+ blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+ cb->npe_addr, cb->size);
+err:
+ release_firmware(fw_entry);
+ return err;
+}
+
+
+struct npe *npe_request(int id)
+{
+ if (id < NPE_COUNT)
+ if (npe_tab[id].valid)
+ if (try_module_get(THIS_MODULE))
+ return &npe_tab[id];
+ return NULL;
+}
+
+void npe_release(struct npe *npe)
+{
+ module_put(THIS_MODULE);
+}
+
+
+static int __init npe_init_module(void)
+{
+
+ int i, found = 0;
+
+ for (i = 0; i < NPE_COUNT; i++) {
+ struct npe *npe = &npe_tab[i];
+ if (!(ixp4xx_read_feature_bits() &
+ (IXP4XX_FEATURE_RESET_NPEA << i)))
+ continue; /* NPE already disabled or not present */
+ if (!(npe->mem_res = request_mem_region(npe->regs_phys,
+ REGS_SIZE,
+ npe_name(npe)))) {
+ print_npe(KERN_ERR, npe,
+ "failed to request memory region\n");
+ continue;
+ }
+
+ if (npe_reset(npe))
+ continue;
+ npe->valid = 1;
+ found++;
+ }
+
+ if (!found)
+ return -ENOSYS;
+ return 0;
+}
+
+static void __exit npe_cleanup_module(void)
+{
+ int i;
+
+ for (i = 0; i < NPE_COUNT; i++)
+ if (npe_tab[i].mem_res) {
+ npe_reset(&npe_tab[i]);
+ release_resource(npe_tab[i].mem_res);
+ }
+}
+
+module_init(npe_init_module);
+module_exit(npe_cleanup_module);
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_LICENSE("GPL v2");
+
+EXPORT_SYMBOL(npe_names);
+EXPORT_SYMBOL(npe_running);
+EXPORT_SYMBOL(npe_request);
+EXPORT_SYMBOL(npe_release);
+EXPORT_SYMBOL(npe_load_firmware);
+EXPORT_SYMBOL(npe_send_message);
+EXPORT_SYMBOL(npe_recv_message);
+EXPORT_SYMBOL(npe_send_recv_message);
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
new file mode 100644
index 0000000..e833013
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
@@ -0,0 +1,274 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ */
+
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/arch/qmgr.h>
+
+#define DEBUG 0
+
+struct qmgr_regs __iomem *qmgr_regs;
+static struct resource *mem_res;
+static spinlock_t qmgr_lock;
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+static void (*irq_handlers[HALF_QUEUES])(void *pdev);
+static void *irq_pdevs[HALF_QUEUES];
+
+void qmgr_set_irq(unsigned int queue, int src,
+ void (*handler)(void *pdev), void *pdev)
+{
+ u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
+ int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+ unsigned long flags;
+
+ src &= 7;
+ spin_lock_irqsave(&qmgr_lock, flags);
+ __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+ irq_handlers[queue] = handler;
+ irq_pdevs[queue] = pdev;
+ spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+
+static irqreturn_t qmgr_irq1(int irq, void *pdev)
+{
+ int i;
+ u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
+ __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
+
+ for (i = 0; i < HALF_QUEUES; i++)
+ if (val & (1 << i))
+ irq_handlers[i](irq_pdevs[i]);
+
+ return val ? IRQ_HANDLED : 0;
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qmgr_lock, flags);
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
+ &qmgr_regs->irqen[0]);
+ spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&qmgr_lock, flags);
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
+ &qmgr_regs->irqen[0]);
+ spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+static inline void shift_mask(u32 *mask)
+{
+ mask[3] = mask[3] << 1 | mask[2] >> 31;
+ mask[2] = mask[2] << 1 | mask[1] >> 31;
+ mask[1] = mask[1] << 1 | mask[0] >> 31;
+ mask[0] <<= 1;
+}
+
+int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark)
+{
+ u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+ int err;
+
+ if (queue >= HALF_QUEUES)
+ return -ERANGE;
+
+ if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
+ return -EINVAL;
+
+ switch (len) {
+ case 16:
+ cfg = 0 << 24;
+ mask[0] = 0x1;
+ break;
+ case 32:
+ cfg = 1 << 24;
+ mask[0] = 0x3;
+ break;
+ case 64:
+ cfg = 2 << 24;
+ mask[0] = 0xF;
+ break;
+ case 128:
+ cfg = 3 << 24;
+ mask[0] = 0xFF;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cfg |= nearly_empty_watermark << 26;
+ cfg |= nearly_full_watermark << 29;
+ len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
+ mask[1] = mask[2] = mask[3] = 0;
+
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
+ spin_lock_irq(&qmgr_lock);
+ if (__raw_readl(&qmgr_regs->sram[queue])) {
+ err = -EBUSY;
+ goto err;
+ }
+
+ while (1) {
+ if (!(used_sram_bitmap[0] & mask[0]) &&
+ !(used_sram_bitmap[1] & mask[1]) &&
+ !(used_sram_bitmap[2] & mask[2]) &&
+ !(used_sram_bitmap[3] & mask[3]))
+ break; /* found free space */
+
+ addr++;
+ shift_mask(mask);
+ if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+ printk(KERN_ERR "qmgr: no free SRAM space for"
+ " queue %i\n", queue);
+ err = -ENOMEM;
+ goto err;
+ }
+ }
+
+ used_sram_bitmap[0] |= mask[0];
+ used_sram_bitmap[1] |= mask[1];
+ used_sram_bitmap[2] |= mask[2];
+ used_sram_bitmap[3] |= mask[3];
+ __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+ spin_unlock_irq(&qmgr_lock);
+
+#if DEBUG
+ printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n",
+ queue, addr);
+#endif
+ return 0;
+
+err:
+ spin_unlock_irq(&qmgr_lock);
+ module_put(THIS_MODULE);
+ return err;
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+ u32 cfg, addr, mask[4];
+
+ BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+
+ spin_lock_irq(&qmgr_lock);
+ cfg = __raw_readl(&qmgr_regs->sram[queue]);
+ addr = (cfg >> 14) & 0xFF;
+
+ BUG_ON(!addr); /* not requested */
+
+ switch ((cfg >> 24) & 3) {
+ case 0: mask[0] = 0x1; break;
+ case 1: mask[0] = 0x3; break;
+ case 2: mask[0] = 0xF; break;
+ case 3: mask[0] = 0xFF; break;
+ }
+
+ while (addr--)
+ shift_mask(mask);
+
+ __raw_writel(0, &qmgr_regs->sram[queue]);
+
+ used_sram_bitmap[0] &= ~mask[0];
+ used_sram_bitmap[1] &= ~mask[1];
+ used_sram_bitmap[2] &= ~mask[2];
+ used_sram_bitmap[3] &= ~mask[3];
+ irq_handlers[queue] = NULL; /* catch IRQ bugs */
+ spin_unlock_irq(&qmgr_lock);
+
+ module_put(THIS_MODULE);
+#if DEBUG
+ printk(KERN_DEBUG "qmgr: released queue %i\n", queue);
+#endif
+}
+
+static int qmgr_init(void)
+{
+ int i, err;
+ mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
+ IXP4XX_QMGR_REGION_SIZE,
+ "IXP4xx Queue Manager");
+ if (mem_res == NULL)
+ return -EBUSY;
+
+ qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
+ if (qmgr_regs == NULL) {
+ err = -ENOMEM;
+ goto error_map;
+ }
+
+ /* reset qmgr registers */
+ for (i = 0; i < 4; i++) {
+ __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+ __raw_writel(0, &qmgr_regs->irqsrc[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ __raw_writel(0, &qmgr_regs->stat2[i]);
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+ __raw_writel(0, &qmgr_regs->irqen[i]);
+ }
+
+ for (i = 0; i < QUEUES; i++)
+ __raw_writel(0, &qmgr_regs->sram[i]);
+
+ err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
+ "IXP4xx Queue Manager", NULL);
+ if (err) {
+ printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
+ IRQ_IXP4XX_QM1);
+ goto error_irq;
+ }
+
+ used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+ spin_lock_init(&qmgr_lock);
+
+ printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
+ return 0;
+
+error_irq:
+ iounmap(qmgr_regs);
+error_map:
+ release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
+ return err;
+}
+
+static void qmgr_remove(void)
+{
+ free_irq(IRQ_IXP4XX_QM1, NULL);
+ synchronize_irq(IRQ_IXP4XX_QM1);
+ iounmap(qmgr_regs);
+ release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
+}
+
+module_init(qmgr_init);
+module_exit(qmgr_remove);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Krzysztof Halasa");
+
+EXPORT_SYMBOL(qmgr_regs);
+EXPORT_SYMBOL(qmgr_set_irq);
+EXPORT_SYMBOL(qmgr_enable_irq);
+EXPORT_SYMBOL(qmgr_disable_irq);
+EXPORT_SYMBOL(qmgr_request_queue);
+EXPORT_SYMBOL(qmgr_release_queue);
diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c
deleted file mode 100644
index 29aa98d3..0000000
--- a/arch/arm/mach-ixp4xx/nas100d-power.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-power.c
- *
- * NAS 100d Power/Reset driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nas100d-io.c
- * Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/reboot.h>
-
-#include <asm/mach-types.h>
-
-static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
-{
- /* Signal init to do the ctrlaltdel action, this will bypass init if
- * it hasn't started and do a kernel_restart.
- */
- ctrl_alt_del();
-
- return IRQ_HANDLED;
-}
-
-static int __init nas100d_power_init(void)
-{
- if (!(machine_is_nas100d()))
- return 0;
-
- set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
-
- if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
- IRQF_DISABLED, "NAS100D reset button", NULL) < 0) {
-
- printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
- NAS100D_RB_IRQ);
-
- return -EIO;
- }
-
- return 0;
-}
-
-static void __exit nas100d_power_exit(void)
-{
- if (!(machine_is_nas100d()))
- return;
-
- free_irq(NAS100D_RB_IRQ, NULL);
-}
-
-module_init(nas100d_power_init);
-module_exit(nas100d_power_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("NAS100D Power/Reset driver");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 54d884f..4cecae8 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -3,8 +3,14 @@
*
* NAS 100d board-setup
*
- * based ixdp425-setup.c:
+ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
+ *
+ * based on ixdp425-setup.c:
* Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * based on nas100d-power.c:
+ * Copyright (C) 2005 Tower Technologies
+ * based on nas100d-io.c
+ * Copyright (C) 2004 Karen Spearel
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Author: Rod Whitby <rod@whitby.id.au>
@@ -12,15 +18,22 @@
*
*/
-#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/leds.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
static struct flash_platform_data nas100d_flash_data = {
.map_name = "cfi_probe",
@@ -39,35 +52,40 @@
.resource = &nas100d_flash_resource,
};
-#ifdef CONFIG_LEDS_IXP4XX
-static struct resource nas100d_led_resources[] = {
+static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
{
- .name = "wlan", /* green led */
- .start = 0,
- .end = 0,
- .flags = IXP4XX_GPIO_LOW,
- },
- {
- .name = "ready", /* blue power led (off is flashing!) */
- .start = 15,
- .end = 15,
- .flags = IXP4XX_GPIO_LOW,
- },
- {
- .name = "disk", /* yellow led */
- .start = 3,
- .end = 3,
- .flags = IXP4XX_GPIO_LOW,
+ I2C_BOARD_INFO("rtc-pcf8563", 0x51),
},
};
-static struct platform_device nas100d_leds = {
- .name = "IXP4XX-GPIO-LED",
- .id = -1,
- .num_resources = ARRAY_SIZE(nas100d_led_resources),
- .resource = nas100d_led_resources,
+static struct gpio_led nas100d_led_pins[] = {
+ {
+ .name = "wlan", /* green led */
+ .gpio = NAS100D_LED_WLAN_GPIO,
+ .active_low = true,
+ },
+ {
+ .name = "power", /* blue power led (off=flashing) */
+ .gpio = NAS100D_LED_PWR_GPIO,
+ .active_low = true,
+ },
+ {
+ .name = "disk", /* yellow led */
+ .gpio = NAS100D_LED_DISK_GPIO,
+ .active_low = true,
+ },
};
-#endif
+
+static struct gpio_led_platform_data nas100d_led_data = {
+ .num_leds = ARRAY_SIZE(nas100d_led_pins),
+ .leds = nas100d_led_pins,
+};
+
+static struct platform_device nas100d_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &nas100d_led_data,
+};
static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
.sda_pin = NAS100D_SDA_PIN,
@@ -125,12 +143,28 @@
.resource = nas100d_uart_resources,
};
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info nas100d_plat_eth[] = {
+ {
+ .phy = 0,
+ .rxq = 3,
+ .txreadyq = 20,
+ }
+};
+
+static struct platform_device nas100d_eth[] = {
+ {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = nas100d_plat_eth,
+ }
+};
+
static struct platform_device *nas100d_devices[] __initdata = {
&nas100d_i2c_gpio,
&nas100d_flash,
-#ifdef CONFIG_LEDS_IXP4XX
&nas100d_leds,
-#endif
+ &nas100d_eth[0],
};
static void nas100d_power_off(void)
@@ -144,8 +178,63 @@
gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
}
+/* This is used to make sure the power-button pusher is serious. The button
+ * must be held until the value of this counter reaches zero.
+ */
+static int power_button_countdown;
+
+/* Must hold the button down for at least this many counts to be processed */
+#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
+
+static void nas100d_power_handler(unsigned long data);
+static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0);
+
+static void nas100d_power_handler(unsigned long data)
+{
+ /* This routine is called twice per second to check the
+ * state of the power button.
+ */
+
+ if (gpio_get_value(NAS100D_PB_GPIO)) {
+
+ /* IO Pin is 1 (button pushed) */
+ if (power_button_countdown > 0)
+ power_button_countdown--;
+
+ } else {
+
+ /* Done on button release, to allow for auto-power-on mods. */
+ if (power_button_countdown == 0) {
+ /* Signal init to do the ctrlaltdel action,
+ * this will bypass init if it hasn't started
+ * and do a kernel_restart.
+ */
+ ctrl_alt_del();
+
+ /* Change the state of the power LED to "blink" */
+ gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
+ } else {
+ power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+ }
+ }
+
+ mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
+{
+ /* This is the paper-clip reset, it shuts the machine down directly. */
+ machine_power_off();
+
+ return IRQ_HANDLED;
+}
+
static void __init nas100d_init(void)
{
+ DECLARE_MAC_BUF(mac_buf);
+ uint8_t __iomem *f;
+ int i;
+
ixp4xx_sys_init();
/* gpio 14 and 15 are _not_ clocks */
@@ -155,7 +244,8 @@
nas100d_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
- pm_power_off = nas100d_power_off;
+ i2c_register_board_info(0, nas100d_i2c_board_info,
+ ARRAY_SIZE(nas100d_i2c_board_info));
/*
* This is only useful on a modified machine, but it is valuable
@@ -165,6 +255,48 @@
(void)platform_device_register(&nas100d_uart);
platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
+
+ pm_power_off = nas100d_power_off;
+
+ if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_LOW,
+ "NAS100D reset button", NULL) < 0) {
+
+ printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+ gpio_to_irq(NAS100D_RB_GPIO));
+ }
+
+ /* The power button on the Iomega NAS100d is on GPIO 14, but
+ * it cannot handle interrupts on that GPIO line. So we'll
+ * have to poll it with a kernel timer.
+ */
+
+ /* Make sure that the power button GPIO is set up as an input */
+ gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN);
+
+ /* Set the initial value for the power button IRQ handler */
+ power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+
+ mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
+
+ /*
+ * Map in a portion of the flash and read the MAC address.
+ * Since it is stored in BE in the flash itself, we need to
+ * byteswap it if we're in LE mode.
+ */
+ f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000);
+ if (f) {
+ for (i = 0; i < 6; i++)
+#ifdef __ARMEB__
+ nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + i);
+#else
+ nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + (i^3));
+#endif
+ iounmap(f);
+ }
+ printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n",
+ print_mac(mac_buf, nas100d_plat_eth[0].hwaddr));
+
}
MACHINE_START(NAS100D, "Iomega NAS 100d")
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
deleted file mode 100644
index 6f10dc20..0000000
--- a/arch/arm/mach-ixp4xx/nslu2-power.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nslu2-power.c
- *
- * NSLU2 Power/Reset driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nslu2-io.c
- * Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-types.h>
-
-static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
-{
- /* Signal init to do the ctrlaltdel action, this will bypass init if
- * it hasn't started and do a kernel_restart.
- */
- ctrl_alt_del();
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
-{
- /* This is the paper-clip reset, it shuts the machine down directly.
- */
- machine_power_off();
-
- return IRQ_HANDLED;
-}
-
-static int __init nslu2_power_init(void)
-{
- if (!(machine_is_nslu2()))
- return 0;
-
- *IXP4XX_GPIO_GPISR = 0x20400000; /* read the 2 irqs to clr */
-
- set_irq_type(NSLU2_RB_IRQ, IRQT_LOW);
- set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH);
-
- if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler,
- IRQF_DISABLED, "NSLU2 reset button", NULL) < 0) {
-
- printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
- NSLU2_RB_IRQ);
-
- return -EIO;
- }
-
- if (request_irq(NSLU2_PB_IRQ, &nslu2_power_handler,
- IRQF_DISABLED, "NSLU2 power button", NULL) < 0) {
-
- printk(KERN_DEBUG "Power Button IRQ %d not available\n",
- NSLU2_PB_IRQ);
-
- return -EIO;
- }
-
- return 0;
-}
-
-static void __exit nslu2_power_exit(void)
-{
- if (!(machine_is_nslu2()))
- return;
-
- free_irq(NSLU2_RB_IRQ, NULL);
- free_irq(NSLU2_PB_IRQ, NULL);
-}
-
-module_init(nslu2_power_init);
-module_exit(nslu2_power_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("NSLU2 Power/Reset driver");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index 77277d2..acaebcb 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -3,27 +3,35 @@
*
* NSLU2 board-setup
*
- * based ixdp425-setup.c:
+ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
+ *
+ * based on ixdp425-setup.c:
* Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * based on nslu2-power.c:
+ * Copyright (C) 2005 Tower Technologies
*
* Author: Mark Rakes <mrakes at mac.com>
* Author: Rod Whitby <rod@whitby.id.au>
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
* Maintainers: http://www.nslu2-linux.org/
*
- * Fixed missing init_time in MACHINE_START kas11 10/22/04
- * Changed to conform to new style __init ixdp425 kas11 10/22/04
*/
-#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/irq.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/leds.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
static struct flash_platform_data nslu2_flash_data = {
.map_name = "cfi_probe",
@@ -47,41 +55,43 @@
.scl_pin = NSLU2_SCL_PIN,
};
-#ifdef CONFIG_LEDS_IXP4XX
-static struct resource nslu2_led_resources[] = {
+static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
{
- .name = "ready", /* green led */
- .start = NSLU2_LED_GRN_GPIO,
- .end = NSLU2_LED_GRN_GPIO,
- .flags = IXP4XX_GPIO_HIGH,
- },
- {
- .name = "status", /* red led */
- .start = NSLU2_LED_RED_GPIO,
- .end = NSLU2_LED_RED_GPIO,
- .flags = IXP4XX_GPIO_HIGH,
- },
- {
- .name = "disk-1",
- .start = NSLU2_LED_DISK1_GPIO,
- .end = NSLU2_LED_DISK1_GPIO,
- .flags = IXP4XX_GPIO_LOW,
- },
- {
- .name = "disk-2",
- .start = NSLU2_LED_DISK2_GPIO,
- .end = NSLU2_LED_DISK2_GPIO,
- .flags = IXP4XX_GPIO_LOW,
+ I2C_BOARD_INFO("rtc-x1205", 0x6f),
},
};
-static struct platform_device nslu2_leds = {
- .name = "IXP4XX-GPIO-LED",
- .id = -1,
- .num_resources = ARRAY_SIZE(nslu2_led_resources),
- .resource = nslu2_led_resources,
+static struct gpio_led nslu2_led_pins[] = {
+ {
+ .name = "ready", /* green led */
+ .gpio = NSLU2_LED_GRN_GPIO,
+ },
+ {
+ .name = "status", /* red led */
+ .gpio = NSLU2_LED_RED_GPIO,
+ },
+ {
+ .name = "disk-1",
+ .gpio = NSLU2_LED_DISK1_GPIO,
+ .active_low = true,
+ },
+ {
+ .name = "disk-2",
+ .gpio = NSLU2_LED_DISK2_GPIO,
+ .active_low = true,
+ },
};
-#endif
+
+static struct gpio_led_platform_data nslu2_led_data = {
+ .num_leds = ARRAY_SIZE(nslu2_led_pins),
+ .leds = nslu2_led_pins,
+};
+
+static struct platform_device nslu2_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &nslu2_led_data,
+};
static struct platform_device nslu2_i2c_gpio = {
.name = "i2c-gpio",
@@ -140,13 +150,29 @@
.resource = nslu2_uart_resources,
};
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info nslu2_plat_eth[] = {
+ {
+ .phy = 1,
+ .rxq = 3,
+ .txreadyq = 20,
+ }
+};
+
+static struct platform_device nslu2_eth[] = {
+ {
+ .name = "ixp4xx_eth",
+ .id = IXP4XX_ETH_NPEB,
+ .dev.platform_data = nslu2_plat_eth,
+ }
+};
+
static struct platform_device *nslu2_devices[] __initdata = {
&nslu2_i2c_gpio,
&nslu2_flash,
&nslu2_beeper,
-#ifdef CONFIG_LEDS_IXP4XX
&nslu2_leds,
-#endif
+ &nslu2_eth[0],
};
static void nslu2_power_off(void)
@@ -160,6 +186,25 @@
gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
}
+static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
+{
+ /* Signal init to do the ctrlaltdel action, this will bypass init if
+ * it hasn't started and do a kernel_restart.
+ */
+ ctrl_alt_del();
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
+{
+ /* This is the paper-clip reset, it shuts the machine down directly.
+ */
+ machine_power_off();
+
+ return IRQ_HANDLED;
+}
+
static void __init nslu2_timer_init(void)
{
/* The xtal on this machine is non-standard. */
@@ -175,13 +220,18 @@
static void __init nslu2_init(void)
{
+ DECLARE_MAC_BUF(mac_buf);
+ uint8_t __iomem *f;
+ int i;
+
ixp4xx_sys_init();
nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
nslu2_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
- pm_power_off = nslu2_power_off;
+ i2c_register_board_info(0, nslu2_i2c_board_info,
+ ARRAY_SIZE(nslu2_i2c_board_info));
/*
* This is only useful on a modified machine, but it is valuable
@@ -191,6 +241,43 @@
(void)platform_device_register(&nslu2_uart);
platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices));
+
+ pm_power_off = nslu2_power_off;
+
+ if (request_irq(gpio_to_irq(NSLU2_RB_GPIO), &nslu2_reset_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_LOW,
+ "NSLU2 reset button", NULL) < 0) {
+
+ printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+ gpio_to_irq(NSLU2_RB_GPIO));
+ }
+
+ if (request_irq(gpio_to_irq(NSLU2_PB_GPIO), &nslu2_power_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_HIGH,
+ "NSLU2 power button", NULL) < 0) {
+
+ printk(KERN_DEBUG "Power Button IRQ %d not available\n",
+ gpio_to_irq(NSLU2_PB_GPIO));
+ }
+
+ /*
+ * Map in a portion of the flash and read the MAC address.
+ * Since it is stored in BE in the flash itself, we need to
+ * byteswap it if we're in LE mode.
+ */
+ f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x40000);
+ if (f) {
+ for (i = 0; i < 6; i++)
+#ifdef __ARMEB__
+ nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + i);
+#else
+ nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + (i^3));
+#endif
+ iounmap(f);
+ }
+ printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n",
+ print_mac(mac_buf, nslu2_plat_eth[0].hwaddr));
+
}
MACHINE_START(NSLU2, "Linksys NSLU2")
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index b5c916c..6e0c4f5 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -3,10 +3,11 @@
#
# Common support (must be linked before board specific support)
-obj-y += clock.o devices.o generic.o irq.o dma.o time.o
+obj-y += clock.o devices.o generic.o irq.o dma.o \
+ time.o gpio.o
obj-$(CONFIG_PXA25x) += pxa25x.o
obj-$(CONFIG_PXA27x) += pxa27x.o
-obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o
+obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o
obj-$(CONFIG_CPU_PXA300) += pxa300.o
obj-$(CONFIG_CPU_PXA320) += pxa320.o
diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
index 28cfd71..6012177 100644
--- a/arch/arm/mach-pxa/cm-x270.c
+++ b/arch/arm/mach-pxa/cm-x270.c
@@ -29,6 +29,7 @@
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/pxafb.h>
#include <asm/arch/ohci.h>
#include <asm/arch/mmc.h>
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
index efba65e..3170622 100644
--- a/arch/arm/mach-pxa/corgi_ssp.c
+++ b/arch/arm/mach-pxa/corgi_ssp.c
@@ -32,7 +32,7 @@
/*
* There are three devices connected to the SSP interface:
* 1. A touchscreen controller (TI ADS7846 compatible)
- * 2. An LCD contoller (with some Backlight functionality)
+ * 2. An LCD controller (with some Backlight functionality)
* 3. A battery monitoring IC (Maxim MAX1111)
*
* Each device uses a different speed/mode of communication.
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 50ff453..bfccb80 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -10,6 +10,7 @@
#include <asm/arch/mmc.h>
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
+#include <asm/arch/ohci.h>
#include "devices.h"
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 698aeec..80721c6 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/pm.h>
#include <linux/string.h>
+#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/irq.h>
@@ -31,7 +32,6 @@
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
-#include <asm/arch/gpio.h>
#include "generic.h"
@@ -66,97 +66,6 @@
EXPORT_SYMBOL(get_memclk_frequency_10khz);
/*
- * Handy function to set GPIO alternate functions
- */
-int pxa_last_gpio;
-
-int pxa_gpio_mode(int gpio_mode)
-{
- unsigned long flags;
- int gpio = gpio_mode & GPIO_MD_MASK_NR;
- int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
- int gafr;
-
- if (gpio > pxa_last_gpio)
- return -EINVAL;
-
- local_irq_save(flags);
- if (gpio_mode & GPIO_DFLT_LOW)
- GPCR(gpio) = GPIO_bit(gpio);
- else if (gpio_mode & GPIO_DFLT_HIGH)
- GPSR(gpio) = GPIO_bit(gpio);
- if (gpio_mode & GPIO_MD_MASK_DIR)
- GPDR(gpio) |= GPIO_bit(gpio);
- else
- GPDR(gpio) &= ~GPIO_bit(gpio);
- gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
- GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
- local_irq_restore(flags);
-
- return 0;
-}
-
-EXPORT_SYMBOL(pxa_gpio_mode);
-
-int gpio_direction_input(unsigned gpio)
-{
- unsigned long flags;
- u32 mask;
-
- if (gpio > pxa_last_gpio)
- return -EINVAL;
-
- mask = GPIO_bit(gpio);
- local_irq_save(flags);
- GPDR(gpio) &= ~mask;
- local_irq_restore(flags);
-
- return 0;
-}
-EXPORT_SYMBOL(gpio_direction_input);
-
-int gpio_direction_output(unsigned gpio, int value)
-{
- unsigned long flags;
- u32 mask;
-
- if (gpio > pxa_last_gpio)
- return -EINVAL;
-
- mask = GPIO_bit(gpio);
- local_irq_save(flags);
- if (value)
- GPSR(gpio) = mask;
- else
- GPCR(gpio) = mask;
- GPDR(gpio) |= mask;
- local_irq_restore(flags);
-
- return 0;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-/*
- * Return GPIO level
- */
-int pxa_gpio_get_value(unsigned gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-EXPORT_SYMBOL(pxa_gpio_get_value);
-
-/*
- * Set output GPIO level
- */
-void pxa_gpio_set_value(unsigned gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-EXPORT_SYMBOL(pxa_gpio_set_value);
-
-/*
* Routine to safely enable or disable a clock in the CKEN
*/
void __pxa_set_cken(int clock, int enable)
@@ -171,7 +80,6 @@
local_irq_restore(flags);
}
-
EXPORT_SYMBOL(__pxa_set_cken);
/*
@@ -226,3 +134,59 @@
iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
get_clk_frequency_khz(1);
}
+
+#ifdef CONFIG_PM
+
+static unsigned long saved_gplr[4];
+static unsigned long saved_gpdr[4];
+static unsigned long saved_grer[4];
+static unsigned long saved_gfer[4];
+
+static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
+{
+ int i, gpio;
+
+ for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) {
+ saved_gplr[i] = GPLR(gpio);
+ saved_gpdr[i] = GPDR(gpio);
+ saved_grer[i] = GRER(gpio);
+ saved_gfer[i] = GFER(gpio);
+
+ /* Clear GPIO transition detect bits */
+ GEDR(gpio) = GEDR(gpio);
+ }
+ return 0;
+}
+
+static int pxa_gpio_resume(struct sys_device *dev)
+{
+ int i, gpio;
+
+ for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) {
+ /* restore level with set/clear */
+ GPSR(gpio) = saved_gplr[i];
+ GPCR(gpio) = ~saved_gplr[i];
+
+ GRER(gpio) = saved_grer[i];
+ GFER(gpio) = saved_gfer[i];
+ GPDR(gpio) = saved_gpdr[i];
+ }
+ return 0;
+}
+#else
+#define pxa_gpio_suspend NULL
+#define pxa_gpio_resume NULL
+#endif
+
+struct sysdev_class pxa_gpio_sysclass = {
+ .name = "gpio",
+ .suspend = pxa_gpio_suspend,
+ .resume = pxa_gpio_resume,
+};
+
+static int __init pxa_gpio_init(void)
+{
+ return sysdev_class_register(&pxa_gpio_sysclass);
+}
+
+core_initcall(pxa_gpio_init);
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index b30f240..b3d10b0e 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -16,6 +16,7 @@
extern void __init pxa_init_irq_high(void);
extern void __init pxa_init_irq_gpio(int gpio_nr);
extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int));
+extern void __init pxa_init_gpio(int gpio_nr);
extern void __init pxa25x_init_irq(void);
extern void __init pxa27x_init_irq(void);
extern void __init pxa3xx_init_irq(void);
@@ -52,3 +53,6 @@
#define pxa3xx_get_clk_frequency_khz(x) (0)
#define pxa3xx_get_memclk_frequency_10khz() (0)
#endif
+
+extern struct sysdev_class pxa_irq_sysclass;
+extern struct sysdev_class pxa_gpio_sysclass;
diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
new file mode 100644
index 0000000..8638dd7
--- /dev/null
+++ b/arch/arm/mach-pxa/gpio.c
@@ -0,0 +1,197 @@
+/*
+ * linux/arch/arm/mach-pxa/gpio.c
+ *
+ * Generic PXA GPIO handling
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "generic.h"
+
+
+struct pxa_gpio_chip {
+ struct gpio_chip chip;
+ void __iomem *regbase;
+};
+
+int pxa_last_gpio;
+
+/*
+ * Configure pins for GPIO or other functions
+ */
+int pxa_gpio_mode(int gpio_mode)
+{
+ unsigned long flags;
+ int gpio = gpio_mode & GPIO_MD_MASK_NR;
+ int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
+ int gafr;
+
+ if (gpio > pxa_last_gpio)
+ return -EINVAL;
+
+ local_irq_save(flags);
+ if (gpio_mode & GPIO_DFLT_LOW)
+ GPCR(gpio) = GPIO_bit(gpio);
+ else if (gpio_mode & GPIO_DFLT_HIGH)
+ GPSR(gpio) = GPIO_bit(gpio);
+ if (gpio_mode & GPIO_MD_MASK_DIR)
+ GPDR(gpio) |= GPIO_bit(gpio);
+ else
+ GPDR(gpio) &= ~GPIO_bit(gpio);
+ gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
+ GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2));
+ local_irq_restore(flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(pxa_gpio_mode);
+
+static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned long flags;
+ u32 mask = 1 << offset;
+ u32 value;
+ struct pxa_gpio_chip *pxa;
+ void __iomem *gpdr;
+
+ pxa = container_of(chip, struct pxa_gpio_chip, chip);
+ gpdr = pxa->regbase + GPDR_OFFSET;
+ local_irq_save(flags);
+ value = __raw_readl(gpdr);
+ value &= ~mask;
+ __raw_writel(value, gpdr);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static int pxa_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ unsigned long flags;
+ u32 mask = 1 << offset;
+ u32 tmp;
+ struct pxa_gpio_chip *pxa;
+ void __iomem *gpdr;
+
+ pxa = container_of(chip, struct pxa_gpio_chip, chip);
+ __raw_writel(mask,
+ pxa->regbase + (value ? GPSR_OFFSET : GPCR_OFFSET));
+ gpdr = pxa->regbase + GPDR_OFFSET;
+ local_irq_save(flags);
+ tmp = __raw_readl(gpdr);
+ tmp |= mask;
+ __raw_writel(tmp, gpdr);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/*
+ * Return GPIO level
+ */
+static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ u32 mask = 1 << offset;
+ struct pxa_gpio_chip *pxa;
+
+ pxa = container_of(chip, struct pxa_gpio_chip, chip);
+ return __raw_readl(pxa->regbase + GPLR_OFFSET) & mask;
+}
+
+/*
+ * Set output GPIO level
+ */
+static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ u32 mask = 1 << offset;
+ struct pxa_gpio_chip *pxa;
+
+ pxa = container_of(chip, struct pxa_gpio_chip, chip);
+
+ if (value)
+ __raw_writel(mask, pxa->regbase + GPSR_OFFSET);
+ else
+ __raw_writel(mask, pxa->regbase + GPCR_OFFSET);
+}
+
+static struct pxa_gpio_chip pxa_gpio_chip[] = {
+ [0] = {
+ .regbase = GPIO0_BASE,
+ .chip = {
+ .label = "gpio-0",
+ .direction_input = pxa_gpio_direction_input,
+ .direction_output = pxa_gpio_direction_output,
+ .get = pxa_gpio_get,
+ .set = pxa_gpio_set,
+ .base = 0,
+ .ngpio = 32,
+ },
+ },
+ [1] = {
+ .regbase = GPIO1_BASE,
+ .chip = {
+ .label = "gpio-1",
+ .direction_input = pxa_gpio_direction_input,
+ .direction_output = pxa_gpio_direction_output,
+ .get = pxa_gpio_get,
+ .set = pxa_gpio_set,
+ .base = 32,
+ .ngpio = 32,
+ },
+ },
+ [2] = {
+ .regbase = GPIO2_BASE,
+ .chip = {
+ .label = "gpio-2",
+ .direction_input = pxa_gpio_direction_input,
+ .direction_output = pxa_gpio_direction_output,
+ .get = pxa_gpio_get,
+ .set = pxa_gpio_set,
+ .base = 64,
+ .ngpio = 32, /* 21 for PXA25x */
+ },
+ },
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ [3] = {
+ .regbase = GPIO3_BASE,
+ .chip = {
+ .label = "gpio-3",
+ .direction_input = pxa_gpio_direction_input,
+ .direction_output = pxa_gpio_direction_output,
+ .get = pxa_gpio_get,
+ .set = pxa_gpio_set,
+ .base = 96,
+ .ngpio = 32,
+ },
+ },
+#endif
+};
+
+void __init pxa_init_gpio(int gpio_nr)
+{
+ int i;
+
+ /* add a GPIO chip for each register bank.
+ * the last PXA25x register only contains 21 GPIOs
+ */
+ for (i = 0; i < gpio_nr; i += 32) {
+ if (i+32 > gpio_nr)
+ pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i;
+ gpiochip_add(&pxa_gpio_chip[i/32].chip);
+ }
+}
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 07acb45..36c6a68 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/irq.h>
@@ -310,6 +311,8 @@
/* Install handler for GPIO>=2 edge detect interrupts */
set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low);
set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
+
+ pxa_init_gpio(gpio_nr);
}
void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
@@ -321,3 +324,64 @@
pxa_low_gpio_chip.set_wake = set_wake;
pxa_muxed_gpio_chip.set_wake = set_wake;
}
+
+#ifdef CONFIG_PM
+static unsigned long saved_icmr[2];
+
+static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+ switch (dev->id) {
+ case 0:
+ saved_icmr[0] = ICMR;
+ ICMR = 0;
+ break;
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ case 1:
+ saved_icmr[1] = ICMR2;
+ ICMR2 = 0;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pxa_irq_resume(struct sys_device *dev)
+{
+ switch (dev->id) {
+ case 0:
+ ICMR = saved_icmr[0];
+ ICLR = 0;
+ ICCR = 1;
+ break;
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ case 1:
+ ICMR2 = saved_icmr[1];
+ ICLR2 = 0;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+#define pxa_irq_suspend NULL
+#define pxa_irq_resume NULL
+#endif
+
+struct sysdev_class pxa_irq_sysclass = {
+ .name = "irq",
+ .suspend = pxa_irq_suspend,
+ .resume = pxa_irq_resume,
+};
+
+static int __init pxa_irq_init(void)
+{
+ return sysdev_class_register(&pxa_irq_sysclass);
+}
+
+core_initcall(pxa_irq_init);
diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c
index ec1b2d8..f5809ad 100644
--- a/arch/arm/mach-pxa/mfp.c
+++ b/arch/arm/mach-pxa/mfp.c
@@ -22,6 +22,7 @@
#include <asm/hardware.h>
#include <asm/arch/mfp.h>
#include <asm/arch/mfp-pxa3xx.h>
+#include <asm/arch/pxa3xx-regs.h>
/* mfp_spin_lock is used to ensure that MFP register configuration
* (most likely a read-modify-write operation) is atomic, and that
@@ -223,11 +224,19 @@
struct pxa3xx_mfp_pin *p = &mfp_table[pin];
__mfp_config_run(p);
}
+
+ /* clear RDH bit when MFP settings are restored
+ *
+ * NOTE: the last 3 bits DxS are write-1-to-clear so carefully
+ * preserve them here in case they will be referenced later
+ */
+ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
+
return 0;
}
static struct sysdev_class mfp_sysclass = {
- set_kset_name("mfp"),
+ .name = "mfp",
.suspend = pxa3xx_mfp_suspend,
.resume = pxa3xx_mfp_resume,
};
diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c
index 540c3bb..c14696b9 100644
--- a/arch/arm/mach-pxa/pcm027.c
+++ b/arch/arm/mach-pxa/pcm027.c
@@ -29,6 +29,7 @@
#include <asm/mach/arch.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/pxa2xx_spi.h>
#include <asm/arch/pcm027.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index dd54496..209eabf 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -164,7 +164,7 @@
},
};
-static unsigned long poodle_get_hsync_len(void)
+static unsigned long poodle_get_hsync_invperiod(void)
{
return 0;
}
@@ -174,9 +174,9 @@
}
static struct corgits_machinfo poodle_ts_machinfo = {
- .get_hsync_len = poodle_get_hsync_len,
- .put_hsync = poodle_null_hsync,
- .wait_hsync = poodle_null_hsync,
+ .get_hsync_invperiod = poodle_get_hsync_invperiod,
+ .put_hsync = poodle_null_hsync,
+ .wait_hsync = poodle_null_hsync,
};
static struct platform_device poodle_ts_device = {
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index ddd05bf..599e53f 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
+#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
@@ -141,11 +142,6 @@
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
-#define RESTORE_GPLEVEL(n) do { \
- GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
- GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
/*
* List of global PXA peripheral registers to preserve.
* More ones like CP and general purpose register values are preserved
@@ -153,10 +149,6 @@
*/
enum { SLEEP_SAVE_START = 0,
- SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
- SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
- SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
- SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
@@ -165,7 +157,6 @@
SLEEP_SAVE_PSTR,
- SLEEP_SAVE_ICMR,
SLEEP_SAVE_CKEN,
SLEEP_SAVE_SIZE
@@ -174,17 +165,12 @@
static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
{
- SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
- SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
- SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
- SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
SAVE(GAFR0_L); SAVE(GAFR0_U);
SAVE(GAFR1_L); SAVE(GAFR1_U);
SAVE(GAFR2_L); SAVE(GAFR2_U);
- SAVE(ICMR); ICMR = 0;
SAVE(CKEN);
SAVE(PSTR);
@@ -198,22 +184,14 @@
PSPR = 0;
/* restore registers */
- RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
- RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
RESTORE(GAFR0_L); RESTORE(GAFR0_U);
RESTORE(GAFR1_L); RESTORE(GAFR1_U);
RESTORE(GAFR2_L); RESTORE(GAFR2_U);
- RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
- RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
PSSR = PSSR_RDH | PSSR_PH;
RESTORE(CKEN);
-
- ICLR = 0;
- ICCR = 1;
- RESTORE(ICMR);
RESTORE(PSTR);
}
@@ -304,9 +282,17 @@
&pxa25x_device_assp,
};
+static struct sys_device pxa25x_sysdev[] = {
+ {
+ .cls = &pxa_irq_sysclass,
+ }, {
+ .cls = &pxa_gpio_sysclass,
+ },
+};
+
static int __init pxa25x_init(void)
{
- int ret = 0;
+ int i, ret = 0;
/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
if (cpu_is_pxa25x())
@@ -320,9 +306,18 @@
pxa25x_init_pm();
+ for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) {
+ ret = sysdev_register(&pxa25x_sysdev[i]);
+ if (ret)
+ pr_err("failed to register sysdev[%d]\n", i);
+ }
+
ret = platform_add_devices(pxa25x_devices,
ARRAY_SIZE(pxa25x_devices));
+ if (ret)
+ return ret;
}
+
/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
if (cpu_is_pxa25x())
ret = platform_device_register(&pxa_device_hwuart);
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 96cf274..46a951c3 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>
+#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/irq.h>
@@ -171,11 +172,6 @@
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
-#define RESTORE_GPLEVEL(n) do { \
- GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
- GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
/*
* List of global PXA peripheral registers to preserve.
* More ones like CP and general purpose register values are preserved
@@ -183,10 +179,6 @@
*/
enum { SLEEP_SAVE_START = 0,
- SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
- SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
- SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
- SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
@@ -196,7 +188,6 @@
SLEEP_SAVE_PSTR,
- SLEEP_SAVE_ICMR,
SLEEP_SAVE_CKEN,
SLEEP_SAVE_MDREFR,
@@ -208,10 +199,6 @@
void pxa27x_cpu_pm_save(unsigned long *sleep_save)
{
- SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3);
- SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3);
- SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3);
- SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3);
SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
SAVE(GAFR0_L); SAVE(GAFR0_U);
@@ -223,12 +210,8 @@
SAVE(PWER); SAVE(PCFR); SAVE(PRER);
SAVE(PFER); SAVE(PKWR);
- SAVE(ICMR); ICMR = 0;
SAVE(CKEN);
SAVE(PSTR);
-
- /* Clear GPIO transition detect bits */
- GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3;
}
void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
@@ -237,15 +220,10 @@
PSPR = 0;
/* restore registers */
- RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1);
- RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3);
- RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3);
RESTORE(GAFR0_L); RESTORE(GAFR0_U);
RESTORE(GAFR1_L); RESTORE(GAFR1_U);
RESTORE(GAFR2_L); RESTORE(GAFR2_U);
RESTORE(GAFR3_L); RESTORE(GAFR3_U);
- RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3);
- RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3);
RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
RESTORE(MDREFR);
@@ -256,9 +234,6 @@
RESTORE(CKEN);
- ICLR = 0;
- ICCR = 1;
- RESTORE(ICMR);
RESTORE(PSTR);
}
@@ -409,9 +384,22 @@
&pxa27x_device_ssp3,
};
+static struct sys_device pxa27x_sysdev[] = {
+ {
+ .id = 0,
+ .cls = &pxa_irq_sysclass,
+ }, {
+ .id = 1,
+ .cls = &pxa_irq_sysclass,
+ }, {
+ .cls = &pxa_gpio_sysclass,
+ },
+};
+
static int __init pxa27x_init(void)
{
- int ret = 0;
+ int i, ret = 0;
+
if (cpu_is_pxa27x()) {
clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));
@@ -420,8 +408,15 @@
pxa27x_init_pm();
+ for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) {
+ ret = sysdev_register(&pxa27x_sysdev[i]);
+ if (ret)
+ pr_err("failed to register sysdev[%d]\n", i);
+ }
+
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
+
return ret;
}
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 5cbf057..e47e67c 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/arch/pxa3xx-regs.h>
@@ -39,6 +40,7 @@
#define RO_CLK 60000000
#define ACCR_D0CS (1 << 26)
+#define ACCR_PCCE (1 << 11)
/* crystal frequency to static memory controller multiplier (SMCFS) */
static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
@@ -203,7 +205,6 @@
};
#ifdef CONFIG_PM
-#define SLEEP_SAVE_SIZE 4
#define ISRAM_START 0x5c000000
#define ISRAM_SIZE SZ_256K
@@ -211,25 +212,29 @@
static void __iomem *sram;
static unsigned long wakeup_src;
+#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
+
+enum { SLEEP_SAVE_START = 0,
+ SLEEP_SAVE_CKENA,
+ SLEEP_SAVE_CKENB,
+ SLEEP_SAVE_ACCR,
+
+ SLEEP_SAVE_SIZE,
+};
+
static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
{
- pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
-
- if (CKENA & (1 << CKEN_USBH)) {
- printk(KERN_ERR "PM: USB host clock not stopped?\n");
- CKENA &= ~(1 << CKEN_USBH);
- }
-// CKENA |= 1 << (CKEN_ISC & 31);
-
- /*
- * Low power modes require the HSIO2 clock to be enabled.
- */
- CKENB |= 1 << (CKEN_HSIO2 & 31);
+ SAVE(CKENA);
+ SAVE(CKENB);
+ SAVE(ACCR);
}
static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
{
- CKENB &= ~(1 << (CKEN_HSIO2 & 31));
+ RESTORE(ACCR);
+ RESTORE(CKENA);
+ RESTORE(CKENB);
}
/*
@@ -265,6 +270,46 @@
printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
}
+/*
+ * NOTE: currently, the OBM (OEM Boot Module) binary comes along with
+ * PXA3xx development kits assumes that the resuming process continues
+ * with the address stored within the first 4 bytes of SDRAM. The PSPR
+ * register is used privately by BootROM and OBM, and _must_ be set to
+ * 0x5c014000 for the moment.
+ */
+static void pxa3xx_cpu_pm_suspend(void)
+{
+ volatile unsigned long *p = (volatile void *)0xc0000000;
+ unsigned long saved_data = *p;
+
+ extern void pxa3xx_cpu_suspend(void);
+ extern void pxa3xx_cpu_resume(void);
+
+ /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
+ CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
+ CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
+
+ /* clear and setup wakeup source */
+ AD3SR = ~0;
+ AD3ER = wakeup_src;
+ ASCR = ASCR;
+ ARSR = ARSR;
+
+ PCFR |= (1u << 13); /* L1_DIS */
+ PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */
+
+ PSPR = 0x5c014000;
+
+ /* overwrite with the resume address */
+ *p = virt_to_phys(pxa3xx_cpu_resume);
+
+ pxa3xx_cpu_suspend();
+
+ *p = saved_data;
+
+ AD3ER = 0;
+}
+
static void pxa3xx_cpu_pm_enter(suspend_state_t state)
{
/*
@@ -279,6 +324,7 @@
break;
case PM_SUSPEND_MEM:
+ pxa3xx_cpu_pm_suspend();
break;
}
}
@@ -452,9 +498,21 @@
&pxa3xx_device_ssp4,
};
+static struct sys_device pxa3xx_sysdev[] = {
+ {
+ .id = 0,
+ .cls = &pxa_irq_sysclass,
+ }, {
+ .id = 1,
+ .cls = &pxa_irq_sysclass,
+ }, {
+ .cls = &pxa_gpio_sysclass,
+ },
+};
+
static int __init pxa3xx_init(void)
{
- int ret = 0;
+ int i, ret = 0;
if (cpu_is_pxa3xx()) {
clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
@@ -464,9 +522,16 @@
pxa3xx_init_pm();
- return platform_add_devices(devices, ARRAY_SIZE(devices));
+ for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
+ ret = sysdev_register(&pxa3xx_sysdev[i]);
+ if (ret)
+ pr_err("failed to register sysdev[%d]\n", i);
+ }
+
+ ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
- return 0;
+
+ return ret;
}
subsys_initcall(pxa3xx_init);
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
index 14bb4a9..784716e 100644
--- a/arch/arm/mach-pxa/sleep.S
+++ b/arch/arm/mach-pxa/sleep.S
@@ -50,6 +50,108 @@
str r0, [r1]
ldr pc, [sp], #4
+#ifdef CONFIG_PXA3xx
+/*
+ * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4)
+ *
+ * NOTE: unfortunately, pxa_cpu_save_cp can not be reused here since
+ * the auxiliary control register address is different between pxa3xx
+ * and pxa{25x,27x}
+ */
+
+ENTRY(pxa3xx_cpu_suspend)
+
+#ifndef CONFIG_IWMMXT
+ mra r2, r3, acc0
+#endif
+ stmfd sp!, {r2 - r12, lr} @ save registers on stack
+
+ mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode
+ mrc p15, 0, r4, c15, c1, 0 @ CP access reg
+ mrc p15, 0, r5, c13, c0, 0 @ PID
+ mrc p15, 0, r6, c3, c0, 0 @ domain ID
+ mrc p15, 0, r7, c2, c0, 0 @ translation table base addr
+ mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg
+ mrc p15, 0, r9, c1, c0, 0 @ control reg
+
+ bic r3, r3, #2 @ clear frequency change bit
+
+ @ store them plus current virtual stack ptr on stack
+ mov r10, sp
+ stmfd sp!, {r3 - r10}
+
+ @ store physical address of stack pointer
+ mov r0, sp
+ bl sleep_phys_sp
+ ldr r1, =sleep_save_sp
+ str r0, [r1]
+
+ @ clean data cache
+ bl xsc3_flush_kern_cache_all
+
+ mov r0, #0x06 @ S2D3C4 mode
+ mcr p14, 0, r0, c7, c0, 0 @ enter sleep
+
+20: b 20b @ waiting for sleep
+
+ .data
+ .align 5
+/*
+ * pxa3xx_cpu_resume
+ */
+
+ENTRY(pxa3xx_cpu_resume)
+
+ mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off
+ msr cpsr_c, r0
+
+ ldr r0, sleep_save_sp @ stack phys addr
+ ldmfd r0, {r3 - r9, sp} @ CP regs + virt stack ptr
+
+ mov r1, #0
+ mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB
+ mcr p15, 0, r1, c7, c10, 4 @ drain write (&fill) buffer
+ mcr p15, 0, r1, c7, c5, 4 @ flush prefetch buffer
+ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
+
+ mcr p14, 0, r3, c6, c0, 0 @ clock configuration, turbo mode.
+ mcr p15, 0, r4, c15, c1, 0 @ CP access reg
+ mcr p15, 0, r5, c13, c0, 0 @ PID
+ mcr p15, 0, r6, c3, c0, 0 @ domain ID
+ mcr p15, 0, r7, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg
+
+ @ temporarily map resume_turn_on_mmu into the page table,
+ @ otherwise prefetch abort occurs after MMU is turned on
+ mov r1, r7
+ bic r1, r1, #0x00ff
+ bic r1, r1, #0x3f00
+ ldr r2, =0x542e
+
+ adr r3, resume_turn_on_mmu
+ mov r3, r3, lsr #20
+ orr r4, r2, r3, lsl #20
+ ldr r5, [r1, r3, lsl #2]
+ str r4, [r1, r3, lsl #2]
+
+ @ Mapping page table address in the page table
+ mov r6, r1, lsr #20
+ orr r7, r2, r6, lsl #20
+ ldr r8, [r1, r6, lsl #2]
+ str r7, [r1, r6, lsl #2]
+
+ ldr r2, =pxa3xx_resume_after_mmu @ absolute virtual address
+ b resume_turn_on_mmu @ cache align execution
+
+ .text
+pxa3xx_resume_after_mmu:
+ /* restore the temporary mapping */
+ str r5, [r1, r3, lsl #2]
+ str r8, [r1, r6, lsl #2]
+ b resume_after_mmu
+
+#endif /* CONFIG_PXA3xx */
+
#ifdef CONFIG_PXA27x
/*
* pxa27x_cpu_suspend()
diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c
new file mode 100644
index 0000000..ad346ad
--- /dev/null
+++ b/arch/arm/mach-pxa/smemc.c
@@ -0,0 +1,88 @@
+/*
+ * Static Memory Controller
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+
+#define SMEMC_PHYS_BASE (0x4A000000)
+#define SMEMC_PHYS_SIZE (0x90)
+
+#define MSC0 (0x08) /* Static Memory Controller Register 0 */
+#define MSC1 (0x0C) /* Static Memory Controller Register 1 */
+#define SXCNFG (0x1C) /* Synchronous Static Memory Control Register */
+#define MEMCLKCFG (0x68) /* Clock Configuration */
+#define CSADRCFG0 (0x80) /* Address Configuration Register for CS0 */
+#define CSADRCFG1 (0x84) /* Address Configuration Register for CS1 */
+#define CSADRCFG2 (0x88) /* Address Configuration Register for CS2 */
+#define CSADRCFG3 (0x8C) /* Address Configuration Register for CS3 */
+
+#ifdef CONFIG_PM
+static void __iomem *smemc_mmio_base;
+
+static unsigned long msc[2];
+static unsigned long sxcnfg, memclkcfg;
+static unsigned long csadrcfg[4];
+
+static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state)
+{
+ msc[0] = __raw_readl(smemc_mmio_base + MSC0);
+ msc[1] = __raw_readl(smemc_mmio_base + MSC1);
+ sxcnfg = __raw_readl(smemc_mmio_base + SXCNFG);
+ memclkcfg = __raw_readl(smemc_mmio_base + MEMCLKCFG);
+ csadrcfg[0] = __raw_readl(smemc_mmio_base + CSADRCFG0);
+ csadrcfg[1] = __raw_readl(smemc_mmio_base + CSADRCFG1);
+ csadrcfg[2] = __raw_readl(smemc_mmio_base + CSADRCFG2);
+ csadrcfg[3] = __raw_readl(smemc_mmio_base + CSADRCFG3);
+
+ return 0;
+}
+
+static int pxa3xx_smemc_resume(struct sys_device *dev)
+{
+ __raw_writel(msc[0], smemc_mmio_base + MSC0);
+ __raw_writel(msc[1], smemc_mmio_base + MSC1);
+ __raw_writel(sxcnfg, smemc_mmio_base + SXCNFG);
+ __raw_writel(memclkcfg, smemc_mmio_base + MEMCLKCFG);
+ __raw_writel(csadrcfg[0], smemc_mmio_base + CSADRCFG0);
+ __raw_writel(csadrcfg[1], smemc_mmio_base + CSADRCFG1);
+ __raw_writel(csadrcfg[2], smemc_mmio_base + CSADRCFG2);
+ __raw_writel(csadrcfg[3], smemc_mmio_base + CSADRCFG3);
+
+ return 0;
+}
+
+static struct sysdev_class smemc_sysclass = {
+ .name = "smemc",
+ .suspend = pxa3xx_smemc_suspend,
+ .resume = pxa3xx_smemc_resume,
+};
+
+static struct sys_device smemc_sysdev = {
+ .id = 0,
+ .cls = &smemc_sysclass,
+};
+
+static int __init smemc_init(void)
+{
+ int ret = 0;
+
+ if (cpu_is_pxa3xx()) {
+ smemc_mmio_base = ioremap(SMEMC_PHYS_BASE, SMEMC_PHYS_SIZE);
+ if (smemc_mmio_base == NULL)
+ return -ENODEV;
+
+ ret = sysdev_class_register(&smemc_sysclass);
+ if (ret)
+ return ret;
+
+ ret = sysdev_register(&smemc_sysdev);
+ }
+
+ return ret;
+}
+subsys_initcall(smemc_init);
+#endif
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 5078ede..9e7773f 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -36,6 +36,7 @@
#include <asm/mach/irq.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/irda.h>
#include <asm/arch/mmc.h>
#include <asm/arch/ohci.h>
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 1919756..9b26fa5 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -29,6 +29,7 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/irda.h>
#include <asm/arch/mmc.h>
#include <asm/arch/udc.h>
@@ -157,15 +158,10 @@
}
}
-static int tosa_udc_is_connected(void)
-{
- return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0);
-}
-
-
static struct pxa2xx_udc_mach_info udc_info __initdata = {
.udc_command = tosa_udc_command,
- .udc_is_connected = tosa_udc_is_connected,
+ .gpio_vbus = TOSA_GPIO_USB_IN,
+ .gpio_vbus_inverted = 1,
};
/*
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 35156ca..39b3bb7 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -7,24 +7,21 @@
help
Include support for the ARM(R) RealView Emulation Baseboard platform.
-config REALVIEW_MPCORE
- bool "Support MPcore tile"
+config REALVIEW_EB_ARM11MP
+ bool "Support ARM11MPCore tile"
depends on MACH_REALVIEW_EB
select CACHE_L2X0
help
- Enable support for the MPCore tile on the Realview platform.
- Since there are device address and interrupt differences, a
- kernel built with this option enabled is not compatible with
- other tiles.
+ Enable support for the ARM11MPCore tile on the Realview platform.
-config REALVIEW_MPCORE_REVB
- bool "Support MPcore RevB tile"
- depends on REALVIEW_MPCORE
+config REALVIEW_EB_ARM11MP_REVB
+ bool "Support ARM11MPCore RevB tile"
+ depends on REALVIEW_EB_ARM11MP
default n
help
- Enable support for the MPCore RevB tile on the Realview platform.
- Since there are device address differences, a
+ Enable support for the ARM11MPCore RevB tile on the Realview
+ platform. Since there are device address differences, a
kernel built with this option enabled is not compatible with
- other tiles.
+ other revisions of the ARM11MPCore tile.
endmenu
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 36e76ba..ca1e390 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -4,6 +4,5 @@
obj-y := core.o clock.o
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 61d7021..98aefc9 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -25,6 +25,8 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -37,7 +39,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
#include <asm/mach/map.h>
#include <asm/mach/mmc.h>
@@ -48,6 +49,9 @@
#define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET)
+/* used by entry-macro.S */
+void __iomem *gic_cpu_base_addr;
+
/*
* This is the RealView sched_clock implementation. This has
* a resolution of 41.7ns, and a maximum value of about 179s.
@@ -121,26 +125,6 @@
.resource = &realview_flash_resource,
};
-static struct resource realview_smc91x_resources[] = {
- [0] = {
- .start = REALVIEW_ETH_BASE,
- .end = REALVIEW_ETH_BASE + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_ETH,
- .end = IRQ_ETH,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device realview_smc91x_device = {
- .name = "smc91x",
- .id = 0,
- .num_resources = ARRAY_SIZE(realview_smc91x_resources),
- .resource = realview_smc91x_resources,
-};
-
static struct resource realview_i2c_resource = {
.start = REALVIEW_I2C_BASE,
.end = REALVIEW_I2C_BASE + SZ_4K - 1,
@@ -484,45 +468,64 @@
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif
-/*
- * Returns number of ms since last clock interrupt. Note that interrupts
- * will have been disabled by do_gettimeoffset()
- */
-static unsigned long realview_gettimeoffset(void)
+static void timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
{
- unsigned long ticks1, ticks2, status;
+ unsigned long ctrl;
- /*
- * Get the current number of ticks. Note that there is a race
- * condition between us reading the timer and checking for
- * an interrupt. We get around this by ensuring that the
- * counter has not reloaded between our two reads.
- */
- ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
- do {
- ticks1 = ticks2;
- status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET)
- + ((IRQ_TIMERINT0_1 >> 5) << 2));
- ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
- } while (ticks2 > ticks1);
+ switch(mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
- /*
- * Number of ticks since last interrupt.
- */
- ticks1 = TIMER_RELOAD - ticks2;
+ ctrl = TIMER_CTRL_PERIODIC;
+ ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* period set, and timer enabled in 'next_event' hook */
+ ctrl = TIMER_CTRL_ONESHOT;
+ ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ ctrl = 0;
+ }
- /*
- * Interrupt pending? If so, we've reloaded once already.
- *
- * FIXME: Need to check this is effectively timer 0 that expires
- */
- if (status & IRQMASK_TIMERINT0_1)
- ticks1 += TIMER_RELOAD;
+ writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
+}
- /*
- * Convert the ticks to usecs
- */
- return TICKS2USECS(ticks1);
+static int timer_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
+
+ writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
+
+ return 0;
+}
+
+static struct clock_event_device timer0_clockevent = {
+ .name = "timer0",
+ .shift = 32,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = timer_set_mode,
+ .set_next_event = timer_set_next_event,
+ .rating = 300,
+ .cpumask = CPU_MASK_ALL,
+};
+
+static void __init realview_clockevents_init(unsigned int timer_irq)
+{
+ timer0_clockevent.irq = timer_irq;
+ timer0_clockevent.mult =
+ div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
+ timer0_clockevent.max_delta_ns =
+ clockevent_delta2ns(0xffffffff, &timer0_clockevent);
+ timer0_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xf, &timer0_clockevent);
+
+ clockevents_register_device(&timer0_clockevent);
}
/*
@@ -530,15 +533,12 @@
*/
static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
{
- // ...clear the interrupt
+ struct clock_event_device *evt = &timer0_clockevent;
+
+ /* clear the interrupt */
writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
- timer_tick();
-
-#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
- smp_send_timer();
- update_process_times(user_mode(get_irq_regs()));
-#endif
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
@@ -549,13 +549,49 @@
.handler = realview_timer_interrupt,
};
+static cycle_t realview_get_cycles(void)
+{
+ return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
+}
+
+static struct clocksource clocksource_realview = {
+ .name = "timer3",
+ .rating = 200,
+ .read = realview_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init realview_clocksource_init(void)
+{
+ /* setup timer 0 as free-running clocksource */
+ writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+ writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
+ writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
+ writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+ TIMER3_VA_BASE + TIMER_CTRL);
+
+ clocksource_realview.mult =
+ clocksource_khz2mult(1000, clocksource_realview.shift);
+ clocksource_register(&clocksource_realview);
+}
+
/*
- * Set up timer interrupt, and return the current time in seconds.
+ * Set up the clock source and clock events devices
*/
-static void __init realview_timer_init(void)
+void __init realview_timer_init(unsigned int timer_irq)
{
u32 val;
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+ /*
+ * The dummy clock device has to be registered before the main device
+ * so that the latter will broadcast the clock events
+ */
+ local_timer_setup(smp_processor_id());
+#endif
+
/*
* set clock frequency:
* REALVIEW_REFCLK is 32KHz
@@ -576,18 +612,11 @@
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
writel(0, TIMER3_VA_BASE + TIMER_CTRL);
- writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
- writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
- writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
- TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
-
/*
* Make irqs happen for the system timer
*/
- setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq);
-}
+ setup_irq(timer_irq, &realview_timer_irq);
-struct sys_timer realview_timer = {
- .init = realview_timer_init,
- .offset = realview_gettimeoffset,
-};
+ realview_clocksource_init();
+ realview_clockevents_init(timer_irq);
+}
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 2b53420..492a14c 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -27,8 +27,6 @@
#include <asm/leds.h>
#include <asm/io.h>
-extern struct sys_timer realview_timer;
-
#define AMBA_DEVICE(name,busid,base,plat) \
static struct amba_device name##_device = { \
.dev = { \
@@ -38,7 +36,7 @@
}, \
.res = { \
.start = REALVIEW_##base##_BASE, \
- .end = (REALVIEW_##base##_BASE) + SZ_4K - 1,\
+ .end = (REALVIEW_##base##_BASE) + SZ_4K - 1, \
.flags = IORESOURCE_MEM, \
}, \
.dma_mask = ~0, \
@@ -46,74 +44,19 @@
/* .dma = base##_DMA,*/ \
}
-/*
- * These devices are connected via the core APB bridge
- */
-#define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ }
-#define GPIO2_DMA { 0, 0 }
-#define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ }
-#define GPIO3_DMA { 0, 0 }
-
-#define AACI_IRQ { IRQ_AACI, NO_IRQ }
-#define AACI_DMA { 0x80, 0x81 }
-#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_MMCI0B }
-#define MMCI0_DMA { 0x84, 0 }
-#define KMI0_IRQ { IRQ_KMI0, NO_IRQ }
-#define KMI0_DMA { 0, 0 }
-#define KMI1_IRQ { IRQ_KMI1, NO_IRQ }
-#define KMI1_DMA { 0, 0 }
-
-/*
- * These devices are connected directly to the multi-layer AHB switch
- */
-#define SMC_IRQ { NO_IRQ, NO_IRQ }
-#define SMC_DMA { 0, 0 }
-#define MPMC_IRQ { NO_IRQ, NO_IRQ }
-#define MPMC_DMA { 0, 0 }
-#define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ }
-#define CLCD_DMA { 0, 0 }
-#define DMAC_IRQ { IRQ_DMAINT, NO_IRQ }
-#define DMAC_DMA { 0, 0 }
-
-/*
- * These devices are connected via the core APB bridge
- */
-#define SCTL_IRQ { NO_IRQ, NO_IRQ }
-#define SCTL_DMA { 0, 0 }
-#define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ }
-#define WATCHDOG_DMA { 0, 0 }
-#define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ }
-#define GPIO0_DMA { 0, 0 }
-#define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ }
-#define GPIO1_DMA { 0, 0 }
-#define RTC_IRQ { IRQ_RTCINT, NO_IRQ }
-#define RTC_DMA { 0, 0 }
-
-/*
- * These devices are connected via the DMA APB bridge
- */
-#define SCI_IRQ { IRQ_SCIINT, NO_IRQ }
-#define SCI_DMA { 7, 6 }
-#define UART0_IRQ { IRQ_UARTINT0, NO_IRQ }
-#define UART0_DMA { 15, 14 }
-#define UART1_IRQ { IRQ_UARTINT1, NO_IRQ }
-#define UART1_DMA { 13, 12 }
-#define UART2_IRQ { IRQ_UARTINT2, NO_IRQ }
-#define UART2_DMA { 11, 10 }
-#define UART3_IRQ { IRQ_UART3, NO_IRQ }
-#define UART3_DMA { 0x86, 0x87 }
-#define SSP_IRQ { IRQ_SSPINT, NO_IRQ }
-#define SSP_DMA { 9, 8 }
-
-
extern struct platform_device realview_flash_device;
-extern struct platform_device realview_smc91x_device;
extern struct platform_device realview_i2c_device;
extern struct mmc_platform_data realview_mmc0_plat_data;
extern struct mmc_platform_data realview_mmc1_plat_data;
extern struct clk realview_clcd_clk;
extern struct clcd_board clcd_plat_data;
+extern void __iomem *gic_cpu_base_addr;
+#ifdef CONFIG_LOCAL_TIMERS
+extern void __iomem *twd_base_addr;
+extern unsigned int twd_size;
+#endif
extern void realview_leds_event(led_event_t ledevt);
+extern void realview_timer_init(unsigned int timer_irq);
#endif
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
index c7bdf04..5060436 100644
--- a/arch/arm/mach-realview/localtimer.c
+++ b/arch/arm/mach-realview/localtimer.c
@@ -14,19 +14,75 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
-#include <asm/mach/time.h>
#include <asm/hardware/arm_twd.h>
#include <asm/hardware/gic.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
-#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \
- ((cpu) * REALVIEW_TWD_SIZE))
+static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
+
+/*
+ * Used on SMP for either the local timer or IPI_TIMER
+ */
+void local_timer_interrupt(void)
+{
+ struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
+
+ clk->event_handler(clk);
+}
+
+#ifdef CONFIG_LOCAL_TIMERS
+
+#define TWD_BASE(cpu) (twd_base_addr + (cpu) * twd_size)
+
+/* set up by the platform code */
+void __iomem *twd_base_addr;
+unsigned int twd_size;
static unsigned long mpcore_timer_rate;
+static void local_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ void __iomem *base = TWD_BASE(smp_processor_id());
+ unsigned long ctrl;
+
+ switch(mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* timer load already set up */
+ ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
+ | TWD_TIMER_CONTROL_PERIODIC;
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* period set, and timer enabled in 'next_event' hook */
+ ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ ctrl = 0;
+ }
+
+ __raw_writel(ctrl, base + TWD_TIMER_CONTROL);
+}
+
+static int local_timer_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ void __iomem *base = TWD_BASE(smp_processor_id());
+ unsigned long ctrl = __raw_readl(base + TWD_TIMER_CONTROL);
+
+ __raw_writel(evt, base + TWD_TIMER_COUNTER);
+ __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, base + TWD_TIMER_CONTROL);
+
+ return 0;
+}
+
/*
* local_timer_ack: checks for a local timer interrupt.
*
@@ -45,12 +101,11 @@
return 0;
}
-void __cpuinit local_timer_setup(unsigned int cpu)
+static void __cpuinit twd_calibrate_rate(unsigned int cpu)
{
void __iomem *base = TWD_BASE(cpu);
- unsigned int load, offset;
+ unsigned long load, count;
u64 waitjiffies;
- unsigned int count;
/*
* If this is the first time round, we need to work out how fast
@@ -88,36 +143,36 @@
load = mpcore_timer_rate / HZ;
__raw_writel(load, base + TWD_TIMER_LOAD);
- __raw_writel(0x7, base + TWD_TIMER_CONTROL);
+}
- /*
- * Now maneuver our local tick into the right part of the jiffy.
- * Start by working out where within the tick our local timer
- * interrupt should go.
- */
- offset = ((mpcore_timer_rate / HZ) / (NR_CPUS + 1)) * (cpu + 1);
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(unsigned int cpu)
+{
+ struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
+ unsigned long flags;
- /*
- * gettimeoffset() will return a number of us since the last tick.
- * Convert this number of us to a local timer tick count.
- * Be careful of integer overflow whilst keeping maximum precision.
- *
- * with HZ=100 and 1MHz (fpga) ~ 1GHz processor:
- * load = 1 ~ 10,000
- * mpcore_timer_rate/10000 = 100 ~ 100,000
- *
- * so the multiply value will be less than 10^9 always.
- */
- load = (system_timer->offset() * (mpcore_timer_rate / 10000)) / 100;
+ twd_calibrate_rate(cpu);
- /* Add on our offset to get the load value */
- load = (load + offset) % (mpcore_timer_rate / HZ);
-
- __raw_writel(load, base + TWD_TIMER_COUNTER);
+ clk->name = "local_timer";
+ clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ clk->rating = 350;
+ clk->set_mode = local_timer_set_mode;
+ clk->set_next_event = local_timer_set_next_event;
+ clk->irq = IRQ_LOCALTIMER;
+ clk->cpumask = cpumask_of_cpu(cpu);
+ clk->shift = 20;
+ clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
+ clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
+ clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
/* Make sure our local interrupt controller has this enabled */
- __raw_writel(1 << IRQ_LOCALTIMER,
- __io_address(REALVIEW_GIC_DIST_BASE) + GIC_DIST_ENABLE_SET);
+ local_irq_save(flags);
+ get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
+ local_irq_restore(flags);
+
+ clockevents_register_device(clk);
}
/*
@@ -127,3 +182,26 @@
{
__raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
}
+
+#else /* CONFIG_LOCAL_TIMERS */
+
+static void dummy_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+}
+
+void __cpuinit local_timer_setup(unsigned int cpu)
+{
+ struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
+
+ clk->name = "dummy_timer";
+ clk->features = CLOCK_EVT_FEAT_DUMMY;
+ clk->rating = 200;
+ clk->set_mode = dummy_timer_set_mode;
+ clk->broadcast = smp_timer_broadcast;
+ clk->cpumask = cpumask_of_cpu(cpu);
+
+ clockevents_register_device(clk);
+}
+
+#endif /* !CONFIG_LOCAL_TIMERS */
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index fce3596..de2b715 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -18,6 +18,7 @@
#include <asm/hardware/arm_scu.h>
#include <asm/hardware.h>
#include <asm/io.h>
+#include <asm/mach-types.h>
extern void realview_secondary_startup(void);
@@ -31,9 +32,13 @@
{
unsigned int ncores;
- ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG);
+ if (machine_is_realview_eb() && core_tile_eb11mp()) {
+ ncores = __raw_readl(__io_address(REALVIEW_EB11MP_SCU_BASE) + SCU_CONFIG);
+ ncores = (ncores & 0x03) + 1;
+ } else
+ ncores = 1;
- return (ncores & 0x03) + 1;
+ return ncores;
}
static DEFINE_SPINLOCK(boot_lock);
@@ -52,7 +57,7 @@
* core (e.g. timer irq), then they will not have been enabled
* for us: do so
*/
- gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
+ gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
/*
* let the primary processor know we're out of the
@@ -187,10 +192,15 @@
if (max_cpus > ncores)
max_cpus = ncores;
+#ifdef CONFIG_LOCAL_TIMERS
/*
- * Enable the local timer for primary CPU
+ * Enable the local timer for primary CPU. If the device is
+ * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
+ * realview_timer_init
*/
- local_timer_setup(cpu);
+ if (machine_is_realview_eb() && core_tile_eb11mp())
+ local_timer_setup(cpu);
+#endif
/*
* Initialise the present map, which describes the set of CPUs
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index ecec2f8..60d9eb8 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -36,7 +36,9 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/mmc.h>
+#include <asm/mach/time.h>
+#include <asm/arch/board-eb.h>
#include <asm/arch/irqs.h>
#include "core.h"
@@ -58,26 +60,7 @@
.pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE),
.length = SZ_4K,
.type = MT_DEVICE,
- },
-#ifdef CONFIG_REALVIEW_MPCORE
- {
- .virtual = IO_ADDRESS(REALVIEW_GIC1_CPU_BASE),
- .pfn = __phys_to_pfn(REALVIEW_GIC1_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
}, {
- .virtual = IO_ADDRESS(REALVIEW_GIC1_DIST_BASE),
- .pfn = __phys_to_pfn(REALVIEW_GIC1_DIST_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = IO_ADDRESS(REALVIEW_MPCORE_L220_BASE),
- .pfn = __phys_to_pfn(REALVIEW_MPCORE_L220_BASE),
- .length = SZ_8K,
- .type = MT_DEVICE,
- },
-#endif
- {
.virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
.pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
.length = SZ_4K,
@@ -103,11 +86,95 @@
#endif
};
+static struct map_desc realview_eb11mp_io_desc[] __initdata = {
+ {
+ .virtual = IO_ADDRESS(REALVIEW_EB11MP_GIC_CPU_BASE),
+ .pfn = __phys_to_pfn(REALVIEW_EB11MP_GIC_CPU_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(REALVIEW_EB11MP_GIC_DIST_BASE),
+ .pfn = __phys_to_pfn(REALVIEW_EB11MP_GIC_DIST_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(REALVIEW_EB11MP_L220_BASE),
+ .pfn = __phys_to_pfn(REALVIEW_EB11MP_L220_BASE),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ }
+};
+
static void __init realview_eb_map_io(void)
{
iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc));
+ if (core_tile_eb11mp())
+ iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc));
}
+/*
+ * RealView EB AMBA devices
+ */
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define GPIO2_IRQ { IRQ_EB_GPIO2, NO_IRQ }
+#define GPIO2_DMA { 0, 0 }
+#define GPIO3_IRQ { IRQ_EB_GPIO3, NO_IRQ }
+#define GPIO3_DMA { 0, 0 }
+
+#define AACI_IRQ { IRQ_EB_AACI, NO_IRQ }
+#define AACI_DMA { 0x80, 0x81 }
+#define MMCI0_IRQ { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B }
+#define MMCI0_DMA { 0x84, 0 }
+#define KMI0_IRQ { IRQ_EB_KMI0, NO_IRQ }
+#define KMI0_DMA { 0, 0 }
+#define KMI1_IRQ { IRQ_EB_KMI1, NO_IRQ }
+#define KMI1_DMA { 0, 0 }
+
+/*
+ * These devices are connected directly to the multi-layer AHB switch
+ */
+#define SMC_IRQ { NO_IRQ, NO_IRQ }
+#define SMC_DMA { 0, 0 }
+#define MPMC_IRQ { NO_IRQ, NO_IRQ }
+#define MPMC_DMA { 0, 0 }
+#define CLCD_IRQ { IRQ_EB_CLCD, NO_IRQ }
+#define CLCD_DMA { 0, 0 }
+#define DMAC_IRQ { IRQ_EB_DMA, NO_IRQ }
+#define DMAC_DMA { 0, 0 }
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define SCTL_IRQ { NO_IRQ, NO_IRQ }
+#define SCTL_DMA { 0, 0 }
+#define WATCHDOG_IRQ { IRQ_EB_WDOG, NO_IRQ }
+#define WATCHDOG_DMA { 0, 0 }
+#define GPIO0_IRQ { IRQ_EB_GPIO0, NO_IRQ }
+#define GPIO0_DMA { 0, 0 }
+#define GPIO1_IRQ { IRQ_EB_GPIO1, NO_IRQ }
+#define GPIO1_DMA { 0, 0 }
+#define RTC_IRQ { IRQ_EB_RTC, NO_IRQ }
+#define RTC_DMA { 0, 0 }
+
+/*
+ * These devices are connected via the DMA APB bridge
+ */
+#define SCI_IRQ { IRQ_EB_SCI, NO_IRQ }
+#define SCI_DMA { 7, 6 }
+#define UART0_IRQ { IRQ_EB_UART0, NO_IRQ }
+#define UART0_DMA { 15, 14 }
+#define UART1_IRQ { IRQ_EB_UART1, NO_IRQ }
+#define UART1_DMA { 13, 12 }
+#define UART2_IRQ { IRQ_EB_UART2, NO_IRQ }
+#define UART2_DMA { 11, 10 }
+#define UART3_IRQ { IRQ_EB_UART3, NO_IRQ }
+#define UART3_DMA { 0x86, 0x87 }
+#define SSP_IRQ { IRQ_EB_SSP, NO_IRQ }
+#define SSP_DMA { 9, 8 }
+
/* FPGA Primecells */
AMBA_DEVICE(aaci, "fpga:04", AACI, NULL);
AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &realview_mmc0_plat_data);
@@ -153,38 +220,127 @@
&kmi1_device,
};
+/*
+ * RealView EB platform devices
+ */
+
+static struct resource realview_eb_smc91x_resources[] = {
+ [0] = {
+ .start = REALVIEW_ETH_BASE,
+ .end = REALVIEW_ETH_BASE + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_EB_ETH,
+ .end = IRQ_EB_ETH,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device realview_eb_smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(realview_eb_smc91x_resources),
+ .resource = realview_eb_smc91x_resources,
+};
+
static void __init gic_init_irq(void)
{
-#ifdef CONFIG_REALVIEW_MPCORE
- unsigned int pldctrl;
- writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
- pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
- pldctrl |= 0x00800000; /* New irq mode */
- writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
- writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
+ if (core_tile_eb11mp()) {
+ unsigned int pldctrl;
+
+ /* new irq mode */
+ writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
+ pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1);
+ pldctrl |= 0x00800000;
+ writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1);
+ writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
+
+ /* core tile GIC, primary */
+ gic_cpu_base_addr = __io_address(REALVIEW_EB11MP_GIC_CPU_BASE);
+ gic_dist_init(0, __io_address(REALVIEW_EB11MP_GIC_DIST_BASE), 29);
+ gic_cpu_init(0, gic_cpu_base_addr);
+
+#ifndef CONFIG_REALVIEW_EB_ARM11MP_REVB
+ /* board GIC, secondary */
+ gic_dist_init(1, __io_address(REALVIEW_GIC_DIST_BASE), 64);
+ gic_cpu_init(1, __io_address(REALVIEW_GIC_CPU_BASE));
+ gic_cascade_irq(1, IRQ_EB11MP_EB_IRQ1);
#endif
- gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
- gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
-#if defined(CONFIG_REALVIEW_MPCORE) && !defined(CONFIG_REALVIEW_MPCORE_REVB)
- gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64);
- gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE));
- gic_cascade_irq(1, IRQ_EB_IRQ1);
-#endif
+ } else {
+ /* board GIC, primary */
+ gic_cpu_base_addr = __io_address(REALVIEW_GIC_CPU_BASE);
+ gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
+ gic_cpu_init(0, gic_cpu_base_addr);
+ }
}
+/*
+ * Fix up the IRQ numbers for the RealView EB/ARM11MPCore tile
+ */
+static void realview_eb11mp_fixup(void)
+{
+ /* AMBA devices */
+ dmac_device.irq[0] = IRQ_EB11MP_DMA;
+ uart0_device.irq[0] = IRQ_EB11MP_UART0;
+ uart1_device.irq[0] = IRQ_EB11MP_UART1;
+ uart2_device.irq[0] = IRQ_EB11MP_UART2;
+ uart3_device.irq[0] = IRQ_EB11MP_UART3;
+ clcd_device.irq[0] = IRQ_EB11MP_CLCD;
+ wdog_device.irq[0] = IRQ_EB11MP_WDOG;
+ gpio0_device.irq[0] = IRQ_EB11MP_GPIO0;
+ gpio1_device.irq[0] = IRQ_EB11MP_GPIO1;
+ gpio2_device.irq[0] = IRQ_EB11MP_GPIO2;
+ rtc_device.irq[0] = IRQ_EB11MP_RTC;
+ sci0_device.irq[0] = IRQ_EB11MP_SCI;
+ ssp0_device.irq[0] = IRQ_EB11MP_SSP;
+ aaci_device.irq[0] = IRQ_EB11MP_AACI;
+ mmc0_device.irq[0] = IRQ_EB11MP_MMCI0A;
+ mmc0_device.irq[1] = IRQ_EB11MP_MMCI0B;
+ kmi0_device.irq[0] = IRQ_EB11MP_KMI0;
+ kmi1_device.irq[0] = IRQ_EB11MP_KMI1;
+
+ /* platform devices */
+ realview_eb_smc91x_resources[1].start = IRQ_EB11MP_ETH;
+ realview_eb_smc91x_resources[1].end = IRQ_EB11MP_ETH;
+}
+
+static void __init realview_eb_timer_init(void)
+{
+ unsigned int timer_irq;
+
+ if (core_tile_eb11mp()) {
+#ifdef CONFIG_LOCAL_TIMERS
+ twd_base_addr = __io_address(REALVIEW_EB11MP_TWD_BASE);
+ twd_size = REALVIEW_EB11MP_TWD_SIZE;
+#endif
+ timer_irq = IRQ_EB11MP_TIMER0_1;
+ } else
+ timer_irq = IRQ_EB_TIMER0_1;
+
+ realview_timer_init(timer_irq);
+}
+
+static struct sys_timer realview_eb_timer = {
+ .init = realview_eb_timer_init,
+};
+
static void __init realview_eb_init(void)
{
int i;
-#ifdef CONFIG_REALVIEW_MPCORE
- /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
- * Bits: .... ...0 0111 1001 0000 .... .... .... */
- l2x0_init(__io_address(REALVIEW_MPCORE_L220_BASE), 0x00790000, 0xfe000fff);
-#endif
+ if (core_tile_eb11mp()) {
+ realview_eb11mp_fixup();
+
+ /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
+ * Bits: .... ...0 0111 1001 0000 .... .... .... */
+ l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff);
+ }
+
clk_register(&realview_clcd_clk);
platform_device_register(&realview_flash_device);
- platform_device_register(&realview_smc91x_device);
+ platform_device_register(&realview_eb_smc91x_device);
platform_device_register(&realview_i2c_device);
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
@@ -204,6 +360,6 @@
.boot_params = 0x00000100,
.map_io = realview_eb_map_io,
.init_irq = gic_init_irq,
- .timer = &realview_timer,
+ .timer = &realview_eb_timer,
.init_machine = realview_eb_init,
MACHINE_END
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index a454451..eca558c 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -17,7 +17,7 @@
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/serial_8250.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <asm/elf.h>
#include <asm/io.h>
diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c
index 1e25b1d..94620be 100644
--- a/arch/arm/mach-sa1100/collie_pm.c
+++ b/arch/arm/mach-sa1100/collie_pm.c
@@ -165,7 +165,7 @@
ucb1x00_adc_enable(ucb);
ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
- /* >1010 = battery removed, 460 = 22C ?, higer = lower temp ? */
+ /* >1010 = battery removed, 460 = 22C ?, higher = lower temp ? */
voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC);
ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
ucb1x00_adc_disable(ucb);
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 9e13c83..5c84c60 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -470,7 +470,7 @@
* If the system is going to use the SA-1111 DMA engines, set up
* the memory bus request/grant pins.
*/
-void __init sa1110_mb_enable(void)
+void __devinit sa1110_mb_enable(void)
{
unsigned long flags;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 7595277..303a7ff 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -162,7 +162,7 @@
* Free the page table, if there was one.
*/
if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
- pte_free_kernel(pmd_page_vaddr(pmd));
+ pte_free_kernel(&init_mm, pmd_page_vaddr(pmd));
}
addr += PGDIR_SIZE;
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index 50b9aed..500c961 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -65,14 +65,14 @@
return new_pgd;
no_pte:
- pmd_free(new_pmd);
+ pmd_free(mm, new_pmd);
no_pmd:
free_pages((unsigned long)new_pgd, 2);
no_pgd:
return NULL;
}
-void free_pgd_slow(pgd_t *pgd)
+void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)
{
pmd_t *pmd;
struct page *pte;
@@ -94,8 +94,8 @@
pmd_clear(pmd);
dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
pte_lock_deinit(pte);
- pte_free(pte);
- pmd_free(pmd);
+ pte_free(mm, pte);
+ pmd_free(mm, pmd);
free:
free_pages((unsigned long) pgd, 2);
}
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index ba3d21d..6fe481f 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -57,8 +57,6 @@
static irqreturn_t
iop_timer_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
-
write_tisr(1);
while ((signed long)(next_jiffy_time - read_tcr1())
@@ -67,8 +65,6 @@
next_jiffy_time -= ticks_per_jiffy;
}
- write_sequnlock(&xtime_lock);
-
return IRQ_HANDLED;
}
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index d486f51..ae2c5d7 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -47,7 +47,7 @@
* Mark IRQ_LCD valid
*
* 25-Jul-2005 Ben Dooks
- * Split the S3C2440 IRQ code to seperate file
+ * Split the S3C2440 IRQ code to separate file
*/
#include <linux/init.h>
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
index 2ec1daa..766473b 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -130,9 +130,7 @@
static irqreturn_t
s3c2410_timer_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
timer_tick();
- write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index e34e2c9..28e0caf 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -10,6 +10,8 @@
# With EMBEDDED=n, we get lots of stuff automatically selected
# that we usually don't need on AVR32.
select EMBEDDED
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
help
AVR32 is a high-performance 32-bit RISC microprocessor core,
designed for cost-sensitive embedded applications, with particular
@@ -54,9 +56,6 @@
config ARCH_HAS_ILOG2_U64
def_bool n
-config ARCH_SUPPORTS_OPROFILE
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
@@ -83,6 +82,7 @@
select SUBARCH_AVR32B
select MMU
select PERFORMANCE_COUNTERS
+ select HAVE_GPIO_LIB
#
# CPU types
@@ -236,8 +236,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/avr32/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index 75c81f2..478bda4 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -293,6 +293,6 @@
.long sys_shmctl
.long sys_utimensat
.long sys_signalfd
- .long sys_timerfd /* 280 */
+ .long sys_ni_syscall /* 280, was sys_timerfd */
.long sys_eventfd
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */
diff --git a/arch/avr32/lib/delay.c b/arch/avr32/lib/delay.c
index b3bc0b5..9aa8800 100644
--- a/arch/avr32/lib/delay.c
+++ b/arch/avr32/lib/delay.c
@@ -12,13 +12,15 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/timex.h>
#include <linux/param.h>
#include <linux/types.h>
+#include <linux/init.h>
#include <asm/processor.h>
#include <asm/sysreg.h>
-int read_current_timer(unsigned long *timer_value)
+int __devinit read_current_timer(unsigned long *timer_value)
{
*timer_value = sysreg_read(COUNT);
return 0;
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index d61a02d..38a8fa3 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -24,11 +24,11 @@
#define MAX_NR_PIO_DEVICES 8
struct pio_device {
+ struct gpio_chip chip;
void __iomem *regs;
const struct platform_device *pdev;
struct clk *clk;
u32 pinmux_mask;
- u32 gpio_mask;
char name[8];
};
@@ -64,7 +64,8 @@
goto fail;
}
- if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+ if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
+ || gpiochip_is_requested(&pio->chip, pin_index))) {
printk("%s: pin %u is busy\n", pio->name, pin_index);
goto fail;
}
@@ -79,9 +80,6 @@
if (!(flags & AT32_GPIOF_PULLUP))
pio_writel(pio, PUDR, mask);
- /* gpio_request NOT allowed */
- set_bit(pin_index, &pio->gpio_mask);
-
return;
fail:
@@ -130,9 +128,6 @@
pio_writel(pio, PER, mask);
- /* gpio_request now allowed */
- clear_bit(pin_index, &pio->gpio_mask);
-
return;
fail:
@@ -166,96 +161,50 @@
/* GPIO API */
-int gpio_request(unsigned int gpio, const char *label)
+static int direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct pio_device *pio;
- unsigned int pin;
+ struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ u32 mask = 1 << offset;
- pio = gpio_to_pio(gpio);
- if (!pio)
- return -ENODEV;
+ if (!(pio_readl(pio, PSR) & mask))
+ return -EINVAL;
- pin = gpio & 0x1f;
- if (test_and_set_bit(pin, &pio->gpio_mask))
- return -EBUSY;
-
+ pio_writel(pio, ODR, mask);
return 0;
}
-EXPORT_SYMBOL(gpio_request);
-void gpio_free(unsigned int gpio)
+static int gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct pio_device *pio;
- unsigned int pin;
+ struct pio_device *pio = container_of(chip, struct pio_device, chip);
- pio = gpio_to_pio(gpio);
- if (!pio) {
- printk(KERN_ERR
- "gpio: attempted to free invalid pin %u\n", gpio);
- return;
- }
-
- pin = gpio & 0x1f;
- if (!test_and_clear_bit(pin, &pio->gpio_mask))
- printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n",
- pio->name, pin);
+ return (pio_readl(pio, PDSR) >> offset) & 1;
}
-EXPORT_SYMBOL(gpio_free);
-int gpio_direction_input(unsigned int gpio)
+static void gpio_set(struct gpio_chip *chip, unsigned offset, int value);
+
+static int direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pio_device *pio;
- unsigned int pin;
+ struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ u32 mask = 1 << offset;
- pio = gpio_to_pio(gpio);
- if (!pio)
- return -ENODEV;
+ if (!(pio_readl(pio, PSR) & mask))
+ return -EINVAL;
- pin = gpio & 0x1f;
- pio_writel(pio, ODR, 1 << pin);
-
+ gpio_set(chip, offset, value);
+ pio_writel(pio, OER, mask);
return 0;
}
-EXPORT_SYMBOL(gpio_direction_input);
-int gpio_direction_output(unsigned int gpio, int value)
+static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct pio_device *pio;
- unsigned int pin;
+ struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ u32 mask = 1 << offset;
- pio = gpio_to_pio(gpio);
- if (!pio)
- return -ENODEV;
-
- gpio_set_value(gpio, value);
-
- pin = gpio & 0x1f;
- pio_writel(pio, OER, 1 << pin);
-
- return 0;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-int gpio_get_value(unsigned int gpio)
-{
- struct pio_device *pio = &pio_dev[gpio >> 5];
-
- return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
-}
-EXPORT_SYMBOL(gpio_get_value);
-
-void gpio_set_value(unsigned int gpio, int value)
-{
- struct pio_device *pio = &pio_dev[gpio >> 5];
- u32 mask;
-
- mask = 1 << (gpio & 0x1f);
if (value)
pio_writel(pio, SODR, mask);
else
pio_writel(pio, CODR, mask);
}
-EXPORT_SYMBOL(gpio_set_value);
/*--------------------------------------------------------------------------*/
@@ -339,6 +288,63 @@
/*--------------------------------------------------------------------------*/
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+/*
+ * This shows more info than the generic gpio dump code:
+ * pullups, deglitching, open drain drive.
+ */
+static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct pio_device *pio = container_of(chip, struct pio_device, chip);
+ u32 psr, osr, imr, pdsr, pusr, ifsr, mdsr;
+ unsigned i;
+ u32 mask;
+ char bank;
+
+ psr = pio_readl(pio, PSR);
+ osr = pio_readl(pio, OSR);
+ imr = pio_readl(pio, IMR);
+ pdsr = pio_readl(pio, PDSR);
+ pusr = pio_readl(pio, PUSR);
+ ifsr = pio_readl(pio, IFSR);
+ mdsr = pio_readl(pio, MDSR);
+
+ bank = 'A' + pio->pdev->id;
+
+ for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
+ const char *label;
+
+ label = gpiochip_is_requested(chip, i);
+ if (!label)
+ continue;
+
+ seq_printf(s, " gpio-%-3d P%c%-2d (%-12s) %s %s %s",
+ chip->base + i, bank, i,
+ label,
+ (osr & mask) ? "out" : "in ",
+ (mask & pdsr) ? "hi" : "lo",
+ (mask & pusr) ? " " : "up");
+ if (ifsr & mask)
+ seq_printf(s, " deglitch");
+ if ((osr & mdsr) & mask)
+ seq_printf(s, " open-drain");
+ if (imr & mask)
+ seq_printf(s, " irq-%d edge-both",
+ gpio_to_irq(chip->base + i));
+ seq_printf(s, "\n");
+ }
+}
+
+#else
+#define pio_bank_show NULL
+#endif
+
+
+/*--------------------------------------------------------------------------*/
+
static int __init pio_probe(struct platform_device *pdev)
{
struct pio_device *pio = NULL;
@@ -349,6 +355,18 @@
pio = &pio_dev[pdev->id];
BUG_ON(!pio->regs);
+ pio->chip.label = pio->name;
+ pio->chip.base = pdev->id * 32;
+ pio->chip.ngpio = 32;
+
+ pio->chip.direction_input = direction_input;
+ pio->chip.get = gpio_get;
+ pio->chip.direction_output = direction_output;
+ pio->chip.set = gpio_set;
+ pio->chip.dbg_show = pio_bank_show;
+
+ gpiochip_add(&pio->chip);
+
gpio_irq_setup(pio, irq, gpio_irq_base);
platform_set_drvdata(pdev, pio);
@@ -406,12 +424,6 @@
pio->pdev = pdev;
pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
- /*
- * request_gpio() is only valid for pins that have been
- * explicitly configured as GPIO and not previously requested
- */
- pio->gpio_mask = ~0UL;
-
/* start with irqs disabled and acked */
pio_writel(pio, IDR, ~0UL);
(void) pio_readl(pio, ISR);
diff --git a/arch/avr32/mach-at32ap/pio.h b/arch/avr32/mach-at32ap/pio.h
index 50fa3aca3..7795116 100644
--- a/arch/avr32/mach-at32ap/pio.h
+++ b/arch/avr32/mach-at32ap/pio.h
@@ -19,7 +19,7 @@
#define PIO_OSR 0x0018
#define PIO_IFER 0x0020
#define PIO_IFDR 0x0024
-#define PIO_ISFR 0x0028
+#define PIO_IFSR 0x0028
#define PIO_SODR 0x0030
#define PIO_CODR 0x0034
#define PIO_ODSR 0x0038
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index fc7ca86..ba21e33 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -24,6 +24,7 @@
config BLACKFIN
bool
default y
+ select HAVE_OPROFILE
config ZONE_DMA
bool
@@ -898,6 +899,10 @@
menu "Power management options"
source "kernel/power/Kconfig"
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
choice
prompt "Select PM Wakeup Event Source"
default PM_WAKEUP_GPIO_BY_SIC_IWR
@@ -969,8 +974,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/blackfin/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index f8c411a..1795aab 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -37,7 +37,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/sl811.h>
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index a72c7a6..97378b0 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -38,7 +38,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <asm/dma.h>
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
index 21df2f3..886f260 100644
--- a/arch/blackfin/mach-bf533/boards/cm_bf533.c
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -34,7 +34,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index c37dd45..4026c2f 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -35,7 +35,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index ac52b04..0185350 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -38,7 +38,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
index 8703b67..f7c1f96 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -36,7 +36,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
index 3e52f3f..8a3397d 100644
--- a/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -38,7 +38,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/sl811.h>
diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
index b8bbba8..d71e0be 100644
--- a/arch/blackfin/mach-bf537/boards/minotaur.c
+++ b/arch/blackfin/mach-bf537/boards/minotaur.c
@@ -10,7 +10,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb_isp1362.h>
#endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb_sl811.h>
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 7725415..119e6ea 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -38,7 +38,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/sl811.h>
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
index 3a79a90..bf9e738 100644
--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -34,7 +34,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index 7601c3b..ed863ce 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -35,7 +35,7 @@
#include <linux/spi/spi.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/portmux.h>
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 56ff51b..fdd9bf43 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1373,7 +1373,7 @@
.long _sys_epoll_pwait
.long _sys_utimensat
.long _sys_signalfd
- .long _sys_timerfd
+ .long _sys_ni_syscall
.long _sys_eventfd /* 350 */
.long _sys_pread64
.long _sys_pwrite64
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 222da15..27b082a 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -150,6 +150,7 @@
Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
source arch/cris/arch-v10/Kconfig
+source arch/cris/arch-v32/Kconfig
endmenu
@@ -157,8 +158,8 @@
# bring in ETRAX built-in drivers
menu "Drivers for built-in interfaces"
-# arch/cris/arch is a symlink to correct arch (arch-v10 or arch-v32)
-source arch/cris/arch/drivers/Kconfig
+source arch/cris/arch-v10/drivers/Kconfig
+source arch/cris/arch-v32/drivers/Kconfig
endmenu
@@ -213,8 +214,6 @@
source "drivers/usb/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/cris/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig
index f1ce6f6..1d61fae 100644
--- a/arch/cris/arch-v10/Kconfig
+++ b/arch/cris/arch-v10/Kconfig
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V10
+
# ETRAX 100LX v1 has a MMU "feature" requiring a low mapping
config CRIS_LOW_MAP
bool
@@ -451,3 +453,5 @@
default "25"
help
Configure where power button is connected.
+
+endif
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
index e3c0f29..96740ef 100644
--- a/arch/cris/arch-v10/drivers/Kconfig
+++ b/arch/cris/arch-v10/drivers/Kconfig
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V10
+
config ETRAX_ETHERNET
bool "Ethernet support"
depends on ETRAX_ARCH_V10
@@ -806,3 +808,5 @@
1 = 2kohm, 2 = 4kohm, 3 = 4kohm
4 = 1 diode, 8 = 2 diodes
Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5
+
+endif
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
index ec62c95..d1361dc 100644
--- a/arch/cris/arch-v10/kernel/entry.S
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -1167,7 +1167,7 @@
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
.long sys_signalfd
- .long sys_timerfd
+ .long sys_ni_syscall
.long sys_eventfd
.long sys_fallocate
diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig
index 4f79d8e..d8acaa9 100644
--- a/arch/cris/arch-v32/Kconfig
+++ b/arch/cris/arch-v32/Kconfig
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V32
+
config ETRAX_DRAM_VIRTUAL_BASE
hex
depends on ETRAX_ARCH_V32
@@ -294,3 +296,5 @@
help
Configures the initial data for the general port E bits. Most
products should use 00000 here.
+
+endif
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index 9bccb5e2..c329cce 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V32
+
config ETRAX_ETHERNET
bool "Ethernet support"
depends on ETRAX_ARCH_V32
@@ -610,3 +612,5 @@
help
This option enables a driver for the stream co-processor
for cryptographic operations.
+
+endif
diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c
index 66f9500..e036465 100644
--- a/arch/cris/arch-v32/drivers/pci/dma.c
+++ b/arch/cris/arch-v32/drivers/pci/dma.c
@@ -93,7 +93,7 @@
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
if (!dev->dma_mem)
- goto out;
+ goto iounmap_out;
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
if (!dev->dma_mem->bitmap)
goto free1_out;
@@ -110,6 +110,8 @@
free1_out:
kfree(dev->dma_mem);
+ iounmap_out:
+ iounmap(mem_base);
out:
return 0;
}
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 43153e7..96f7d70 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -79,7 +79,7 @@
Setting this option causes the FR-V atomic operations to be mostly
implemented out-of-line.
- See Documentation/fujitsu/frv/atomic-ops.txt for more information.
+ See Documentation/frv/atomic-ops.txt for more information.
config HIGHMEM
bool "High memory support"
@@ -138,6 +138,15 @@
endchoice
+config PAGE_OFFSET
+ hex
+ default 0x20000000 if UCPAGE_OFFSET_20000000
+ default 0x40000000 if UCPAGE_OFFSET_40000000
+ default 0x60000000 if UCPAGE_OFFSET_60000000
+ default 0x80000000 if UCPAGE_OFFSET_80000000
+ default 0xA0000000 if UCPAGE_OFFSET_A0000000
+ default 0xC0000000
+
config PROTECT_KERNEL
bool "Protect core kernel against userspace"
depends on !MMU
@@ -322,11 +331,6 @@
onboard. If you have one of these boards and you wish to use the PCI
facilities, say Y here.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config RESERVE_DMA_COHERENT
bool "Reserve DMA coherent memory"
depends on PCI && !MMU
@@ -357,6 +361,11 @@
# should probably wait a while.
menu "Power management options"
+
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
source kernel/power/Kconfig
endmenu
@@ -375,8 +384,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/frv/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index f926c70..ca6a345 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -253,7 +253,7 @@
andi.p gr5,#~PSR_ET,gr5
# set CCCR.CC3 to Undefined to abort atomic-modify completion inside the kernel
- # - for an explanation of how it works, see: Documentation/fujitsu/frv/atomic-ops.txt
+ # - for an explanation of how it works, see: Documentation/frv/atomic-ops.txt
andi gr25,#~0xc0,gr25
sti gr20,@(gr28,#REG_TBR)
@@ -445,7 +445,7 @@
sti gr22,@(sp,#REG_SP)
# set CCCR.CC3 to Undefined to abort atomic-modify completion inside the kernel
- # - for an explanation of how it works, see: Documentation/fujitsu/frv/atomic-ops.txt
+ # - for an explanation of how it works, see: Documentation/frv/atomic-ops.txt
movsg cccr,gr20
andi gr20,#~0xc0,gr20
movgs gr20,cccr
@@ -1494,7 +1494,7 @@
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
.long sys_signalfd
- .long sys_timerfd
+ .long sys_ni_syscall
.long sys_eventfd
.long sys_fallocate
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index a74c087..b38ae1f 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -708,7 +708,7 @@
/*
* calibrate the delay loop
*/
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
{
loops_per_jiffy = __delay_loops_MHz * (1000000 / HZ);
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index f42b328..ef7527b 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -13,7 +13,7 @@
jiffies = jiffies_64 + 4;
-__page_offset = 0xc0000000; /* start of area covered by struct pages */
+__page_offset = CONFIG_PAGE_OFFSET; /* start of area covered by struct pages */
__kernel_image_start = __page_offset; /* address at which kernel image resides */
SECTIONS
diff --git a/arch/frv/lib/atomic-ops.S b/arch/frv/lib/atomic-ops.S
index 545cd32..ee0ac90 100644
--- a/arch/frv/lib/atomic-ops.S
+++ b/arch/frv/lib/atomic-ops.S
@@ -1,7 +1,7 @@
/* atomic-ops.S: kernel atomic operations
*
* For an explanation of how atomic ops work in this arch, see:
- * Documentation/fujitsu/frv/atomic-ops.txt
+ * Documentation/frv/atomic-ops.txt
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
diff --git a/arch/frv/mm/mmu-context.c b/arch/frv/mm/mmu-context.c
index 1530a411..81757d5 100644
--- a/arch/frv/mm/mmu-context.c
+++ b/arch/frv/mm/mmu-context.c
@@ -181,7 +181,7 @@
/* get a handle on the mm_struct */
read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
+ tsk = find_task_by_vpid(pid);
if (tsk) {
ret = -EINVAL;
diff --git a/arch/frv/mm/pgalloc.c b/arch/frv/mm/pgalloc.c
index 7787c3c..1a2e5c8 100644
--- a/arch/frv/mm/pgalloc.c
+++ b/arch/frv/mm/pgalloc.c
@@ -140,7 +140,7 @@
return pgd;
}
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
/* in the non-PAE case, clear_page_tables() clears user pgd entries */
quicklist_free(0, pgd_dtor, pgd);
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index ff6a871..dc61222 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -223,8 +223,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/h8300/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c
index 8dec4dd..5a1b4cf 100644
--- a/arch/h8300/kernel/irq.c
+++ b/arch/h8300/kernel/irq.c
@@ -14,6 +14,7 @@
#include <linux/random.h>
#include <linux/bootmem.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/traps.h>
diff --git a/arch/h8300/platform/h8s/ints.c b/arch/h8300/platform/h8s/ints.c
index 551fd5f..ac10b97 100644
--- a/arch/h8300/platform/h8s/ints.c
+++ b/arch/h8300/platform/h8s/ints.c
@@ -121,7 +121,7 @@
printk("virtual vector at 0x%08lx\n",(unsigned long)ramvec);
#if defined(CONFIG_GDB_DEBUG)
- /* save orignal break vector */
+ /* save original break vector */
break_vec = ramvec[TRAP3_VEC];
#else
break_vec = VECTOR(trace_break);
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index c9307c9..b0de113 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -15,6 +15,8 @@
select ACPI if (!IA64_HP_SIM)
select PM if (!IA64_HP_SIM)
select ARCH_SUPPORTS_MSI
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
@@ -283,8 +285,8 @@
single processor systems. On a single processor system, the kernel
will run faster if you say N here.
- See also the <file:Documentation/smp.txt> and the SMP-HOWTO
- available at <http://www.tldp.org/docs.html#howto>.
+ See also the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -600,8 +602,6 @@
source "arch/ia64/hp/sim/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/ia64/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 45bf04e..a944454 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1265,7 +1265,7 @@
* the sglist do both.
*/
static SBA_INLINE int
-sba_coalesce_chunks( struct ioc *ioc,
+sba_coalesce_chunks(struct ioc *ioc, struct device *dev,
struct scatterlist *startsg,
int nents)
{
@@ -1275,6 +1275,7 @@
struct scatterlist *dma_sg; /* next DMA stream head */
unsigned long dma_offset, dma_len; /* start/len of DMA stream */
int n_mappings = 0;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
while (nents > 0) {
unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
@@ -1314,6 +1315,9 @@
> DMA_CHUNK_SIZE)
break;
+ if (dma_len + startsg->length > max_seg_size)
+ break;
+
/*
** Then look for virtually contiguous blocks.
**
@@ -1441,7 +1445,7 @@
** w/o this association, we wouldn't have coherent DMA!
** Access to the virtual address is what forces a two pass algorithm.
*/
- coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+ coalesced = sba_coalesce_chunks(ioc, dev, sglist, nents);
/*
** Program the I/O Pdir
@@ -1871,7 +1875,7 @@
return 0;
}
-static struct seq_operations ioc_seq_ops = {
+static const struct seq_operations ioc_seq_ops = {
.start = ioc_start,
.next = ioc_next,
.stop = ioc_stop,
diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c
index d1d50cd..896b1eb 100644
--- a/arch/ia64/ia32/ia32_support.c
+++ b/arch/ia64/ia32/ia32_support.c
@@ -27,7 +27,7 @@
#include "ia32priv.h"
-extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
+extern int die_if_kernel (char *str, struct pt_regs *regs, long err);
struct exec_domain ia32_exec_domain;
struct page *ia32_shared_page[NR_CPUS];
@@ -217,7 +217,8 @@
{
siginfo_t siginfo;
- die_if_kernel("Bad IA-32 interrupt", regs, int_num);
+ if (die_if_kernel("Bad IA-32 interrupt", regs, int_num))
+ return;
siginfo.si_signo = SIGTRAP;
siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 00b5d08..9068025 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -69,6 +69,20 @@
unsigned long acpi_wakeup_address = 0;
+#ifdef CONFIG_IA64_GENERIC
+static unsigned long __init acpi_find_rsdp(void)
+{
+ unsigned long rsdp_phys = 0;
+
+ if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+ rsdp_phys = efi.acpi20;
+ else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+ printk(KERN_WARNING PREFIX
+ "v1.0/r0.71 tables no longer supported\n");
+ return rsdp_phys;
+}
+#endif
+
const char __init *
acpi_get_sysname(void)
{
@@ -152,7 +166,7 @@
return vector;
}
-char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
{
return __va(phys_addr);
}
@@ -631,18 +645,6 @@
return 0;
}
-unsigned long __init acpi_find_rsdp(void)
-{
- unsigned long rsdp_phys = 0;
-
- if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- rsdp_phys = efi.acpi20;
- else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- printk(KERN_WARNING PREFIX
- "v1.0/r0.71 tables no longer supported\n");
- return rsdp_phys;
-}
-
int __init acpi_boot_init(void)
{
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 242d793..919070a 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -1,7 +1,8 @@
/*
* Extensible Firmware Interface
*
- * Based on Extensible Firmware Interface Specification version 0.9 April 30, 1999
+ * Based on Extensible Firmware Interface Specification version 0.9
+ * April 30, 1999
*
* Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
@@ -48,145 +49,157 @@
#define efi_call_virt(f, args...) (*(f))(args)
-#define STUB_GET_TIME(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_time_cap_t *atc = NULL; \
- efi_status_t ret; \
- \
- if (tc) \
- atc = adjust_arg(tc); \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm), atc); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_GET_TIME(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_time_cap_t *atc = NULL; \
+ efi_status_t ret; \
+ \
+ if (tc) \
+ atc = adjust_arg(tc); \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), \
+ adjust_arg(tm), atc); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_SET_TIME(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_set_time (efi_time_t *tm) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_status_t ret; \
- \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), adjust_arg(tm)); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_SET_TIME(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_set_time (efi_time_t *tm) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_status_t ret; \
+ \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), \
+ adjust_arg(tm)); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_status_t ret; \
- \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time), \
- adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm)); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, \
+ efi_time_t *tm) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_status_t ret; \
+ \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix( \
+ (efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time), \
+ adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm)); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_time_t *atm = NULL; \
- efi_status_t ret; \
- \
- if (tm) \
- atm = adjust_arg(tm); \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time), \
- enabled, atm); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_time_t *atm = NULL; \
+ efi_status_t ret; \
+ \
+ if (tm) \
+ atm = adjust_arg(tm); \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix( \
+ (efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time), \
+ enabled, atm); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_GET_VARIABLE(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, \
- unsigned long *data_size, void *data) \
-{ \
- struct ia64_fpreg fr[6]; \
- u32 *aattr = NULL; \
- efi_status_t ret; \
- \
- if (attr) \
- aattr = adjust_arg(attr); \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable), \
- adjust_arg(name), adjust_arg(vendor), aattr, \
- adjust_arg(data_size), adjust_arg(data)); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_GET_VARIABLE(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, \
+ unsigned long *data_size, void *data) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ u32 *aattr = NULL; \
+ efi_status_t ret; \
+ \
+ if (attr) \
+ aattr = adjust_arg(attr); \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix( \
+ (efi_get_variable_t *) __va(runtime->get_variable), \
+ adjust_arg(name), adjust_arg(vendor), aattr, \
+ adjust_arg(data_size), adjust_arg(data)); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_status_t ret; \
- \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_get_next_variable_t *) __va(runtime->get_next_variable), \
- adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor)); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, \
+ efi_guid_t *vendor) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_status_t ret; \
+ \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix( \
+ (efi_get_next_variable_t *) __va(runtime->get_next_variable), \
+ adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor)); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_SET_VARIABLE(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, unsigned long attr, \
- unsigned long data_size, void *data) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_status_t ret; \
- \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_set_variable_t *) __va(runtime->set_variable), \
- adjust_arg(name), adjust_arg(vendor), attr, data_size, \
- adjust_arg(data)); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_SET_VARIABLE(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, \
+ unsigned long attr, unsigned long data_size, \
+ void *data) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_status_t ret; \
+ \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix( \
+ (efi_set_variable_t *) __va(runtime->set_variable), \
+ adjust_arg(name), adjust_arg(vendor), attr, data_size, \
+ adjust_arg(data)); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg) \
-static efi_status_t \
-prefix##_get_next_high_mono_count (u32 *count) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_status_t ret; \
- \
- ia64_save_scratch_fpregs(fr); \
- ret = efi_call_##prefix((efi_get_next_high_mono_count_t *) \
- __va(runtime->get_next_high_mono_count), adjust_arg(count)); \
- ia64_load_scratch_fpregs(fr); \
- return ret; \
+#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg) \
+static efi_status_t \
+prefix##_get_next_high_mono_count (u32 *count) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_status_t ret; \
+ \
+ ia64_save_scratch_fpregs(fr); \
+ ret = efi_call_##prefix((efi_get_next_high_mono_count_t *) \
+ __va(runtime->get_next_high_mono_count), \
+ adjust_arg(count)); \
+ ia64_load_scratch_fpregs(fr); \
+ return ret; \
}
-#define STUB_RESET_SYSTEM(prefix, adjust_arg) \
-static void \
-prefix##_reset_system (int reset_type, efi_status_t status, \
- unsigned long data_size, efi_char16_t *data) \
-{ \
- struct ia64_fpreg fr[6]; \
- efi_char16_t *adata = NULL; \
- \
- if (data) \
- adata = adjust_arg(data); \
- \
- ia64_save_scratch_fpregs(fr); \
- efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system), \
- reset_type, status, data_size, adata); \
- /* should not return, but just in case... */ \
- ia64_load_scratch_fpregs(fr); \
+#define STUB_RESET_SYSTEM(prefix, adjust_arg) \
+static void \
+prefix##_reset_system (int reset_type, efi_status_t status, \
+ unsigned long data_size, efi_char16_t *data) \
+{ \
+ struct ia64_fpreg fr[6]; \
+ efi_char16_t *adata = NULL; \
+ \
+ if (data) \
+ adata = adjust_arg(data); \
+ \
+ ia64_save_scratch_fpregs(fr); \
+ efi_call_##prefix( \
+ (efi_reset_system_t *) __va(runtime->reset_system), \
+ reset_type, status, data_size, adata); \
+ /* should not return, but just in case... */ \
+ ia64_load_scratch_fpregs(fr); \
}
#define phys_ptr(arg) ((__typeof__(arg)) ia64_tpa(arg))
@@ -223,7 +236,8 @@
return;
}
- ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
+ ts->tv_sec = mktime(tm.year, tm.month, tm.day,
+ tm.hour, tm.minute, tm.second);
ts->tv_nsec = tm.nanosecond;
}
@@ -297,8 +311,8 @@
}
/*
- * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that
- * has memory that is available for OS use.
+ * Walk the EFI memory map and call CALLBACK once for each EFI memory
+ * descriptor that has memory that is available for OS use.
*/
void
efi_memmap_walk (efi_freemem_callback_t callback, void *arg)
@@ -307,8 +321,8 @@
}
/*
- * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that
- * has memory that is available for uncached allocator.
+ * Walk the EFI memory map and call CALLBACK once for each EFI memory
+ * descriptor that has memory that is available for uncached allocator.
*/
void
efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg)
@@ -317,11 +331,10 @@
}
/*
- * Look for the PAL_CODE region reported by EFI and maps it using an
+ * Look for the PAL_CODE region reported by EFI and map it using an
* ITR to enable safe PAL calls in virtual mode. See IA-64 Processor
* Abstraction Layer chapter 11 in ADAG
*/
-
void *
efi_get_pal_addr (void)
{
@@ -341,45 +354,47 @@
continue;
if (++pal_code_count > 1) {
- printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n",
- md->phys_addr);
+ printk(KERN_ERR "Too many EFI Pal Code memory ranges, "
+ "dropped @ %lx\n", md->phys_addr);
continue;
}
/*
- * The only ITLB entry in region 7 that is used is the one installed by
- * __start(). That entry covers a 64MB range.
+ * The only ITLB entry in region 7 that is used is the one
+ * installed by __start(). That entry covers a 64MB range.
*/
mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1);
vaddr = PAGE_OFFSET + md->phys_addr;
/*
- * We must check that the PAL mapping won't overlap with the kernel
- * mapping.
+ * We must check that the PAL mapping won't overlap with the
+ * kernel mapping.
*
- * PAL code is guaranteed to be aligned on a power of 2 between 4k and
- * 256KB and that only one ITR is needed to map it. This implies that the
- * PAL code is always aligned on its size, i.e., the closest matching page
- * size supported by the TLB. Therefore PAL code is guaranteed never to
- * cross a 64MB unless it is bigger than 64MB (very unlikely!). So for
- * now the following test is enough to determine whether or not we need a
- * dedicated ITR for the PAL code.
+ * PAL code is guaranteed to be aligned on a power of 2 between
+ * 4k and 256KB and that only one ITR is needed to map it. This
+ * implies that the PAL code is always aligned on its size,
+ * i.e., the closest matching page size supported by the TLB.
+ * Therefore PAL code is guaranteed never to cross a 64MB unless
+ * it is bigger than 64MB (very unlikely!). So for now the
+ * following test is enough to determine whether or not we need
+ * a dedicated ITR for the PAL code.
*/
if ((vaddr & mask) == (KERNEL_START & mask)) {
- printk(KERN_INFO "%s: no need to install ITR for PAL code\n",
- __FUNCTION__);
+ printk(KERN_INFO "%s: no need to install ITR for "
+ "PAL code\n", __FUNCTION__);
continue;
}
if (efi_md_size(md) > IA64_GRANULE_SIZE)
- panic("Woah! PAL code size bigger than a granule!");
+ panic("Whoa! PAL code size bigger than a granule!");
#if EFI_DEBUG
mask = ~((1 << IA64_GRANULE_SHIFT) - 1);
- printk(KERN_INFO "CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
- smp_processor_id(), md->phys_addr,
- md->phys_addr + efi_md_size(md),
- vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
+ printk(KERN_INFO "CPU %d: mapping PAL code "
+ "[0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
+ smp_processor_id(), md->phys_addr,
+ md->phys_addr + efi_md_size(md),
+ vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
#endif
return __va(md->phys_addr);
}
@@ -401,11 +416,11 @@
* Cannot write to CRx with PSR.ic=1
*/
psr = ia64_clear_ic();
- ia64_itr(0x1, IA64_TR_PALCODE, GRANULEROUNDDOWN((unsigned long) pal_vaddr),
+ ia64_itr(0x1, IA64_TR_PALCODE,
+ GRANULEROUNDDOWN((unsigned long) pal_vaddr),
pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
IA64_GRANULE_SHIFT);
ia64_set_psr(psr); /* restore psr */
- ia64_srlz_i();
}
void __init
@@ -418,7 +433,10 @@
char *cp, vendor[100] = "unknown";
int i;
- /* it's too early to be able to use the standard kernel command line support... */
+ /*
+ * It's too early to be able to use the standard kernel command line
+ * support...
+ */
for (cp = boot_command_line; *cp; ) {
if (memcmp(cp, "mem=", 4) == 0) {
mem_limit = memparse(cp + 4, &cp);
@@ -434,9 +452,11 @@
}
}
if (min_addr != 0UL)
- printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20);
+ printk(KERN_INFO "Ignoring memory below %luMB\n",
+ min_addr >> 20);
if (max_addr != ~0UL)
- printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20);
+ printk(KERN_INFO "Ignoring memory above %luMB\n",
+ max_addr >> 20);
efi.systab = __va(ia64_boot_param->efi_systab);
@@ -444,9 +464,9 @@
* Verify the EFI Table
*/
if (efi.systab == NULL)
- panic("Woah! Can't find EFI system table.\n");
+ panic("Whoa! Can't find EFI system table.\n");
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
- panic("Woah! EFI system table signature incorrect\n");
+ panic("Whoa! EFI system table signature incorrect\n");
if ((efi.systab->hdr.revision >> 16) == 0)
printk(KERN_WARNING "Warning: EFI system table version "
"%d.%02d, expected 1.00 or greater\n",
@@ -464,7 +484,8 @@
}
printk(KERN_INFO "EFI v%u.%.02u by %s:",
- efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor);
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
efi.mps = EFI_INVALID_TABLE_ADDR;
efi.acpi = EFI_INVALID_TABLE_ADDR;
@@ -519,9 +540,12 @@
efi_memory_desc_t *md;
void *p;
- for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) {
+ for (i = 0, p = efi_map_start; p < efi_map_end;
+ ++i, p += efi_desc_size)
+ {
md = p;
- printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
+ printk("mem%02u: type=%u, attr=0x%lx, "
+ "range=[0x%016lx-0x%016lx) (%luMB)\n",
i, md->type, md->attribute, md->phys_addr,
md->phys_addr + efi_md_size(md),
md->num_pages >> (20 - EFI_PAGE_SHIFT));
@@ -549,8 +573,8 @@
md = p;
if (md->attribute & EFI_MEMORY_RUNTIME) {
/*
- * Some descriptors have multiple bits set, so the order of
- * the tests is relevant.
+ * Some descriptors have multiple bits set, so the
+ * order of the tests is relevant.
*/
if (md->attribute & EFI_MEMORY_WB) {
md->virt_addr = (u64) __va(md->phys_addr);
@@ -558,21 +582,26 @@
md->virt_addr = (u64) ioremap(md->phys_addr, 0);
} else if (md->attribute & EFI_MEMORY_WC) {
#if 0
- md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P
- | _PAGE_D
- | _PAGE_MA_WC
- | _PAGE_PL_0
- | _PAGE_AR_RW));
+ md->virt_addr = ia64_remap(md->phys_addr,
+ (_PAGE_A |
+ _PAGE_P |
+ _PAGE_D |
+ _PAGE_MA_WC |
+ _PAGE_PL_0 |
+ _PAGE_AR_RW));
#else
printk(KERN_INFO "EFI_MEMORY_WC mapping\n");
md->virt_addr = (u64) ioremap(md->phys_addr, 0);
#endif
} else if (md->attribute & EFI_MEMORY_WT) {
#if 0
- md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P
- | _PAGE_D | _PAGE_MA_WT
- | _PAGE_PL_0
- | _PAGE_AR_RW));
+ md->virt_addr = ia64_remap(md->phys_addr,
+ (_PAGE_A |
+ _PAGE_P |
+ _PAGE_D |
+ _PAGE_MA_WT |
+ _PAGE_PL_0 |
+ _PAGE_AR_RW));
#else
printk(KERN_INFO "EFI_MEMORY_WT mapping\n");
md->virt_addr = (u64) ioremap(md->phys_addr, 0);
@@ -583,16 +612,18 @@
status = efi_call_phys(__va(runtime->set_virtual_address_map),
ia64_boot_param->efi_memmap_size,
- efi_desc_size, ia64_boot_param->efi_memdesc_version,
+ efi_desc_size,
+ ia64_boot_param->efi_memdesc_version,
ia64_boot_param->efi_memmap);
if (status != EFI_SUCCESS) {
- printk(KERN_WARNING "warning: unable to switch EFI into virtual mode "
- "(status=%lu)\n", status);
+ printk(KERN_WARNING "warning: unable to switch EFI into "
+ "virtual mode (status=%lu)\n", status);
return;
}
/*
- * Now that EFI is in virtual mode, we call the EFI functions more efficiently:
+ * Now that EFI is in virtual mode, we call the EFI functions more
+ * efficiently:
*/
efi.get_time = virt_get_time;
efi.set_time = virt_set_time;
@@ -606,8 +637,8 @@
}
/*
- * Walk the EFI memory map looking for the I/O port range. There can only be one entry of
- * this type, other I/O port ranges should be described via ACPI.
+ * Walk the EFI memory map looking for the I/O port range. There can only be
+ * one entry of this type, other I/O port ranges should be described via ACPI.
*/
u64
efi_get_iobase (void)
@@ -678,7 +709,6 @@
for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
md = p;
-
if (md->phys_addr < end && efi_md_end(md) > phys_addr)
return 1;
}
@@ -731,7 +761,7 @@
if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr)
return 0;
} while (md);
- return 0;
+ return 0; /* never reached */
}
u64
@@ -767,7 +797,7 @@
if (!md || md->attribute != attr)
return 0;
} while (md);
- return 0;
+ return 0; /* never reached */
}
EXPORT_SYMBOL(kern_mem_attribute);
@@ -883,7 +913,7 @@
return 1;
uart = 0;
}
- hdr = (struct efi_generic_dev_path *) ((u8 *) hdr + hdr->length);
+ hdr = (struct efi_generic_dev_path *)((u8 *) hdr + hdr->length);
}
printk(KERN_ERR "Malformed %s value\n", name);
return 0;
@@ -921,10 +951,12 @@
if (!efi_wb(md)) {
continue;
}
- if (pmd == NULL || !efi_wb(pmd) || efi_md_end(pmd) != md->phys_addr) {
+ if (pmd == NULL || !efi_wb(pmd) ||
+ efi_md_end(pmd) != md->phys_addr) {
contig_low = GRANULEROUNDUP(md->phys_addr);
contig_high = efi_md_end(md);
- for (q = p + efi_desc_size; q < efi_map_end; q += efi_desc_size) {
+ for (q = p + efi_desc_size; q < efi_map_end;
+ q += efi_desc_size) {
check_md = q;
if (!efi_wb(check_md))
break;
@@ -988,8 +1020,9 @@
for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) {
md = p;
if (!efi_wb(md)) {
- if (efi_uc(md) && (md->type == EFI_CONVENTIONAL_MEMORY ||
- md->type == EFI_BOOT_SERVICES_DATA)) {
+ if (efi_uc(md) &&
+ (md->type == EFI_CONVENTIONAL_MEMORY ||
+ md->type == EFI_BOOT_SERVICES_DATA)) {
k->attribute = EFI_MEMORY_UC;
k->start = md->phys_addr;
k->num_pages = md->num_pages;
@@ -997,10 +1030,12 @@
}
continue;
}
- if (pmd == NULL || !efi_wb(pmd) || efi_md_end(pmd) != md->phys_addr) {
+ if (pmd == NULL || !efi_wb(pmd) ||
+ efi_md_end(pmd) != md->phys_addr) {
contig_low = GRANULEROUNDUP(md->phys_addr);
contig_high = efi_md_end(md);
- for (q = p + efi_desc_size; q < efi_map_end; q += efi_desc_size) {
+ for (q = p + efi_desc_size; q < efi_map_end;
+ q += efi_desc_size) {
check_md = q;
if (!efi_wb(check_md))
break;
@@ -1025,13 +1060,17 @@
if (md->phys_addr < contig_low) {
lim = min(efi_md_end(md), contig_low);
if (efi_uc(md)) {
- if (k > kern_memmap && (k-1)->attribute == EFI_MEMORY_UC &&
+ if (k > kern_memmap &&
+ (k-1)->attribute == EFI_MEMORY_UC &&
kmd_end(k-1) == md->phys_addr) {
- (k-1)->num_pages += (lim - md->phys_addr) >> EFI_PAGE_SHIFT;
+ (k-1)->num_pages +=
+ (lim - md->phys_addr)
+ >> EFI_PAGE_SHIFT;
} else {
k->attribute = EFI_MEMORY_UC;
k->start = md->phys_addr;
- k->num_pages = (lim - md->phys_addr) >> EFI_PAGE_SHIFT;
+ k->num_pages = (lim - md->phys_addr)
+ >> EFI_PAGE_SHIFT;
k++;
}
}
@@ -1049,7 +1088,8 @@
} else {
k->attribute = EFI_MEMORY_UC;
k->start = lim;
- k->num_pages = (efi_md_end(md) - lim) >> EFI_PAGE_SHIFT;
+ k->num_pages = (efi_md_end(md) - lim)
+ >> EFI_PAGE_SHIFT;
k++;
}
}
@@ -1151,8 +1191,10 @@
break;
}
- if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "failed to alocate resource for iomem\n");
+ if ((res = kzalloc(sizeof(struct resource),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR
+ "failed to allocate resource for iomem\n");
return;
}
@@ -1187,44 +1229,44 @@
rsvd_regions are sorted
*/
unsigned long __init
-kdump_find_rsvd_region (unsigned long size,
- struct rsvd_region *r, int n)
+kdump_find_rsvd_region (unsigned long size, struct rsvd_region *r, int n)
{
- int i;
- u64 start, end;
- u64 alignment = 1UL << _PAGE_SIZE_64M;
- void *efi_map_start, *efi_map_end, *p;
- efi_memory_desc_t *md;
- u64 efi_desc_size;
+ int i;
+ u64 start, end;
+ u64 alignment = 1UL << _PAGE_SIZE_64M;
+ void *efi_map_start, *efi_map_end, *p;
+ efi_memory_desc_t *md;
+ u64 efi_desc_size;
- efi_map_start = __va(ia64_boot_param->efi_memmap);
- efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
- efi_desc_size = ia64_boot_param->efi_memdesc_size;
+ efi_map_start = __va(ia64_boot_param->efi_memmap);
+ efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
+ efi_desc_size = ia64_boot_param->efi_memdesc_size;
- for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
- md = p;
- if (!efi_wb(md))
- continue;
- start = ALIGN(md->phys_addr, alignment);
- end = efi_md_end(md);
- for (i = 0; i < n; i++) {
- if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
- if (__pa(r[i].start) > start + size)
- return start;
- start = ALIGN(__pa(r[i].end), alignment);
- if (i < n-1 && __pa(r[i+1].start) < start + size)
- continue;
- else
- break;
+ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+ md = p;
+ if (!efi_wb(md))
+ continue;
+ start = ALIGN(md->phys_addr, alignment);
+ end = efi_md_end(md);
+ for (i = 0; i < n; i++) {
+ if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
+ if (__pa(r[i].start) > start + size)
+ return start;
+ start = ALIGN(__pa(r[i].end), alignment);
+ if (i < n-1 &&
+ __pa(r[i+1].start) < start + size)
+ continue;
+ else
+ break;
+ }
}
- }
- if (end > start + size)
- return start;
- }
+ if (end > start + size)
+ return start;
+ }
- printk(KERN_WARNING "Cannot reserve 0x%lx byte of memory for crashdump\n",
- size);
- return ~0UL;
+ printk(KERN_WARNING
+ "Cannot reserve 0x%lx byte of memory for crashdump\n", size);
+ return ~0UL;
}
#endif
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index c36f43c..f5d3efb 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1586,7 +1586,7 @@
data8 sys_epoll_pwait // 1305
data8 sys_utimensat
data8 sys_signalfd
- data8 sys_timerfd
+ data8 sys_ni_syscall
data8 sys_eventfd
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
index 490dab5..57d2ee6 100644
--- a/arch/ia64/kernel/fsyscall_gtod_data.h
+++ b/arch/ia64/kernel/fsyscall_gtod_data.h
@@ -14,10 +14,10 @@
u32 clk_shift;
void *clk_fsys_mmio;
cycle_t clk_cycle_last;
-} __attribute__ ((aligned (L1_CACHE_BYTES)));
+} ____cacheline_aligned;
struct itc_jitter_data_t {
int itc_jitter;
cycle_t itc_lastcycle;
-} __attribute__ ((aligned (L1_CACHE_BYTES)));
+} ____cacheline_aligned;
diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
index c3b4412..8e7193d 100644
--- a/arch/ia64/kernel/ia64_ksyms.c
+++ b/arch/ia64/kernel/ia64_ksyms.c
@@ -12,6 +12,9 @@
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(strlen);
+#include<asm/pgtable.h>
+EXPORT_SYMBOL_GPL(empty_zero_page);
+
#include <asm/checksum.h>
EXPORT_SYMBOL(ip_fast_csum); /* hand-coded assembly */
EXPORT_SYMBOL(csum_ipv6_magic);
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index fc4d267..b618487 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -381,9 +381,10 @@
static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
{
unsigned int i;
- i = atomic_sub_return(1, &kcb->prev_kprobe_index);
- __get_cpu_var(current_kprobe) = kcb->prev_kprobe[i].kp;
- kcb->kprobe_status = kcb->prev_kprobe[i].status;
+ i = atomic_read(&kcb->prev_kprobe_index);
+ __get_cpu_var(current_kprobe) = kcb->prev_kprobe[i-1].kp;
+ kcb->kprobe_status = kcb->prev_kprobe[i-1].status;
+ atomic_sub(1, &kcb->prev_kprobe_index);
}
static void __kprobes set_current_kprobe(struct kprobe *p,
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 6dbf591..846e7e0 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -2,61 +2,69 @@
* File: mca.c
* Purpose: Generic MCA handling layer
*
- * Updated for latest kernel
* Copyright (C) 2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* Copyright (C) 2002 Dell Inc.
- * Copyright (C) Matt Domsch (Matt_Domsch@dell.com)
+ * Copyright (C) Matt Domsch <Matt_Domsch@dell.com>
*
* Copyright (C) 2002 Intel
- * Copyright (C) Jenna Hall (jenna.s.hall@intel.com)
+ * Copyright (C) Jenna Hall <jenna.s.hall@intel.com>
*
* Copyright (C) 2001 Intel
- * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com)
+ * Copyright (C) Fred Lewis <frederick.v.lewis@intel.com>
*
* Copyright (C) 2000 Intel
- * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
+ * Copyright (C) Chuck Fleckenstein <cfleck@co.intel.com>
*
* Copyright (C) 1999, 2004 Silicon Graphics, Inc.
- * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
+ * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
*
- * 03/04/15 D. Mosberger Added INIT backtrace support.
- * 02/03/25 M. Domsch GUID cleanups
+ * Copyright (C) 2006 FUJITSU LIMITED
+ * Copyright (C) Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
*
- * 02/01/04 J. Hall Aligned MCA stack to 16 bytes, added platform vs. CPU
- * error flag, set SAL default return values, changed
- * error record structure to linked list, added init call
- * to sal_get_state_info_size().
+ * 2000-03-29 Chuck Fleckenstein <cfleck@co.intel.com>
+ * Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
+ * added min save state dump, added INIT handler.
*
- * 01/01/03 F. Lewis Added setup of CMCI and CPEI IRQs, logging of corrected
- * platform errors, completed code for logging of
- * corrected & uncorrected machine check errors, and
- * updated for conformance with Nov. 2000 revision of the
- * SAL 3.0 spec.
- * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
- * added min save state dump, added INIT handler.
+ * 2001-01-03 Fred Lewis <frederick.v.lewis@intel.com>
+ * Added setup of CMCI and CPEI IRQs, logging of corrected platform
+ * errors, completed code for logging of corrected & uncorrected
+ * machine check errors, and updated for conformance with Nov. 2000
+ * revision of the SAL 3.0 spec.
+ *
+ * 2002-01-04 Jenna Hall <jenna.s.hall@intel.com>
+ * Aligned MCA stack to 16 bytes, added platform vs. CPU error flag,
+ * set SAL default return values, changed error record structure to
+ * linked list, added init call to sal_get_state_info_size().
+ *
+ * 2002-03-25 Matt Domsch <Matt_Domsch@dell.com>
+ * GUID cleanups.
+ *
+ * 2003-04-15 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Added INIT backtrace support.
*
* 2003-12-08 Keith Owens <kaos@sgi.com>
- * smp_call_function() must not be called from interrupt context (can
- * deadlock on tasklist_lock). Use keventd to call smp_call_function().
+ * smp_call_function() must not be called from interrupt context
+ * (can deadlock on tasklist_lock).
+ * Use keventd to call smp_call_function().
*
* 2004-02-01 Keith Owens <kaos@sgi.com>
- * Avoid deadlock when using printk() for MCA and INIT records.
- * Delete all record printing code, moved to salinfo_decode in user space.
- * Mark variables and functions static where possible.
- * Delete dead variables and functions.
- * Reorder to remove the need for forward declarations and to consolidate
- * related code.
+ * Avoid deadlock when using printk() for MCA and INIT records.
+ * Delete all record printing code, moved to salinfo_decode in user
+ * space. Mark variables and functions static where possible.
+ * Delete dead variables and functions. Reorder to remove the need
+ * for forward declarations and to consolidate related code.
*
* 2005-08-12 Keith Owens <kaos@sgi.com>
- * Convert MCA/INIT handlers to use per event stacks and SAL/OS state.
+ * Convert MCA/INIT handlers to use per event stacks and SAL/OS
+ * state.
*
* 2005-10-07 Keith Owens <kaos@sgi.com>
* Add notify_die() hooks.
*
* 2006-09-15 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
- * Add printing support for MCA/INIT.
+ * Add printing support for MCA/INIT.
*
* 2007-04-27 Russ Anderson <rja@sgi.com>
* Support multiple cpus going through OS_MCA in the same event.
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 0f5965f..8bc7d25 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -1,24 +1,28 @@
-//
-// assembly portion of the IA64 MCA handling
-//
-// Mods by cfleck to integrate into kernel build
-// 00/03/15 davidm Added various stop bits to get a clean compile
-//
-// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp
-// kstack, switch modes, jump to C INIT handler
-//
-// 02/01/04 J.Hall <jenna.s.hall@intel.com>
-// Before entering virtual mode code:
-// 1. Check for TLB CPU error
-// 2. Restore current thread pointer to kr6
-// 3. Move stack ptr 16 bytes to conform to C calling convention
-//
-// 04/11/12 Russ Anderson <rja@sgi.com>
-// Added per cpu MCA/INIT stack save areas.
-//
-// 12/08/05 Keith Owens <kaos@sgi.com>
-// Use per cpu MCA/INIT stacks for all data.
-//
+/*
+ * File: mca_asm.S
+ * Purpose: assembly portion of the IA64 MCA handling
+ *
+ * Mods by cfleck to integrate into kernel build
+ *
+ * 2000-03-15 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Added various stop bits to get a clean compile
+ *
+ * 2000-03-29 Chuck Fleckenstein <cfleck@co.intel.com>
+ * Added code to save INIT handoff state in pt_regs format,
+ * switch to temp kstack, switch modes, jump to C INIT handler
+ *
+ * 2002-01-04 J.Hall <jenna.s.hall@intel.com>
+ * Before entering virtual mode code:
+ * 1. Check for TLB CPU error
+ * 2. Restore current thread pointer to kr6
+ * 3. Move stack ptr 16 bytes to conform to C calling convention
+ *
+ * 2004-11-12 Russ Anderson <rja@sgi.com>
+ * Added per cpu MCA/INIT stack save areas.
+ *
+ * 2005-12-08 Keith Owens <kaos@sgi.com>
+ * Use per cpu MCA/INIT stacks for all data.
+ */
#include <linux/threads.h>
#include <asm/asmmacro.h>
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index aba813c2..fab1d21 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -3,7 +3,7 @@
* Purpose: Generic MCA handling layer
*
* Copyright (C) 2004 FUJITSU LIMITED
- * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
* Copyright (C) 2005 Silicon Graphics, Inc
* Copyright (C) 2005 Keith Owens <kaos@sgi.com>
* Copyright (C) 2006 Russ Anderson <rja@sgi.com>
diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h
index 485e34d..53b8ecb 100644
--- a/arch/ia64/kernel/mca_drv.h
+++ b/arch/ia64/kernel/mca_drv.h
@@ -3,7 +3,7 @@
* Purpose: Define helpers for Generic MCA handling
*
* Copyright (C) 2004 FUJITSU LIMITED
- * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
*/
/*
* Processor error section:
diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S
index 3bccb06..767ac2c 100644
--- a/arch/ia64/kernel/mca_drv_asm.S
+++ b/arch/ia64/kernel/mca_drv_asm.S
@@ -3,7 +3,7 @@
* Purpose: Assembly portion of Generic MCA handling
*
* Copyright (C) 2004 FUJITSU LIMITED
- * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
*/
#include <linux/threads.h>
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 5ae177f..78acd9f 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2654,11 +2654,11 @@
/* XXX: need to add more checks here */
if (pid < 2) return -EPERM;
- if (pid != current->pid) {
+ if (pid != task_pid_vnr(current)) {
read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
+ p = find_task_by_vpid(pid);
/* make sure task cannot go away while we operate on it */
if (p) get_task_struct(p);
@@ -5795,7 +5795,7 @@
return 0;
}
-struct seq_operations pfm_seq_ops = {
+const struct seq_operations pfm_seq_ops = {
.start = pfm_proc_start,
.next = pfm_proc_next,
.stop = pfm_proc_stop,
diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c
index 27c2ef4..f44fe84 100644
--- a/arch/ia64/kernel/sal.c
+++ b/arch/ia64/kernel/sal.c
@@ -284,6 +284,7 @@
SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0);
return isrv.status;
}
+EXPORT_SYMBOL_GPL(ia64_sal_cache_flush);
void __init
ia64_sal_init (struct ia64_sal_systab *systab)
@@ -372,3 +373,16 @@
return 0;
}
EXPORT_SYMBOL(ia64_sal_oemcall_reentrant);
+
+long
+ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
+ unsigned long *drift_info)
+{
+ struct ia64_sal_retval isrv;
+
+ SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0);
+ *ticks_per_second = isrv.v0;
+ *drift_info = isrv.v1;
+ return isrv.status;
+}
+EXPORT_SYMBOL_GPL(ia64_sal_freq_base);
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 86028c6..ebd1a09f 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -654,7 +654,7 @@
{
}
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index f0fc4d8..32ee597 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -120,7 +120,6 @@
#define DEBUG_ITC_SYNC 0
-extern void __devinit calibrate_delay (void);
extern void start_ap (void);
extern unsigned long ia64_iobase;
@@ -477,7 +476,7 @@
return 0;
}
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
{
return NULL;
}
@@ -767,17 +766,6 @@
}
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
}
-#else /* !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
-{
- return -ENOSYS;
-}
-
-void __cpu_die(unsigned int cpu)
-{
- /* We said "no" in __cpu_disable */
- BUG();
-}
#endif /* CONFIG_HOTPLUG_CPU */
void
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 78d65cb..f0cda76 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -35,7 +35,7 @@
fpswa_interface = __va(ia64_boot_param->fpswa);
}
-void
+int
die (const char *str, struct pt_regs *regs, long err)
{
static struct {
@@ -62,8 +62,11 @@
if (++die.lock_owner_depth < 3) {
printk("%s[%d]: %s %ld [%d]\n",
current->comm, task_pid_nr(current), str, err, ++die_counter);
- (void) notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
- show_regs(regs);
+ if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV)
+ != NOTIFY_STOP)
+ show_regs(regs);
+ else
+ regs = NULL;
} else
printk(KERN_ERR "Recursive die() failure, output suppressed\n");
@@ -72,17 +75,22 @@
add_taint(TAINT_DIE);
spin_unlock_irq(&die.lock);
+ if (!regs)
+ return 1;
+
if (panic_on_oops)
panic("Fatal exception");
do_exit(SIGSEGV);
+ return 0;
}
-void
+int
die_if_kernel (char *str, struct pt_regs *regs, long err)
{
if (!user_mode(regs))
- die(str, regs, err);
+ return die(str, regs, err);
+ return 0;
}
void
@@ -102,7 +110,8 @@
if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
== NOTIFY_STOP)
return;
- die_if_kernel("bugcheck!", regs, break_num);
+ if (die_if_kernel("bugcheck!", regs, break_num))
+ return;
sig = SIGILL; code = ILL_ILLOPC;
break;
@@ -155,8 +164,9 @@
break;
default:
- if (break_num < 0x40000 || break_num > 0x100000)
- die_if_kernel("Bad break", regs, break_num);
+ if ((break_num < 0x40000 || break_num > 0x100000)
+ && die_if_kernel("Bad break", regs, break_num))
+ return;
if (break_num < 0x80000) {
sig = SIGILL; code = __ILL_BREAK;
@@ -402,14 +412,15 @@
#endif
sprintf(buf, "IA-64 Illegal operation fault");
- die_if_kernel(buf, ®s, 0);
+ rv.fkt = 0;
+ if (die_if_kernel(buf, ®s, 0))
+ return rv;
memset(&si, 0, sizeof(si));
si.si_signo = SIGILL;
si.si_code = ILL_ILLOPC;
si.si_addr = (void __user *) (regs.cr_iip + ia64_psr(®s)->ri);
force_sig_info(SIGILL, &si, current);
- rv.fkt = 0;
return rv;
}
@@ -644,6 +655,6 @@
sprintf(buf, "Fault %lu", vector);
break;
}
- die_if_kernel(buf, ®s, error);
- force_sig(SIGILL, current);
+ if (!die_if_kernel(buf, ®s, error))
+ force_sig(SIGILL, current);
}
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index f6a1aeb..52f70bb 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -23,7 +23,7 @@
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-extern void die_if_kernel(char *str, struct pt_regs *regs, long err);
+extern int die_if_kernel(char *str, struct pt_regs *regs, long err);
#undef DEBUG_UNALIGNED_TRAP
@@ -675,8 +675,9 @@
*/
if (ld.x6_op == 1 || ld.x6_op == 3) {
printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
- die_if_kernel("unaligned reference on speculative load with register update\n",
- regs, 30);
+ if (die_if_kernel("unaligned reference on speculative load with register update\n",
+ regs, 30))
+ return;
}
@@ -1317,7 +1318,8 @@
if (ia64_psr(regs)->be) {
/* we don't support big-endian accesses */
- die_if_kernel("big-endian unaligned accesses are not supported", regs, 0);
+ if (die_if_kernel("big-endian unaligned accesses are not supported", regs, 0))
+ return;
goto force_sigbus;
}
@@ -1534,7 +1536,8 @@
ia64_handle_exception(regs, eh);
goto done;
}
- die_if_kernel("error during unaligned kernel access\n", regs, ret);
+ if (die_if_kernel("error during unaligned kernel access\n", regs, ret))
+ return;
/* NOT_REACHED */
}
force_sigbus:
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 7571076..3e698816 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -16,7 +16,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-extern void die (char *, struct pt_regs *, long);
+extern int die(char *, struct pt_regs *, long);
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs, int trap)
@@ -267,9 +267,11 @@
else
printk(KERN_ALERT "Unable to handle kernel paging request at "
"virtual address %016lx\n", address);
- die("Oops", regs, isr);
+ if (die("Oops", regs, isr))
+ regs = NULL;
bust_spinlocks(0);
- do_exit(SIGKILL);
+ if (regs)
+ do_exit(SIGKILL);
return;
out_of_memory:
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index f3c6932..dfc6bf1 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -523,7 +523,7 @@
return count;
}
-static struct seq_operations sn2_ptc_seq_ops = {
+static const struct seq_operations sn2_ptc_seq_ops = {
.start = sn2_ptc_seq_start,
.next = sn2_ptc_seq_next,
.stop = sn2_ptc_seq_stop,
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 1a8e496..4b0d153 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -33,6 +33,7 @@
#include <linux/smp_lock.h>
#include <linux/nodemask.h>
#include <linux/smp.h>
+#include <linux/mutex.h>
#include <asm/processor.h>
#include <asm/topology.h>
@@ -50,7 +51,7 @@
static int sn_hwperf_obj_cnt = 0;
static nasid_t sn_hwperf_master_nasid = INVALID_NASID;
static int sn_hwperf_init(void);
-static DECLARE_MUTEX(sn_hwperf_init_mutex);
+static DEFINE_MUTEX(sn_hwperf_init_mutex);
#define cnode_possible(n) ((n) < num_cnodes)
@@ -577,7 +578,7 @@
/*
* /proc/sgi_sn/sn_topology, read-only using seq_file
*/
-static struct seq_operations sn_topology_seq_ops = {
+static const struct seq_operations sn_topology_seq_ops = {
.start = sn_topology_start,
.next = sn_topology_next,
.stop = sn_topology_stop,
@@ -884,10 +885,10 @@
int e = 0;
/* single threaded, once-only initialization */
- down(&sn_hwperf_init_mutex);
+ mutex_lock(&sn_hwperf_init_mutex);
if (sn_hwperf_salheap) {
- up(&sn_hwperf_init_mutex);
+ mutex_unlock(&sn_hwperf_init_mutex);
return e;
}
@@ -936,7 +937,7 @@
sn_hwperf_salheap = NULL;
sn_hwperf_obj_cnt = 0;
}
- up(&sn_hwperf_init_mutex);
+ mutex_unlock(&sn_hwperf_init_mutex);
return e;
}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index ab3eaf8..2c676cc 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -100,11 +100,11 @@
static irqreturn_t
pcibr_error_intr_handler(int irq, void *arg)
{
- struct pcibus_info *soft = (struct pcibus_info *)arg;
+ struct pcibus_info *soft = arg;
- if (sal_pcibr_error_interrupt(soft) < 0) {
+ if (sal_pcibr_error_interrupt(soft) < 0)
panic("pcibr_error_intr_handler(): Fatal Bridge Error");
- }
+
return IRQ_HANDLED;
}
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index f7237c5..795180b 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -8,6 +8,7 @@
config M32R
bool
default y
+ select HAVE_OPROFILE
config SBUS
bool
@@ -302,8 +303,7 @@
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
- See also the <file:Documentation/smp.txt>,
- and the SMP-HOWTO available at
+ See also the SMP-HOWTO available at
<http://www.linuxdoc.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -359,11 +359,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.linuxdoc.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
choice
prompt "PCI access mode"
depends on PCI
@@ -431,8 +426,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/m32r/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c
index ee3c8be..01d877c 100644
--- a/arch/m32r/boot/compressed/m32r_sio.c
+++ b/arch/m32r/boot/compressed/m32r_sio.c
@@ -17,7 +17,7 @@
return 0;
}
-#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
#include <asm/m32r.h>
#include <asm/io.h>
@@ -52,7 +52,7 @@
}
*BOOT_SIO0TXB = c;
}
-#else /* !(CONFIG_PLAT_M32700UT_Alpha) && !(CONFIG_PLAT_M32700UT) */
+#else /* !(CONFIG_PLAT_M32700UT) */
#if defined(CONFIG_PLAT_MAPPI2)
#define SIO0STS (volatile unsigned short *)(0xa0efd000 + 14)
#define SIO0TXB (volatile unsigned short *)(0xa0efd000 + 30)
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
index ed4d075..9aa615d 100644
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -476,7 +476,7 @@
return 0;
}
- /* Recover orignal instruction code. */
+ /* Recover original instruction code. */
*code = p->insn[i];
/* Shift debug trap entries. */
diff --git a/arch/m32r/kernel/syscall_table.S b/arch/m32r/kernel/syscall_table.S
index 95aa798..aa3bf4c 100644
--- a/arch/m32r/kernel/syscall_table.S
+++ b/arch/m32r/kernel/syscall_table.S
@@ -321,6 +321,6 @@
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
.long sys_signalfd
- .long sys_timerfd
+ .long sys_ni_syscall
.long sys_eventfd
.long sys_fallocate
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 01dee84..ffabd01 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -145,11 +145,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config MAC
bool "Macintosh support"
depends on !MMU_SUN3
@@ -582,20 +577,6 @@
depends on INPUT_ADBHID
default y
-config MAC_ADBKEYCODES
- bool "Support for ADB raw keycodes"
- depends on INPUT_ADBHID
- help
- This provides support for sending raw ADB keycodes to console
- devices. This is the default up to 2.4.0, but in future this may be
- phased out in favor of generic Linux keycodes. If you say Y here,
- you can dynamically switch via the
- /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
- sysctl and with the "keyboard_sends_linux_keycodes=" kernel
- argument.
-
- If unsure, say Y here.
-
config ADB_KEYBOARD
bool "Support for ADB keyboard (old driver)"
depends on MAC && !INPUT_ADBHID
@@ -683,8 +664,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/m68k/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 4a1bd44..2cba605 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -13,16 +13,15 @@
# Copyright (C) 1994 by Hamish Macdonald
#
-# test for cross compiling
-COMPILE_ARCH = $(shell uname -m)
-
# override top level makefile
AS += -m68020
LDFLAGS := -m m68kelf
LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
-ifneq ($(COMPILE_ARCH),$(ARCH))
- # prefix for cross-compiling binaries
- CROSS_COMPILE = m68k-linux-gnu-
+ifneq ($(SUBARCH),$(ARCH))
+ ifeq ($(CROSS_COMPILE),)
+ CROSS_COMPILE := $(call cc-cross-prefix, \
+ m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
+ endif
endif
ifdef CONFIG_SUN3
diff --git a/arch/m68k/amiga/Makefile b/arch/m68k/amiga/Makefile
index 8b41565..6a0d765 100644
--- a/arch/m68k/amiga/Makefile
+++ b/arch/m68k/amiga/Makefile
@@ -2,6 +2,6 @@
# Makefile for Linux arch/m68k/amiga source directory
#
-obj-y := config.o amiints.o cia.o chipram.o amisound.o amiga_ksyms.o
+obj-y := config.o amiints.o cia.o chipram.o amisound.o
obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o
diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c
deleted file mode 100644
index 7fdcf6b..0000000
--- a/arch/m68k/amiga/amiga_ksyms.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/ptrace.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amipcmcia.h>
-
-extern volatile u_short amiga_audio_min_period;
-extern u_short amiga_audio_period;
-
-/*
- * Add things here when you find the need for it.
- */
-EXPORT_SYMBOL(amiga_model);
-EXPORT_SYMBOL(amiga_chipset);
-EXPORT_SYMBOL(amiga_hw_present);
-EXPORT_SYMBOL(amiga_eclock);
-EXPORT_SYMBOL(amiga_colorclock);
-EXPORT_SYMBOL(amiga_chip_alloc);
-EXPORT_SYMBOL(amiga_chip_free);
-EXPORT_SYMBOL(amiga_chip_avail);
-EXPORT_SYMBOL(amiga_chip_size);
-EXPORT_SYMBOL(amiga_audio_period);
-EXPORT_SYMBOL(amiga_audio_min_period);
-
-#ifdef CONFIG_AMIGA_PCMCIA
- EXPORT_SYMBOL(pcmcia_reset);
- EXPORT_SYMBOL(pcmcia_copy_tuple);
- EXPORT_SYMBOL(pcmcia_program_voltage);
- EXPORT_SYMBOL(pcmcia_access_speed);
- EXPORT_SYMBOL(pcmcia_write_enable);
- EXPORT_SYMBOL(pcmcia_write_disable);
-#endif
diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c
index 1f5bfb5..61e5c54 100644
--- a/arch/m68k/amiga/amisound.c
+++ b/arch/m68k/amiga/amisound.c
@@ -12,6 +12,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/amigahw.h>
@@ -21,7 +22,7 @@
0, 39, 75, 103, 121, 127, 121, 103, 75, 39,
0, -39, -75, -103, -121, -127, -121, -103, -75, -39
};
-#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0]))
+#define DATA_SIZE ARRAY_SIZE(sine_data)
#define custom amiga_custom
@@ -31,6 +32,7 @@
*/
volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */
+EXPORT_SYMBOL(amiga_audio_min_period);
#define MAX_PERIOD (65535)
@@ -40,6 +42,7 @@
*/
unsigned short amiga_audio_period = MAX_PERIOD;
+EXPORT_SYMBOL(amiga_audio_period);
static unsigned long clock_constant;
diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c
index fa015d8..cbe3653 100644
--- a/arch/m68k/amiga/chipram.c
+++ b/arch/m68k/amiga/chipram.c
@@ -13,10 +13,13 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/module.h>
+
#include <asm/page.h>
#include <asm/amigahw.h>
unsigned long amiga_chip_size;
+EXPORT_SYMBOL(amiga_chip_size);
static struct resource chipram_res = {
.name = "Chip RAM", .start = CHIP_PHYSADDR
@@ -29,12 +32,10 @@
if (!AMIGAHW_PRESENT(CHIP_RAM))
return;
-#ifndef CONFIG_APUS_FAST_EXCEPT
/*
* Remove the first 4 pages where PPC exception handlers will be located
*/
amiga_chip_size -= 0x4000;
-#endif
chipram_res.end = amiga_chip_size-1;
request_resource(&iomem_resource, &chipram_res);
@@ -67,6 +68,7 @@
#endif
return (void *)ZTWO_VADDR(res->start);
}
+EXPORT_SYMBOL(amiga_chip_alloc);
/*
@@ -120,6 +122,7 @@
}
printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr);
}
+EXPORT_SYMBOL(amiga_chip_free);
unsigned long amiga_chip_avail(void)
@@ -129,3 +132,5 @@
#endif
return chipavail;
}
+EXPORT_SYMBOL(amiga_chip_avail);
+
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index c4a4ffd..343fab4 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -84,7 +84,7 @@
static irqreturn_t cia_handler(int irq, void *dev_id)
{
- struct ciabase *base = (struct ciabase *)dev_id;
+ struct ciabase *base = dev_id;
int mach_irq;
unsigned char ints;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 3574853..50f5daa 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/zorro.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -36,13 +37,24 @@
#include <asm/io.h>
unsigned long amiga_model;
+EXPORT_SYMBOL(amiga_model);
+
unsigned long amiga_eclock;
+EXPORT_SYMBOL(amiga_eclock);
+
unsigned long amiga_masterclock;
+
unsigned long amiga_colorclock;
+EXPORT_SYMBOL(amiga_colorclock);
+
unsigned long amiga_chipset;
+EXPORT_SYMBOL(amiga_chipset);
+
unsigned char amiga_vblank;
unsigned char amiga_psfreq;
+
struct amiga_hw_present amiga_hw_present;
+EXPORT_SYMBOL(amiga_hw_present);
static char s_a500[] __initdata = "A500";
static char s_a500p[] __initdata = "A500+";
diff --git a/arch/m68k/amiga/pcmcia.c b/arch/m68k/amiga/pcmcia.c
index 186662c..7106f0c 100644
--- a/arch/m68k/amiga/pcmcia.c
+++ b/arch/m68k/amiga/pcmcia.c
@@ -15,6 +15,8 @@
#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
+#include <linux/module.h>
+
#include <asm/amigayle.h>
#include <asm/amipcmcia.h>
@@ -30,6 +32,7 @@
while (time_before(jiffies, reset_start_time + 1*HZ/100));
b = gayle_reset;
}
+EXPORT_SYMBOL(pcmcia_reset);
/* copy a tuple, including tuple header. return nb bytes copied */
@@ -61,6 +64,7 @@
return 0;
}
+EXPORT_SYMBOL(pcmcia_copy_tuple);
void pcmcia_program_voltage(int voltage)
{
@@ -84,6 +88,7 @@
gayle.config = cfg_byte;
}
+EXPORT_SYMBOL(pcmcia_program_voltage);
void pcmcia_access_speed(int speed)
{
@@ -101,13 +106,17 @@
cfg_byte = (cfg_byte & 0xf3) | s;
gayle.config = cfg_byte;
}
+EXPORT_SYMBOL(pcmcia_access_speed);
void pcmcia_write_enable(void)
{
gayle.cardstatus = GAYLE_CS_WR|GAYLE_CS_DA;
}
+EXPORT_SYMBOL(pcmcia_write_enable);
void pcmcia_write_disable(void)
{
gayle.cardstatus = 0;
}
+EXPORT_SYMBOL(pcmcia_write_disable);
+
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
index 2cb8619..2cd905e 100644
--- a/arch/m68k/atari/Makefile
+++ b/arch/m68k/atari/Makefile
@@ -3,7 +3,7 @@
#
obj-y := config.o time.o debug.o ataints.o stdma.o \
- atasound.o stram.o atari_ksyms.o
+ atasound.o stram.o
ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_HADES) += hades-pci.o
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index b85ca22..b45593a 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -40,6 +40,7 @@
#include <linux/kernel_stat.h>
#include <linux/init.h>
#include <linux/seq_file.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/traps.h>
@@ -446,6 +447,7 @@
free_vme_vec_bitmap |= 1 << i;
return VME_SOURCE_BASE + i;
}
+EXPORT_SYMBOL(atari_register_vme_int);
void atari_unregister_vme_int(unsigned long irq)
@@ -455,5 +457,6 @@
free_vme_vec_bitmap &= ~(1 << irq);
}
}
+EXPORT_SYMBOL(atari_unregister_vme_int);
diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c
deleted file mode 100644
index a047571..0000000
--- a/arch/m68k/atari/atari_ksyms.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <linux/module.h>
-
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atarikb.h>
-#include <asm/atari_joystick.h>
-#include <asm/atari_stdma.h>
-#include <asm/atari_stram.h>
-
-extern void atari_microwire_cmd( int cmd );
-extern int atari_MFP_init_done;
-extern int atari_SCC_init_done;
-extern int atari_SCC_reset_done;
-
-EXPORT_SYMBOL(atari_mch_cookie);
-EXPORT_SYMBOL(atari_mch_type);
-EXPORT_SYMBOL(atari_hw_present);
-EXPORT_SYMBOL(atari_switches);
-EXPORT_SYMBOL(atari_dont_touch_floppy_select);
-EXPORT_SYMBOL(atari_register_vme_int);
-EXPORT_SYMBOL(atari_unregister_vme_int);
-EXPORT_SYMBOL(stdma_lock);
-EXPORT_SYMBOL(stdma_release);
-EXPORT_SYMBOL(stdma_others_waiting);
-EXPORT_SYMBOL(stdma_islocked);
-EXPORT_SYMBOL(atari_stram_alloc);
-EXPORT_SYMBOL(atari_stram_free);
-
-EXPORT_SYMBOL(atari_MFP_init_done);
-EXPORT_SYMBOL(atari_SCC_init_done);
-EXPORT_SYMBOL(atari_SCC_reset_done);
-
-EXPORT_SYMBOL(atari_microwire_cmd);
diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c
index ee04250..d266fe8 100644
--- a/arch/m68k/atari/atasound.c
+++ b/arch/m68k/atari/atasound.c
@@ -22,6 +22,7 @@
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <asm/atarihw.h>
#include <asm/system.h>
@@ -43,6 +44,7 @@
while( tt_microwire.mask != 0x7ff)
;
}
+EXPORT_SYMBOL(atari_microwire_cmd);
/* PSG base frequency */
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index e40e5dc..5945e15 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/vt_kern.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -43,10 +44,20 @@
#include <asm/io.h>
u_long atari_mch_cookie;
+EXPORT_SYMBOL(atari_mch_cookie);
+
u_long atari_mch_type;
+EXPORT_SYMBOL(atari_mch_type);
+
struct atari_hw_present atari_hw_present;
+EXPORT_SYMBOL(atari_hw_present);
+
u_long atari_switches;
+EXPORT_SYMBOL(atari_switches);
+
int atari_dont_touch_floppy_select;
+EXPORT_SYMBOL(atari_dont_touch_floppy_select);
+
int atari_rtc_year_offset;
/* local function prototypes */
diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c
index fbeed8c..043ddbc 100644
--- a/arch/m68k/atari/debug.c
+++ b/arch/m68k/atari/debug.c
@@ -15,17 +15,23 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <asm/atarihw.h>
#include <asm/atariints.h>
/* Flag that Modem1 port is already initialized and used */
int atari_MFP_init_done;
+EXPORT_SYMBOL(atari_MFP_init_done);
+
/* Flag that Modem1 port is already initialized and used */
int atari_SCC_init_done;
+EXPORT_SYMBOL(atari_SCC_init_done);
+
/* Can be set somewhere, if a SCC master reset has already be done and should
* not be repeated; used by kgdb */
int atari_SCC_reset_done;
+EXPORT_SYMBOL(atari_SCC_reset_done);
static struct console atari_console_driver = {
.name = "debug",
diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c
index bee2b14..2bbabc0 100644
--- a/arch/m68k/atari/hades-pci.c
+++ b/arch/m68k/atari/hades-pci.c
@@ -376,8 +376,8 @@
*/
bus = kzalloc(sizeof(struct pci_bus_info), GFP_KERNEL);
- if (!bus)
- return NULL;
+ if (unlikely(!bus))
+ goto iounmap_base_virt;
/*
* Claim resources. The m68k has no separate I/O space, both
@@ -385,43 +385,25 @@
* the I/O resources are requested in memory space as well.
*/
- if (request_resource(&iomem_resource, &config_space) != 0)
- {
- kfree(bus);
- return NULL;
- }
+ if (unlikely(request_resource(&iomem_resource, &config_space) != 0))
+ goto free_bus;
- if (request_resource(&iomem_resource, &io_space) != 0)
- {
- release_resource(&config_space);
- kfree(bus);
- return NULL;
- }
+ if (unlikely(request_resource(&iomem_resource, &io_space) != 0))
+ goto release_config_space;
bus->mem_space.start = HADES_MEM_BASE;
bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1;
bus->mem_space.name = pci_mem_name;
#if 1
- if (request_resource(&iomem_resource, &bus->mem_space) != 0)
- {
- release_resource(&io_space);
- release_resource(&config_space);
- kfree(bus);
- return NULL;
- }
+ if (unlikely(request_resource(&iomem_resource, &bus->mem_space) != 0))
+ goto release_io_space;
#endif
bus->io_space.start = pci_io_base_virt;
bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1;
bus->io_space.name = pci_io_name;
#if 1
- if (request_resource(&ioport_resource, &bus->io_space) != 0)
- {
- release_resource(&bus->mem_space);
- release_resource(&io_space);
- release_resource(&config_space);
- kfree(bus);
- return NULL;
- }
+ if (unlikely(request_resource(&ioport_resource, &bus->io_space) != 0))
+ goto release_bus_mem_space;
#endif
/*
* Set hardware dependent functions.
@@ -438,5 +420,21 @@
tt_mfp.active_edge &= ~0x27;
return bus;
+
+release_bus_mem_space:
+ release_resource(&bus->mem_space);
+release_io_space:
+ release_resource(&io_space);
+release_config_space:
+ release_resource(&config_space);
+free_bus:
+ kfree(bus);
+iounmap_base_virt:
+ iounmap((void *)pci_io_base_virt);
+
+ for (i = 0; i < N_SLOTS; i++)
+ iounmap((void *)pci_conf_base_virt[i]);
+
+ return NULL;
}
#endif
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index ab3fd52..d1bd029 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
+#include <linux/module.h>
#include <asm/atari_stdma.h>
#include <asm/atariints.h>
@@ -91,6 +92,7 @@
stdma_isr_data = data;
local_irq_restore(flags);
}
+EXPORT_SYMBOL(stdma_lock);
/*
@@ -117,6 +119,7 @@
local_irq_restore(flags);
}
+EXPORT_SYMBOL(stdma_release);
/*
@@ -134,6 +137,7 @@
{
return waitqueue_active(&stdma_wait);
}
+EXPORT_SYMBOL(stdma_others_waiting);
/*
@@ -155,6 +159,7 @@
{
return stdma_locked;
}
+EXPORT_SYMBOL(stdma_islocked);
/*
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index bf4588c..8dda651 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -20,6 +20,7 @@
#include <linux/bootmem.h>
#include <linux/mount.h>
#include <linux/blkdev.h>
+#include <linux/module.h>
#include <asm/setup.h>
#include <asm/machdep.h>
@@ -208,6 +209,7 @@
}
return( addr );
}
+EXPORT_SYMBOL(atari_stram_alloc);
void atari_stram_free( void *addr )
@@ -237,6 +239,7 @@
printk( KERN_ERR "atari_stram_free: cannot free block at %p "
"(called from %p)\n", addr, __builtin_return_address(0) );
}
+EXPORT_SYMBOL(atari_stram_free);
/* ------------------------------------------------------------------------ */
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 15b80ab..ff9dffa 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -678,7 +678,6 @@
#
CONFIG_MAC_SCC=y
CONFIG_MAC_HID=y
-CONFIG_MAC_ADBKEYCODES=y
CONFIG_SERIAL_CONSOLE=y
#
diff --git a/arch/m68k/hp300/Makefile b/arch/m68k/hp300/Makefile
index 288b9c6..96d4244 100644
--- a/arch/m68k/hp300/Makefile
+++ b/arch/m68k/hp300/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/hp300 source directory
#
-obj-y := ksyms.o config.o time.o reboot.o
+obj-y := config.o time.o reboot.o
diff --git a/arch/m68k/hp300/ksyms.c b/arch/m68k/hp300/ksyms.c
deleted file mode 100644
index 8202830..0000000
--- a/arch/m68k/hp300/ksyms.c
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * linux/arch/m68k/hp300/ksyms.c
- *
- * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- *
- * This file contains the HP300-specific kernel symbols. None yet. :-)
- */
-
-#include <linux/module.h>
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 918f5db..6dfa3b3 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -742,7 +742,7 @@
.long sys_epoll_pwait /* 315 */
.long sys_utimensat
.long sys_signalfd
- .long sys_timerfd
+ .long sys_ni_syscall
.long sys_eventfd
.long sys_fallocate /* 320 */
diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile
index 995a09d9..1d265ba 100644
--- a/arch/m68k/mac/Makefile
+++ b/arch/m68k/mac/Makefile
@@ -3,4 +3,4 @@
#
obj-y := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
- baboon.o macboing.o debug.o misc.o mac_ksyms.o
+ baboon.o macboing.o debug.o misc.o
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 01b468b..735a49b 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -58,8 +58,6 @@
extern struct mem_info m68k_ramdisk;
-extern char m68k_command_line[CL_SIZE];
-
void *mac_env; /* Loaded by the boot asm */
/* The phys. video addr. - might be bogus on some machines */
diff --git a/arch/m68k/mac/mac_ksyms.c b/arch/m68k/mac/mac_ksyms.c
deleted file mode 100644
index 6e37ceb..0000000
--- a/arch/m68k/mac/mac_ksyms.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-
-/* Says whether we're using A/UX interrupts or not */
-extern int via_alt_mapping;
-
-EXPORT_SYMBOL(via_alt_mapping);
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index 8df270e..fa485df 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ide.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/macintosh.h>
@@ -41,7 +42,9 @@
/* See note in mac_via.h about how this is possibly not useful */
volatile long *via_memory_bogon=(long *)&via_memory_bogon;
#endif
-int rbv_present, via_alt_mapping;
+int rbv_present;
+int via_alt_mapping;
+EXPORT_SYMBOL(via_alt_mapping);
__u8 rbv_clear;
/*
diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile
index 950e82f..edb3f6e 100644
--- a/arch/m68k/mvme16x/Makefile
+++ b/arch/m68k/mvme16x/Makefile
@@ -2,4 +2,4 @@
# Makefile for Linux arch/m68k/mvme16x source directory
#
-obj-y := config.o rtc.o mvme16x_ksyms.o
+obj-y := config.o rtc.o
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index daa7851..24cbc30 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -25,6 +25,7 @@
#include <linux/genhd.h>
#include <linux/rtc.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -58,6 +59,7 @@
unsigned short mvme16x_config;
+EXPORT_SYMBOL(mvme16x_config);
int mvme16x_parse_bootinfo(const struct bi_record *bi)
diff --git a/arch/m68k/mvme16x/mvme16x_ksyms.c b/arch/m68k/mvme16x/mvme16x_ksyms.c
deleted file mode 100644
index 4a8a363..0000000
--- a/arch/m68k/mvme16x/mvme16x_ksyms.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/ptrace.h>
-#include <asm/mvme16xhw.h>
-
-EXPORT_SYMBOL(mvme16x_config);
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index bd92137..6abbbb8 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -711,8 +711,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/m68knommu/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug
index 9ff47bd..ed6d9a83 100644
--- a/arch/m68knommu/Kconfig.debug
+++ b/arch/m68knommu/Kconfig.debug
@@ -21,13 +21,6 @@
default 'console=ttyS0,19200'
depends on BOOTPARAM
-config DUMPTOFLASH
- bool "Panic/Dump to FLASH"
- depends on COLDFIRE
- help
- Dump any panic of trap output into a flash memory segment
- for later analysis.
-
config NO_KERNEL_MSG
bool "Suppress Kernel BUG Messages"
help
diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig
index 5a0ecaa..6481130 100644
--- a/arch/m68knommu/defconfig
+++ b/arch/m68knommu/defconfig
@@ -597,7 +597,6 @@
# CONFIG_FULLDEBUG is not set
# CONFIG_HIGHPROFILE is not set
# CONFIG_BOOTPARAM is not set
-# CONFIG_DUMPTOFLASH is not set
# CONFIG_NO_KERNEL_MSG is not set
# CONFIG_BDM_DISABLE is not set
diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c
index f795062..53fad14 100644
--- a/arch/m68knommu/kernel/m68k_ksyms.c
+++ b/arch/m68knommu/kernel/m68k_ksyms.c
@@ -24,14 +24,6 @@
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(ip_fast_csum);
@@ -46,9 +38,6 @@
it's OK to leave it out of version control. */
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(__down_failed);
EXPORT_SYMBOL(__down_failed_interruptible);
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 332345d..81507c5 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -64,9 +64,6 @@
#ifdef CONFIG_M68VZ328
#define CPU "MC68VZ328"
#endif
-#ifdef CONFIG_M68332
- #define CPU "MC68332"
-#endif
#ifdef CONFIG_M68360
#define CPU "MC68360"
#endif
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
index 9620093..1b02b88 100644
--- a/arch/m68knommu/kernel/syscalltable.S
+++ b/arch/m68knommu/kernel/syscalltable.S
@@ -336,7 +336,7 @@
.long sys_epoll_pwait /* 315 */
.long sys_utimensat
.long sys_signalfd
- .long sys_timerfd
+ .long sys_ni_syscall
.long sys_eventfd
.long sys_fallocate /* 320 */
diff --git a/arch/m68knommu/lib/memcpy.c b/arch/m68knommu/lib/memcpy.c
index 0d55775..b50dbca 100644
--- a/arch/m68knommu/lib/memcpy.c
+++ b/arch/m68knommu/lib/memcpy.c
@@ -1,6 +1,5 @@
#include <linux/types.h>
-#include <linux/autoconf.h>
void * memcpy(void * to, const void * from, size_t n)
{
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4fad0a3..ec78a57 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1,6 +1,7 @@
config MIPS
bool
default y
+ select HAVE_OPROFILE
# Horrible source of confusion. Die, die, die ...
select EMBEDDED
select RTC_LIB
@@ -1754,8 +1755,8 @@
People using multiprocessor machines who say Y here should also say
Y to "Enhanced Real Time Clock Support", below.
- See also the <file:Documentation/smp.txt> and the SMP-HOWTO
- available at <http://www.tldp.org/docs.html#howto>.
+ See also the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -1961,11 +1962,6 @@
your box. Other bus systems are ISA, EISA, or VESA. If you have PCI,
say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config PCI_DOMAINS
bool
@@ -2086,6 +2082,10 @@
menu "Power management options"
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
source "kernel/power/Kconfig"
endmenu
@@ -2096,8 +2096,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/mips/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c
index 8527856..0b658f1 100644
--- a/arch/mips/au1000/common/gpio.c
+++ b/arch/mips/au1000/common/gpio.c
@@ -27,7 +27,6 @@
* others have a second one : GPIO2
*/
-#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/types.h>
diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c
index abfc4bc..310d5dff 100644
--- a/arch/mips/au1000/mtx-1/board_setup.c
+++ b/arch/mips/au1000/mtx-1/board_setup.c
@@ -99,7 +99,7 @@
#endif
if (assert && devsel != 0) {
- // supress signal to cardbus
+ // suppress signal to cardbus
au_writel( 0x00000002, SYS_OUTPUTCLR ); // set EXT_IO3 OFF
}
else {
diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
index 9b34238..77db347 100644
--- a/arch/mips/kernel/binfmt_elfn32.c
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -98,7 +98,7 @@
jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
{
/*
- * Convert jiffies to nanoseconds and seperate with
+ * Convert jiffies to nanoseconds and separate with
* one divide.
*/
u64 nsec = (u64)jiffies * TICK_NSEC;
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index da41eac..08f4cd7 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -100,7 +100,7 @@
jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
{
/*
- * Convert jiffies to nanoseconds and seperate with
+ * Convert jiffies to nanoseconds and separate with
* one divide.
*/
u64 nsec = (u64)jiffies * TICK_NSEC;
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index f6704ab..998c4ef 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -221,7 +221,7 @@
}
}
- /* Run the syscall at the priviledge of the user who loaded the
+ /* Run the syscall at the privilege of the user who loaded the
SP program */
if (vpe_getuid(tclimit))
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 82480a1..f798139 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -660,7 +660,7 @@
sys sys_ioprio_get 2 /* 4315 */
sys sys_utimensat 4
sys sys_signalfd 3
- sys sys_timerfd 4
+ sys sys_ni_syscall 0
sys sys_eventfd 1
sys sys_fallocate 6 /* 4320 */
.endm
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index c2c1087..a626be6 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -475,7 +475,7 @@
PTR sys_ioprio_get
PTR sys_utimensat /* 5275 */
PTR sys_signalfd
- PTR sys_timerfd
+ PTR sys_ni_syscall
PTR sys_eventfd
PTR sys_fallocate
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 01993ec..9d5bcaf 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -401,7 +401,7 @@
PTR sys_ioprio_get
PTR compat_sys_utimensat
PTR compat_sys_signalfd /* 5280 */
- PTR compat_sys_timerfd
+ PTR sys_ni_syscall
PTR sys_eventfd
PTR sys_fallocate
.size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index dd68afc..fd2019c 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -523,7 +523,7 @@
PTR sys_ioprio_get /* 4315 */
PTR compat_sys_utimensat
PTR compat_sys_signalfd
- PTR compat_sys_timerfd
+ PTR sys_ni_syscall
PTR sys_eventfd
PTR sys32_fallocate /* 4320 */
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 269c252..c032409 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -424,13 +424,13 @@
#endif /* CONFIG_SGI_IP27 */
/*
- * arch_mem_init - initialize memory managment subsystem
+ * arch_mem_init - initialize memory management subsystem
*
* o plat_mem_setup() detects the memory configuration and will record detected
* memory areas using add_memory_region.
*
* At this stage the memory configuration of the system is known to the
- * kernel but generic memory managment system is still entirely uninitialized.
+ * kernel but generic memory management system is still entirely uninitialized.
*
* o bootmem_init()
* o sparse_init()
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 1e5dfc2..9d41dab 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -52,7 +52,6 @@
EXPORT_SYMBOL(phys_cpu_present_map);
EXPORT_SYMBOL(cpu_online_map);
-extern void __init calibrate_delay(void);
extern void cpu_idle(void);
/* Number of TCs (or siblings in Intel speak) per CPU core */
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 85f700e..b42e71c 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -65,7 +65,7 @@
static atomic_t ipi_timer_latch[NR_CPUS];
/*
- * Number of InterProcessor Interupt (IPI) message buffers to allocate
+ * Number of InterProcessor Interrupt (IPI) message buffers to allocate
*/
#define IPIBUF_PER_CPU 4
@@ -780,7 +780,7 @@
if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
if (type == SMTC_CLOCK_TICK)
atomic_inc(&ipi_timer_latch[cpu]);
- /* If not on same VPE, enqueue and send cross-VPE interupt */
+ /* If not on same VPE, enqueue and send cross-VPE interrupt */
smtc_ipi_nq(&IPIQ[cpu], pipi);
LOCK_CORE_PRA();
settc(cpu_data[cpu].tc_id);
@@ -1063,7 +1063,7 @@
return;
if (!cpu_has_vint)
- panic("SMTC Kernel requires Vectored Interupt support");
+ panic("SMTC Kernel requires Vectored Interrupt support");
set_vi_handler(MIPS_CPU_IPI_IRQ, ipi_irq_dispatch);
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 4c477c7..22fd41e 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -356,7 +356,7 @@
retval = NGROUPS_MAX;
goto out;
case 5:
- retval = NR_OPEN;
+ retval = sysctl_nr_open;
goto out;
case 6:
retval = 1;
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 02bd180..53ec052 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1101,7 +1101,7 @@
/*
* Do the probing thing on R4000SC and R4400SC processors. Other
* processors don't have a S-cache that would be relevant to the
- * Linux memory managment.
+ * Linux memory management.
*/
switch (c->cputype) {
case CPU_R4000SC:
diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c
index 524b371..a1fa4ab 100644
--- a/arch/mips/sgi-ip27/ip27-hubio.c
+++ b/arch/mips/sgi-ip27/ip27-hubio.c
@@ -168,7 +168,7 @@
}
/*
- * hub_pio_init - PIO-related hub initalization
+ * hub_pio_init - PIO-related hub initialization
*
* @hub: hubinfo structure for our hub
*/
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 2b649c4..028d8a0 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -7,6 +7,7 @@
config PARISC
def_bool y
+ select HAVE_OPROFILE
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
in many of their workstations & servers (HP9000 700 and 800 series,
@@ -205,9 +206,8 @@
singleprocessor machines. On a singleprocessor machine, the kernel
will run faster if you say N here.
- See also the <file:Documentation/smp.txt>,
- <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available
- at <http://www.tldp.org/docs.html#howto>.
+ See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+ available at <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -272,8 +272,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/parisc/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug
index 9166bd1..bc989e5 100644
--- a/arch/parisc/Kconfig.debug
+++ b/arch/parisc/Kconfig.debug
@@ -2,15 +2,6 @@
source "lib/Kconfig.debug"
-config DEBUG_RWLOCK
- bool "Read-write spinlock debugging"
- depends on DEBUG_KERNEL && SMP
- help
- If you say Y here then read-write lock processing will count how many
- times it has tried to get the lock and issue an error message after
- too many attempts. If you suspect a rwlock problem or a kernel
- hacker asks for this option then say Y. Otherwise say N.
-
config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
depends on DEBUG_KERNEL
diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
index ea07121..ddacc72 100644
--- a/arch/parisc/configs/a500_defconfig
+++ b/arch/parisc/configs/a500_defconfig
@@ -1050,7 +1050,6 @@
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_FAULT_INJECTION is not set
-# CONFIG_DEBUG_RWLOCK is not set
# CONFIG_DEBUG_RODATA is not set
#
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 395bbce..e10d25d 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -305,7 +305,7 @@
/* save the current process space and pgd */
unsigned long space = mfsp(3), pgd = mfctl(25);
- /* we don't mind taking interrups since they may not
+ /* we don't mind taking interrupts since they may not
* do anything with user space, but we can't
* be preempted here */
preempt_disable();
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
index 04848b2..84b9611 100644
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -1187,7 +1187,7 @@
{HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI USB KB"},
{HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI SuperIO RS-232"},
{HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI USB KB"},
- {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscelaneous PCI Plug-in"},
+ {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscellaneous PCI Plug-in"},
{HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI SuperIO RS-232"},
{HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI USB KB"},
{HPHW_FIO, 0x004, 0x00320, 0x0, "Metheus Frame Buffer"},
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 2ce3806..58fccc9 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -333,7 +333,7 @@
flush_user_icache_range((unsigned long) &frame->tramp[0],
(unsigned long) &frame->tramp[TRAMP_SIZE]);
- /* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP
+ /* TRAMP Words 0-4, Length 5 = SIGRESTARTBLOCK_TRAMP
* TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP
* So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP
*/
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 9c44af3..cf030b0 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -87,6 +87,8 @@
config PPC
bool
default y
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
config EARLY_PRINTK
bool
@@ -151,11 +153,25 @@
config REDBOOT
bool
-config PPC64_SWSUSP
+config HIBERNATE_32
bool
- depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
+ depends on (PPC_PMAC && !SMP) || BROKEN
default y
+config HIBERNATE_64
+ bool
+ depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL)
+ default y
+
+config ARCH_HIBERNATION_POSSIBLE
+ bool
+ depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
+ default y
+
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200
+
config PPC_DCR_NATIVE
bool
default n
@@ -240,6 +256,9 @@
Most drivers don't have this problem; it is safe to say Y here.
+config IOMMU_HELPER
+ def_bool PPC64
+
config HOTPLUG_CPU
bool "Support for enabling/disabling CPUs"
depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
@@ -391,6 +410,10 @@
most cases you will need to specify the root device here.
if !44x || BROKEN
+config ARCH_WANTS_FREEZER_CONTROL
+ def_bool y
+ depends on ADB_PMU
+
source kernel/power/Kconfig
endif
@@ -695,8 +718,6 @@
source "lib/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/powerpc/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c
index 8423907..3a317cb 100644
--- a/arch/powerpc/kernel/dma_64.c
+++ b/arch/powerpc/kernel/dma_64.c
@@ -31,8 +31,8 @@
static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
- return iommu_alloc_coherent(dev->archdata.dma_data, size, dma_handle,
- device_to_mask(dev), flag,
+ return iommu_alloc_coherent(dev, dev->archdata.dma_data, size,
+ dma_handle, device_to_mask(dev), flag,
dev->archdata.numa_node);
}
@@ -52,7 +52,7 @@
size_t size,
enum dma_data_direction direction)
{
- return iommu_map_single(dev->archdata.dma_data, vaddr, size,
+ return iommu_map_single(dev, dev->archdata.dma_data, vaddr, size,
device_to_mask(dev), direction);
}
@@ -68,7 +68,7 @@
static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
- return iommu_map_sg(dev->archdata.dma_data, sglist, nelems,
+ return iommu_map_sg(dev, sglist, nelems,
device_to_mask(dev), direction);
}
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index a3c406a..8f1f4e5 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -31,6 +31,7 @@
#include <linux/string.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
+#include <linux/iommu-helper.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/iommu.h>
@@ -81,17 +82,19 @@
__setup("protect4gb=", setup_protect4gb);
__setup("iommu=", setup_iommu);
-static unsigned long iommu_range_alloc(struct iommu_table *tbl,
+static unsigned long iommu_range_alloc(struct device *dev,
+ struct iommu_table *tbl,
unsigned long npages,
unsigned long *handle,
unsigned long mask,
unsigned int align_order)
{
- unsigned long n, end, i, start;
+ unsigned long n, end, start;
unsigned long limit;
int largealloc = npages > 15;
int pass = 0;
unsigned long align_mask;
+ unsigned long boundary_size;
align_mask = 0xffffffffffffffffl >> (64 - align_order);
@@ -136,14 +139,17 @@
start &= mask;
}
- n = find_next_zero_bit(tbl->it_map, limit, start);
+ if (dev)
+ boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+ 1 << IOMMU_PAGE_SHIFT);
+ else
+ boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT);
+ /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */
- /* Align allocation */
- n = (n + align_mask) & ~align_mask;
-
- end = n + npages;
-
- if (unlikely(end >= limit)) {
+ n = iommu_area_alloc(tbl->it_map, limit, start, npages,
+ tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT,
+ align_mask);
+ if (n == -1) {
if (likely(pass < 2)) {
/* First failure, just rescan the half of the table.
* Second failure, rescan the other half of the table.
@@ -158,14 +164,7 @@
}
}
- for (i = n; i < end; i++)
- if (test_bit(i, tbl->it_map)) {
- start = i+1;
- goto again;
- }
-
- for (i = n; i < end; i++)
- __set_bit(i, tbl->it_map);
+ end = n + npages;
/* Bump the hint to a new block for small allocs. */
if (largealloc) {
@@ -184,16 +183,17 @@
return n;
}
-static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page,
- unsigned int npages, enum dma_data_direction direction,
- unsigned long mask, unsigned int align_order)
+static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
+ void *page, unsigned int npages,
+ enum dma_data_direction direction,
+ unsigned long mask, unsigned int align_order)
{
unsigned long entry, flags;
dma_addr_t ret = DMA_ERROR_CODE;
spin_lock_irqsave(&(tbl->it_lock), flags);
- entry = iommu_range_alloc(tbl, npages, NULL, mask, align_order);
+ entry = iommu_range_alloc(dev, tbl, npages, NULL, mask, align_order);
if (unlikely(entry == DMA_ERROR_CODE)) {
spin_unlock_irqrestore(&(tbl->it_lock), flags);
@@ -224,7 +224,6 @@
unsigned int npages)
{
unsigned long entry, free_entry;
- unsigned long i;
entry = dma_addr >> IOMMU_PAGE_SHIFT;
free_entry = entry - tbl->it_offset;
@@ -246,9 +245,7 @@
}
ppc_md.tce_free(tbl, entry, npages);
-
- for (i = 0; i < npages; i++)
- __clear_bit(free_entry+i, tbl->it_map);
+ iommu_area_free(tbl->it_map, free_entry, npages);
}
static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
@@ -270,16 +267,18 @@
spin_unlock_irqrestore(&(tbl->it_lock), flags);
}
-int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+int iommu_map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, unsigned long mask,
enum dma_data_direction direction)
{
+ struct iommu_table *tbl = dev->archdata.dma_data;
dma_addr_t dma_next = 0, dma_addr;
unsigned long flags;
struct scatterlist *s, *outs, *segstart;
int outcount, incount, i;
unsigned int align;
unsigned long handle;
+ unsigned int max_seg_size;
BUG_ON(direction == DMA_NONE);
@@ -298,6 +297,7 @@
spin_lock_irqsave(&(tbl->it_lock), flags);
+ max_seg_size = dma_get_max_seg_size(dev);
for_each_sg(sglist, s, nelems, i) {
unsigned long vaddr, npages, entry, slen;
@@ -314,7 +314,7 @@
if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
(vaddr & ~PAGE_MASK) == 0)
align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
- entry = iommu_range_alloc(tbl, npages, &handle,
+ entry = iommu_range_alloc(dev, tbl, npages, &handle,
mask >> IOMMU_PAGE_SHIFT, align);
DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen);
@@ -344,7 +344,8 @@
/* We cannot merge if:
* - allocated dma_addr isn't contiguous to previous allocation
*/
- if (novmerge || (dma_addr != dma_next)) {
+ if (novmerge || (dma_addr != dma_next) ||
+ (outs->dma_length + s->length > max_seg_size)) {
/* Can't merge: create a new segment */
segstart = s;
outcount++;
@@ -452,9 +453,6 @@
struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
{
unsigned long sz;
- unsigned long start_index, end_index;
- unsigned long entries_per_4g;
- unsigned long index;
static int welcomed = 0;
struct page *page;
@@ -476,6 +474,7 @@
#ifdef CONFIG_CRASH_DUMP
if (ppc_md.tce_get) {
+ unsigned long index;
unsigned long tceval;
unsigned long tcecount = 0;
@@ -506,23 +505,6 @@
ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
#endif
- /*
- * DMA cannot cross 4 GB boundary. Mark last entry of each 4
- * GB chunk as reserved.
- */
- if (protect4gb) {
- entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT;
-
- /* Mark the last bit before a 4GB boundary as used */
- start_index = tbl->it_offset | (entries_per_4g - 1);
- start_index -= tbl->it_offset;
-
- end_index = tbl->it_size;
-
- for (index = start_index; index < end_index - 1; index += entries_per_4g)
- __set_bit(index, tbl->it_map);
- }
-
if (!welcomed) {
printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
novmerge ? "disabled" : "enabled");
@@ -570,9 +552,9 @@
* need not be page aligned, the dma_addr_t returned will point to the same
* byte within the page as vaddr.
*/
-dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
- size_t size, unsigned long mask,
- enum dma_data_direction direction)
+dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl,
+ void *vaddr, size_t size, unsigned long mask,
+ enum dma_data_direction direction)
{
dma_addr_t dma_handle = DMA_ERROR_CODE;
unsigned long uaddr;
@@ -589,7 +571,7 @@
((unsigned long)vaddr & ~PAGE_MASK) == 0)
align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
- dma_handle = iommu_alloc(tbl, vaddr, npages, direction,
+ dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction,
mask >> IOMMU_PAGE_SHIFT, align);
if (dma_handle == DMA_ERROR_CODE) {
if (printk_ratelimit()) {
@@ -621,8 +603,9 @@
* Returns the virtual address of the buffer and sets dma_handle
* to the dma address (mapping) of the first page.
*/
-void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
- dma_addr_t *dma_handle, unsigned long mask, gfp_t flag, int node)
+void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
+ size_t size, dma_addr_t *dma_handle,
+ unsigned long mask, gfp_t flag, int node)
{
void *ret = NULL;
dma_addr_t mapping;
@@ -656,7 +639,7 @@
/* Set up tces to cover the allocated range */
nio_pages = size >> IOMMU_PAGE_SHIFT;
io_order = get_iommu_order(size);
- mapping = iommu_alloc(tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
+ mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
mask >> IOMMU_PAGE_SHIFT, io_order);
if (mapping == DMA_ERROR_CODE) {
free_pages((unsigned long)ret, order);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 5cd3db5..3b26fbd6 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -66,6 +66,7 @@
#include <asm/smp.h>
#include <asm/vdso_datapage.h>
#include <asm/firmware.h>
+#include <asm/cputime.h>
#ifdef CONFIG_PPC_ISERIES
#include <asm/iseries/it_lp_queue.h>
#include <asm/iseries/hv_call_xm.h>
@@ -189,6 +190,8 @@
EXPORT_SYMBOL(__cputime_sec_factor);
u64 __cputime_clockt_factor;
EXPORT_SYMBOL(__cputime_clockt_factor);
+DEFINE_PER_CPU(unsigned long, cputime_last_delta);
+DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
static void calc_cputime_factors(void)
{
@@ -257,8 +260,8 @@
}
account_system_time(tsk, 0, delta);
account_system_time_scaled(tsk, deltascaled);
- get_paca()->purrdelta = delta;
- get_paca()->spurrdelta = deltascaled;
+ per_cpu(cputime_last_delta, smp_processor_id()) = delta;
+ per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled;
local_irq_restore(flags);
}
@@ -276,10 +279,7 @@
get_paca()->user_time = 0;
account_user_time(tsk, utime);
- /* Estimate the scaled utime by scaling the real utime based
- * on the last spurr to purr ratio */
- utimescaled = utime * get_paca()->spurrdelta / get_paca()->purrdelta;
- get_paca()->spurrdelta = get_paca()->purrdelta = 0;
+ utimescaled = cputime_to_scaled(utime);
account_user_time_scaled(tsk, utimescaled);
}
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 6448872..f80f90c 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -86,7 +86,7 @@
return ret;
}
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_pages((unsigned long)pgd, PGDIR_ORDER);
}
@@ -123,7 +123,7 @@
return ptepage;
}
-void pte_free_kernel(pte_t *pte)
+void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
#ifdef CONFIG_SMP
hash_page_sync();
@@ -131,7 +131,7 @@
free_page((unsigned long)pte);
}
-void pte_free(struct page *ptepage)
+void pte_free(struct mm_struct *mm, struct page *ptepage)
{
#ifdef CONFIG_SMP
hash_page_sync();
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index c0f13e8..41c7fd9 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -31,7 +31,7 @@
}
}
-static int lite5200_pm_set_target(suspend_state_t state)
+static int lite5200_pm_begin(suspend_state_t state)
{
if (lite5200_pm_valid(state)) {
lite5200_pm_target_state = state;
@@ -219,12 +219,18 @@
mpc52xx_pm_finish();
}
+static void lite5200_pm_end(void)
+{
+ lite5200_pm_target_state = PM_SUSPEND_ON;
+}
+
static struct platform_suspend_ops lite5200_pm_ops = {
.valid = lite5200_pm_valid,
- .set_target = lite5200_pm_set_target,
+ .begin = lite5200_pm_begin,
.prepare = lite5200_pm_prepare,
.enter = lite5200_pm_enter,
.finish = lite5200_pm_finish,
+ .end = lite5200_pm_end,
};
int __init lite5200_pm_init(void)
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index 6a0c6f6..11fa3c7 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -199,7 +199,7 @@
void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)
{
- return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle,
+ return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle,
DMA_32BIT_MASK, flag, -1);
}
EXPORT_SYMBOL_GPL(iseries_hv_alloc);
@@ -213,7 +213,7 @@
dma_addr_t iseries_hv_map(void *vaddr, size_t size,
enum dma_data_direction direction)
{
- return iommu_map_single(&vio_iommu_table, vaddr, size,
+ return iommu_map_single(NULL, &vio_iommu_table, vaddr, size,
DMA_32BIT_MASK, direction);
}
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index c04abcc..792d3ce 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -113,8 +113,6 @@
* result. We backup/restore the value to avoid affecting the
* core cpufreq framework's own calculation.
*/
- extern void calibrate_delay(void);
-
unsigned long save_lpj = loops_per_jiffy;
calibrate_delay();
loops_per_jiffy = save_lpj;
diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
index 25ef55ba..ec1defe 100644
--- a/arch/ppc/8260_io/enet.c
+++ b/arch/ppc/8260_io/enet.c
@@ -418,7 +418,7 @@
struct sk_buff *skb;
ushort pkt_len;
- cep = (struct scc_enet_private *)dev->priv;
+ cep = dev->priv;
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index a3a27da..bcc3aa9 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -682,7 +682,7 @@
struct sk_buff *skb;
ushort pkt_len;
- cep = (struct fcc_enet_private *)dev->priv;
+ cep = dev->priv;
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index db5934c..531156f 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -42,6 +42,8 @@
config PPC
bool
default y
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
config PPC32
bool
@@ -1256,8 +1258,6 @@
source "lib/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/ppc/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
index 52b64fc..8a24bc4 100644
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -143,11 +143,6 @@
. = ALIGN(4096);
__init_end = .;
-
- . = ALIGN(4096);
- _sextratext = .;
- _eextratext = .;
-
__bss_start = .;
.bss :
{
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
index fadacfd..409fcaa 100644
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -74,7 +74,7 @@
return ret;
}
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_pages((unsigned long)pgd, PGDIR_ORDER);
}
@@ -111,7 +111,7 @@
return ptepage;
}
-void pte_free_kernel(pte_t *pte)
+void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
#ifdef CONFIG_SMP
hash_page_sync();
@@ -119,7 +119,7 @@
free_page((unsigned long)pte);
}
-void pte_free(struct page *ptepage)
+void pte_free(struct mm_struct *mm, struct page *ptepage)
{
#ifdef CONFIG_SMP
hash_page_sync();
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 3c56654..3844985 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -91,20 +91,11 @@
#define cached_21 (((char *)(ppc_cached_irq_mask))[3])
#define cached_A1 (((char *)(ppc_cached_irq_mask))[2])
-#ifdef CONFIG_SOUND_CS4232
-long ppc_cs4232_dma, ppc_cs4232_dma2;
-#endif
-
extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern int probingmem;
extern unsigned long loops_per_jiffy;
-#ifdef CONFIG_SOUND_CS4232
-EXPORT_SYMBOL(ppc_cs4232_dma);
-EXPORT_SYMBOL(ppc_cs4232_dma2);
-#endif
-
/* useful ISA ports */
#define PREP_SYSCTL 0x81c
/* present in the IBM reference design; possibly identical in Mot boxes: */
@@ -569,74 +560,6 @@
return 0;
}
-#ifdef CONFIG_SOUND_CS4232
-static long __init masktoint(unsigned int i)
-{
- int t = -1;
- while (i >> ++t)
- ;
- return (t-1);
-}
-
-/*
- * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h
- * to distinguish sound dma-channels from others. This is because
- * blocksize on 16 bit dma-channels 5,6,7 is 128k, but
- * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3
- */
-
-static void __init prep_init_sound(void)
-{
- PPC_DEVICE *audiodevice = NULL;
-
- /*
- * Get the needed resource information from residual data.
- *
- */
- if (have_residual_data)
- audiodevice = residual_find_device(~0, NULL,
- MultimediaController, AudioController, -1, 0);
-
- if (audiodevice != NULL) {
- PnP_TAG_PACKET *pkt;
-
- pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
- S5_Packet, 0);
- if (pkt != NULL)
- ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask);
- pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
- S5_Packet, 1);
- if (pkt != NULL)
- ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
- }
-
- /*
- * These are the PReP specs' defaults for the cs4231. We use these
- * as fallback incase we don't have residual data.
- * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7
- * will use the other values.
- */
- if (audiodevice == NULL) {
- switch (_prep_type) {
- case _PREP_IBM:
- ppc_cs4232_dma = 1;
- ppc_cs4232_dma2 = -1;
- break;
- default:
- ppc_cs4232_dma = 6;
- ppc_cs4232_dma2 = 7;
- }
- }
-
- /*
- * Find a way to push this information to the cs4232 driver
- * Give it out with printk, when not in cmd_line?
- * Append it to cmd_line and boot_command_line?
- * Format is cs4232=io,irq,dma,dma2
- */
-}
-#endif /* CONFIG_SOUND_CS4232 */
-
/*
* Fill out screen_info according to the residual data. This allows us to use
* at least vesafb.
@@ -898,10 +821,6 @@
}
}
-#ifdef CONFIG_SOUND_CS4232
- prep_init_sound();
-#endif /* CONFIG_SOUND_CS4232 */
-
prep_init_vesa();
switch (_prep_type) {
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 6ef54d2..92a4f7b 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -16,6 +16,9 @@
config STACKTRACE_SUPPORT
def_bool y
+config HAVE_LATENCYTOP_SUPPORT
+ def_bool y
+
config RWSEM_GENERIC_SPINLOCK
bool
@@ -47,10 +50,17 @@
config NO_DMA
def_bool y
+config GENERIC_LOCKBREAK
+ bool
+ default y
+ depends on SMP && PREEMPT
+
mainmenu "Linux Kernel Configuration"
config S390
def_bool y
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
source "init/Kconfig"
@@ -81,8 +91,8 @@
singleprocessor machines. On a singleprocessor machine, the kernel
will run faster if you say N here.
- See also the <file:Documentation/smp.txt> and the SMP-HOWTO
- available at <http://www.tldp.org/docs.html#howto>.
+ See also the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
Even if you don't know what to do here, say Y.
@@ -526,8 +536,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/s390/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
index 2283933..4599fa0 100644
--- a/arch/s390/Kconfig.debug
+++ b/arch/s390/Kconfig.debug
@@ -6,4 +6,12 @@
source "lib/Kconfig.debug"
+config DEBUG_PAGEALLOC
+ bool "Debug page memory allocations"
+ depends on DEBUG_KERNEL
+ help
+ Unmap pages from the kernel linear mapping after free_pages().
+ This results in a slowdown, but helps to find certain types of
+ memory corruptions.
+
endmenu
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 6ee1bed..062c3d4 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1698,14 +1698,6 @@
llgfr %r4,%r4 # compat_size_t
jg compat_sys_signalfd
- .globl compat_sys_timerfd_wrapper
-compat_sys_timerfd_wrapper:
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # struct compat_itimerspec *
- jg compat_sys_timerfd
-
.globl sys_eventfd_wrapper
sys_eventfd_wrapper:
llgfr %r2,%r2 # unsigned int
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 1a6dac8..6766e37 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -11,6 +11,7 @@
#include <linux/sys.h>
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/cache.h>
#include <asm/lowcore.h>
#include <asm/errno.h>
@@ -830,9 +831,7 @@
* Restart interruption handler, kick starter for additional CPUs
*/
#ifdef CONFIG_SMP
-#ifndef CONFIG_HOTPLUG_CPU
- .section .init.text,"ax"
-#endif
+ __CPUINIT
.globl restart_int_handler
restart_int_handler:
l %r15,__LC_SAVE_AREA+60 # load ksp
@@ -845,9 +844,7 @@
br %r14 # branch to start_secondary
restart_addr:
.long start_secondary
-#ifndef CONFIG_HOTPLUG_CPU
.previous
-#endif
#else
/*
* If we do not run with SMP enabled, let the new CPU crash ...
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index a3e47b8..efde6e1 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -11,6 +11,7 @@
#include <linux/sys.h>
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/cache.h>
#include <asm/lowcore.h>
#include <asm/errno.h>
@@ -801,9 +802,7 @@
* Restart interruption handler, kick starter for additional CPUs
*/
#ifdef CONFIG_SMP
-#ifndef CONFIG_HOTPLUG_CPU
- .section .init.text,"ax"
-#endif
+ __CPUINIT
.globl restart_int_handler
restart_int_handler:
lg %r15,__LC_SAVE_AREA+120 # load ksp
@@ -814,9 +813,7 @@
lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
jg start_secondary
-#ifndef CONFIG_HOTPLUG_CPU
.previous
-#endif
#else
/*
* If we do not run with SMP enabled, let the new CPU crash ...
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index db28cca..60acdc2 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -439,7 +439,7 @@
reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
}
-static int ipl_init(void)
+static int __init ipl_init(void)
{
int rc;
@@ -471,8 +471,11 @@
return 0;
}
-static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
- ipl_init};
+static struct shutdown_action __refdata ipl_action = {
+ .name = SHUTDOWN_ACTION_IPL_STR,
+ .fn = ipl_run,
+ .init = ipl_init,
+};
/*
* reipl shutdown action: Reboot Linux on shutdown.
@@ -792,7 +795,7 @@
return 0;
}
-static int reipl_init(void)
+static int __init reipl_init(void)
{
int rc;
@@ -819,8 +822,11 @@
return 0;
}
-static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
- reipl_run, reipl_init};
+static struct shutdown_action __refdata reipl_action = {
+ .name = SHUTDOWN_ACTION_REIPL_STR,
+ .fn = reipl_run,
+ .init = reipl_init,
+};
/*
* dump shutdown action: Dump Linux on shutdown.
@@ -998,7 +1004,7 @@
return 0;
}
-static int dump_init(void)
+static int __init dump_init(void)
{
int rc;
@@ -1020,8 +1026,11 @@
return 0;
}
-static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
- dump_run, dump_init};
+static struct shutdown_action __refdata dump_action = {
+ .name = SHUTDOWN_ACTION_DUMP_STR,
+ .fn = dump_run,
+ .init = dump_init,
+};
/*
* vmcmd shutdown action: Trigger vm command on shutdown.
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 766c783..29ae165 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -77,7 +77,7 @@
unsigned long elf_hwcap = 0;
char elf_platform[ELF_PLATFORM_SIZE];
-struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
+struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS];
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
static unsigned long __initdata memory_end;
@@ -145,7 +145,7 @@
static int __init conmode_setup(char *str)
{
-#if defined(CONFIG_SCLP_CONSOLE)
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
SET_CONSOLE_SCLP;
#endif
@@ -183,7 +183,7 @@
*/
cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
if (ptr == NULL) {
-#if defined(CONFIG_SCLP_CONSOLE)
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
SET_CONSOLE_SCLP;
#endif
return;
@@ -193,7 +193,7 @@
SET_CONSOLE_3270;
#elif defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215;
-#elif defined(CONFIG_SCLP_CONSOLE)
+#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
SET_CONSOLE_SCLP;
#endif
} else if (strncmp(ptr + 8, "3215", 4) == 0) {
@@ -201,7 +201,7 @@
SET_CONSOLE_3215;
#elif defined(CONFIG_TN3270_CONSOLE)
SET_CONSOLE_3270;
-#elif defined(CONFIG_SCLP_CONSOLE)
+#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
SET_CONSOLE_SCLP;
#endif
}
@@ -212,7 +212,7 @@
SET_CONSOLE_3270;
#endif
} else {
-#if defined(CONFIG_SCLP_CONSOLE)
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
SET_CONSOLE_SCLP;
#endif
}
@@ -528,7 +528,7 @@
memory_size = 0;
memory_end &= PAGE_MASK;
- max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
+ max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS;
memory_end = min(max_mem, memory_end);
/*
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index aa37fa1..8506065 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -225,12 +225,11 @@
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
*/
-int
-smp_call_function_mask(cpumask_t mask,
- void (*func)(void *), void *info,
- int wait)
+int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
+ int wait)
{
preempt_disable();
+ cpu_clear(smp_processor_id(), mask);
__smp_call_function_map(func, info, 0, wait, mask);
preempt_enable();
return 0;
@@ -1008,7 +1007,7 @@
.notifier_call = smp_cpu_notify,
};
-static int smp_add_present_cpu(int cpu)
+static int __devinit smp_add_present_cpu(int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
struct sys_device *s = &c->sysdev;
@@ -1036,8 +1035,8 @@
}
#ifdef CONFIG_HOTPLUG_CPU
-static ssize_t rescan_store(struct sys_device *dev, const char *buf,
- size_t count)
+static ssize_t __ref rescan_store(struct sys_device *dev,
+ const char *buf, size_t count)
{
cpumask_t newcpus;
int cpu;
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index da69247..85e46a5 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -14,7 +14,8 @@
static unsigned long save_context_stack(struct stack_trace *trace,
unsigned long sp,
unsigned long low,
- unsigned long high)
+ unsigned long high,
+ int savesched)
{
struct stack_frame *sf;
struct pt_regs *regs;
@@ -47,10 +48,12 @@
return sp;
regs = (struct pt_regs *)sp;
addr = regs->psw.addr & PSW_ADDR_INSN;
- if (!trace->skip)
- trace->entries[trace->nr_entries++] = addr;
- else
- trace->skip--;
+ if (savesched || !in_sched_functions(addr)) {
+ if (!trace->skip)
+ trace->entries[trace->nr_entries++] = addr;
+ else
+ trace->skip--;
+ }
if (trace->nr_entries >= trace->max_entries)
return sp;
low = sp;
@@ -66,15 +69,27 @@
orig_sp = sp & PSW_ADDR_INSN;
new_sp = save_context_stack(trace, orig_sp,
S390_lowcore.panic_stack - PAGE_SIZE,
- S390_lowcore.panic_stack);
+ S390_lowcore.panic_stack, 1);
if (new_sp != orig_sp)
return;
new_sp = save_context_stack(trace, new_sp,
S390_lowcore.async_stack - ASYNC_SIZE,
- S390_lowcore.async_stack);
+ S390_lowcore.async_stack, 1);
if (new_sp != orig_sp)
return;
save_context_stack(trace, new_sp,
S390_lowcore.thread_info,
- S390_lowcore.thread_info + THREAD_SIZE);
+ S390_lowcore.thread_info + THREAD_SIZE, 1);
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+ unsigned long sp, low, high;
+
+ sp = tsk->thread.ksp & PSW_ADDR_INSN;
+ low = (unsigned long) task_stack_page(tsk);
+ high = (unsigned long) task_pt_regs(tsk);
+ save_context_stack(trace, sp, low, high, 0);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 9e26ed9..25eac78 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -325,5 +325,5 @@
SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
-SYSCALL(sys_timerfd,sys_timerfd,compat_sys_timerfd_wrapper)
+NI_SYSCALL /* 317 old sys_timer_fd */
SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 52b8342c..1a2fdb69 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -271,7 +271,10 @@
printk("PREEMPT ");
#endif
#ifdef CONFIG_SMP
- printk("SMP");
+ printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ printk("DEBUG_PAGEALLOC");
#endif
printk("\n");
notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 7d43c3c..b4607155 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -35,7 +35,7 @@
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
- } = 0x0700
+ } :text = 0x0700
_etext = .; /* End of text section */
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index b234bb4..983ec6e 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -167,6 +167,33 @@
PFN_ALIGN((unsigned long)&_eshared) - 1);
}
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long address;
+ int i;
+
+ for (i = 0; i < numpages; i++) {
+ address = page_to_phys(page + i);
+ pgd = pgd_offset_k(address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+ if (!enable) {
+ ptep_invalidate(address, pte);
+ continue;
+ }
+ *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
+ /* Flush cpu write queue. */
+ mb();
+ }
+}
+#endif
+
void free_initmem(void)
{
unsigned long addr;
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 79d13a1..7c1287c 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -62,7 +62,7 @@
}
}
-static void __init_refok *vmem_alloc_pages(unsigned int order)
+static void __ref *vmem_alloc_pages(unsigned int order)
{
if (slab_is_available())
return (void *)__get_free_pages(GFP_KERNEL, order);
@@ -250,7 +250,7 @@
{
struct memory_segment *tmp;
- if (seg->start + seg->size >= VMALLOC_START ||
+ if (seg->start + seg->size >= VMEM_MAX_PHYS ||
seg->start + seg->size < seg->start)
return -ERANGE;
@@ -360,7 +360,6 @@
{
int i;
- BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
NODE_DATA(0)->node_mem_map = VMEM_MAP;
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 1cd9c8f..1c3a908 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -8,6 +8,7 @@
config SUPERH
def_bool y
select EMBEDDED
+ select HAVE_OPROFILE
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
@@ -672,9 +673,8 @@
People using multiprocessor machines who say Y here should also say
Y to "Enhanced Real Time Clock Support", below.
- See also the <file:Documentation/smp.txt>,
- <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available
- at <http://www.tldp.org/docs.html#howto>.
+ See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+ available at <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -882,6 +882,10 @@
menu "Power management options (EXPERIMENTAL)"
depends on EXPERIMENTAL && SYS_SUPPORTS_PM
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !SMP
+
source kernel/power/Kconfig
endmenu
@@ -892,8 +896,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/sh/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c
index eda7176..2b708ec 100644
--- a/arch/sh/boards/landisk/setup.c
+++ b/arch/sh/boards/landisk/setup.c
@@ -14,7 +14,7 @@
*/
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/pm.h>
#include <linux/mm.h>
#include <asm/machvec.h>
diff --git a/arch/sh/boards/lboxre2/setup.c b/arch/sh/boards/lboxre2/setup.c
index 9c830fd..c74440d 100644
--- a/arch/sh/boards/lboxre2/setup.c
+++ b/arch/sh/boards/lboxre2/setup.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <asm/machvec.h>
#include <asm/addrspace.h>
#include <asm/lboxre2.h>
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index a43b477..f7a8d5c 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -15,7 +15,7 @@
*/
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/types.h>
#include <net/ax88796.h>
#include <asm/machvec.h>
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
index 3452b07..a0ef81b 100644
--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -10,7 +10,7 @@
*/
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/serial_8250.h>
#include <linux/sm501.h>
#include <linux/sm501-regs.h>
diff --git a/arch/sh/boards/renesas/sdk7780/setup.c b/arch/sh/boards/renesas/sdk7780/setup.c
index 5df32f2..acc5932 100644
--- a/arch/sh/boards/renesas/sdk7780/setup.c
+++ b/arch/sh/boards/renesas/sdk7780/setup.c
@@ -11,7 +11,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <asm/machvec.h>
#include <asm/sdk7780.h>
#include <asm/heartbeat.h>
diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c
index eb97dca..b1a3d9d 100644
--- a/arch/sh/boards/se/7722/setup.c
+++ b/arch/sh/boards/se/7722/setup.c
@@ -12,7 +12,7 @@
*/
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <asm/machvec.h>
#include <asm/se7722.h>
#include <asm/io.h>
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
index fbc6f2c..7e816ed 100644
--- a/arch/sh/drivers/pci/Kconfig
+++ b/arch/sh/drivers/pci/Kconfig
@@ -6,11 +6,6 @@
bus system, i.e. the way the CPU talks to the other stuff inside
your box. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config SH_PCIDMA_NONCOHERENT
bool "Cache and PCI noncoherent"
depends on PCI
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index 10bec45..719e127 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -338,6 +338,6 @@
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
.long sys_signalfd
- .long sys_timerfd
+ .long sys_ni_syscall
.long sys_eventfd
.long sys_fallocate
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 98a93ef..12c7340 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -376,6 +376,6 @@
.long sys_epoll_pwait
.long sys_utimensat
.long sys_signalfd
- .long sys_timerfd /* 350 */
+ .long sys_ni_syscall /* 350 */
.long sys_eventfd
.long sys_fallocate
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 527adc8..99f8971 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -48,9 +48,8 @@
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
- See also the <file:Documentation/smp.txt>,
- <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
- <http://www.tldp.org/docs.html#howto>.
+ See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+ available at <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -63,6 +62,7 @@
config SPARC
bool
default y
+ select HAVE_OPROFILE
# Identify this as a Sparc32 build
config SPARC32
@@ -320,8 +320,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/sparc/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 97aa50d..ad0ede2 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -305,7 +305,7 @@
struct resource *res;
int order;
- /* XXX why are some lenghts signed, others unsigned? */
+ /* XXX why are some lengths signed, others unsigned? */
if (len <= 0) {
return NULL;
}
@@ -393,7 +393,7 @@
*/
dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
{
- /* XXX why are some lenghts signed, others unsigned? */
+ /* XXX why are some lengths signed, others unsigned? */
if (len <= 0) {
return 0;
}
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 89a6de95..0def481 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -19,12 +19,12 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/profile.h>
+#include <linux/delay.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
#include <asm/irq_regs.h>
-#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
@@ -41,8 +41,6 @@
extern ctxd_t *srmmu_ctx_table_phys;
-extern void calibrate_delay(void);
-
static volatile int smp_processors_ready = 0;
static int smp_highest_cpu;
extern volatile unsigned long cpu_callin_map[NR_CPUS];
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 730eb579..0b94072 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -16,6 +16,8 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/profile.h>
+#include <linux/delay.h>
+
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/irq_regs.h>
@@ -23,7 +25,6 @@
#include <asm/ptrace.h>
#include <asm/atomic.h>
-#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
@@ -39,8 +40,6 @@
extern ctxd_t *srmmu_ctx_table_phys;
-extern void calibrate_delay(void);
-
extern volatile unsigned long cpu_callin_map[NR_CPUS];
extern unsigned char boot_cpu_id;
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 5572284..9064485 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -79,7 +79,8 @@
/*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
/*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
+/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+/*315*/ .long sys_timerfd_settime, sys_timerfd_gettime
#ifdef CONFIG_SUNOS_EMUL
/* Now the SunOS syscall table. */
@@ -197,6 +198,7 @@
.long sunos_nosys, sunos_nosys, sunos_nosys
.long sunos_nosys
/*310*/ .long sunos_nosys, sunos_nosys, sunos_nosys
- .long sunos_nosys, sunos_nosys
+ .long sunos_nosys, sunos_nosys, sunos_nosys
+ .long sunos_nosys
#endif
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 73fc05d..a8c6366 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -8,6 +8,8 @@
config SPARC
bool
default y
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
config SPARC64
bool
@@ -166,9 +168,8 @@
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
- See also the <file:Documentation/smp.txt>,
- <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
- <http://www.tldp.org/docs.html#howto>.
+ See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+ available at <http://www.tldp.org/docs.html#howto>.
If you don't know what to do here, say N.
@@ -351,11 +352,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
config PCI_DOMAINS
def_bool PCI
@@ -470,8 +466,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/sparc64/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index f62d9f6..833d74b 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24-rc4
-# Tue Dec 4 00:37:59 2007
+# Linux kernel version: 2.6.24
+# Tue Feb 5 17:28:19 2008
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -17,6 +17,7 @@
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_OF=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
@@ -30,13 +31,15 @@
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_HOTPLUG_CPU=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# General setup
#
CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
@@ -76,6 +79,7 @@
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
@@ -83,6 +87,14 @@
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
@@ -92,6 +104,7 @@
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_BLK_DEV_BSG=y
@@ -109,6 +122,8 @@
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
CONFIG_SYSVIPC_COMPAT=y
CONFIG_GENERIC_HARDIRQS=y
@@ -119,7 +134,8 @@
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_SMP is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
# CONFIG_CPU_FREQ is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -169,9 +185,12 @@
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
CONFIG_SOLARIS_EMUL=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
+# CONFIG_RCU_TRACE is not set
# CONFIG_CMDLINE_BOOL is not set
#
@@ -189,6 +208,7 @@
CONFIG_XFRM_USER=m
# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
CONFIG_NET_KEY=m
CONFIG_NET_KEY_MIGRATE=y
CONFIG_INET=y
@@ -249,9 +269,9 @@
CONFIG_IP_DCCP_CCID2=m
# CONFIG_IP_DCCP_CCID2_DEBUG is not set
CONFIG_IP_DCCP_CCID3=m
-CONFIG_IP_DCCP_TFRC_LIB=m
# CONFIG_IP_DCCP_CCID3_DEBUG is not set
CONFIG_IP_DCCP_CCID3_RTO=100
+CONFIG_IP_DCCP_TFRC_LIB=m
#
# DCCP Kernel Hacking
@@ -279,6 +299,7 @@
CONFIG_NET_PKTGEN=m
CONFIG_NET_TCPPROBE=m
# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
@@ -343,6 +364,7 @@
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
@@ -359,7 +381,6 @@
# PCI IDE chipsets support
#
CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_IDEPCI_PCIBUS_ORDER=y
# CONFIG_BLK_DEV_GENERIC is not set
# CONFIG_BLK_DEV_OPTI621 is not set
@@ -389,7 +410,6 @@
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDE_ARCH_OBSOLETE_INIT=y
# CONFIG_BLK_DEV_HD is not set
@@ -501,7 +521,6 @@
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_VETH is not set
-# CONFIG_IP1000 is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
@@ -533,6 +552,7 @@
# CONFIG_NE2K_PCI is not set
# CONFIG_8139CP is not set
# CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
@@ -545,6 +565,9 @@
CONFIG_E1000_NAPI=y
# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
# CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
@@ -570,6 +593,7 @@
CONFIG_NIU=m
# CONFIG_MLX4_CORE is not set
# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
# CONFIG_TR is not set
#
@@ -602,7 +626,6 @@
# CONFIG_SLIP is not set
CONFIG_SLHC=m
# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
@@ -679,6 +702,7 @@
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
#
# Serial drivers
@@ -747,13 +771,13 @@
#
# Miscellaneous I2C Chip support
#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
# CONFIG_DS1682 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
@@ -990,6 +1014,7 @@
# CONFIG_SND_BT87X is not set
# CONFIG_SND_CA0106 is not set
# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_DARLA20 is not set
@@ -1014,6 +1039,7 @@
# CONFIG_SND_HDA_INTEL is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
# CONFIG_SND_ICE1712 is not set
# CONFIG_SND_ICE1724 is not set
# CONFIG_SND_INTEL8X0 is not set
@@ -1031,6 +1057,7 @@
# CONFIG_SND_TRIDENT is not set
# CONFIG_SND_VIA82XX is not set
# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_YMFPCI is not set
# CONFIG_SND_AC97_POWER_SAVE is not set
@@ -1058,6 +1085,10 @@
#
#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
# Open Sound System
#
# CONFIG_SOUND_PRIME is not set
@@ -1080,6 +1111,7 @@
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
#
# Miscellaneous USB options
@@ -1093,7 +1125,6 @@
# USB Host Controller Drivers
#
CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
@@ -1143,10 +1174,6 @@
#
# USB port drivers
#
-
-#
-# USB Serial Converter support
-#
# CONFIG_USB_SERIAL is not set
#
@@ -1172,14 +1199,6 @@
# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
# CONFIG_USB_GADGET is not set
# CONFIG_MMC is not set
# CONFIG_NEW_LEDS is not set
@@ -1332,11 +1351,6 @@
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
# CONFIG_DLM is not set
-CONFIG_INSTRUMENTATION=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_KPROBES=y
-# CONFIG_MARKERS is not set
#
# Kernel hacking
@@ -1374,6 +1388,8 @@
CONFIG_FORCED_INLINING=y
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_SAMPLES is not set
@@ -1396,8 +1412,9 @@
CONFIG_ASYNC_XOR=m
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_BLKCIPHER=y
+# CONFIG_CRYPTO_SEQIV is not set
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
@@ -1416,6 +1433,9 @@
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_XTS=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_FCRYPT=m
@@ -1431,13 +1451,16 @@
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_SEED=m
+# CONFIG_CRYPTO_SALSA20 is not set
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_AUTHENC=m
+# CONFIG_CRYPTO_LZO is not set
CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
#
# Library routines
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index ef50d21..4b78b24 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -11,7 +11,7 @@
traps.o auxio.o una_asm.o sysfs.o iommu.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
- power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
+ power.o sbus.o sparc64_ksyms.o chmc.o \
visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c
index 070a484..5623a4d 100644
--- a/arch/sparc64/kernel/iommu.c
+++ b/arch/sparc64/kernel/iommu.c
@@ -472,94 +472,15 @@
spin_unlock_irqrestore(&iommu->lock, flags);
}
-#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG))))
-
-static void fill_sg(iopte_t *iopte, struct scatterlist *sg,
- int nused, int nelems,
- unsigned long iopte_protection)
-{
- struct scatterlist *dma_sg = sg;
- int i;
-
- for (i = 0; i < nused; i++) {
- unsigned long pteval = ~0UL;
- u32 dma_npages;
-
- dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
- dma_sg->dma_length +
- ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
- do {
- unsigned long offset;
- signed int len;
-
- /* If we are here, we know we have at least one
- * more page to map. So walk forward until we
- * hit a page crossing, and begin creating new
- * mappings from that spot.
- */
- for (;;) {
- unsigned long tmp;
-
- tmp = SG_ENT_PHYS_ADDRESS(sg);
- len = sg->length;
- if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
- pteval = tmp & IO_PAGE_MASK;
- offset = tmp & (IO_PAGE_SIZE - 1UL);
- break;
- }
- if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
- pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
- offset = 0UL;
- len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
- break;
- }
- sg = sg_next(sg);
- nelems--;
- }
-
- pteval = iopte_protection | (pteval & IOPTE_PAGE);
- while (len > 0) {
- *iopte++ = __iopte(pteval);
- pteval += IO_PAGE_SIZE;
- len -= (IO_PAGE_SIZE - offset);
- offset = 0;
- dma_npages--;
- }
-
- pteval = (pteval & IOPTE_PAGE) + len;
- sg = sg_next(sg);
- nelems--;
-
- /* Skip over any tail mappings we've fully mapped,
- * adjusting pteval along the way. Stop when we
- * detect a page crossing event.
- */
- while (nelems &&
- (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
- (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
- ((pteval ^
- (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
- pteval += sg->length;
- sg = sg_next(sg);
- nelems--;
- }
- if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
- pteval = ~0UL;
- } while (dma_npages != 0);
- dma_sg = sg_next(dma_sg);
- }
-}
-
static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
- struct iommu *iommu;
+ unsigned long flags, ctx, i, npages, iopte_protection;
+ struct scatterlist *sg;
struct strbuf *strbuf;
- unsigned long flags, ctx, npages, iopte_protection;
+ struct iommu *iommu;
iopte_t *base;
u32 dma_base;
- struct scatterlist *sgtmp;
- int used;
/* Fast path single entry scatterlists. */
if (nelems == 1) {
@@ -578,11 +499,7 @@
if (unlikely(direction == DMA_NONE))
goto bad_no_ctx;
- /* Step 1: Prepare scatter list. */
-
- npages = prepare_sg(sglist, nelems);
-
- /* Step 2: Allocate a cluster and context, if necessary. */
+ npages = calc_npages(sglist, nelems);
spin_lock_irqsave(&iommu->lock, flags);
@@ -599,18 +516,6 @@
dma_base = iommu->page_table_map_base +
((base - iommu->page_table) << IO_PAGE_SHIFT);
- /* Step 3: Normalize DMA addresses. */
- used = nelems;
-
- sgtmp = sglist;
- while (used && sgtmp->dma_length) {
- sgtmp->dma_address += dma_base;
- sgtmp = sg_next(sgtmp);
- used--;
- }
- used = nelems - used;
-
- /* Step 4: Create the mappings. */
if (strbuf->strbuf_enabled)
iopte_protection = IOPTE_STREAMING(ctx);
else
@@ -618,13 +523,27 @@
if (direction != DMA_TO_DEVICE)
iopte_protection |= IOPTE_WRITE;
- fill_sg(base, sglist, used, nelems, iopte_protection);
+ for_each_sg(sglist, sg, nelems, i) {
+ unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+ unsigned long slen = sg->length;
+ unsigned long this_npages;
-#ifdef VERIFY_SG
- verify_sglist(sglist, nelems, base, npages);
-#endif
+ this_npages = iommu_num_pages(paddr, slen);
- return used;
+ sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
+ sg->dma_length = slen;
+
+ paddr &= IO_PAGE_MASK;
+ while (this_npages--) {
+ iopte_val(*base) = iopte_protection | paddr;
+
+ base++;
+ paddr += IO_PAGE_SIZE;
+ dma_base += IO_PAGE_SIZE;
+ }
+ }
+
+ return nelems;
bad:
iommu_free_ctx(iommu, ctx);
@@ -637,11 +556,10 @@
static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
- struct iommu *iommu;
- struct strbuf *strbuf;
- iopte_t *base;
unsigned long flags, ctx, i, npages;
- struct scatterlist *sg, *sgprv;
+ struct strbuf *strbuf;
+ struct iommu *iommu;
+ iopte_t *base;
u32 bus_addr;
if (unlikely(direction == DMA_NONE)) {
@@ -654,15 +572,7 @@
bus_addr = sglist->dma_address & IO_PAGE_MASK;
- sgprv = NULL;
- for_each_sg(sglist, sg, nelems, i) {
- if (sg->dma_length == 0)
- break;
- sgprv = sg;
- }
-
- npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) -
- bus_addr) >> IO_PAGE_SHIFT;
+ npages = calc_npages(sglist, nelems);
base = iommu->page_table +
((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c
deleted file mode 100644
index efd5dff..0000000
--- a/arch/sparc64/kernel/iommu_common.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $
- * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
- *
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#include "iommu_common.h"
-
-/* You are _strongly_ advised to enable the following debugging code
- * any time you make changes to the sg code below, run it for a while
- * with filesystems mounted read-only before buying the farm... -DaveM
- */
-
-#ifdef VERIFY_SG
-static int verify_lengths(struct scatterlist *sglist, int nents, int npages)
-{
- int sg_len, dma_len;
- int i, pgcount;
- struct scatterlist *sg;
-
- sg_len = 0;
- for_each_sg(sglist, sg, nents, i)
- sg_len += sg->length;
-
- dma_len = 0;
- for_each_sg(sglist, sg, nents, i) {
- if (!sg->dma_length)
- break;
- dma_len += sg->dma_length;
- }
-
- if (sg_len != dma_len) {
- printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
- sg_len, dma_len);
- return -1;
- }
-
- pgcount = 0;
- for_each_sg(sglist, sg, nents, i) {
- unsigned long start, end;
-
- if (!sg->dma_length)
- break;
-
- start = sg->dma_address;
- start = start & IO_PAGE_MASK;
-
- end = sg->dma_address + sg->dma_length;
- end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
-
- pgcount += ((end - start) >> IO_PAGE_SHIFT);
- }
-
- if (pgcount != npages) {
- printk("verify_lengths: Error, page count wrong, "
- "npages[%d] pgcount[%d]\n",
- npages, pgcount);
- return -1;
- }
-
- /* This test passes... */
- return 0;
-}
-
-static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
-{
- struct scatterlist *sg = *__sg;
- iopte_t *iopte = *__iopte;
- u32 dlen = dma_sg->dma_length;
- u32 daddr;
- unsigned int sglen;
- unsigned long sgaddr;
-
- daddr = dma_sg->dma_address;
- sglen = sg->length;
- sgaddr = (unsigned long) sg_virt(sg);
- while (dlen > 0) {
- unsigned long paddr;
-
- /* SG and DMA_SG must begin at the same sub-page boundary. */
- if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
- printk("verify_one_map: Wrong start offset "
- "sg[%08lx] dma[%08x]\n",
- sgaddr, daddr);
- nents = -1;
- goto out;
- }
-
- /* Verify the IOPTE points to the right page. */
- paddr = iopte_val(*iopte) & IOPTE_PAGE;
- if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
- printk("verify_one_map: IOPTE[%08lx] maps the "
- "wrong page, should be [%08lx]\n",
- iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
- nents = -1;
- goto out;
- }
-
- /* If this SG crosses a page, adjust to that next page
- * boundary and loop.
- */
- if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
- unsigned long next_page, diff;
-
- next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
- diff = next_page - sgaddr;
- sgaddr += diff;
- daddr += diff;
- sglen -= diff;
- dlen -= diff;
- if (dlen > 0)
- iopte++;
- continue;
- }
-
- /* SG wholly consumed within this page. */
- daddr += sglen;
- dlen -= sglen;
-
- if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
- iopte++;
-
- sg = sg_next(sg);
- if (--nents <= 0)
- break;
- sgaddr = (unsigned long) sg_virt(sg);
- sglen = sg->length;
- }
- if (dlen < 0) {
- /* Transfer overrun, big problems. */
- printk("verify_one_map: Transfer overrun by %d bytes.\n",
- -dlen);
- nents = -1;
- } else {
- /* Advance to next dma_sg implies that the next iopte will
- * begin it.
- */
- iopte++;
- }
-
-out:
- *__sg = sg;
- *__iopte = iopte;
- return nents;
-}
-
-static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
-{
- struct scatterlist *dma_sg = sg;
- struct scatterlist *orig_dma_sg = dma_sg;
- int orig_nents = nents;
-
- for (;;) {
- nents = verify_one_map(dma_sg, &sg, nents, &iopte);
- if (nents <= 0)
- break;
- dma_sg = sg_next(dma_sg);
- if (dma_sg->dma_length == 0)
- break;
- }
-
- if (nents > 0) {
- printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
- nents);
- return -1;
- }
-
- if (nents < 0) {
- printk("verify_maps: Error, messed up mappings, "
- "at sg %d dma_sg %d\n",
- (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
- return -1;
- }
-
- /* This test passes... */
- return 0;
-}
-
-void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int npages)
-{
- struct scatterlist *sg;
-
- if (verify_lengths(sglist, nents, npages) < 0 ||
- verify_maps(sglist, nents, iopte) < 0) {
- int i;
-
- printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
- printk("%016lx.\n", sglist->dma_address & IO_PAGE_MASK);
-
- for_each_sg(sglist, sg, nents, i) {
- printk("sg(%d): page_addr(%p) off(%x) length(%x) "
- "dma_address[%016x] dma_length[%016x]\n",
- i,
- page_address(sg_page(sg)), sg->offset,
- sg->length,
- sg->dma_address, sg->dma_length);
- }
- }
-
- /* Seems to be ok */
-}
-#endif
-
-unsigned long prepare_sg(struct scatterlist *sg, int nents)
-{
- struct scatterlist *dma_sg = sg;
- unsigned long prev;
- u32 dent_addr, dent_len;
-
- prev = (unsigned long) sg_virt(sg);
- prev += (unsigned long) (dent_len = sg->length);
- dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL));
- while (--nents) {
- unsigned long addr;
-
- sg = sg_next(sg);
- addr = (unsigned long) sg_virt(sg);
- if (! VCONTIG(prev, addr)) {
- dma_sg->dma_address = dent_addr;
- dma_sg->dma_length = dent_len;
- dma_sg = sg_next(dma_sg);
-
- dent_addr = ((dent_addr +
- dent_len +
- (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
- dent_addr <<= IO_PAGE_SHIFT;
- dent_addr += addr & (IO_PAGE_SIZE - 1UL);
- dent_len = 0;
- }
- dent_len += sg->length;
- prev = addr + sg->length;
- }
- dma_sg->dma_address = dent_addr;
- dma_sg->dma_length = dent_len;
-
- if (dma_sg != sg) {
- dma_sg = sg_next(dma_sg);
- dma_sg->dma_length = 0;
- }
-
- return ((unsigned long) dent_addr +
- (unsigned long) dent_len +
- (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
-}
diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h
index 75b5a58..4b5cafa 100644
--- a/arch/sparc64/kernel/iommu_common.h
+++ b/arch/sparc64/kernel/iommu_common.h
@@ -9,6 +9,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
+#include <linux/device.h>
#include <asm/iommu.h>
#include <asm/scatterlist.h>
@@ -29,6 +30,32 @@
*/
#define IOMMU_PAGE_SHIFT 13
+#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG))))
+
+static inline unsigned long iommu_num_pages(unsigned long vaddr,
+ unsigned long slen)
+{
+ unsigned long npages;
+
+ npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK);
+ npages >>= IO_PAGE_SHIFT;
+
+ return npages;
+}
+
+static inline unsigned long calc_npages(struct scatterlist *sglist, int nelems)
+{
+ unsigned long i, npages = 0;
+ struct scatterlist *sg;
+
+ for_each_sg(sglist, sg, nelems, i) {
+ unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+ npages += iommu_num_pages(paddr, sg->length);
+ }
+
+ return npages;
+}
+
/* You are _strongly_ advised to enable the following debugging code
* any time you make changes to the sg code below, run it for a while
* with filesystems mounted read-only before buying the farm... -DaveM
@@ -46,4 +73,4 @@
#define VCONTIG(__X, __Y) (((__X) == (__Y)) || \
(((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL)
-extern unsigned long prepare_sg(struct scatterlist *sg, int nents);
+extern unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents);
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 1aa8e04..61baf8d 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -365,113 +365,14 @@
spin_unlock_irqrestore(&iommu->lock, flags);
}
-#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG))))
-
-static long fill_sg(long entry, struct device *dev,
- struct scatterlist *sg,
- int nused, int nelems, unsigned long prot)
-{
- struct scatterlist *dma_sg = sg;
- unsigned long flags;
- int i;
-
- local_irq_save(flags);
-
- iommu_batch_start(dev, prot, entry);
-
- for (i = 0; i < nused; i++) {
- unsigned long pteval = ~0UL;
- u32 dma_npages;
-
- dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
- dma_sg->dma_length +
- ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
- do {
- unsigned long offset;
- signed int len;
-
- /* If we are here, we know we have at least one
- * more page to map. So walk forward until we
- * hit a page crossing, and begin creating new
- * mappings from that spot.
- */
- for (;;) {
- unsigned long tmp;
-
- tmp = SG_ENT_PHYS_ADDRESS(sg);
- len = sg->length;
- if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
- pteval = tmp & IO_PAGE_MASK;
- offset = tmp & (IO_PAGE_SIZE - 1UL);
- break;
- }
- if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
- pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
- offset = 0UL;
- len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
- break;
- }
- sg = sg_next(sg);
- nelems--;
- }
-
- pteval = (pteval & IOPTE_PAGE);
- while (len > 0) {
- long err;
-
- err = iommu_batch_add(pteval);
- if (unlikely(err < 0L))
- goto iommu_map_failed;
-
- pteval += IO_PAGE_SIZE;
- len -= (IO_PAGE_SIZE - offset);
- offset = 0;
- dma_npages--;
- }
-
- pteval = (pteval & IOPTE_PAGE) + len;
- sg = sg_next(sg);
- nelems--;
-
- /* Skip over any tail mappings we've fully mapped,
- * adjusting pteval along the way. Stop when we
- * detect a page crossing event.
- */
- while (nelems &&
- (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
- (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
- ((pteval ^
- (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
- pteval += sg->length;
- sg = sg_next(sg);
- nelems--;
- }
- if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
- pteval = ~0UL;
- } while (dma_npages != 0);
- dma_sg = sg_next(dma_sg);
- }
-
- if (unlikely(iommu_batch_end() < 0L))
- goto iommu_map_failed;
-
- local_irq_restore(flags);
- return 0;
-
-iommu_map_failed:
- local_irq_restore(flags);
- return -1L;
-}
-
static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
+ unsigned long flags, npages, i, prot;
+ struct scatterlist *sg;
struct iommu *iommu;
- unsigned long flags, npages, prot;
- u32 dma_base;
- struct scatterlist *sgtmp;
long entry, err;
- int used;
+ u32 dma_base;
/* Fast path single entry scatterlists. */
if (nelems == 1) {
@@ -489,10 +390,8 @@
if (unlikely(direction == DMA_NONE))
goto bad;
- /* Step 1: Prepare scatter list. */
- npages = prepare_sg(sglist, nelems);
+ npages = calc_npages(sglist, nelems);
- /* Step 2: Allocate a cluster and context, if necessary. */
spin_lock_irqsave(&iommu->lock, flags);
entry = arena_alloc(&iommu->arena, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -503,27 +402,45 @@
dma_base = iommu->page_table_map_base +
(entry << IO_PAGE_SHIFT);
- /* Step 3: Normalize DMA addresses. */
- used = nelems;
-
- sgtmp = sglist;
- while (used && sgtmp->dma_length) {
- sgtmp->dma_address += dma_base;
- sgtmp = sg_next(sgtmp);
- used--;
- }
- used = nelems - used;
-
- /* Step 4: Create the mappings. */
prot = HV_PCI_MAP_ATTR_READ;
if (direction != DMA_TO_DEVICE)
prot |= HV_PCI_MAP_ATTR_WRITE;
- err = fill_sg(entry, dev, sglist, used, nelems, prot);
+ local_irq_save(flags);
+
+ iommu_batch_start(dev, prot, entry);
+
+ for_each_sg(sglist, sg, nelems, i) {
+ unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+ unsigned long slen = sg->length;
+ unsigned long this_npages;
+
+ this_npages = iommu_num_pages(paddr, slen);
+
+ sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
+ sg->dma_length = slen;
+
+ paddr &= IO_PAGE_MASK;
+ while (this_npages--) {
+ err = iommu_batch_add(paddr);
+ if (unlikely(err < 0L)) {
+ local_irq_restore(flags);
+ goto iommu_map_failed;
+ }
+
+ paddr += IO_PAGE_SIZE;
+ dma_base += IO_PAGE_SIZE;
+ }
+ }
+
+ err = iommu_batch_end();
+
+ local_irq_restore(flags);
+
if (unlikely(err < 0L))
goto iommu_map_failed;
- return used;
+ return nelems;
bad:
if (printk_ratelimit())
@@ -541,12 +458,11 @@
static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction)
{
+ unsigned long flags, npages;
struct pci_pbm_info *pbm;
- struct iommu *iommu;
- unsigned long flags, i, npages;
- struct scatterlist *sg, *sgprv;
- long entry;
u32 devhandle, bus_addr;
+ struct iommu *iommu;
+ long entry;
if (unlikely(direction == DMA_NONE)) {
if (printk_ratelimit())
@@ -558,16 +474,8 @@
devhandle = pbm->devhandle;
bus_addr = sglist->dma_address & IO_PAGE_MASK;
- sgprv = NULL;
- for_each_sg(sglist, sg, nelems, i) {
- if (sg->dma_length == 0)
- break;
- sgprv = sg;
- }
-
- npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) -
- bus_addr) >> IO_PAGE_SHIFT;
+ npages = calc_npages(sglist, nelems);
entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
@@ -625,8 +533,8 @@
/* XXX register error interrupt handlers XXX */
}
-static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
- struct iommu *iommu)
+static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm,
+ struct iommu *iommu)
{
struct iommu_arena *arena = &iommu->arena;
unsigned long i, cnt = 0;
@@ -653,7 +561,7 @@
return cnt;
}
-static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
struct property *prop;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index c399449..a8052b7 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -46,8 +46,6 @@
#include <asm/ldc.h>
#include <asm/hypervisor.h>
-extern void calibrate_delay(void);
-
int sparc64_multi_core __read_mostly;
cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 60765e3..8649635 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -277,6 +277,7 @@
EXPORT_SYMBOL(sys_geteuid);
EXPORT_SYMBOL(sys_getuid);
EXPORT_SYMBOL(sys_getegid);
+EXPORT_SYMBOL(sysctl_nr_open);
EXPORT_SYMBOL(sys_getgid);
EXPORT_SYMBOL(svr4_getcontext);
EXPORT_SYMBOL(svr4_setcontext);
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 06d10907..adc62f4 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -80,7 +80,8 @@
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
+/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
+ .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime
#endif /* CONFIG_COMPAT */
@@ -152,7 +153,8 @@
.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
+/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+ .word sys_timerfd_settime, sys_timerfd_gettime
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -271,6 +273,7 @@
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys
/*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys
- .word sunos_nosys, sunos_nosys
+ .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys
#endif
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 4352ee4..d204f1a 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1707,6 +1707,11 @@
misc_deregister(&rtc_mini_dev);
}
+int __devinit read_current_timer(unsigned long *timer_val)
+{
+ *timer_val = tick_ops->get_tick();
+ return 0;
+}
module_init(rtc_mini_init);
module_exit(rtc_mini_exit);
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 61be597..9311bfe 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -624,7 +624,7 @@
case 3: /* UL_GMEMLIM */
return current->signal->rlim[RLIMIT_DATA].rlim_cur;
case 4: /* UL_GDESLIM */
- return NR_OPEN;
+ return sysctl_nr_open;
}
return -EINVAL;
}
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
index a9d32ce..f53123c 100644
--- a/arch/sparc64/solaris/timod.c
+++ b/arch/sparc64/solaris/timod.c
@@ -859,7 +859,8 @@
SOLD("entry");
lock_kernel();
- if(fd >= NR_OPEN) goto out;
+ if (fd >= sysctl_nr_open)
+ goto out;
fdt = files_fdtable(current->files);
filp = fdt->fd[fd];
@@ -927,7 +928,8 @@
SOLD("entry");
lock_kernel();
- if(fd >= NR_OPEN) goto out;
+ if (fd >= sysctl_nr_open)
+ goto out;
fdt = files_fdtable(current->files);
filp = fdt->fd[fd];
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index dd1689b..99e51d0 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -68,6 +68,10 @@
bool
default y
+config HZ
+ int
+ default 100
+
menu "UML-specific options"
config STATIC_LINK
@@ -95,23 +99,6 @@
default y
depends on !LD_SCRIPT_STATIC
-config NET
- bool "Networking support"
- help
- Unless you really know what you are doing, you should say Y here.
- The reason is that some programs need kernel networking support even
- when running on a stand-alone machine that isn't connected to any
- other computer. If you are upgrading from an older kernel, you
- should consider updating your networking tools too because changes
- in the kernel and the tools often go hand in hand. The tools are
- contained in the package net-tools, the location and version number
- of which are given in <file:Documentation/Changes>.
-
- For a general introduction to Linux networking, it is highly
- recommended to read the NET-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
-
source "fs/Kconfig.binfmt"
config HOSTFS
@@ -145,7 +132,7 @@
by removing or changing anything in /proc which gives away the
identity of a UML.
- See <http://user-mode-linux.sf.net/hppfs.html> for more information.
+ See <http://user-mode-linux.sf.net/old/hppfs.html> for more information.
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
@@ -189,8 +176,7 @@
config SMP
bool "Symmetric multi-processing support (EXPERIMENTAL)"
default n
- #SMP_BROKEN is for x86_64.
- depends on EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
+ depends on BROKEN
help
This option enables UML SMP support.
It is NOT related to having a real SMP box. Not directly, at least.
@@ -289,6 +275,4 @@
bool
default n
-source "kernel/Kconfig.instrumentation"
-
source "arch/um/Kconfig.debug"
diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
index 9a78d35..3a4b396 100644
--- a/arch/um/Kconfig.char
+++ b/arch/um/Kconfig.char
@@ -18,7 +18,7 @@
lines on the UML that are usually made to show up on the host as
ttys or ptys.
- See <http://user-mode-linux.sourceforge.net/input.html> for more
+ See <http://user-mode-linux.sourceforge.net/old/input.html> for more
information and command line examples of how to use this facility.
Unless you have a specific reason for disabling this, say Y.
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index 1f6462f..8fce5e5 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -4,12 +4,12 @@
config GPROF
bool "Enable gprof support"
- depends on DEBUG_INFO
+ depends on DEBUG_INFO && FRAME_POINTER
help
This allows profiling of a User-Mode Linux kernel with the gprof
utility.
- See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+ See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more
details.
If you're involved in UML kernel development and want to use gprof,
@@ -22,7 +22,7 @@
This option allows developers to retrieve coverage data from a UML
session.
- See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+ See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more
details.
If you're involved in UML kernel development and want to use gcov,
diff --git a/arch/um/Kconfig.net b/arch/um/Kconfig.net
index 66e5002..9e9a4aa 100644
--- a/arch/um/Kconfig.net
+++ b/arch/um/Kconfig.net
@@ -14,7 +14,7 @@
For more information, including explanations of the networking and
sample configurations, see
- <http://user-mode-linux.sourceforge.net/networking.html>.
+ <http://user-mode-linux.sourceforge.net/old/networking.html>.
If you'd like to be able to enable networking in the User-Mode
linux environment, say Y; otherwise say N. Note that you must
@@ -38,7 +38,7 @@
CONFIG_NETLINK_DEV configured as Y or M.
For more information, see
- <http://user-mode-linux.sourceforge.net/networking.html> That site
+ <http://user-mode-linux.sourceforge.net/old/networking.html> That site
has examples of the UML command line to use to enable Ethertap
networking.
@@ -72,7 +72,7 @@
To use this, your host must support slip devices.
For more information, see
- <http://user-mode-linux.sourceforge.net/networking.html>. That site
+ <http://user-mode-linux.sourceforge.net/old/networking.html>.
has examples of the UML command line to use to enable slip
networking, and details of a few quirks with it.
@@ -96,7 +96,7 @@
networking daemon on the host.
For more information, see
- <http://user-mode-linux.sourceforge.net/networking.html> That site
+ <http://user-mode-linux.sourceforge.net/old/networking.html> That site
has examples of the UML command line to use to enable Daemon
networking.
@@ -144,7 +144,7 @@
To use this, your host kernel(s) must support IP Multicasting.
For more information, see
- <http://user-mode-linux.sourceforge.net/networking.html> That site
+ <http://user-mode-linux.sourceforge.net/old/networking.html> That site
has examples of the UML command line to use to enable Multicast
networking, and notes about the security of this approach.
@@ -165,7 +165,7 @@
installed in order to build the pcap transport into UML.
For more information, see
- <http://user-mode-linux.sourceforge.net/networking.html> That site
+ <http://user-mode-linux.sourceforge.net/old/networking.html> That site
has examples of the UML command line to use to enable this option.
If you intend to use UML as a network monitor for the host, say
diff --git a/arch/um/Makefile b/arch/um/Makefile
index ba6813a..cb4af9b 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -49,7 +49,7 @@
#
# These apply to USER_CFLAGS to.
-KBUILD_CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
-Din6addr_loopback=kernel_in6addr_loopback \
-Din6addr_any=kernel_in6addr_any
@@ -58,7 +58,7 @@
USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\
$(patsubst -I%,,$(KBUILD_CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \
- -D_FILE_OFFSET_BITS=64
+ $(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64
include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
@@ -130,7 +130,9 @@
# The wrappers will select whether using "malloc" or the kernel allocator.
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
-CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS)
+LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt))
+
+CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE)
define cmd_vmlinux__
$(CC) $(CFLAGS_vmlinux) -o $@ \
-Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
@@ -158,7 +160,7 @@
$(Q)mkdir -p $(objtree)/include/asm-um
$(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@
else
- $(Q)cd $(TOPDIR)/$(dir $@) ; \
+ $(Q)cd $(srctree)/$(dir $@) ; \
ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
endif
@@ -168,7 +170,7 @@
$(Q)mkdir -p $(objtree)/include/asm-um
$(Q)ln -fsn $(srctree)/include/asm-$(HEADER_ARCH) include/asm-um/arch
else
- $(Q)cd $(TOPDIR)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) arch
+ $(Q)cd $(srctree)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) arch
endif
$(objtree)/$(ARCH_DIR)/include:
diff --git a/arch/um/Makefile-tt b/arch/um/Makefile-tt
deleted file mode 100644
index 03f7b10..0000000
--- a/arch/um/Makefile-tt
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
-# Licensed under the GPL
-#
-
diff --git a/arch/um/defconfig b/arch/um/defconfig
index f609ede..86db286 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -77,7 +77,7 @@
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-# CONFIG_HOSTFS is not set
+CONFIG_HOSTFS=y
# CONFIG_HPPFS is not set
CONFIG_MCONSOLE=y
CONFIG_MAGIC_SYSRQ=y
@@ -188,7 +188,7 @@
CONFIG_SSL_CHAN="pts"
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LEGACY_PTY_COUNT=32
# CONFIG_WATCHDOG is not set
CONFIG_UML_SOUND=m
CONFIG_SOUND=m
@@ -508,7 +508,7 @@
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SLAB_LEAK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK is not set
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 83bf15a..2c898c4 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -8,6 +8,7 @@
#include "chan_kern.h"
#include "irq_kern.h"
#include "irq_user.h"
+#include "kern_util.h"
#include "os.h"
#define LINE_BUFSIZE 4096
@@ -48,7 +49,7 @@
n = line->head - line->tail;
if (n <= 0)
- n = LINE_BUFSIZE + n; /* The other case */
+ n += LINE_BUFSIZE; /* The other case */
return n - 1;
}
@@ -58,17 +59,10 @@
unsigned long flags;
int room;
- if (tty->stopped)
- return 0;
-
spin_lock_irqsave(&line->lock, flags);
room = write_room(line);
spin_unlock_irqrestore(&line->lock, flags);
- /*XXX: Warning to remove */
- if (0 == room)
- printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
- __FUNCTION__,tty->name);
return room;
}
@@ -79,8 +73,7 @@
int ret;
spin_lock_irqsave(&line->lock, flags);
-
- /*write_room subtracts 1 for the needed NULL, so we readd it.*/
+ /* write_room subtracts 1 for the needed NULL, so we readd it.*/
ret = LINE_BUFSIZE - (write_room(line) + 1);
spin_unlock_irqrestore(&line->lock, flags);
@@ -184,10 +177,6 @@
unsigned long flags;
int err;
- /*XXX: copied from line_write, verify if it is correct!*/
- if (tty->stopped)
- return;
-
spin_lock_irqsave(&line->lock, flags);
err = flush_buffer(line);
spin_unlock_irqrestore(&line->lock, flags);
@@ -213,9 +202,6 @@
unsigned long flags;
int n, ret = 0;
- if (tty->stopped)
- return 0;
-
spin_lock_irqsave(&line->lock, flags);
if (line->head != line->tail)
ret = buffer_data(line, buf, len);
@@ -788,9 +774,11 @@
tty = winch->tty;
if (tty != NULL) {
line = tty->driver_data;
- chan_window_size(&line->chan_list, &tty->winsize.ws_row,
- &tty->winsize.ws_col);
- kill_pgrp(tty->pgrp, SIGWINCH, 1);
+ if (line != NULL) {
+ chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+ &tty->winsize.ws_col);
+ kill_pgrp(tty->pgrp, SIGWINCH, 1);
+ }
}
out:
if (winch->fd != -1)
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 0f3c7d1..ebb265c 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -1,23 +1,25 @@
/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/console.h"
-#include "linux/ctype.h"
-#include "linux/interrupt.h"
-#include "linux/list.h"
-#include "linux/mm.h"
-#include "linux/module.h"
-#include "linux/notifier.h"
-#include "linux/reboot.h"
-#include "linux/proc_fs.h"
-#include "linux/slab.h"
-#include "linux/syscalls.h"
-#include "linux/utsname.h"
-#include "linux/workqueue.h"
-#include "asm/uaccess.h"
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/utsname.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+
#include "init.h"
#include "irq_kern.h"
#include "irq_user.h"
@@ -305,7 +307,9 @@
deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
os_set_fd_block(req->originating_fd, 1);
mconsole_reply(req, "stopped", 0, 0);
- while (mconsole_get_request(req->originating_fd, req)) {
+ for (;;) {
+ if (!mconsole_get_request(req->originating_fd, req))
+ continue;
if (req->cmd->handler == mconsole_go)
break;
if (req->cmd->handler == mconsole_stop) {
@@ -358,7 +362,7 @@
void *pages[UNPLUGGED_PER_PAGE];
};
-static DECLARE_MUTEX(plug_mem_mutex);
+static DEFINE_MUTEX(plug_mem_mutex);
static unsigned long long unplugged_pages_count = 0;
static LIST_HEAD(unplugged_pages);
static int unplug_index = UNPLUGGED_PER_PAGE;
@@ -394,7 +398,7 @@
diff /= PAGE_SIZE;
- down(&plug_mem_mutex);
+ mutex_lock(&plug_mem_mutex);
for (i = 0; i < diff; i++) {
struct unplugged_pages *unplugged;
void *addr;
@@ -451,7 +455,7 @@
err = 0;
out_unlock:
- up(&plug_mem_mutex);
+ mutex_unlock(&plug_mem_mutex);
out:
return err;
}
@@ -741,7 +745,6 @@
{
char *ptr = req->request.data;
int pid_requested= -1;
- struct task_struct *from = NULL;
struct task_struct *to = NULL;
/*
@@ -763,9 +766,7 @@
return;
}
- from = current;
-
- to = find_task_by_pid(pid_requested);
+ to = find_task_by_pid_ns(pid_requested, &init_pid_ns);
if ((to == NULL) || (pid_requested == 0)) {
mconsole_reply(req, "Couldn't find that pid", 1, 0);
return;
@@ -795,6 +796,8 @@
printk(KERN_ERR "Failed to initialize management console\n");
return 1;
}
+ if (os_set_fd_block(sock, 0))
+ goto out;
register_reboot_notifier(&reboot_notifier);
@@ -803,7 +806,7 @@
"mconsole", (void *)sock);
if (err) {
printk(KERN_ERR "Failed to get IRQ for management console\n");
- return 1;
+ goto out;
}
if (notify_socket != NULL) {
@@ -819,6 +822,10 @@
printk(KERN_INFO "mconsole (version %d) initialized on %s\n",
MCONSOLE_VERSION, mconsole_socket_name);
return 0;
+
+ out:
+ os_close_file(sock);
+ return 1;
}
__initcall(mconsole_init);
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 430c024..13af2f0 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -83,9 +83,8 @@
int len;
req->originlen = sizeof(req->origin);
- req->len = recvfrom(fd, &req->request, sizeof(req->request),
- MSG_DONTWAIT, (struct sockaddr *) req->origin,
- &req->originlen);
+ req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
+ (struct sockaddr *) req->origin, &req->originlen);
if (req->len < 0)
return 0;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 3c6c44c..1e8f41a 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -318,7 +318,7 @@
if (str == NULL)
goto random;
- for (i = 0;i < 6; i++) {
+ for (i = 0; i < 6; i++) {
addr[i] = simple_strtoul(str, &end, 16);
if ((end == str) ||
((*end != ':') && (*end != ',') && (*end != '\0'))) {
@@ -343,14 +343,13 @@
}
if (!is_local_ether_addr(addr)) {
printk(KERN_WARNING
- "Warning: attempt to assign a globally valid ethernet "
+ "Warning: Assigning a globally valid ethernet "
"address to a device\n");
- printk(KERN_WARNING "You should better enable the 2nd "
- "rightmost bit in the first byte of the MAC,\n");
+ printk(KERN_WARNING "You should set the 2nd rightmost bit in "
+ "the first byte of the MAC,\n");
printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n",
addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4],
addr[5]);
- goto random;
}
return;
@@ -368,7 +367,6 @@
.name = DRIVER_NAME,
},
};
-static int driver_registered;
static void net_device_release(struct device *dev)
{
@@ -383,6 +381,12 @@
free_netdev(netdev);
}
+/*
+ * Ensures that platform_driver_register is called only once by
+ * eth_configure. Will be set in an initcall.
+ */
+static int driver_registered;
+
static void eth_configure(int n, void *init, char *mac,
struct transport *transport)
{
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 29185ca..abf2653 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -201,7 +201,7 @@
close(fds[1]);
if (pid > 0)
- helper_wait(pid, 0, "change_tramp");
+ helper_wait(pid);
return pid;
}
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index 330543b..1993008 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -6,6 +6,7 @@
#include "linux/completion.h"
#include "linux/interrupt.h"
#include "linux/list.h"
+#include "linux/mutex.h"
#include "asm/atomic.h"
#include "init.h"
#include "irq_kern.h"
@@ -120,7 +121,7 @@
return 0;
}
-static DECLARE_MUTEX(ports_sem);
+static DEFINE_MUTEX(ports_mutex);
static LIST_HEAD(ports);
static void port_work_proc(struct work_struct *unused)
@@ -161,7 +162,7 @@
struct port_dev *dev = NULL;
int fd;
- down(&ports_sem);
+ mutex_lock(&ports_mutex);
list_for_each(ele, &ports) {
port = list_entry(ele, struct port_list, list);
if (port->port == port_num)
@@ -216,7 +217,7 @@
out_free:
kfree(port);
out:
- up(&ports_sem);
+ mutex_unlock(&ports_mutex);
return dev;
}
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index e942e83..71f0959 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -5,6 +5,7 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
+#include <linux/sched.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index b8711e5..8b80505 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -109,7 +109,7 @@
read_output(fds[0], output, output_len);
printk("%s", output);
- err = helper_wait(pid, 0, argv[0]);
+ err = helper_wait(pid);
close(fds[0]);
out_free:
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index 89c1be2..a0ada8f 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -98,7 +98,7 @@
"(%d)\n", pri->pid, errno);
}
#endif
- err = helper_wait(pri->pid, 1, "slirp_close");
+ err = helper_wait(pri->pid);
if (err < 0)
return;
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 875d60d..f1786e6 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -15,7 +15,6 @@
#include "line.h"
#include "ssl.h"
#include "chan_kern.h"
-#include "kern_util.h"
#include "kern.h"
#include "init.h"
#include "irq_user.h"
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 656036e..cec0c33 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -22,7 +22,6 @@
#include "stdio_console.h"
#include "line.h"
#include "chan_kern.h"
-#include "kern_util.h"
#include "irq_user.h"
#include "mconsole_kern.h"
#include "init.h"
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 99f9f96..be3a279 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -49,6 +49,7 @@
#include "irq_user.h"
#include "irq_kern.h"
#include "ubd_user.h"
+#include "kern_util.h"
#include "os.h"
#include "mem.h"
#include "mem_kern.h"
@@ -229,7 +230,7 @@
return len;
}
-static void make_ide_entries(char *dev_name)
+static void make_ide_entries(const char *dev_name)
{
struct proc_dir_entry *dir, *ent;
char name[64];
@@ -244,7 +245,7 @@
ent->data = NULL;
ent->read_proc = proc_ide_read_media;
ent->write_proc = NULL;
- sprintf(name,"ide0/%s", dev_name);
+ snprintf(name, sizeof(name), "ide0/%s", dev_name);
proc_symlink(dev_name, proc_ide_root, name);
}
@@ -437,7 +438,10 @@
" machine by running 'dd' on the device. <n> must be in the range\n"
" 0 to 7. Appending an 'r' to the number will cause that device\n"
" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
-" an 's' will cause data to be written to disk on the host immediately.\n\n"
+" an 's' will cause data to be written to disk on the host immediately.\n"
+" 'c' will cause the device to be treated as being shared between multiple\n"
+" UMLs and file locking will be turned off - this is appropriate for a\n"
+" cluster filesystem and inappropriate at almost all other times.\n\n"
);
static int udb_setup(char *str)
@@ -456,20 +460,6 @@
" in the boot output.\n\n"
);
-static int fakehd_set = 0;
-static int fakehd(char *str)
-{
- printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
- fakehd_set = 1;
- return 1;
-}
-
-__setup("fakehd", fakehd);
-__uml_help(fakehd,
-"fakehd\n"
-" Change the ubd device name to \"hd\".\n\n"
-);
-
static void do_ubd_request(struct request_queue * q);
/* Only changed by ubd_init, which is an initcall. */
@@ -718,8 +708,10 @@
ubd_disk_register(fake_major, ubd_dev->size, n,
&fake_gendisk[n]);
- /* perhaps this should also be under the "if (fake_major)" above */
- /* using the fake_disk->disk_name and also the fakehd_set name */
+ /*
+ * Perhaps this should also be under the "if (fake_major)" above
+ * using the fake_disk->disk_name
+ */
if (fake_ide)
make_ide_entries(ubd_gendisk[n]->disk_name);
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index 48fc745..b591bb9 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -16,7 +16,6 @@
#include <sys/mman.h>
#include <sys/param.h>
#include "asm/types.h"
-#include "kern_util.h"
#include "user.h"
#include "ubd_user.h"
#include "os.h"
diff --git a/arch/um/drivers/vde_user.c b/arch/um/drivers/vde_user.c
index d9941fe..56533db 100644
--- a/arch/um/drivers/vde_user.c
+++ b/arch/um/drivers/vde_user.c
@@ -80,7 +80,7 @@
vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
if (vpri->args == NULL) {
- printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args"
+ printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args "
"allocation failed");
return;
}
diff --git a/arch/um/include/arch.h b/arch/um/include/arch.h
index 49c601ff..2de92a0 100644
--- a/arch/um/include/arch.h
+++ b/arch/um/include/arch.h
@@ -10,6 +10,6 @@
extern void arch_check_bugs(void);
extern int arch_fixup(unsigned long address, struct uml_pt_regs *regs);
-extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
+extern void arch_examine_signal(int sig, struct uml_pt_regs *regs);
#endif
diff --git a/arch/um/include/as-layout.h b/arch/um/include/as-layout.h
index a5cdf95..606bb5c 100644
--- a/arch/um/include/as-layout.h
+++ b/arch/um/include/as-layout.h
@@ -10,24 +10,32 @@
#include "kern_constants.h"
/*
- * Assembly doesn't want any casting, but C does, so define these
- * without casts here, and define new symbols with casts inside the C
- * section.
+ * Stolen from linux/const.h, which can't be directly included since
+ * this is used in userspace code, which has no access to the kernel
+ * headers. Changed to be suitable for adding casts to the start,
+ * rather than "UL" to the end.
*/
-#define ASM_STUB_CODE (UML_CONFIG_TOP_ADDR - 2 * UM_KERN_PAGE_SIZE)
-#define ASM_STUB_DATA (UML_CONFIG_TOP_ADDR - UM_KERN_PAGE_SIZE)
-#define ASM_STUB_START ASM_STUB_CODE
-/*
- * This file is included by the assembly stubs, which just want the
- * definitions above.
+/* Some constant macros are used in both assembler and
+ * C code. Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally. We
+ * use the following macros to deal with this.
*/
+
+#ifdef __ASSEMBLY__
+#define _AC(X, Y) (Y)
+#else
+#define __AC(X, Y) (X (Y))
+#define _AC(X, Y) __AC(X, Y)
+#endif
+
+#define STUB_START _AC(, 0x100000)
+#define STUB_CODE _AC((unsigned long), STUB_START)
+#define STUB_DATA _AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE)
+#define STUB_END _AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE)
+
#ifndef __ASSEMBLY__
-#define STUB_CODE ((unsigned long) ASM_STUB_CODE)
-#define STUB_DATA ((unsigned long) ASM_STUB_DATA)
-#define STUB_START ((unsigned long) ASM_STUB_START)
-
#include "sysdep/ptrace.h"
struct cpu_task {
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index 5a2263e..9b9ced8 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -48,7 +48,7 @@
#define __channel_help(fn, prefix) \
__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
" Attach a console or serial line to a host channel. See\n" \
-" http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
+" http://user-mode-linux.sourceforge.net/old/input.html for a complete\n" \
" description of this switch.\n\n" \
);
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 0edab69..b54bd35 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -18,6 +18,7 @@
DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
DEFINE_STR(UM_KERN_INFO, KERN_INFO);
DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+DEFINE_STR(UM_KERN_CONT, KERN_CONT);
DEFINE(UM_ELF_CLASS, ELF_CLASS);
DEFINE(UM_ELFCLASS32, ELFCLASS32);
diff --git a/arch/um/include/init.h b/arch/um/include/init.h
index cebc6cae..b00a9574 100644
--- a/arch/um/include/init.h
+++ b/arch/um/include/init.h
@@ -40,6 +40,20 @@
typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void);
+#ifndef __KERNEL__
+#ifndef __section
+# define __section(S) __attribute__ ((__section__(#S)))
+#endif
+
+#if __GNUC_MINOR__ >= 3
+# define __used __attribute__((__used__))
+#else
+# define __used __attribute__((__unused__))
+#endif
+
+#else
+#include <linux/compiler.h>
+#endif
/* These are for everybody (although not all archs will actually
discard it in modules) */
#define __init __section(.init.text)
@@ -127,14 +141,3 @@
#endif
#endif /* _LINUX_UML_INIT_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h
index 884a9c1..e60b318 100644
--- a/arch/um/include/irq_user.h
+++ b/arch/um/include/irq_user.h
@@ -14,7 +14,6 @@
int fd;
int type;
int irq;
- int pid;
int events;
int current_events;
};
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 74ce8e5..3c34122 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -9,107 +9,61 @@
#include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h"
-typedef void (*kern_hndl)(int, struct uml_pt_regs *);
-
-struct kern_handlers {
- kern_hndl relay_signal;
- kern_hndl winch;
- kern_hndl bus_handler;
- kern_hndl page_fault;
- kern_hndl sigio_handler;
- kern_hndl timer_handler;
-};
-
-extern const struct kern_handlers handlinfo_kern;
+extern int uml_exitcode;
extern int ncpus;
-extern char *gdb_init;
extern int kmalloc_ok;
-extern int jail;
-extern int nsyscalls;
-#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
#define UML_ROUND_UP(addr) \
- UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
+ ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK)
-extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
-extern int kernel_thread_proc(void *data);
-extern void syscall_segv(int sig);
-extern int current_pid(void);
extern unsigned long alloc_stack(int order, int atomic);
+extern void free_stack(unsigned long stack, int order);
+
extern int do_signal(void);
-extern int is_stack_fault(unsigned long sp);
+extern void copy_sc(struct uml_pt_regs *regs, void *from);
+extern void interrupt_end(void);
+extern void relay_signal(int sig, struct uml_pt_regs *regs);
+
extern unsigned long segv(struct faultinfo fi, unsigned long ip,
int is_user, struct uml_pt_regs *regs);
extern int handle_page_fault(unsigned long address, unsigned long ip,
int is_write, int is_user, int *code_out);
-extern void syscall_ready(void);
-extern void set_tracing(void *t, int tracing);
-extern int is_tracing(void *task);
-extern int segv_syscall(void);
-extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
-extern unsigned long page_mask(void);
-extern int need_finish_fork(void);
-extern void free_stack(unsigned long stack, int order);
-extern void add_input_request(int op, void (*proc)(int), void *arg);
-extern char *current_cmd(void);
-extern void timer_handler(int sig, struct uml_pt_regs *regs);
-extern int set_signals(int enable);
-extern int pid_to_processor_id(int pid);
-extern void deliver_signals(void *t);
-extern int next_trap_index(int max);
-extern void default_idle(void);
-extern void finish_fork(void);
-extern void paging_init(void);
-extern void init_flush_vm(void);
-extern void *syscall_sp(void *t);
-extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
+
extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
-extern void interrupt_end(void);
-extern void initial_thread_cb(void (*proc)(void *), void *arg);
-extern int debugger_signal(int status, int pid);
-extern void debugger_parent_signal(int status, int pid);
-extern void child_signal(int pid, int status);
-extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
-extern int init_parent_proxy(int pid);
-extern int singlestepping(void *t);
-extern void check_stack_overflow(void *ptr);
-extern void relay_signal(int sig, struct uml_pt_regs *regs);
-extern int user_context(unsigned long sp);
-extern void timer_irq(struct uml_pt_regs *regs);
-extern void do_uml_exitcalls(void);
-extern int attach_debugger(int idle_pid, int pid, int stop);
-extern int config_gdb(char *str);
-extern int remove_gdb(void);
-extern char *uml_strdup(char *string);
-extern void unprotect_kernel_mem(void);
-extern void protect_kernel_mem(void);
-extern void uml_cleanup(void);
-extern void lock_signalled_task(void *t);
-extern void IPI_handler(int cpu);
-extern int jail_setup(char *line, int *add);
-extern void *get_init_task(void);
-extern int clear_user_proc(void *buf, int size);
-extern int copy_to_user_proc(void *to, void *from, int size);
-extern int copy_from_user_proc(void *to, void *from, int size);
-extern int strlen_user_proc(char *str);
-extern long execute_syscall(void *r);
extern int smp_sigio_handler(void);
-extern void *get_current(void);
-extern struct task_struct *get_task(int pid, int require);
-extern void machine_halt(void);
+extern void initial_thread_cb(void (*proc)(void *), void *arg);
extern int is_syscall(unsigned long addr);
+extern void timer_handler(int sig, struct uml_pt_regs *regs);
-extern void free_irq(unsigned int, void *);
-extern int cpu(void);
+extern void timer_handler(int sig, struct uml_pt_regs *regs);
-extern void time_init_kern(void);
-
-/* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */
-extern int __cant_sleep(void);
-extern void sigio_handler(int sig, struct uml_pt_regs *regs);
-extern void copy_sc(struct uml_pt_regs *regs, void *from);
-extern unsigned long to_irq_stack(unsigned long *mask_out);
-unsigned long from_irq_stack(int nested);
extern int start_uml(void);
+extern void paging_init(void);
+
+extern void uml_cleanup(void);
+extern void do_uml_exitcalls(void);
+
+/*
+ * Are we disallowed to sleep? Used to choose between GFP_KERNEL and
+ * GFP_ATOMIC.
+ */
+extern int __cant_sleep(void);
+extern void *get_current(void);
+extern int copy_from_user_proc(void *to, void *from, int size);
+extern int cpu(void);
+extern char *uml_strdup(const char *string);
+
+extern unsigned long to_irq_stack(unsigned long *mask_out);
+extern unsigned long from_irq_stack(int nested);
+
+extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
+extern int singlestepping(void *t);
+
+extern void segv_handler(int sig, struct uml_pt_regs *regs);
+extern void bus_handler(int sig, struct uml_pt_regs *regs);
+extern void winch(int sig, struct uml_pt_regs *regs);
+extern void fatal_sigsegv(void) __attribute__ ((noreturn));
+
+
#endif
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
index a54514d..46384acd 100644
--- a/arch/um/include/mem_user.h
+++ b/arch/um/include/mem_user.h
@@ -46,9 +46,6 @@
#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
-extern unsigned long host_task_size;
-extern unsigned long task_size;
-
extern int init_mem_user(void);
extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
@@ -59,9 +56,7 @@
unsigned long len, unsigned long long highmem);
extern void add_iomem(char *name, int fd, unsigned long size);
extern unsigned long phys_offset(unsigned long phys);
-extern void unmap_physmem(void);
extern void map_memory(unsigned long virt, unsigned long phys,
unsigned long len, int r, int w, int x);
-extern unsigned long get_kmem_end(void);
#endif
diff --git a/arch/um/include/misc_constants.h b/arch/um/include/misc_constants.h
deleted file mode 100644
index 989bc08..0000000
--- a/arch/um/include/misc_constants.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __MISC_CONSTANT_H_
-#define __MISC_CONSTANT_H_
-
-#include <user_constants.h>
-
-#endif
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 6f0d1c7..0b6b627 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -8,7 +8,6 @@
#include <stdarg.h>
#include "irq_user.h"
-#include "kern_util.h"
#include "longjmp.h"
#include "mm_id.h"
#include "sysdep/tls.h"
@@ -128,33 +127,31 @@
extern int os_stat_file(const char *file_name, struct uml_stat *buf);
extern int os_stat_fd(const int fd, struct uml_stat *buf);
extern int os_access(const char *file, int mode);
-extern int os_get_exec_close(int fd, int *close_on_exec);
extern int os_set_exec_close(int fd);
extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
extern int os_get_ifname(int fd, char *namebuf);
extern int os_set_slip(int fd);
-extern int os_set_owner(int fd, int pid);
extern int os_mode_fd(int fd, int mode);
extern int os_seek_file(int fd, unsigned long long offset);
-extern int os_open_file(char *file, struct openflags flags, int mode);
+extern int os_open_file(const char *file, struct openflags flags, int mode);
extern int os_read_file(int fd, void *buf, int len);
extern int os_write_file(int fd, const void *buf, int count);
-extern int os_file_size(char *file, unsigned long long *size_out);
-extern int os_file_modtime(char *file, unsigned long *modtime);
+extern int os_file_size(const char *file, unsigned long long *size_out);
+extern int os_file_modtime(const char *file, unsigned long *modtime);
extern int os_pipe(int *fd, int stream, int close_on_exec);
-extern int os_set_fd_async(int fd, int owner);
+extern int os_set_fd_async(int fd);
extern int os_clear_fd_async(int fd);
extern int os_set_fd_block(int fd, int blocking);
extern int os_accept_connection(int fd);
-extern int os_create_unix_socket(char *file, int len, int close_on_exec);
+extern int os_create_unix_socket(const char *file, int len, int close_on_exec);
extern int os_shutdown_socket(int fd, int r, int w);
extern void os_close_file(int fd);
extern int os_rcv_fd(int fd, int *helper_pid_out);
extern int create_unix_socket(char *file, int len, int close_on_exec);
-extern int os_connect_socket(char *name);
+extern int os_connect_socket(const char *name);
extern int os_file_type(char *file);
-extern int os_file_mode(char *file, struct openflags *mode_out);
+extern int os_file_mode(const char *file, struct openflags *mode_out);
extern int os_lock_file(int fd, int excl);
extern void os_flush_stdout(void);
extern int os_stat_filesystem(char *path, long *bsize_out,
@@ -168,14 +165,10 @@
/* start_up.c */
extern void os_early_checks(void);
-extern int can_do_skas(void);
+extern void can_do_skas(void);
extern void os_check_bugs(void);
extern void check_host_supports_tls(int *supports_tls, int *tls_min);
-/* Make sure they are clear when running in TT mode. Required by
- * SEGV_MAYBE_FIXABLE */
-#define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0)
-
/* mem.c */
extern int create_mem_file(unsigned long long len);
@@ -214,7 +207,7 @@
extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv);
extern int run_helper_thread(int (*proc)(void *), void *arg,
unsigned int flags, unsigned long *stack_out);
-extern int helper_wait(int pid, int nohang, char *pname);
+extern int helper_wait(int pid);
/* tls.c */
@@ -237,16 +230,12 @@
extern int get_signals(void);
extern int set_signals(int enable);
-/* trap.c */
-extern void os_fill_handlinfo(struct kern_handlers h);
-
/* util.c */
extern void stack_protections(unsigned long address);
extern int raw(int fd);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(char *buf, int len);
-extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
-extern void os_dump_core(void);
+extern void os_dump_core(void) __attribute__ ((noreturn));
/* time.c */
extern void idle_sleep(unsigned long long nsecs);
@@ -275,11 +264,9 @@
extern int is_skas_winch(int pid, int fd, void *data);
extern int start_userspace(unsigned long stub_stack);
extern int copy_context_skas0(unsigned long stack, int pid);
-extern void save_registers(int pid, struct uml_pt_regs *regs);
-extern void restore_registers(int pid, struct uml_pt_regs *regs);
extern void userspace(struct uml_pt_regs *regs);
-extern void map_stub_pages(int fd, unsigned long code,
- unsigned long data, unsigned long stack);
+extern int map_stub_pages(int fd, unsigned long code, unsigned long data,
+ unsigned long stack);
extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
extern void switch_threads(jmp_buf *me, jmp_buf *you);
extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
@@ -298,16 +285,12 @@
extern int os_get_pollfd(int i);
extern void os_set_pollfd(int i, int fd);
extern void os_set_ioignore(void);
-extern void init_irq_signals(int on_sigstack);
/* sigio.c */
extern int add_sigio_fd(int fd);
extern int ignore_sigio_fd(int fd);
extern void maybe_sigio_broken(int fd, int read);
-/* skas/trap */
-extern void sig_handler_common_skas(int sig, void *sc_ptr);
-
/* sys-x86_64/prctl.c */
extern int os_arch_prctl(int pid, int code, unsigned long *addr);
diff --git a/arch/um/include/ptrace_user.h b/arch/um/include/ptrace_user.h
index f3450e6..4bce6e0 100644
--- a/arch/um/include/ptrace_user.h
+++ b/arch/um/include/ptrace_user.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -10,12 +10,6 @@
extern int ptrace_getregs(long pid, unsigned long *regs_out);
extern int ptrace_setregs(long pid, unsigned long *regs_in);
-extern int ptrace_getfpregs(long pid, unsigned long *regs_out);
-extern int ptrace_setfpregs(long pid, unsigned long *regs);
-extern void arch_enter_kernel(void *task, int pid);
-extern void arch_leave_kernel(void *task, int pid);
-extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
-
/* syscall emulation path in ptrace */
@@ -54,7 +48,8 @@
(((int[3][3] ) { \
{ PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \
{ PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \
- { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, PTRACE_SYSEMU_SINGLESTEP }}) \
+ { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \
+ PTRACE_SYSEMU_SINGLESTEP } }) \
[sysemu_mode][singlestep_mode])
#endif
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
index 0e27406..9ea1ae3 100644
--- a/arch/um/include/registers.h
+++ b/arch/um/include/registers.h
@@ -9,14 +9,13 @@
#include "sysdep/ptrace.h"
#include "sysdep/archsetjmp.h"
-extern void init_thread_registers(struct uml_pt_regs *to);
extern int save_fp_registers(int pid, unsigned long *fp_regs);
extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern int save_fpx_registers(int pid, unsigned long *fp_regs);
extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
-extern void save_registers(int pid, struct uml_pt_regs *regs);
-extern void restore_registers(int pid, struct uml_pt_regs *regs);
-extern void init_registers(int pid);
+extern int save_registers(int pid, struct uml_pt_regs *regs);
+extern int restore_registers(int pid, struct uml_pt_regs *regs);
+extern int init_registers(int pid);
extern void get_safe_registers(unsigned long *regs);
extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
diff --git a/arch/um/include/signal_kern.h b/arch/um/include/signal_kern.h
deleted file mode 100644
index aeb5d5a..0000000
--- a/arch/um/include/signal_kern.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SIGNAL_KERN_H__
-#define __SIGNAL_KERN_H__
-
-extern int have_signals(void *t);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h
deleted file mode 100644
index e065feb..0000000
--- a/arch/um/include/skas/mode-skas.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
- * Licensed under the GPL
- */
-
-#ifndef __MODE_SKAS_H__
-#define __MODE_SKAS_H__
-
-extern void kill_off_processes_skas(void);
-
-#endif
diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h
index 57bd79e..9056981 100644
--- a/arch/um/include/sysdep-i386/syscalls.h
+++ b/arch/um/include/sysdep-i386/syscalls.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -18,7 +18,8 @@
extern syscall_handler_t *sys_call_table[];
#define EXECUTE_SYSCALL(syscall, regs) \
- ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs))
+ ((long (*)(struct syscall_args)) \
+ (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs))
extern long sys_mmap2(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h
index c978b58..a307237 100644
--- a/arch/um/include/sysdep-x86_64/kernel-offsets.h
+++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h
@@ -17,16 +17,7 @@
#define OFFSET(sym, str, mem) \
DEFINE(sym, offsetof(struct str, mem));
-#define __NO_STUBS 1
-#undef __SYSCALL
-#undef _ASM_X86_64_UNISTD_H_
-#define __SYSCALL(nr, sym) [nr] = 1,
-static char syscalls[] = {
-#include <asm/arch/unistd.h>
-};
-
void foo(void)
{
#include <common-offsets.h>
-DEFINE(UM_NR_syscall_max, sizeof(syscalls) - 1);
}
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h
index cf72256..7cfb0b08 100644
--- a/arch/um/include/sysdep-x86_64/syscalls.h
+++ b/arch/um/include/sysdep-x86_64/syscalls.h
@@ -30,6 +30,4 @@
extern syscall_handler_t sys_modify_ldt;
extern syscall_handler_t sys_arch_prctl;
-#define NR_syscalls (UM_NR_syscall_max + 1)
-
#endif
diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h
index 8855d8d..82865fc 100644
--- a/arch/um/include/um_mmu.h
+++ b/arch/um/include/um_mmu.h
@@ -12,10 +12,6 @@
typedef struct mm_context {
struct mm_id id;
- unsigned long last_page_table;
-#ifdef CONFIG_3_LEVEL_PGTABLES
- unsigned long last_pmd;
-#endif
struct uml_ldt ldt;
} mm_context_t;
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index fdfc06b..2b6fc8e 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -6,7 +6,9 @@
#ifndef __ARCH_UM_UACCESS_H
#define __ARCH_UM_UACCESS_H
-#include "asm/fixmap.h"
+#include <asm/elf.h>
+#include <asm/fixmap.h>
+#include "sysdep/archsetjmp.h"
#define __under_task_size(addr, size) \
(((unsigned long) (addr) < TASK_SIZE) && \
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 8196450..76a62c0 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -19,12 +19,13 @@
void flush_thread(void)
{
void *data = NULL;
- unsigned long end = proc_mm ? task_size : STUB_START;
int ret;
arch_flush_thread(¤t->thread.arch);
- ret = unmap(¤t->mm->context.id, 0, end, 1, &data);
+ ret = unmap(¤t->mm->context.id, 0, STUB_START, 0, &data);
+ ret = ret || unmap(¤t->mm->context.id, STUB_END,
+ TASK_SIZE - STUB_END, 1, &data);
if (ret) {
printk(KERN_ERR "flush_thread - clearing address space failed, "
"err = %d\n", ret);
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
index c716b5a..984f80e 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -1,15 +1,17 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/kernel.h"
-#include "linux/init.h"
-#include "linux/ctype.h"
-#include "linux/proc_fs.h"
-#include "asm/uaccess.h"
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
-/* If read and write race, the read will still atomically read a valid
+/*
+ * If read and write race, the read will still atomically read a valid
* value.
*/
int uml_exitcode = 0;
@@ -19,18 +21,19 @@
{
int len, val;
- /* Save uml_exitcode in a local so that we don't need to guarantee
+ /*
+ * Save uml_exitcode in a local so that we don't need to guarantee
* that sprintf accesses it atomically.
*/
val = uml_exitcode;
len = sprintf(page, "%d\n", val);
len -= off;
- if(len <= off+count)
+ if (len <= off+count)
*eof = 1;
*start = page + off;
- if(len > count)
+ if (len > count)
len = count;
- if(len < 0)
+ if (len < 0)
len = 0;
return len;
}
@@ -41,11 +44,11 @@
char *end, buf[sizeof("nnnnn\0")];
int tmp;
- if(copy_from_user(buf, buffer, count))
+ if (copy_from_user(buf, buffer, count))
return -EFAULT;
tmp = simple_strtol(buf, &end, 0);
- if((*end != '\0') && !isspace(*end))
+ if ((*end != '\0') && !isspace(*end))
return -EINVAL;
uml_exitcode = tmp;
@@ -57,7 +60,7 @@
struct proc_dir_entry *ent;
ent = create_proc_entry("exitcode", 0600, &proc_root);
- if(ent == NULL){
+ if (ent == NULL) {
printk(KERN_WARNING "make_proc_exitcode : Failed to register "
"/proc/exitcode\n");
return 0;
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
index 734f873..72eccd2 100644
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -8,12 +8,13 @@
extern void __bb_init_func(void *) __attribute__((weak));
EXPORT_SYMBOL(__bb_init_func);
-/* This is defined (and referred to in profiling stub code) only by some GCC
+/*
+ * This is defined (and referred to in profiling stub code) only by some GCC
* versions in libgcov.
*
* Since SuSE backported the fix, we cannot handle it depending on GCC version.
- * So, unconditionally export it. But also give it a weak declaration, which will
- * be overridden by any other one.
+ * So, unconditionally export it. But also give it a weak declaration, which
+ * will be overridden by any other one.
*/
extern void __gcov_init(void *) __attribute__((weak));
diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c
index 9244f01..e2f043d 100644
--- a/arch/um/kernel/gprof_syms.c
+++ b/arch/um/kernel/gprof_syms.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -7,14 +7,3 @@
extern void mcount(void);
EXPORT_SYMBOL(mcount);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c
index 16dc43e..fa01556 100644
--- a/arch/um/kernel/initrd.c
+++ b/arch/um/kernel/initrd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -7,7 +7,6 @@
#include "linux/bootmem.h"
#include "linux/initrd.h"
#include "asm/types.h"
-#include "kern_util.h"
#include "initrd.h"
#include "init.h"
#include "os.h"
@@ -21,18 +20,27 @@
long long size;
int err;
- if(initrd == NULL)
+ if (initrd == NULL)
return 0;
err = os_file_size(initrd, &size);
- if(err)
+ if (err)
return 0;
+ /*
+ * This is necessary because alloc_bootmem craps out if you
+ * ask for no memory.
+ */
+ if (size == 0) {
+ printk(KERN_ERR "\"%\" is a zero-size initrd\n");
+ return 0;
+ }
+
area = alloc_bootmem(size);
- if(area == NULL)
+ if (area == NULL)
return 0;
- if(load_initrd(initrd, area, size) == -1)
+ if (load_initrd(initrd, area, size) == -1)
return 0;
initrd_start = (unsigned long) area;
@@ -59,13 +67,15 @@
int fd, n;
fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
- if(fd < 0){
- printk("Opening '%s' failed - err = %d\n", filename, -fd);
+ if (fd < 0) {
+ printk(KERN_ERR "Opening '%s' failed - err = %d\n", filename,
+ -fd);
return -1;
}
n = os_read_file(fd, buf, size);
- if(n != size){
- printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+ if (n != size) {
+ printk(KERN_ERR "Read of %d bytes from '%s' failed, "
+ "err = %d\n", size,
filename, -n);
return -1;
}
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index ba11ccd..91587f8 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -107,10 +107,9 @@
struct pollfd *tmp_pfd;
struct irq_fd *new_fd, *irq_fd;
unsigned long flags;
- int pid, events, err, n;
+ int events, err, n;
- pid = os_getpid();
- err = os_set_fd_async(fd, pid);
+ err = os_set_fd_async(fd);
if (err < 0)
goto out;
@@ -127,7 +126,6 @@
.fd = fd,
.type = type,
.irq = irq,
- .pid = pid,
.events = events,
.current_events = 0 } );
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 7c7142b..5311ee9 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -18,15 +18,11 @@
EXPORT_SYMBOL(get_signals);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(sys_waitpid);
-EXPORT_SYMBOL(task_size);
EXPORT_SYMBOL(flush_tlb_range);
-EXPORT_SYMBOL(host_task_size);
EXPORT_SYMBOL(arch_validate);
-EXPORT_SYMBOL(get_kmem_end);
EXPORT_SYMBOL(high_physmem);
EXPORT_SYMBOL(empty_zero_page);
-EXPORT_SYMBOL(um_virt_to_phys);
EXPORT_SYMBOL(handle_page_fault);
EXPORT_SYMBOL(find_iomem);
@@ -40,7 +36,6 @@
EXPORT_SYMBOL(os_stat_fd);
EXPORT_SYMBOL(os_stat_file);
EXPORT_SYMBOL(os_access);
-EXPORT_SYMBOL(os_get_exec_close);
EXPORT_SYMBOL(os_set_exec_close);
EXPORT_SYMBOL(os_getpid);
EXPORT_SYMBOL(os_open_file);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 59822dee..d872fdc 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -1,49 +1,41 @@
/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/stddef.h"
-#include "linux/kernel.h"
-#include "linux/mm.h"
-#include "linux/bootmem.h"
-#include "linux/swap.h"
-#include "linux/highmem.h"
-#include "linux/gfp.h"
-#include "asm/page.h"
-#include "asm/fixmap.h"
-#include "asm/pgalloc.h"
-#include "kern_util.h"
+#include <linux/stddef.h>
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <asm/fixmap.h>
+#include <asm/page.h>
#include "as-layout.h"
-#include "kern.h"
-#include "mem_user.h"
-#include "um_uaccess.h"
-#include "os.h"
-#include "linux/types.h"
-#include "linux/string.h"
#include "init.h"
-#include "kern_constants.h"
+#include "kern.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "os.h"
/* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
unsigned long *empty_zero_page = NULL;
/* allocated in paging_init and unchanged thereafter */
unsigned long *empty_bad_page = NULL;
+
+/*
+ * Initialized during boot, and readonly for initializing page tables
+ * afterwards
+ */
pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/* Initialized at boot time, and readonly after that */
unsigned long long highmem;
int kmalloc_ok = 0;
+/* Used during early boot */
static unsigned long brk_end;
-void unmap_physmem(void)
-{
- os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
-}
-
-static void map_cb(void *unused)
-{
- map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
-}
-
#ifdef CONFIG_HIGHMEM
static void setup_highmem(unsigned long highmem_start,
unsigned long highmem_len)
@@ -53,7 +45,7 @@
int i;
highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
- for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
+ for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) {
page = &mem_map[highmem_pfn + i];
ClearPageReserved(page);
init_page_count(page);
@@ -65,14 +57,13 @@
void __init mem_init(void)
{
/* clear the zero-page */
- memset((void *) empty_zero_page, 0, PAGE_SIZE);
+ memset(empty_zero_page, 0, PAGE_SIZE);
/* Map in the area just after the brk now that kmalloc is about
* to be turned on.
*/
brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
- map_cb(NULL);
- initial_thread_cb(map_cb, NULL);
+ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
free_bootmem(__pa(brk_end), uml_reserved - brk_end);
uml_reserved = brk_end;
@@ -85,7 +76,7 @@
#endif
num_physpages = totalram_pages;
max_pfn = totalram_pages;
- printk(KERN_INFO "Memory: %luk available\n",
+ printk(KERN_INFO "Memory: %luk available\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
kmalloc_ok = 1;
@@ -119,7 +110,7 @@
#endif
}
-static void __init fixrange_init(unsigned long start, unsigned long end,
+static void __init fixrange_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
pgd_t *pgd;
@@ -138,7 +129,7 @@
if (pud_none(*pud))
one_md_table_init(pud);
pmd = pmd_offset(pud, vaddr);
- for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+ for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) {
one_page_table_init(pmd);
vaddr += PMD_SIZE;
}
@@ -152,7 +143,7 @@
#define kmap_get_fixmap_pte(vaddr) \
pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
- (vaddr)), (vaddr))
+ (vaddr)), (vaddr))
static void __init kmap_init(void)
{
@@ -197,21 +188,23 @@
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- unsigned long paddr, vaddr = FIXADDR_USER_START;
+ phys_t p;
+ unsigned long v, vaddr = FIXADDR_USER_START;
- if ( ! size )
+ if (!size)
return;
fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
- paddr = (unsigned long)alloc_bootmem_low_pages( size);
- memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size);
- paddr = __pa(paddr);
- for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){
+ v = (unsigned long) alloc_bootmem_low_pages(size);
+ memcpy((void *) v , (void *) FIXADDR_USER_START, size);
+ p = __pa(v);
+ for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
+ p += PAGE_SIZE) {
pgd = swapper_pg_dir + pgd_index(vaddr);
pud = pud_offset(pgd, vaddr);
pmd = pmd_offset(pud, vaddr);
pte = pte_offset_kernel(pmd, vaddr);
- pte_set_val( (*pte), paddr, PAGE_READONLY);
+ pte_set_val(*pte, p, PAGE_READONLY);
}
#endif
}
@@ -223,7 +216,7 @@
empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
- for(i = 0; i < ARRAY_SIZE(zones_size); i++)
+ for (i = 0; i < ARRAY_SIZE(zones_size); i++)
zones_size[i] = 0;
zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
@@ -253,32 +246,33 @@
int i;
again:
- if(page == NULL)
+ if (page == NULL)
return page;
- if(PageHighMem(page))
+ if (PageHighMem(page))
return page;
addr = (unsigned long) page_address(page);
- for(i = 0; i < (1 << order); i++){
+ for (i = 0; i < (1 << order); i++) {
current->thread.fault_addr = (void *) addr;
- if(__do_copy_to_user((void __user *) addr, &zero,
+ if (__do_copy_to_user((void __user *) addr, &zero,
sizeof(zero),
¤t->thread.fault_addr,
- ¤t->thread.fault_catcher)){
- if(!(mask & __GFP_WAIT))
+ ¤t->thread.fault_catcher)) {
+ if (!(mask & __GFP_WAIT))
return NULL;
else break;
}
addr += PAGE_SIZE;
}
- if(i == (1 << order))
+ if (i == (1 << order))
return page;
page = alloc_pages(mask, order);
goto again;
}
-/* This can't do anything because nothing in the kernel image can be freed
+/*
+ * This can't do anything because nothing in the kernel image can be freed
* since it's not in kernel physical memory.
*/
@@ -290,8 +284,8 @@
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (start < end)
- printk ("Freeing initrd memory: %ldk freed\n",
- (end - start) >> 10);
+ printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+ (end - start) >> 10);
for (; start < end; start += PAGE_SIZE) {
ClearPageReserved(virt_to_page(start));
init_page_count(virt_to_page(start));
@@ -308,32 +302,31 @@
int highmem = 0;
struct page *page;
- printk("Mem-info:\n");
+ printk(KERN_INFO "Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ printk(KERN_INFO "Free swap: %6ldkB\n",
+ nr_swap_pages<<(PAGE_SHIFT-10));
pfn = max_mapnr;
- while(pfn-- > 0) {
+ while (pfn-- > 0) {
page = pfn_to_page(pfn);
total++;
- if(PageHighMem(page))
+ if (PageHighMem(page))
highmem++;
- if(PageReserved(page))
+ if (PageReserved(page))
reserved++;
- else if(PageSwapCache(page))
+ else if (PageSwapCache(page))
cached++;
- else if(page_count(page))
+ else if (page_count(page))
shared += page_count(page) - 1;
}
- printk("%d pages of RAM\n", total);
- printk("%d pages of HIGHMEM\n", highmem);
- printk("%d reserved pages\n", reserved);
- printk("%d pages shared\n", shared);
- printk("%d pages swap cached\n", cached);
+ printk(KERN_INFO "%d pages of RAM\n", total);
+ printk(KERN_INFO "%d pages of HIGHMEM\n", highmem);
+ printk(KERN_INFO "%d reserved pages\n", reserved);
+ printk(KERN_INFO "%d pages shared\n", shared);
+ printk(KERN_INFO "%d pages swap cached\n", cached);
}
-/*
- * Allocate and free page tables.
- */
+/* Allocate and free page tables. */
pgd_t *pgd_alloc(struct mm_struct *mm)
{
@@ -341,14 +334,14 @@
if (pgd) {
memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
- memcpy(pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
}
return pgd;
}
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long) pgd);
}
@@ -368,3 +361,15 @@
pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
return pte;
}
+
+#ifdef CONFIG_3_LEVEL_PGTABLES
+pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+
+ if (pmd)
+ memset(pmd, 0, PAGE_SIZE);
+
+ return pmd;
+}
+#endif
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index e66432f..9757085 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -55,16 +55,6 @@
return 0;
}
-/* Changed during early boot */
-static unsigned long kmem_top = 0;
-
-unsigned long get_kmem_end(void)
-{
- if (kmem_top == 0)
- kmem_top = host_task_size - 1024 * 1024;
- return kmem_top;
-}
-
void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x)
{
@@ -174,10 +164,10 @@
* setup_iomem, both of which run during early boot. Afterwards, it's
* unchanged.
*/
-struct iomem_region *iomem_regions = NULL;
+struct iomem_region *iomem_regions;
-/* Initialized in parse_iomem */
-int iomem_size = 0;
+/* Initialized in parse_iomem and unchanged thereafter */
+int iomem_size;
unsigned long find_iomem(char *driver, unsigned long *len_out)
{
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 0eae00b..c07961b 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -4,19 +4,21 @@
* Licensed under the GPL
*/
-#include "linux/stddef.h"
-#include "linux/err.h"
-#include "linux/hardirq.h"
-#include "linux/mm.h"
-#include "linux/personality.h"
-#include "linux/proc_fs.h"
-#include "linux/ptrace.h"
-#include "linux/random.h"
-#include "linux/sched.h"
-#include "linux/tick.h"
-#include "linux/threads.h"
-#include "asm/pgtable.h"
-#include "asm/uaccess.h"
+#include <linux/stddef.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/personality.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
+#include <linux/threads.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
#include "as-layout.h"
#include "kern_util.h"
#include "os.h"
@@ -30,7 +32,7 @@
*/
struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
-static inline int external_pid(struct task_struct *task)
+static inline int external_pid(void)
{
/* FIXME: Need to look up userspace_pid by cpu */
return userspace_pid[0];
@@ -40,7 +42,7 @@
{
int i;
- for(i = 0; i < ncpus; i++) {
+ for (i = 0; i < ncpus; i++) {
if (cpu_tasks[i].pid == pid)
return i;
}
@@ -60,8 +62,6 @@
if (atomic)
flags = GFP_ATOMIC;
page = __get_free_pages(flags, order);
- if (page == 0)
- return 0;
return page;
}
@@ -80,15 +80,15 @@
static inline void set_current(struct task_struct *task)
{
cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
- { external_pid(task), task });
+ { external_pid(), task });
}
-extern void arch_switch_to(struct task_struct *from, struct task_struct *to);
+extern void arch_switch_to(struct task_struct *to);
void *_switch_to(void *prev, void *next, void *last)
{
struct task_struct *from = prev;
- struct task_struct *to= next;
+ struct task_struct *to = next;
to->thread.prev_sched = from;
set_current(to);
@@ -99,13 +99,13 @@
switch_threads(&from->thread.switch_buf,
&to->thread.switch_buf);
- arch_switch_to(current->thread.prev_sched, current);
+ arch_switch_to(current);
if (current->thread.saved_task)
show_regs(&(current->thread.regs));
- next= current->thread.saved_task;
- prev= current;
- } while(current->thread.saved_task);
+ to = current->thread.saved_task;
+ from = current;
+ } while (current->thread.saved_task);
return current->thread.prev_sched;
@@ -163,8 +163,6 @@
void fork_handler(void)
{
force_flush_all();
- if (current->thread.prev_sched == NULL)
- panic("blech");
schedule_tail(current->thread.prev_sched);
@@ -173,7 +171,7 @@
* arch_switch_to isn't needed. We could want to apply this to
* improve performance. -bb
*/
- arch_switch_to(current->thread.prev_sched, current);
+ arch_switch_to(current);
current->thread.prev_sched = NULL;
@@ -204,7 +202,7 @@
arch_copy_thread(¤t->thread.arch, &p->thread.arch);
}
else {
- init_thread_registers(&p->thread.regs.regs);
+ get_safe_registers(p->thread.regs.regs.gp);
p->thread.request.u.thread = current->thread.request.u.thread;
handler = new_thread_handler;
}
@@ -237,7 +235,7 @@
{
unsigned long long nsecs;
- while(1) {
+ while (1) {
/* endless idle loop with no priority at all */
/*
@@ -256,53 +254,10 @@
void cpu_idle(void)
{
- cpu_tasks[current_thread->cpu].pid = os_getpid();
+ cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
default_idle();
}
-void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
- pte_t *pte_out)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- pte_t ptent;
-
- if (task->mm == NULL)
- return ERR_PTR(-EINVAL);
- pgd = pgd_offset(task->mm, addr);
- if (!pgd_present(*pgd))
- return ERR_PTR(-EINVAL);
-
- pud = pud_offset(pgd, addr);
- if (!pud_present(*pud))
- return ERR_PTR(-EINVAL);
-
- pmd = pmd_offset(pud, addr);
- if (!pmd_present(*pmd))
- return ERR_PTR(-EINVAL);
-
- pte = pte_offset_kernel(pmd, addr);
- ptent = *pte;
- if (!pte_present(ptent))
- return ERR_PTR(-EINVAL);
-
- if (pte_out != NULL)
- *pte_out = ptent;
- return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK);
-}
-
-char *current_cmd(void)
-{
-#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
- return "(Unknown)";
-#else
- void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
- return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
-#endif
-}
-
void dump_thread(struct pt_regs *regs, struct user *u)
{
}
@@ -317,7 +272,7 @@
unsigned long stack;
stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
- return stack != (unsigned long) current_thread;
+ return stack != (unsigned long) current_thread_info();
}
extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
@@ -331,7 +286,7 @@
(*call)();
}
-char *uml_strdup(char *string)
+char *uml_strdup(const char *string)
{
return kstrdup(string, GFP_KERNEL);
}
@@ -359,7 +314,7 @@
int smp_sigio_handler(void)
{
#ifdef CONFIG_SMP
- int cpu = current_thread->cpu;
+ int cpu = current_thread_info()->cpu;
IPI_handler(cpu);
if (cpu != 0)
return 1;
@@ -369,7 +324,7 @@
int cpu(void)
{
- return current_thread->cpu;
+ return current_thread_info()->cpu;
}
static atomic_t using_sysemu = ATOMIC_INIT(0);
@@ -435,7 +390,7 @@
{
struct task_struct *task = t ? t : current;
- if ( ! (task->ptrace & PT_DTRACE) )
+ if (!(task->ptrace & PT_DTRACE))
return 0;
if (task->thread.singlestep_syscall)
@@ -459,3 +414,46 @@
return sp & ~0xf;
}
#endif
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long stack_page, sp, ip;
+ bool seen_sched = 0;
+
+ if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING))
+ return 0;
+
+ stack_page = (unsigned long) task_stack_page(p);
+ /* Bail if the process has no kernel stack for some reason */
+ if (stack_page == 0)
+ return 0;
+
+ sp = p->thread.switch_buf->JB_SP;
+ /*
+ * Bail if the stack pointer is below the bottom of the kernel
+ * stack for some reason
+ */
+ if (sp < stack_page)
+ return 0;
+
+ while (sp < stack_page + THREAD_SIZE) {
+ ip = *((unsigned long *) sp);
+ if (in_sched_functions(ip))
+ /* Ignore everything until we're above the scheduler */
+ seen_sched = 1;
+ else if (kernel_text_address(ip) && seen_sched)
+ return ip;
+
+ sp += sizeof(unsigned long);
+ }
+
+ return 0;
+}
+
+int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+{
+ int cpu = current_thread_info()->cpu;
+
+ return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
+}
+
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 04cebcf..00197d3 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -4,6 +4,7 @@
*/
#include "linux/sched.h"
+#include "kern_util.h"
#include "os.h"
#include "skas.h"
@@ -11,7 +12,7 @@
static void kill_off_processes(void)
{
- if(proc_mm)
+ if (proc_mm)
/*
* FIXME: need to loop over userspace_pids
*/
@@ -21,8 +22,8 @@
int pid, me;
me = os_getpid();
- for_each_process(p){
- if(p->mm == NULL)
+ for_each_process(p) {
+ if (p->mm == NULL)
continue;
pid = p->mm->context.id.u.pid;
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c
index 89f9866..2b272b6 100644
--- a/arch/um/kernel/sigio.c
+++ b/arch/um/kernel/sigio.c
@@ -1,18 +1,12 @@
/*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
* Licensed under the GPL
*/
-#include "linux/kernel.h"
-#include "linux/list.h"
-#include "linux/slab.h"
-#include "linux/signal.h"
-#include "linux/interrupt.h"
-#include "init.h"
-#include "sigio.h"
-#include "irq_user.h"
+#include <linux/interrupt.h>
#include "irq_kern.h"
#include "os.h"
+#include "sigio.h"
/* Protected by sigio_lock() called from write_sigio_workaround */
static int sigio_irq_fd = -1;
@@ -33,9 +27,9 @@
err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio",
NULL);
- if(err){
- printk("write_sigio_irq : um_request_irq failed, err = %d\n",
- err);
+ if (err) {
+ printk(KERN_ERR "write_sigio_irq : um_request_irq failed, "
+ "err = %d\n", err);
return -1;
}
sigio_irq_fd = fd;
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 19cb977..b0fce72 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -3,12 +3,12 @@
* Licensed under the GPL
*/
-#include "linux/module.h"
-#include "linux/ptrace.h"
-#include "linux/sched.h"
-#include "asm/siginfo.h"
-#include "asm/signal.h"
-#include "asm/unistd.h"
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <asm/siginfo.h>
+#include <asm/signal.h>
+#include <asm/unistd.h>
#include "frame_kern.h"
#include "kern_util.h"
#include "sigcontext.h"
@@ -36,7 +36,7 @@
/* Did we come from a system call? */
if (PT_REGS_SYSCALL_NR(regs) >= 0) {
/* If so, check system call restarting.. */
- switch(PT_REGS_SYSCALL_RET(regs)) {
+ switch (PT_REGS_SYSCALL_RET(regs)) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
PT_REGS_SYSCALL_RET(regs) = -EINTR;
@@ -116,7 +116,7 @@
/* Did we come from a system call? */
if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) {
/* Restart the system call - no handlers present */
- switch(PT_REGS_SYSCALL_RET(regs)) {
+ switch (PT_REGS_SYSCALL_RET(regs)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index 8d07a7a..2c8583c 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -1,17 +1,20 @@
-#include <sched.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <asm/unistd.h>
-#include "as-layout.h"
-#include "ptrace_user.h"
-#include "skas.h"
-#include "stub-data.h"
-#include "uml-config.h"
-#include "sysdep/stub.h"
-#include "kern_constants.h"
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
-/* This is in a separate file because it needs to be compiled with any
+#include <signal.h>
+#include <sched.h>
+#include <asm/unistd.h>
+#include <sys/time.h>
+#include "as-layout.h"
+#include "kern_constants.h"
+#include "ptrace_user.h"
+#include "stub-data.h"
+#include "sysdep/stub.h"
+
+/*
+ * This is in a separate file because it needs to be compiled with any
* extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
*
* Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize
@@ -26,25 +29,26 @@
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *));
- if(err != 0)
+ if (err != 0)
goto out;
err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
- if(err)
+ if (err)
goto out;
- err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+ err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
(long) &data->timer, 0);
- if(err)
+ if (err)
goto out;
remap_stack(data->fd, data->offset);
goto done;
out:
- /* save current result.
- * Parent: pid;
- * child: retcode of mmap already saved and it jumps around this
+ /*
+ * save current result.
+ * Parent: pid;
+ * child: retcode of mmap already saved and it jumps around this
* assignment
*/
data->err = err;
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index f859ec3..78b3e9f 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -34,33 +34,14 @@
if (!pte)
goto out_pte;
- /*
- * There's an interaction between the skas0 stub pages, stack
- * randomization, and the BUG at the end of exit_mmap. exit_mmap
- * checks that the number of page tables freed is the same as had
- * been allocated. If the stack is on the last page table page,
- * then the stack pte page will be freed, and if not, it won't. To
- * avoid having to know where the stack is, or if the process mapped
- * something at the top of its address space for some other reason,
- * we set TASK_SIZE to end at the start of the last page table.
- * This keeps exit_mmap off the last page, but introduces a leak
- * of that page. So, we hang onto it here and free it in
- * destroy_context_skas.
- */
-
- mm->context.last_page_table = pmd_page_vaddr(*pmd);
-#ifdef CONFIG_3_LEVEL_PGTABLES
- mm->context.last_pmd = (unsigned long) __va(pud_val(*pud));
-#endif
-
*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
*pte = pte_mkread(*pte);
return 0;
out_pmd:
- pud_free(pud);
+ pud_free(mm, pud);
out_pte:
- pmd_free(pmd);
+ pmd_free(mm, pmd);
out:
return -ENOMEM;
}
@@ -76,24 +57,6 @@
stack = get_zeroed_page(GFP_KERNEL);
if (stack == 0)
goto out;
-
- /*
- * This zeros the entry that pgd_alloc didn't, needed since
- * we are about to reinitialize it, and want mm.nr_ptes to
- * be accurate.
- */
- mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
-
- ret = init_stub_pte(mm, STUB_CODE,
- (unsigned long) &__syscall_stub_start);
- if (ret)
- goto out_free;
-
- ret = init_stub_pte(mm, STUB_DATA, stack);
- if (ret)
- goto out_free;
-
- mm->nr_ptes--;
}
to_mm->id.stack = stack;
@@ -114,6 +77,11 @@
to_mm->id.u.pid = copy_context_skas0(stack,
from_mm->id.u.pid);
else to_mm->id.u.pid = start_userspace(stack);
+
+ if (to_mm->id.u.pid < 0) {
+ ret = to_mm->id.u.pid;
+ goto out_free;
+ }
}
ret = init_new_ldt(to_mm, from_mm);
@@ -132,24 +100,87 @@
return ret;
}
+void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+ struct page **pages;
+ int err, ret;
+
+ if (!skas_needs_stub)
+ return;
+
+ ret = init_stub_pte(mm, STUB_CODE,
+ (unsigned long) &__syscall_stub_start);
+ if (ret)
+ goto out;
+
+ ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack);
+ if (ret)
+ goto out;
+
+ pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL);
+ if (pages == NULL) {
+ printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page "
+ "pointers\n");
+ goto out;
+ }
+
+ pages[0] = virt_to_page(&__syscall_stub_start);
+ pages[1] = virt_to_page(mm->context.id.stack);
+
+ /* dup_mmap already holds mmap_sem */
+ err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
+ VM_READ | VM_MAYREAD | VM_EXEC |
+ VM_MAYEXEC | VM_DONTCOPY, pages);
+ if (err) {
+ printk(KERN_ERR "install_special_mapping returned %d\n", err);
+ goto out_free;
+ }
+ return;
+
+out_free:
+ kfree(pages);
+out:
+ force_sigsegv(SIGSEGV, current);
+}
+
+void arch_exit_mmap(struct mm_struct *mm)
+{
+ pte_t *pte;
+
+ pte = virt_to_pte(mm, STUB_CODE);
+ if (pte != NULL)
+ pte_clear(mm, STUB_CODE, pte);
+
+ pte = virt_to_pte(mm, STUB_DATA);
+ if (pte == NULL)
+ return;
+
+ pte_clear(mm, STUB_DATA, pte);
+}
+
void destroy_context(struct mm_struct *mm)
{
struct mm_context *mmu = &mm->context;
if (proc_mm)
os_close_file(mmu->id.u.mm_fd);
- else
+ else {
+ /*
+ * If init_new_context wasn't called, this will be
+ * zero, resulting in a kill(0), which will result in the
+ * whole UML suddenly dying. Also, cover negative and
+ * 1 cases, since they shouldn't happen either.
+ */
+ if (mmu->id.u.pid < 2) {
+ printk(KERN_ERR "corrupt mm_context - pid = %d\n",
+ mmu->id.u.pid);
+ return;
+ }
os_kill_ptraced_process(mmu->id.u.pid, 1);
-
- if (!proc_mm || !ptrace_faultinfo) {
- free_page(mmu->id.stack);
- pte_lock_deinit(virt_to_page(mmu->last_page_table));
- pte_free_kernel((pte_t *) mmu->last_page_table);
- dec_zone_page_state(virt_to_page(mmu->last_page_table), NR_PAGETABLE);
-#ifdef CONFIG_3_LEVEL_PGTABLES
- pmd_free((pmd_t *) mmu->last_pmd);
-#endif
}
+ if (skas_needs_stub)
+ free_page(mmu->id.stack);
+
free_ldt(mmu);
}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index fce389c..2e9852c 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -6,19 +6,25 @@
#include "linux/init.h"
#include "linux/sched.h"
#include "as-layout.h"
+#include "kern.h"
#include "os.h"
#include "skas.h"
int new_mm(unsigned long stack)
{
- int fd;
+ int fd, err;
fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
if (fd < 0)
return fd;
- if (skas_needs_stub)
- map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+ if (skas_needs_stub) {
+ err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+ if (err) {
+ os_close_file(fd);
+ return err;
+ }
+ }
return fd;
}
@@ -49,8 +55,14 @@
{
stack_protections((unsigned long) &cpu0_irqstack);
set_sigstack(cpu0_irqstack, THREAD_SIZE);
- if (proc_mm)
+ if (proc_mm) {
userspace_pid[0] = start_userspace(0);
+ if (userspace_pid[0] < 0) {
+ printf("start_uml - start_userspace returned %d\n",
+ userspace_pid[0]);
+ exit(1);
+ }
+ }
init_new_thread_signals();
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index 50b476f..4e3b820 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -9,6 +9,9 @@
#include "sysdep/ptrace.h"
#include "sysdep/syscalls.h"
+extern int syscall_table_size;
+#define NR_syscalls (syscall_table_size / sizeof(void *))
+
void handle_syscall(struct uml_pt_regs *r)
{
struct pt_regs *regs = container_of(r, struct pt_regs, regs);
@@ -17,9 +20,6 @@
syscall_trace(r, 0);
- current->thread.nsyscalls++;
- nsyscalls++;
-
/*
* This should go in the declaration of syscall, but when I do that,
* strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index 1d8b119..e22c969 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -3,128 +3,130 @@
* Licensed under the GPL
*/
-#include "linux/err.h"
-#include "linux/highmem.h"
-#include "linux/mm.h"
-#include "asm/current.h"
-#include "asm/page.h"
-#include "asm/pgtable.h"
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
#include "kern_util.h"
#include "os.h"
-extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
- pte_t *pte_out);
-
-static unsigned long maybe_map(unsigned long virt, int is_write)
+pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
{
- pte_t pte;
- int err;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
- void *phys = um_virt_to_phys(current, virt, &pte);
- int dummy_code;
+ if (mm == NULL)
+ return NULL;
- if (IS_ERR(phys) || (is_write && !pte_write(pte))) {
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd))
+ return NULL;
+
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ return NULL;
+
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd))
+ return NULL;
+
+ return pte_offset_kernel(pmd, addr);
+}
+
+static pte_t *maybe_map(unsigned long virt, int is_write)
+{
+ pte_t *pte = virt_to_pte(current->mm, virt);
+ int err, dummy_code;
+
+ if ((pte == NULL) || !pte_present(*pte) ||
+ (is_write && !pte_write(*pte))) {
err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
if (err)
- return -1UL;
- phys = um_virt_to_phys(current, virt, NULL);
+ return NULL;
+ pte = virt_to_pte(current->mm, virt);
}
- if (IS_ERR(phys))
- phys = (void *) -1;
+ if (!pte_present(*pte))
+ pte = NULL;
- return (unsigned long) phys;
+ return pte;
}
static int do_op_one_page(unsigned long addr, int len, int is_write,
int (*op)(unsigned long addr, int len, void *arg), void *arg)
{
+ jmp_buf buf;
struct page *page;
- int n;
+ pte_t *pte;
+ int n, faulted;
- addr = maybe_map(addr, is_write);
- if (addr == -1UL)
+ pte = maybe_map(addr, is_write);
+ if (pte == NULL)
return -1;
- page = phys_to_page(addr);
+ page = pte_page(*pte);
addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) +
(addr & ~PAGE_MASK);
- n = (*op)(addr, len, arg);
+ current->thread.fault_catcher = &buf;
+
+ faulted = UML_SETJMP(&buf);
+ if (faulted == 0)
+ n = (*op)(addr, len, arg);
+ else
+ n = -1;
+
+ current->thread.fault_catcher = NULL;
kunmap_atomic(page, KM_UML_USERCOPY);
return n;
}
-static void do_buffer_op(void *jmpbuf, void *arg_ptr)
+static int buffer_op(unsigned long addr, int len, int is_write,
+ int (*op)(unsigned long, int, void *), void *arg)
{
- va_list args;
- unsigned long addr;
- int len, is_write, size, remain, n;
- int (*op)(unsigned long, int, void *);
- void *arg;
- int *res;
+ int size, remain, n;
- va_copy(args, *(va_list *)arg_ptr);
- addr = va_arg(args, unsigned long);
- len = va_arg(args, int);
- is_write = va_arg(args, int);
- op = va_arg(args, void *);
- arg = va_arg(args, void *);
- res = va_arg(args, int *);
- va_end(args);
size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
remain = len;
- current->thread.fault_catcher = jmpbuf;
n = do_op_one_page(addr, size, is_write, op, arg);
if (n != 0) {
- *res = (n < 0 ? remain : 0);
+ remain = (n < 0 ? remain : 0);
goto out;
}
addr += size;
remain -= size;
- if (remain == 0) {
- *res = 0;
+ if (remain == 0)
goto out;
- }
- while(addr < ((addr + remain) & PAGE_MASK)) {
+ while (addr < ((addr + remain) & PAGE_MASK)) {
n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg);
if (n != 0) {
- *res = (n < 0 ? remain : 0);
+ remain = (n < 0 ? remain : 0);
goto out;
}
addr += PAGE_SIZE;
remain -= PAGE_SIZE;
}
- if (remain == 0) {
- *res = 0;
+ if (remain == 0)
+ goto out;
+
+ n = do_op_one_page(addr, remain, is_write, op, arg);
+ if (n != 0) {
+ remain = (n < 0 ? remain : 0);
goto out;
}
- n = do_op_one_page(addr, remain, is_write, op, arg);
- if (n != 0)
- *res = (n < 0 ? remain : 0);
- else *res = 0;
+ return 0;
out:
- current->thread.fault_catcher = NULL;
-}
-
-static int buffer_op(unsigned long addr, int len, int is_write,
- int (*op)(unsigned long addr, int len, void *arg),
- void *arg)
-{
- int faulted, res;
-
- faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
- &res);
- if (!faulted)
- return res;
-
- return addr + len - (unsigned long) current->thread.fault_addr;
+ return remain;
}
static int copy_chunk_from_user(unsigned long from, int len, void *arg)
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 36d89cf..e1062ec 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -21,7 +21,6 @@
#include "asm/smp.h"
#include "asm/processor.h"
#include "asm/spinlock.h"
-#include "kern_util.h"
#include "kern.h"
#include "irq_user.h"
#include "os.h"
@@ -61,7 +60,7 @@
continue;
os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
}
- printk(KERN_INFO "done\n");
+ printk(KERN_CONT "done\n");
}
static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
@@ -75,8 +74,7 @@
if (err < 0)
panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
- os_set_fd_async(cpu_data[cpu].ipi_pipe[0],
- current->thread.mode.tt.extern_pid);
+ os_set_fd_async(cpu_data[cpu].ipi_pipe[0]);
wmb();
if (cpu_test_and_set(cpu, cpu_callin_map)) {
@@ -129,8 +127,7 @@
if (err < 0)
panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
- os_set_fd_async(cpu_data[me].ipi_pipe[0],
- current->thread.mode.tt.extern_pid);
+ os_set_fd_async(cpu_data[me].ipi_pipe[0]);
for (cpu = 1; cpu < ncpus; cpu++) {
printk(KERN_INFO "Booting processor %d...\n", cpu);
@@ -143,9 +140,8 @@
while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
cpu_relax();
- if (cpu_isset(cpu, cpu_callin_map))
- printk(KERN_INFO "done\n");
- else printk(KERN_INFO "failed\n");
+ printk(KERN_INFO "%s\n",
+ cpu_isset(cpu, cpu_calling_map) ? "done" : "failed");
}
}
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index b9d92b2..9cffc62 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -13,9 +13,6 @@
#include "asm/uaccess.h"
#include "asm/unistd.h"
-/* Unlocked, I don't care if this is a bit off */
-int nsyscalls = 0;
-
long sys_fork(void)
{
long ret;
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index 9326357..56d43d0 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -1,38 +1,37 @@
-/*
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/sched.h"
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/kallsyms.h"
-#include "asm/page.h"
-#include "asm/processor.h"
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
#include "sysrq.h"
/* Catch non-i386 SUBARCH's. */
#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
void show_trace(struct task_struct *task, unsigned long * stack)
{
- unsigned long addr;
+ unsigned long addr;
- if (!stack) {
+ if (!stack) {
stack = (unsigned long*) &stack;
WARN_ON(1);
}
- printk("Call Trace: \n");
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
- addr = *stack;
+ printk(KERN_INFO "Call Trace: \n");
+ while (((long) stack & (THREAD_SIZE-1)) != 0) {
+ addr = *stack;
if (__kernel_text_address(addr)) {
- printk("%08lx: [<%08lx>]", (unsigned long) stack, addr);
- print_symbol(" %s", addr);
- printk("\n");
- }
- stack++;
- }
- printk("\n");
+ printk(KERN_INFO "%08lx: [<%08lx>]",
+ (unsigned long) stack, addr);
+ print_symbol(KERN_CONT " %s", addr);
+ printk(KERN_CONT "\n");
+ }
+ stack++;
+ }
+ printk(KERN_INFO "\n");
}
#endif
@@ -67,14 +66,13 @@
}
stack = esp;
- for(i = 0; i < kstack_depth_to_print; i++) {
+ for (i = 0; i < kstack_depth_to_print; i++) {
if (kstack_end(stack))
break;
if (i && ((i % 8) == 0))
- printk("\n ");
+ printk("\n" KERN_INFO " ");
printk("%08lx ", *stack++);
}
- printk("Call Trace: \n");
show_trace(task, esp);
}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 1ac746a..e066e844 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -3,12 +3,12 @@
* Licensed under the GPL
*/
-#include "linux/clockchips.h"
-#include "linux/interrupt.h"
-#include "linux/jiffies.h"
-#include "linux/threads.h"
-#include "asm/irq.h"
-#include "asm/param.h"
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/threads.h>
+#include <asm/irq.h>
+#include <asm/param.h>
#include "kern_util.h"
#include "os.h"
@@ -32,7 +32,7 @@
static void itimer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- switch(mode) {
+ switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
set_interval();
break;
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index f4a0e407..d175d05 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -3,9 +3,10 @@
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "asm/pgtable.h"
-#include "asm/tlbflush.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
#include "as-layout.h"
#include "mem_user.h"
#include "os.h"
@@ -56,7 +57,7 @@
for (i = 0; i < end && !ret; i++) {
op = &hvc->ops[i];
- switch(op->type) {
+ switch (op->type) {
case MMAP:
ret = map(hvc->id, op->u.mmap.addr, op->u.mmap.len,
op->u.mmap.prot, op->u.mmap.fd,
@@ -183,27 +184,30 @@
pte = pte_offset_kernel(pmd, addr);
do {
+ if ((addr >= STUB_START) && (addr < STUB_END))
+ continue;
+
r = pte_read(*pte);
w = pte_write(*pte);
x = pte_exec(*pte);
if (!pte_young(*pte)) {
r = 0;
w = 0;
- } else if (!pte_dirty(*pte)) {
+ } else if (!pte_dirty(*pte))
w = 0;
- }
+
prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
(x ? UM_PROT_EXEC : 0));
if (hvc->force || pte_newpage(*pte)) {
if (pte_present(*pte))
ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK,
PAGE_SIZE, prot, hvc);
- else ret = add_munmap(addr, PAGE_SIZE, hvc);
- }
- else if (pte_newprot(*pte))
+ else
+ ret = add_munmap(addr, PAGE_SIZE, hvc);
+ } else if (pte_newprot(*pte))
ret = add_mprotect(addr, PAGE_SIZE, prot, hvc);
*pte = pte_mkuptodate(*pte);
- } while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret));
+ } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret));
return ret;
}
@@ -225,7 +229,7 @@
}
}
else ret = update_pte_range(pmd, addr, next, hvc);
- } while (pmd++, addr = next, ((addr != end) && !ret));
+ } while (pmd++, addr = next, ((addr < end) && !ret));
return ret;
}
@@ -247,7 +251,7 @@
}
}
else ret = update_pmd_range(pud, addr, next, hvc);
- } while (pud++, addr = next, ((addr != end) && !ret));
+ } while (pud++, addr = next, ((addr < end) && !ret));
return ret;
}
@@ -270,7 +274,7 @@
}
}
else ret = update_pud_range(pgd, addr, next, &hvc);
- } while (pgd++, addr = next, ((addr != end_addr) && !ret));
+ } while (pgd++, addr = next, ((addr < end_addr) && !ret));
if (!ret)
ret = do_ops(&hvc, hvc.index, 1);
@@ -485,9 +489,6 @@
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force)
{
- if (!proc_mm && (end_addr > STUB_START))
- end_addr = STUB_START;
-
fix_range_common(mm, start_addr, end_addr, force);
}
@@ -499,10 +500,9 @@
else fix_range(vma->vm_mm, start, end, 0);
}
-void flush_tlb_mm(struct mm_struct *mm)
+void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
{
- unsigned long end;
-
/*
* Don't bother flushing if this address space is about to be
* destroyed.
@@ -510,8 +510,17 @@
if (atomic_read(&mm->mm_users) == 0)
return;
- end = proc_mm ? task_size : STUB_START;
- fix_range(mm, 0, end, 0);
+ fix_range(mm, start, end, 0);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma = mm->mmap;
+
+ while (vma != NULL) {
+ fix_range(mm, vma->vm_start, vma->vm_end, 0);
+ vma = vma->vm_next;
+ }
}
void force_flush_all(void)
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index cb3321f..44e4904 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -13,6 +13,7 @@
#include "as-layout.h"
#include "kern_util.h"
#include "os.h"
+#include "skas.h"
#include "sysdep/sigcontext.h"
/*
@@ -128,7 +129,19 @@
force_sig_info(SIGSEGV, &si, current);
}
-static void segv_handler(int sig, struct uml_pt_regs *regs)
+void fatal_sigsegv(void)
+{
+ force_sigsegv(SIGSEGV, current);
+ do_signal();
+ /*
+ * This is to tell gcc that we're not returning - do_signal
+ * can, in general, return, but in this case, it's not, since
+ * we just got a fatal SIGSEGV queued.
+ */
+ os_dump_core();
+}
+
+void segv_handler(int sig, struct uml_pt_regs *regs)
{
struct faultinfo * fi = UPT_FAULTINFO(regs);
@@ -216,9 +229,6 @@
void relay_signal(int sig, struct uml_pt_regs *regs)
{
- if (arch_handle_signal(sig, regs))
- return;
-
if (!UPT_IS_USER(regs)) {
if (sig == SIGBUS)
printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
@@ -226,31 +236,24 @@
panic("Kernel mode signal %d", sig);
}
+ arch_examine_signal(sig, regs);
+
current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
force_sig(sig, current);
}
-static void bus_handler(int sig, struct uml_pt_regs *regs)
+void bus_handler(int sig, struct uml_pt_regs *regs)
{
if (current->thread.fault_catcher != NULL)
UML_LONGJMP(current->thread.fault_catcher, 1);
else relay_signal(sig, regs);
}
-static void winch(int sig, struct uml_pt_regs *regs)
+void winch(int sig, struct uml_pt_regs *regs)
{
do_IRQ(WINCH_IRQ, regs);
}
-const struct kern_handlers handlinfo_kern = {
- .relay_signal = relay_signal,
- .winch = winch,
- .bus_handler = bus_handler,
- .page_fault = segv_handler,
- .sigio_handler = sigio_handler,
- .timer_handler = timer_handler
-};
-
void trap_init(void)
{
}
diff --git a/arch/um/kernel/uaccess.c b/arch/um/kernel/uaccess.c
index d7436aa..f0f4b04 100644
--- a/arch/um/kernel/uaccess.c
+++ b/arch/um/kernel/uaccess.c
@@ -1,10 +1,11 @@
/*
* Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-/* These are here rather than tt/uaccess.c because skas mode needs them in
+/*
+ * These are here rather than tt/uaccess.c because skas mode needs them in
* order to do SIGBUS recovery when a tmpfs mount runs out of room.
*/
@@ -25,6 +26,8 @@
fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
__do_copy, &faulted);
- if(!faulted) return(0);
- else return(n - (fault - (unsigned long) to));
+ if (!faulted)
+ return 0;
+ else
+ return n - (fault - (unsigned long) to);
}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index f1c7139..468aba9 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -3,22 +3,23 @@
* Licensed under the GPL
*/
-#include "linux/delay.h"
-#include "linux/mm.h"
-#include "linux/module.h"
-#include "linux/seq_file.h"
-#include "linux/string.h"
-#include "linux/utsname.h"
-#include "asm/pgtable.h"
-#include "asm/processor.h"
-#include "asm/setup.h"
-#include "arch.h"
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/utsname.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
#include "as-layout.h"
+#include "arch.h"
#include "init.h"
#include "kern.h"
+#include "kern_util.h"
#include "mem_user.h"
#include "os.h"
-#include "skas.h"
#define DEFAULT_COMMAND_LINE "root=98:0"
@@ -100,8 +101,6 @@
};
/* Set in linux_main */
-unsigned long host_task_size;
-unsigned long task_size;
unsigned long uml_physmem;
unsigned long uml_reserved; /* Also modified in mem_init */
unsigned long start_vm;
@@ -197,20 +196,19 @@
" Prints this message.\n\n"
);
-static int __init uml_checksetup(char *line, int *add)
+static void __init uml_checksetup(char *line, int *add)
{
struct uml_param *p;
p = &__uml_setup_start;
- while(p < &__uml_setup_end) {
+ while (p < &__uml_setup_end) {
int n;
n = strlen(p->str);
if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
- return 1;
+ return;
p++;
}
- return 0;
}
static void __init uml_postsetup(void)
@@ -218,13 +216,30 @@
initcall_t *p;
p = &__uml_postsetup_start;
- while(p < &__uml_postsetup_end) {
+ while (p < &__uml_postsetup_end) {
(*p)();
p++;
}
return;
}
+static int panic_exit(struct notifier_block *self, unsigned long unused1,
+ void *unused2)
+{
+ bust_spinlocks(1);
+ show_regs(&(current->thread.regs));
+ bust_spinlocks(0);
+ uml_exitcode = 1;
+ os_dump_core();
+ return 0;
+}
+
+static struct notifier_block panic_exit_notifier = {
+ .notifier_call = panic_exit,
+ .next = NULL,
+ .priority = 0
+};
+
/* Set during early boot */
unsigned long brk_start;
unsigned long end_iomem;
@@ -234,20 +249,6 @@
extern char __binary_start;
-static unsigned long set_task_sizes_skas(unsigned long *task_size_out)
-{
- /* Round up to the nearest 4M */
- unsigned long host_task_size = ROUND_4M((unsigned long)
- &host_task_size);
-
- if (!skas_needs_stub)
- *task_size_out = host_task_size;
- else
- *task_size_out = STUB_START & PGDIR_MASK;
-
- return host_task_size;
-}
-
int __init linux_main(int argc, char **argv)
{
unsigned long avail, diff;
@@ -278,13 +279,6 @@
printf("UML running in %s mode\n", mode);
- host_task_size = set_task_sizes_skas(&task_size);
-
- /*
- * Setting up handlers to 'sig_info' struct
- */
- os_fill_handlinfo(handlinfo_kern);
-
brk_start = (unsigned long) sbrk(0);
/*
@@ -309,7 +303,7 @@
highmem = 0;
iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
- max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
+ max_physmem = CONFIG_TOP_ADDR - uml_physmem - iomem_size - MIN_VMALLOC;
/*
* Zones have to begin on a 1 << MAX_ORDER page boundary,
@@ -341,7 +335,7 @@
}
virtmem_size = physmem_size;
- avail = get_kmem_end() - start_vm;
+ avail = CONFIG_TOP_ADDR - start_vm;
if (physmem_size > avail)
virtmem_size = avail;
end_vm = start_vm + virtmem_size;
@@ -350,6 +344,9 @@
printf("Kernel virtual memory size shrunk to %lu bytes\n",
virtmem_size);
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &panic_exit_notifier);
+
uml_postsetup();
stack_protections((unsigned long) &init_thread_info);
@@ -358,29 +355,8 @@
return start_uml();
}
-extern int uml_exitcode;
-
-static int panic_exit(struct notifier_block *self, unsigned long unused1,
- void *unused2)
-{
- bust_spinlocks(1);
- show_regs(&(current->thread.regs));
- bust_spinlocks(0);
- uml_exitcode = 1;
- os_dump_core();
- return 0;
-}
-
-static struct notifier_block panic_exit_notifier = {
- .notifier_call = panic_exit,
- .next = NULL,
- .priority = 0
-};
-
void __init setup_arch(char **cmdline_p)
{
- atomic_notifier_chain_register(&panic_notifier_list,
- &panic_exit_notifier);
paging_init();
strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 039e16e..81e07e2b 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -1,13 +1,12 @@
-/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "asm/errno.h"
+#include <asm/errno.h>
#include "init.h"
-#include "os.h"
#include "kern.h"
-#include "linux/kernel.h"
+#include "os.h"
/* Changed by set_umid_arg */
static int umid_inited = 0;
@@ -16,16 +15,16 @@
{
int err;
- if(umid_inited){
+ if (umid_inited) {
printf("umid already set\n");
return 0;
}
*add = 0;
err = set_umid(name);
- if(err == -EEXIST)
+ if (err == -EEXIST)
printf("umid '%s' already in use\n", name);
- else if(!err)
+ else if (!err)
umid_inited = 1;
return 0;
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 8e129af..8a48d6a 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -4,7 +4,7 @@
#
obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
- registers.o sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o \
+ registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \
umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/
obj-$(CONFIG_TTY_LOG) += tty_log.o
@@ -12,7 +12,7 @@
USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \
main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
- trap.o tty.o tls.o uaccess.o umid.o util.o
+ tty.o tls.o uaccess.o umid.o util.o
CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index 93dc0c8..b8d8c9c 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -12,6 +12,7 @@
#include "aio.h"
#include "init.h"
#include "kern_constants.h"
+#include "kern_util.h"
#include "os.h"
#include "user.h"
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index 07ca0cb..6fb0b17 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -131,7 +131,7 @@
}
if (c != 1) {
printk(UM_KERN_ERR "etap_tramp : uml_net failed\n");
- err = helper_wait(pid, 0, "uml_net");
+ err = helper_wait(pid);
}
return err;
}
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index 1037a3b6..2448be0 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -14,6 +14,7 @@
#include <sys/wait.h>
#include <sys/uio.h>
#include "kern_constants.h"
+#include "kern_util.h"
#include "os.h"
#include "tuntap.h"
#include "user.h"
@@ -107,7 +108,7 @@
"errno = %d\n", errno);
return err;
}
- helper_wait(pid, 0, "tuntap_open_tramp");
+ helper_wait(pid);
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg == NULL) {
@@ -148,7 +149,7 @@
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
- if (ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0) {
+ if (ioctl(pri->fd, TUNSETIFF, &ifr) < 0) {
err = -errno;
printk(UM_KERN_ERR "TUNSETIFF failed, errno = %d\n",
errno);
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index f834627..b5afcfd 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -8,18 +8,16 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
-#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include "kern_constants.h"
#include "os.h"
#include "user.h"
-#include "kern_util.h"
-static void copy_stat(struct uml_stat *dst, struct stat64 *src)
+static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
{
*dst = ((struct uml_stat) {
.ust_dev = src->st_dev, /* device */
@@ -43,10 +41,10 @@
int err;
CATCH_EINTR(err = fstat64(fd, &sbuf));
- if(err < 0)
+ if (err < 0)
return -errno;
- if(ubuf != NULL)
+ if (ubuf != NULL)
copy_stat(ubuf, &sbuf);
return err;
}
@@ -56,27 +54,26 @@
struct stat64 sbuf;
int err;
- do {
- err = stat64(file_name, &sbuf);
- } while((err < 0) && (errno == EINTR)) ;
-
- if(err < 0)
+ CATCH_EINTR(err = stat64(file_name, &sbuf));
+ if (err < 0)
return -errno;
- if(ubuf != NULL)
+ if (ubuf != NULL)
copy_stat(ubuf, &sbuf);
return err;
}
-int os_access(const char* file, int mode)
+int os_access(const char *file, int mode)
{
int amode, err;
- amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
- (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
+ amode = (mode & OS_ACC_R_OK ? R_OK : 0) |
+ (mode & OS_ACC_W_OK ? W_OK : 0) |
+ (mode & OS_ACC_X_OK ? X_OK : 0) |
+ (mode & OS_ACC_F_OK ? F_OK : 0);
err = access(file, amode);
- if(err < 0)
+ if (err < 0)
return -errno;
return 0;
@@ -88,7 +85,7 @@
int err;
err = ioctl(fd, cmd, arg);
- if(err < 0)
+ if (err < 0)
return -errno;
return err;
@@ -97,7 +94,7 @@
/* FIXME: ensure namebuf in os_get_if_name is big enough */
int os_get_ifname(int fd, char* namebuf)
{
- if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
+ if (ioctl(fd, SIOCGIFNAME, namebuf) < 0)
return -errno;
return 0;
@@ -108,37 +105,22 @@
int disc, sencap;
disc = N_SLIP;
- if(ioctl(fd, TIOCSETD, &disc) < 0)
+ if (ioctl(fd, TIOCSETD, &disc) < 0)
return -errno;
sencap = 0;
- if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
+ if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
return -errno;
return 0;
}
-int os_set_owner(int fd, int pid)
-{
- if(fcntl(fd, F_SETOWN, pid) < 0){
- int save_errno = errno;
-
- if(fcntl(fd, F_GETOWN, 0) != pid)
- return -save_errno;
- }
-
- return 0;
-}
-
int os_mode_fd(int fd, int mode)
{
int err;
- do {
- err = fchmod(fd, mode);
- } while((err < 0) && (errno==EINTR)) ;
-
- if(err < 0)
+ CATCH_EINTR(err = fchmod(fd, mode));
+ if (err < 0)
return -errno;
return 0;
@@ -150,64 +132,73 @@
int err;
err = os_stat_file(file, &buf);
- if(err < 0)
+ if (err < 0)
return err;
- if(S_ISDIR(buf.ust_mode))
+ if (S_ISDIR(buf.ust_mode))
return OS_TYPE_DIR;
- else if(S_ISLNK(buf.ust_mode))
+ else if (S_ISLNK(buf.ust_mode))
return OS_TYPE_SYMLINK;
- else if(S_ISCHR(buf.ust_mode))
+ else if (S_ISCHR(buf.ust_mode))
return OS_TYPE_CHARDEV;
- else if(S_ISBLK(buf.ust_mode))
+ else if (S_ISBLK(buf.ust_mode))
return OS_TYPE_BLOCKDEV;
- else if(S_ISFIFO(buf.ust_mode))
+ else if (S_ISFIFO(buf.ust_mode))
return OS_TYPE_FIFO;
- else if(S_ISSOCK(buf.ust_mode))
+ else if (S_ISSOCK(buf.ust_mode))
return OS_TYPE_SOCK;
else return OS_TYPE_FILE;
}
-int os_file_mode(char *file, struct openflags *mode_out)
+int os_file_mode(const char *file, struct openflags *mode_out)
{
int err;
*mode_out = OPENFLAGS();
err = access(file, W_OK);
- if(err && (errno != EACCES))
+ if (err && (errno != EACCES))
return -errno;
- else if(!err)
+ else if (!err)
*mode_out = of_write(*mode_out);
err = access(file, R_OK);
- if(err && (errno != EACCES))
+ if (err && (errno != EACCES))
return -errno;
- else if(!err)
+ else if (!err)
*mode_out = of_read(*mode_out);
return err;
}
-int os_open_file(char *file, struct openflags flags, int mode)
+int os_open_file(const char *file, struct openflags flags, int mode)
{
int fd, err, f = 0;
- if(flags.r && flags.w) f = O_RDWR;
- else if(flags.r) f = O_RDONLY;
- else if(flags.w) f = O_WRONLY;
+ if (flags.r && flags.w)
+ f = O_RDWR;
+ else if (flags.r)
+ f = O_RDONLY;
+ else if (flags.w)
+ f = O_WRONLY;
else f = 0;
- if(flags.s) f |= O_SYNC;
- if(flags.c) f |= O_CREAT;
- if(flags.t) f |= O_TRUNC;
- if(flags.e) f |= O_EXCL;
+ if (flags.s)
+ f |= O_SYNC;
+ if (flags.c)
+ f |= O_CREAT;
+ if (flags.t)
+ f |= O_TRUNC;
+ if (flags.e)
+ f |= O_EXCL;
+ if (flags.a)
+ f |= O_APPEND;
fd = open64(file, f, mode);
- if(fd < 0)
+ if (fd < 0)
return -errno;
- if(flags.cl && fcntl(fd, F_SETFD, 1)){
+ if (flags.cl && fcntl(fd, F_SETFD, 1)) {
err = -errno;
close(fd);
return err;
@@ -216,7 +207,7 @@
return fd;
}
-int os_connect_socket(char *name)
+int os_connect_socket(const char *name)
{
struct sockaddr_un sock;
int fd, err;
@@ -225,13 +216,13 @@
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if(fd < 0) {
+ if (fd < 0) {
err = -errno;
goto out;
}
err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
- if(err) {
+ if (err) {
err = -errno;
goto out_close;
}
@@ -254,7 +245,7 @@
unsigned long long actual;
actual = lseek64(fd, offset, SEEK_SET);
- if(actual != offset)
+ if (actual != offset)
return -errno;
return 0;
}
@@ -263,7 +254,7 @@
{
int n = read(fd, buf, len);
- if(n < 0)
+ if (n < 0)
return -errno;
return n;
}
@@ -272,37 +263,38 @@
{
int n = write(fd, (void *) buf, len);
- if(n < 0)
+ if (n < 0)
return -errno;
return n;
}
-int os_file_size(char *file, unsigned long long *size_out)
+int os_file_size(const char *file, unsigned long long *size_out)
{
struct uml_stat buf;
int err;
err = os_stat_file(file, &buf);
- if(err < 0){
- printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
+ if (err < 0) {
+ printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
+ -err);
return err;
}
- if(S_ISBLK(buf.ust_mode)){
+ if (S_ISBLK(buf.ust_mode)) {
int fd;
long blocks;
fd = open(file, O_RDONLY, 0);
- if(fd < 0) {
+ if (fd < 0) {
err = -errno;
- printk("Couldn't open \"%s\", errno = %d\n", file,
- errno);
+ printk(UM_KERN_ERR "Couldn't open \"%s\", "
+ "errno = %d\n", file, errno);
return err;
}
- if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
+ if (ioctl(fd, BLKGETSIZE, &blocks) < 0) {
err = -errno;
- printk("Couldn't get the block size of \"%s\", "
- "errno = %d\n", file, errno);
+ printk(UM_KERN_ERR "Couldn't get the block size of "
+ "\"%s\", errno = %d\n", file, errno);
close(fd);
return err;
}
@@ -314,14 +306,15 @@
return 0;
}
-int os_file_modtime(char *file, unsigned long *modtime)
+int os_file_modtime(const char *file, unsigned long *modtime)
{
struct uml_stat buf;
int err;
err = os_stat_file(file, &buf);
- if(err < 0){
- printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
+ if (err < 0) {
+ printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
+ -err);
return err;
}
@@ -329,26 +322,13 @@
return 0;
}
-int os_get_exec_close(int fd, int *close_on_exec)
-{
- int ret;
-
- CATCH_EINTR(ret = fcntl(fd, F_GETFD));
-
- if(ret < 0)
- return -errno;
-
- *close_on_exec = (ret & FD_CLOEXEC) ? 1 : 0;
- return ret;
-}
-
int os_set_exec_close(int fd)
{
int err;
CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC));
- if(err < 0)
+ if (err < 0)
return -errno;
return err;
}
@@ -358,53 +338,51 @@
int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
err = socketpair(AF_UNIX, type, 0, fds);
- if(err < 0)
+ if (err < 0)
return -errno;
- if(!close_on_exec)
+ if (!close_on_exec)
return 0;
err = os_set_exec_close(fds[0]);
- if(err < 0)
+ if (err < 0)
goto error;
err = os_set_exec_close(fds[1]);
- if(err < 0)
+ if (err < 0)
goto error;
return 0;
error:
- printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
+ printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n",
+ -err);
close(fds[1]);
close(fds[0]);
return err;
}
-int os_set_fd_async(int fd, int owner)
+int os_set_fd_async(int fd)
{
- int err;
+ int err, flags;
- /* XXX This should do F_GETFL first */
- if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ return -errno;
+
+ flags |= O_ASYNC | O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) < 0) {
err = -errno;
- printk("os_set_fd_async : failed to set O_ASYNC and "
- "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
+ printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC "
+ "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
return err;
}
-#ifdef notdef
- if(fcntl(fd, F_SETFD, 1) < 0){
- printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
- "errno = %d\n", errno);
- }
-#endif
- if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
- (fcntl(fd, F_SETOWN, owner) < 0)){
+ if ((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
+ (fcntl(fd, F_SETOWN, os_getpid()) < 0)) {
err = -errno;
- printk("os_set_fd_async : Failed to fcntl F_SETOWN "
- "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd,
- owner, errno);
+ printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN "
+ "(or F_SETSIG) fd %d, errno = %d\n", fd, errno);
return err;
}
@@ -413,10 +391,14 @@
int os_clear_fd_async(int fd)
{
- int flags = fcntl(fd, F_GETFL);
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ return -errno;
flags &= ~(O_ASYNC | O_NONBLOCK);
- if(fcntl(fd, F_SETFL, flags) < 0)
+ if (fcntl(fd, F_SETFL, flags) < 0)
return -errno;
return 0;
}
@@ -426,11 +408,15 @@
int flags;
flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ return -errno;
- if(blocking) flags &= ~O_NONBLOCK;
- else flags |= O_NONBLOCK;
+ if (blocking)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
- if(fcntl(fd, F_SETFL, flags) < 0)
+ if (fcntl(fd, F_SETFL, flags) < 0)
return -errno;
return 0;
@@ -441,7 +427,7 @@
int new;
new = accept(fd, NULL, 0);
- if(new < 0)
+ if (new < 0)
return -errno;
return new;
}
@@ -462,15 +448,17 @@
{
int what, err;
- if(r && w) what = SHUT_RDWR;
- else if(r) what = SHUT_RD;
- else if(w) what = SHUT_WR;
- else {
- printk("os_shutdown_socket : neither r or w was set\n");
+ if (r && w)
+ what = SHUT_RDWR;
+ else if (r)
+ what = SHUT_RD;
+ else if (w)
+ what = SHUT_WR;
+ else
return -EINVAL;
- }
+
err = shutdown(fd, what);
- if(err < 0)
+ if (err < 0)
return -errno;
return 0;
}
@@ -494,19 +482,20 @@
msg.msg_flags = 0;
n = recvmsg(fd, &msg, 0);
- if(n < 0)
+ if (n < 0)
return -errno;
- else if(n != iov.iov_len)
+ else if (n != iov.iov_len)
*helper_pid_out = -1;
cmsg = CMSG_FIRSTHDR(&msg);
- if(cmsg == NULL){
- printk("rcv_fd didn't receive anything, error = %d\n", errno);
+ if (cmsg == NULL) {
+ printk(UM_KERN_ERR "rcv_fd didn't receive anything, "
+ "error = %d\n", errno);
return -1;
}
- if((cmsg->cmsg_level != SOL_SOCKET) ||
- (cmsg->cmsg_type != SCM_RIGHTS)){
- printk("rcv_fd didn't receive a descriptor\n");
+ if ((cmsg->cmsg_level != SOL_SOCKET) ||
+ (cmsg->cmsg_type != SCM_RIGHTS)) {
+ printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n");
return -1;
}
@@ -514,29 +503,28 @@
return new;
}
-int os_create_unix_socket(char *file, int len, int close_on_exec)
+int os_create_unix_socket(const char *file, int len, int close_on_exec)
{
struct sockaddr_un addr;
int sock, err;
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
- if(sock < 0)
+ if (sock < 0)
return -errno;
- if(close_on_exec) {
+ if (close_on_exec) {
err = os_set_exec_close(sock);
- if(err < 0)
- printk("create_unix_socket : close_on_exec failed, "
- "err = %d", -err);
+ if (err < 0)
+ printk(UM_KERN_ERR "create_unix_socket : "
+ "close_on_exec failed, err = %d", -err);
}
addr.sun_family = AF_UNIX;
- /* XXX Be more careful about overflow */
snprintf(addr.sun_path, len, "%s", file);
err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
- if(err < 0)
+ if (err < 0)
return -errno;
return sock;
@@ -557,17 +545,18 @@
int err, save;
err = fcntl(fd, F_SETLK, &lock);
- if(!err)
+ if (!err)
goto out;
save = -errno;
err = fcntl(fd, F_GETLK, &lock);
- if(err){
+ if (err) {
err = -errno;
goto out;
}
- printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
+ printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n",
+ lock.l_pid);
err = save;
out:
return err;
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index fba3f0f..f4bd349 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -1,22 +1,19 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
-#include <limits.h>
-#include <sys/signal.h>
-#include <sys/wait.h>
#include <sys/socket.h>
-#include "user.h"
+#include <sys/wait.h>
+#include "kern_constants.h"
#include "kern_util.h"
#include "os.h"
#include "um_malloc.h"
-#include "kern_constants.h"
+#include "user.h"
struct helper_data {
void (*pre_exec)(void*);
@@ -30,21 +27,19 @@
{
struct helper_data *data = arg;
char **argv = data->argv;
- int errval;
+ int err;
if (data->pre_exec != NULL)
(*data->pre_exec)(data->pre_data);
- errval = execvp_noalloc(data->buf, argv[0], argv);
- printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0],
- -errval);
- write(data->fd, &errval, sizeof(errval));
- kill(os_getpid(), SIGKILL);
+ err = execvp_noalloc(data->buf, argv[0], argv);
+
+ /* If the exec succeeds, we don't get here */
+ write(data->fd, &err, sizeof(err));
+
return 0;
}
-/* Returns either the pid of the child process we run or -E* on failure.
- * XXX The alloc_stack here breaks if this is called in the tracing thread, so
- * we need to receive a preallocated stack (a local buffer is ok). */
+/* Returns either the pid of the child process we run or -E* on failure. */
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
{
struct helper_data data;
@@ -58,14 +53,15 @@
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
if (ret < 0) {
ret = -errno;
- printk("run_helper : pipe failed, errno = %d\n", errno);
+ printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
+ errno);
goto out_free;
}
ret = os_set_exec_close(fds[1]);
if (ret < 0) {
- printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
- -ret);
+ printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
+ "ret = %d\n", -ret);
goto out_close;
}
@@ -79,7 +75,8 @@
pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
if (pid < 0) {
ret = -errno;
- printk("run_helper : clone failed, errno = %d\n", errno);
+ printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
+ errno);
goto out_free2;
}
@@ -96,10 +93,9 @@
} else {
if (n < 0) {
n = -errno;
- printk("run_helper : read on pipe failed, ret = %d\n",
- -n);
+ printk(UM_KERN_ERR "run_helper : read on pipe failed, "
+ "ret = %d\n", -n);
ret = n;
- kill(pid, SIGKILL);
}
CATCH_EINTR(waitpid(pid, NULL, __WCLONE));
}
@@ -129,50 +125,40 @@
pid = clone(proc, (void *) sp, flags, arg);
if (pid < 0) {
err = -errno;
- printk("run_helper_thread : clone failed, errno = %d\n",
- errno);
+ printk(UM_KERN_ERR "run_helper_thread : clone failed, "
+ "errno = %d\n", errno);
return err;
}
if (stack_out == NULL) {
CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE));
if (pid < 0) {
err = -errno;
- printk("run_helper_thread - wait failed, errno = %d\n",
- errno);
+ printk(UM_KERN_ERR "run_helper_thread - wait failed, "
+ "errno = %d\n", errno);
pid = err;
}
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
- printk("run_helper_thread - thread returned status "
- "0x%x\n", status);
+ printk(UM_KERN_ERR "run_helper_thread - thread "
+ "returned status 0x%x\n", status);
free_stack(stack, 0);
} else
*stack_out = stack;
return pid;
}
-int helper_wait(int pid, int nohang, char *pname)
+int helper_wait(int pid)
{
int ret, status;
int wflags = __WCLONE;
- if (nohang)
- wflags |= WNOHANG;
-
- if (!pname)
- pname = "helper_wait";
-
CATCH_EINTR(ret = waitpid(pid, &status, wflags));
if (ret < 0) {
- printk(UM_KERN_ERR "%s : waitpid process %d failed, "
- "errno = %d\n", pname, pid, errno);
+ printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
+ "errno = %d\n", pid, errno);
return -errno;
- } else if (nohang && ret == 0) {
- printk(UM_KERN_ERR "%s : process %d has not exited\n",
- pname, pid);
- return -ECHILD;
} else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- printk(UM_KERN_ERR "%s : process %d didn't exit with "
- "status 0\n", pname, pid);
+ printk(UM_KERN_ERR "helper_wait : process %d exited with "
+ "status 0x%x\n", pid, status);
return -ECHILD;
} else
return 0;
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
index 6aa6f95..0348b97 100644
--- a/arch/um/os-Linux/irq.c
+++ b/arch/um/os-Linux/irq.c
@@ -1,23 +1,19 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <stdlib.h>
-#include <unistd.h>
#include <errno.h>
+#include <poll.h>
#include <signal.h>
#include <string.h>
-#include <sys/poll.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include "kern_util.h"
-#include "user.h"
-#include "process.h"
-#include "sigio.h"
#include "irq_user.h"
+#include "kern_constants.h"
#include "os.h"
+#include "process.h"
#include "um_malloc.h"
+#include "user.h"
/*
* Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd
@@ -36,7 +32,7 @@
if (n < 0) {
err = -errno;
if (errno != EINTR)
- printk("sigio_handler: os_waiting_for_events:"
+ printk(UM_KERN_ERR "os_waiting_for_events:"
" poll returned %d, errno = %d\n", n, errno);
return err;
}
@@ -95,24 +91,26 @@
struct irq_fd *old_fd = *prev;
if ((pollfds[i].fd != -1) &&
(pollfds[i].fd != (*prev)->fd)) {
- printk("os_free_irq_by_cb - mismatch between "
- "active_fds and pollfds, fd %d vs %d\n",
+ printk(UM_KERN_ERR "os_free_irq_by_cb - "
+ "mismatch between active_fds and "
+ "pollfds, fd %d vs %d\n",
(*prev)->fd, pollfds[i].fd);
goto out;
}
pollfds_num--;
- /* This moves the *whole* array after pollfds[i]
+ /*
+ * This moves the *whole* array after pollfds[i]
* (though it doesn't spot as such)!
*/
memmove(&pollfds[i], &pollfds[i + 1],
(pollfds_num - i) * sizeof(pollfds[0]));
- if(*last_irq_ptr2 == &old_fd->next)
+ if (*last_irq_ptr2 == &old_fd->next)
*last_irq_ptr2 = prev;
*prev = (*prev)->next;
- if(old_fd->type == IRQ_WRITE)
+ if (old_fd->type == IRQ_WRITE)
ignore_sigio_fd(old_fd->fd);
kfree(old_fd);
continue;
@@ -138,14 +136,3 @@
{
signal(SIGIO, SIG_IGN);
}
-
-void init_irq_signals(int on_sigstack)
-{
- int flags;
-
- flags = on_sigstack ? SA_ONSTACK : 0;
-
- set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
- SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
- signal(SIGWINCH, SIG_IGN);
-}
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 82c3778..abb9b0ff 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -73,7 +73,7 @@
action.sa_handler = last_ditch_exit;
if (sigaction(sig, &action, NULL) < 0) {
printf("failed to install handler for signal %d - errno = %d\n",
- errno);
+ sig, errno);
exit(1);
}
}
@@ -92,7 +92,8 @@
* just use the default + /usr/lib/uml
*/
if (!old_path || (path_len = strlen(old_path)) == 0) {
- putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH);
+ if (putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH))
+ perror("couldn't putenv");
return;
}
@@ -100,15 +101,16 @@
path_len += strlen("PATH=" UML_LIB_PATH) + 1;
new_path = malloc(path_len);
if (!new_path) {
- perror("coudn't malloc to set a new PATH");
+ perror("couldn't malloc to set a new PATH");
return;
}
snprintf(new_path, path_len, "PATH=%s" UML_LIB_PATH, old_path);
- putenv(new_path);
+ if (putenv(new_path)) {
+ perror("couldn't putenv to set a new PATH");
+ free(new_path);
+ }
}
-extern int uml_exitcode;
-
extern void scan_elf_aux( char **envp);
int __init main(int argc, char **argv, char **envp)
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index 436f8d2..eedc2d8 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -9,7 +9,6 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/statfs.h>
-#include "kern_util.h"
#include "user.h"
#include "mem_user.h"
#include "init.h"
@@ -30,7 +29,7 @@
static void __init find_tempdir(void)
{
- char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
+ const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
int i;
char *dir = NULL;
@@ -59,9 +58,10 @@
* read the file as needed. If there's an error, -errno is returned;
* if the end of the file is reached, 0 is returned.
*/
-static int next(int fd, char *buf, int size, char c)
+static int next(int fd, char *buf, size_t size, char c)
{
- int n, len;
+ ssize_t n;
+ size_t len;
char *ptr;
while((ptr = strchr(buf, c)) == NULL){
@@ -172,13 +172,15 @@
which_tmpdir();
tempname = malloc(MAXPATHLEN);
+ if (!tempname)
+ goto out;
find_tempdir();
if (template[0] != '/')
strcpy(tempname, tempdir);
else
tempname[0] = '\0';
- strcat(tempname, template);
+ strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
fd = mkstemp(tempname);
if(fd < 0){
fprintf(stderr, "open - cannot create %s: %s\n", tempname,
@@ -268,6 +270,7 @@
if(addr == MAP_FAILED){
err = errno;
perror("failed");
+ close(fd);
if(err == EPERM)
printf("%s must be not mounted noexec\n",tempdir);
exit(1);
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index bda5c31..abf6bea 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -249,7 +249,10 @@
SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
signal(SIGHUP, SIG_IGN);
- init_irq_signals(1);
+ set_handler(SIGIO, (__sighandler_t) sig_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM,
+ SIGVTALRM, -1);
+ signal(SIGWINCH, SIG_IGN);
}
int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c
index a32ba6a..830fe6a 100644
--- a/arch/um/os-Linux/registers.c
+++ b/arch/um/os-Linux/registers.c
@@ -8,47 +8,41 @@
#include <string.h>
#include <sys/ptrace.h>
#include "sysdep/ptrace.h"
-#include "user.h"
-/* This is set once at boot time and not changed thereafter */
-
-static unsigned long exec_regs[MAX_REG_NR];
-
-void init_thread_registers(struct uml_pt_regs *to)
-{
- memcpy(to->gp, exec_regs, sizeof(to->gp));
-}
-
-void save_registers(int pid, struct uml_pt_regs *regs)
+int save_registers(int pid, struct uml_pt_regs *regs)
{
int err;
err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp);
if (err < 0)
- panic("save_registers - saving registers failed, errno = %d\n",
- errno);
+ return -errno;
+ return 0;
}
-void restore_registers(int pid, struct uml_pt_regs *regs)
+int restore_registers(int pid, struct uml_pt_regs *regs)
{
int err;
err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp);
if (err < 0)
- panic("restore_registers - saving registers failed, "
- "errno = %d\n", errno);
+ return -errno;
+ return 0;
}
-void init_registers(int pid)
+/* This is set once at boot time and not changed thereafter */
+
+static unsigned long exec_regs[MAX_REG_NR];
+
+int init_registers(int pid)
{
int err;
err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
- if (err)
- panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
- errno);
+ if (err < 0)
+ return -errno;
arch_init_registers(pid);
+ return 0;
}
void get_safe_registers(unsigned long *regs)
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index dc03e9c..abf47a7c 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -1,34 +1,33 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <unistd.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <pty.h>
-#include <signal.h>
-#include <fcntl.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pty.h>
#include <sched.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include "init.h"
-#include "user.h"
+#include <signal.h>
+#include <string.h>
+#include "kern_constants.h"
#include "kern_util.h"
-#include "sigio.h"
-#include "os.h"
-#include "um_malloc.h"
#include "init.h"
+#include "os.h"
+#include "sigio.h"
+#include "um_malloc.h"
+#include "user.h"
-/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
+/*
+ * Protected by sigio_lock(), also used by sigio_cleanup, which is an
* exitcall.
*/
static int write_sigio_pid = -1;
static unsigned long write_sigio_stack;
-/* These arrays are initialized before the sigio thread is started, and
+/*
+ * These arrays are initialized before the sigio thread is started, and
* the descriptors closed after it is killed. So, it can't see them change.
* On the UML side, they are changed under the sigio_lock.
*/
@@ -43,7 +42,8 @@
int used;
};
-/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread
+/*
+ * Protected by sigio_lock(). Used by the sigio thread, but the UML thread
* synchronizes with it.
*/
static struct pollfds current_poll;
@@ -57,23 +57,26 @@
int i, n, respond_fd;
char c;
- signal(SIGWINCH, SIG_IGN);
+ signal(SIGWINCH, SIG_IGN);
fds = ¤t_poll;
- while(1){
+ while (1) {
n = poll(fds->poll, fds->used, -1);
- if(n < 0){
- if(errno == EINTR) continue;
- printk("write_sigio_thread : poll returned %d, "
- "errno = %d\n", n, errno);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ printk(UM_KERN_ERR "write_sigio_thread : poll returned "
+ "%d, errno = %d\n", n, errno);
}
- for(i = 0; i < fds->used; i++){
+ for (i = 0; i < fds->used; i++) {
p = &fds->poll[i];
- if(p->revents == 0) continue;
- if(p->fd == sigio_private[1]){
+ if (p->revents == 0)
+ continue;
+ if (p->fd == sigio_private[1]) {
CATCH_EINTR(n = read(sigio_private[1], &c,
sizeof(c)));
- if(n != sizeof(c))
- printk("write_sigio_thread : "
+ if (n != sizeof(c))
+ printk(UM_KERN_ERR
+ "write_sigio_thread : "
"read on socket failed, "
"err = %d\n", errno);
tmp = current_poll;
@@ -89,9 +92,10 @@
}
CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
- if(n != sizeof(c))
- printk("write_sigio_thread : write on socket "
- "failed, err = %d\n", errno);
+ if (n != sizeof(c))
+ printk(UM_KERN_ERR "write_sigio_thread : "
+ "write on socket failed, err = %d\n",
+ errno);
}
}
@@ -102,12 +106,13 @@
{
struct pollfd *new;
- if(n <= polls->size)
+ if (n <= polls->size)
return 0;
new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
- if(new == NULL){
- printk("need_poll : failed to allocate new pollfds\n");
+ if (new == NULL) {
+ printk(UM_KERN_ERR "need_poll : failed to allocate new "
+ "pollfds\n");
return -ENOMEM;
}
@@ -119,7 +124,8 @@
return 0;
}
-/* Must be called with sigio_lock held, because it's needed by the marked
+/*
+ * Must be called with sigio_lock held, because it's needed by the marked
* critical section.
*/
static void update_thread(void)
@@ -129,15 +135,17 @@
char c;
flags = set_signals(0);
- n = write(sigio_private[0], &c, sizeof(c));
- if(n != sizeof(c)){
- printk("update_thread : write failed, err = %d\n", errno);
+ CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c)));
+ if (n != sizeof(c)) {
+ printk(UM_KERN_ERR "update_thread : write failed, err = %d\n",
+ errno);
goto fail;
}
CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
- if(n != sizeof(c)){
- printk("update_thread : read failed, err = %d\n", errno);
+ if (n != sizeof(c)) {
+ printk(UM_KERN_ERR "update_thread : read failed, err = %d\n",
+ errno);
goto fail;
}
@@ -164,23 +172,23 @@
int err = 0, i, n;
sigio_lock();
- for(i = 0; i < all_sigio_fds.used; i++){
- if(all_sigio_fds.poll[i].fd == fd)
+ for (i = 0; i < all_sigio_fds.used; i++) {
+ if (all_sigio_fds.poll[i].fd == fd)
break;
}
- if(i == all_sigio_fds.used)
+ if (i == all_sigio_fds.used)
goto out;
p = &all_sigio_fds.poll[i];
- for(i = 0; i < current_poll.used; i++){
- if(current_poll.poll[i].fd == fd)
+ for (i = 0; i < current_poll.used; i++) {
+ if (current_poll.poll[i].fd == fd)
goto out;
}
n = current_poll.used;
err = need_poll(&next_poll, n + 1);
- if(err)
+ if (err)
goto out;
memcpy(next_poll.poll, current_poll.poll,
@@ -198,27 +206,29 @@
struct pollfd *p;
int err = 0, i, n = 0;
- /* This is called from exitcalls elsewhere in UML - if
+ /*
+ * This is called from exitcalls elsewhere in UML - if
* sigio_cleanup has already run, then update_thread will hang
* or fail because the thread is no longer running.
*/
- if(write_sigio_pid == -1)
+ if (write_sigio_pid == -1)
return -EIO;
sigio_lock();
- for(i = 0; i < current_poll.used; i++){
- if(current_poll.poll[i].fd == fd) break;
+ for (i = 0; i < current_poll.used; i++) {
+ if (current_poll.poll[i].fd == fd)
+ break;
}
- if(i == current_poll.used)
+ if (i == current_poll.used)
goto out;
err = need_poll(&next_poll, current_poll.used - 1);
- if(err)
+ if (err)
goto out;
- for(i = 0; i < current_poll.used; i++){
+ for (i = 0; i < current_poll.used; i++) {
p = ¤t_poll.poll[i];
- if(p->fd != fd)
+ if (p->fd != fd)
next_poll.poll[n++] = *p;
}
next_poll.used = current_poll.used - 1;
@@ -235,7 +245,8 @@
p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
if (p == NULL) {
- printk("setup_initial_poll : failed to allocate poll\n");
+ printk(UM_KERN_ERR "setup_initial_poll : failed to allocate "
+ "poll\n");
return NULL;
}
*p = ((struct pollfd) { .fd = fd,
@@ -261,27 +272,29 @@
return;
err = os_pipe(l_write_sigio_fds, 1, 1);
- if(err < 0){
- printk("write_sigio_workaround - os_pipe 1 failed, "
+ if (err < 0) {
+ printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, "
"err = %d\n", -err);
return;
}
err = os_pipe(l_sigio_private, 1, 1);
- if(err < 0){
- printk("write_sigio_workaround - os_pipe 2 failed, "
+ if (err < 0) {
+ printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, "
"err = %d\n", -err);
goto out_close1;
}
p = setup_initial_poll(l_sigio_private[1]);
- if(!p)
+ if (!p)
goto out_close2;
sigio_lock();
- /* Did we race? Don't try to optimize this, please, it's not so likely
- * to happen, and no more than once at the boot. */
- if(write_sigio_pid != -1)
+ /*
+ * Did we race? Don't try to optimize this, please, it's not so likely
+ * to happen, and no more than once at the boot.
+ */
+ if (write_sigio_pid != -1)
goto out_free;
current_poll = ((struct pollfds) { .poll = p,
@@ -333,19 +346,19 @@
{
int err;
- if(!isatty(fd))
+ if (!isatty(fd))
return;
- if((read || pty_output_sigio) && (!read || pty_close_sigio))
+ if ((read || pty_output_sigio) && (!read || pty_close_sigio))
return;
write_sigio_workaround();
sigio_lock();
err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
- if(err){
- printk("maybe_sigio_broken - failed to add pollfd for "
- "descriptor %d\n", fd);
+ if (err) {
+ printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd "
+ "for descriptor %d\n", fd);
goto out;
}
@@ -388,7 +401,7 @@
struct openpty_arg *info = arg;
info->err = 0;
- if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+ if (openpty(&info->master, &info->slave, NULL, NULL, NULL))
info->err = -errno;
}
@@ -397,17 +410,17 @@
int flags;
flags = fcntl(master, F_GETFL);
- if(flags < 0)
+ if (flags < 0)
return -errno;
- if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
- (fcntl(master, F_SETOWN, os_getpid()) < 0))
+ if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+ (fcntl(master, F_SETOWN, os_getpid()) < 0))
return -errno;
- if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+ if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
return -errno;
- return(0);
+ return 0;
}
static void __init check_one_sigio(void (*proc)(int, int))
@@ -417,34 +430,49 @@
int master, slave, err;
initial_thread_cb(openpty_cb, &pty);
- if(pty.err){
- printk("openpty failed, errno = %d\n", -pty.err);
+ if (pty.err) {
+ printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n",
+ -pty.err);
return;
}
master = pty.master;
slave = pty.slave;
- if((master == -1) || (slave == -1)){
- printk("openpty failed to allocate a pty\n");
+ if ((master == -1) || (slave == -1)) {
+ printk(UM_KERN_ERR "check_one_sigio failed to allocate a "
+ "pty\n");
return;
}
/* Not now, but complain so we now where we failed. */
err = raw(master);
- if (err < 0)
- panic("check_sigio : __raw failed, errno = %d\n", -err);
+ if (err < 0) {
+ printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n",
+ -err);
+ return;
+ }
err = async_pty(master, slave);
- if(err < 0)
- panic("tty_fds : sigio_async failed, err = %d\n", -err);
+ if (err < 0) {
+ printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, "
+ "err = %d\n", -err);
+ return;
+ }
- if(sigaction(SIGIO, NULL, &old) < 0)
- panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+ if (sigaction(SIGIO, NULL, &old) < 0) {
+ printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, "
+ "errno = %d\n", errno);
+ return;
+ }
+
new = old;
new.sa_handler = handler;
- if(sigaction(SIGIO, &new, NULL) < 0)
- panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+ if (sigaction(SIGIO, &new, NULL) < 0) {
+ printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, "
+ "errno = %d\n", errno);
+ return;
+ }
got_sigio = 0;
(*proc)(master, slave);
@@ -452,8 +480,9 @@
close(master);
close(slave);
- if(sigaction(SIGIO, &old, NULL) < 0)
- panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+ if (sigaction(SIGIO, &old, NULL) < 0)
+ printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, "
+ "errno = %d\n", errno);
}
static void tty_output(int master, int slave)
@@ -461,42 +490,45 @@
int n;
char buf[512];
- printk("Checking that host ptys support output SIGIO...");
+ printk(UM_KERN_INFO "Checking that host ptys support output SIGIO...");
memset(buf, 0, sizeof(buf));
- while(write(master, buf, sizeof(buf)) > 0) ;
- if(errno != EAGAIN)
- panic("tty_output : write failed, errno = %d\n", errno);
- while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+ while (write(master, buf, sizeof(buf)) > 0) ;
+ if (errno != EAGAIN)
+ printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n",
+ errno);
+ while (((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio)
+ ;
- if(got_sigio){
- printk("Yes\n");
+ if (got_sigio) {
+ printk(UM_KERN_CONT "Yes\n");
pty_output_sigio = 1;
- }
- else if(n == -EAGAIN)
- printk("No, enabling workaround\n");
- else panic("tty_output : read failed, err = %d\n", n);
+ } else if (n == -EAGAIN)
+ printk(UM_KERN_CONT "No, enabling workaround\n");
+ else
+ printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n);
}
static void tty_close(int master, int slave)
{
- printk("Checking that host ptys support SIGIO on close...");
+ printk(UM_KERN_INFO "Checking that host ptys support SIGIO on "
+ "close...");
close(slave);
- if(got_sigio){
- printk("Yes\n");
+ if (got_sigio) {
+ printk(UM_KERN_CONT "Yes\n");
pty_close_sigio = 1;
- }
- else printk("No, enabling workaround\n");
+ } else
+ printk(UM_KERN_CONT "No, enabling workaround\n");
}
void __init check_sigio(void)
{
- if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
- (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
- printk("No pseudo-terminals available - skipping pty SIGIO "
- "check\n");
+ if ((access("/dev/ptmx", R_OK) < 0) &&
+ (access("/dev/ptyp0", R_OK) < 0)) {
+ printk(UM_KERN_WARNING "No pseudo-terminals available - "
+ "skipping pty SIGIO check\n");
return;
}
check_one_sigio(tty_output);
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index e9800b0..0fb0cc8 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -9,11 +9,47 @@
#include <errno.h>
#include <signal.h>
#include <strings.h>
+#include "as-layout.h"
+#include "kern_util.h"
#include "os.h"
#include "sysdep/barrier.h"
#include "sysdep/sigcontext.h"
#include "user.h"
+/* Copied from linux/compiler-gcc.h since we can't include it directly */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
+ [SIGTRAP] = relay_signal,
+ [SIGFPE] = relay_signal,
+ [SIGILL] = relay_signal,
+ [SIGWINCH] = winch,
+ [SIGBUS] = bus_handler,
+ [SIGSEGV] = segv_handler,
+ [SIGIO] = sigio_handler,
+ [SIGVTALRM] = timer_handler };
+
+static void sig_handler_common(int sig, struct sigcontext *sc)
+{
+ struct uml_pt_regs r;
+ int save_errno = errno;
+
+ r.is_user = 0;
+ if (sig == SIGSEGV) {
+ /* For segfaults, we want the data from the sigcontext. */
+ copy_sc(&r, sc);
+ GET_FAULTINFO_FROM_SC(r.faultinfo, sc);
+ }
+
+ /* enable signals if sig isn't IRQ signal */
+ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
+ unblock_signals();
+
+ (*sig_info[sig])(sig, &r);
+
+ errno = save_errno;
+}
+
/*
* These are the asynchronous signals. SIGPROF is excluded because we want to
* be able to profile all of UML, not just the non-critical sections. If
@@ -26,13 +62,8 @@
#define SIGVTALRM_BIT 1
#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
-/*
- * These are used by both the signal handlers and
- * block/unblock_signals. I don't want modifications cached in a
- * register - they must go straight to memory.
- */
-static volatile int signals_enabled = 1;
-static volatile int pending = 0;
+static int signals_enabled;
+static unsigned int signals_pending;
void sig_handler(int sig, struct sigcontext *sc)
{
@@ -40,13 +71,13 @@
enabled = signals_enabled;
if (!enabled && (sig == SIGIO)) {
- pending |= SIGIO_MASK;
+ signals_pending |= SIGIO_MASK;
return;
}
block_signals();
- sig_handler_common_skas(sig, sc);
+ sig_handler_common(sig, sc);
set_signals(enabled);
}
@@ -68,7 +99,7 @@
enabled = signals_enabled;
if (!signals_enabled) {
- pending |= SIGVTALRM_MASK;
+ signals_pending |= SIGVTALRM_MASK;
return;
}
@@ -94,16 +125,6 @@
panic("enabling signal stack failed, errno = %d\n", errno);
}
-void remove_sigstack(void)
-{
- stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
- .ss_sp = NULL,
- .ss_size = 0 });
-
- if (sigaltstack(&stack, NULL) != 0)
- panic("disabling signal stack failed, errno = %d\n", errno);
-}
-
void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
void handle_signal(int sig, struct sigcontext *sc)
@@ -166,6 +187,9 @@
sigaddset(&action.sa_mask, mask);
va_end(ap);
+ if (sig == SIGSEGV)
+ flags |= SA_NODEFER;
+
action.sa_flags = flags;
action.sa_restorer = NULL;
if (sigaction(sig, &action, NULL) < 0)
@@ -179,12 +203,14 @@
int change_sig(int signal, int on)
{
- sigset_t sigset, old;
+ sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, signal);
- sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
- return !sigismember(&old, signal);
+ if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0)
+ return -errno;
+
+ return 0;
}
void block_signals(void)
@@ -196,7 +222,7 @@
* This might matter if gcc figures out how to inline this and
* decides to shuffle this code into the caller.
*/
- mb();
+ barrier();
}
void unblock_signals(void)
@@ -209,36 +235,26 @@
/*
* We loop because the IRQ handler returns with interrupts off. So,
* interrupts may have arrived and we need to re-enable them and
- * recheck pending.
+ * recheck signals_pending.
*/
while(1) {
/*
* Save and reset save_pending after enabling signals. This
- * way, pending won't be changed while we're reading it.
+ * way, signals_pending won't be changed while we're reading it.
*/
signals_enabled = 1;
/*
- * Setting signals_enabled and reading pending must
+ * Setting signals_enabled and reading signals_pending must
* happen in this order.
*/
- mb();
+ barrier();
- save_pending = pending;
- if (save_pending == 0) {
- /*
- * This must return with signals enabled, so
- * this barrier ensures that writes are
- * flushed out before the return. This might
- * matter if gcc figures out how to inline
- * this (unlikely, given its size) and decides
- * to shuffle this code into the caller.
- */
- mb();
+ save_pending = signals_pending;
+ if (save_pending == 0)
return;
- }
- pending = 0;
+ signals_pending = 0;
/*
* We have pending interrupts, so disable signals, as the
@@ -254,7 +270,7 @@
* back here.
*/
if (save_pending & SIGIO_MASK)
- sig_handler_common_skas(SIGIO, NULL);
+ sig_handler_common(SIGIO, NULL);
if (save_pending & SIGVTALRM_MASK)
real_alarm_handler(NULL);
diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile
index 5fd8d4d..d2ea340 100644
--- a/arch/um/os-Linux/skas/Makefile
+++ b/arch/um/os-Linux/skas/Makefile
@@ -1,10 +1,10 @@
#
-# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
# Licensed under the GPL
#
-obj-y := mem.o process.o trap.o
+obj-y := mem.o process.o
-USER_OBJS := mem.o process.o trap.o
+USER_OBJS := $(obj-y)
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index e8b7a97..d36c89c 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -15,6 +15,7 @@
#include "as-layout.h"
#include "chan_user.h"
#include "kern_constants.h"
+#include "kern_util.h"
#include "mem.h"
#include "os.h"
#include "process.h"
@@ -37,27 +38,27 @@
static int ptrace_dump_regs(int pid)
{
- unsigned long regs[MAX_REG_NR];
- int i;
+ unsigned long regs[MAX_REG_NR];
+ int i;
- if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
- return -errno;
+ if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
+ return -errno;
printk(UM_KERN_ERR "Stub registers -\n");
for (i = 0; i < ARRAY_SIZE(regs); i++)
printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]);
- return 0;
+ return 0;
}
/*
* Signals that are OK to receive in the stub - we'll just continue it.
* SIGWINCH will happen when UML is inside a detached screen.
*/
-#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))
+#define STUB_SIG_MASK (1 << SIGVTALRM)
/* Signals that the stub will finish with - anything else is an error */
-#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP))
+#define STUB_DONE_MASK (1 << SIGTRAP)
void wait_stub_done(int pid)
{
@@ -72,9 +73,11 @@
break;
err = ptrace(PTRACE_CONT, pid, 0, 0);
- if (err)
- panic("wait_stub_done : continue failed, errno = %d\n",
- errno);
+ if (err) {
+ printk(UM_KERN_ERR "wait_stub_done : continue failed, "
+ "errno = %d\n", errno);
+ fatal_sigsegv();
+ }
}
if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
@@ -85,8 +88,10 @@
if (err)
printk(UM_KERN_ERR "Failed to get registers from stub, "
"errno = %d\n", -err);
- panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, "
- "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status);
+ printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, "
+ "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno,
+ status);
+ fatal_sigsegv();
}
extern unsigned long current_stub_stack(void);
@@ -97,9 +102,11 @@
if (ptrace_faultinfo) {
err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
- if (err)
- panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
- "errno = %d\n", errno);
+ if (err) {
+ printk(UM_KERN_ERR "get_skas_faultinfo - "
+ "PTRACE_FAULTINFO failed, errno = %d\n", errno);
+ fatal_sigsegv();
+ }
/* Special handling for i386, which has different structs */
if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
@@ -109,9 +116,11 @@
}
else {
err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
- if (err)
- panic("Failed to continue stub, pid = %d, errno = %d\n",
- pid, errno);
+ if (err) {
+ printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
+ "errno = %d\n", pid, errno);
+ fatal_sigsegv();
+ }
wait_stub_done(pid);
/*
@@ -137,6 +146,9 @@
{
int err, status;
+ if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
+ fatal_sigsegv();
+
/* Mark this as a syscall */
UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp);
@@ -144,25 +156,31 @@
{
err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
__NR_getpid);
- if (err < 0)
- panic("handle_trap - nullifying syscall failed, "
- "errno = %d\n", errno);
+ if (err < 0) {
+ printk(UM_KERN_ERR "handle_trap - nullifying syscall "
+ "failed, errno = %d\n", errno);
+ fatal_sigsegv();
+ }
err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
- if (err < 0)
- panic("handle_trap - continuing to end of syscall "
- "failed, errno = %d\n", errno);
+ if (err < 0) {
+ printk(UM_KERN_ERR "handle_trap - continuing to end of "
+ "syscall failed, errno = %d\n", errno);
+ fatal_sigsegv();
+ }
CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
if ((err < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGTRAP + 0x80)) {
- err = ptrace_dump_regs(pid);
- if (err)
- printk(UM_KERN_ERR "Failed to get registers "
+ (WSTOPSIG(status) != SIGTRAP + 0x80)) {
+ err = ptrace_dump_regs(pid);
+ if (err)
+ printk(UM_KERN_ERR "Failed to get registers "
"from process, errno = %d\n", -err);
- panic("handle_trap - failed to wait at end of syscall, "
- "errno = %d, status = %d\n", errno, status);
- }
+ printk(UM_KERN_ERR "handle_trap - failed to wait at "
+ "end of syscall, errno = %d, status = %d\n",
+ errno, status);
+ fatal_sigsegv();
+ }
}
handle_syscall(regs);
@@ -178,10 +196,13 @@
ptrace(PTRACE_TRACEME, 0, 0, 0);
signal(SIGTERM, SIG_DFL);
+ signal(SIGWINCH, SIG_IGN);
err = set_interval();
- if (err)
- panic("userspace_tramp - setting timer failed, errno = %d\n",
- err);
+ if (err) {
+ printk(UM_KERN_ERR "userspace_tramp - setting timer failed, "
+ "errno = %d\n", err);
+ exit(1);
+ }
if (!proc_mm) {
/*
@@ -221,16 +242,14 @@
set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE);
sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGIO);
- sigaddset(&sa.sa_mask, SIGWINCH);
- sigaddset(&sa.sa_mask, SIGVTALRM);
- sigaddset(&sa.sa_mask, SIGUSR1);
- sa.sa_flags = SA_ONSTACK;
+ sa.sa_flags = SA_ONSTACK | SA_NODEFER;
sa.sa_handler = (void *) v;
sa.sa_restorer = NULL;
- if (sigaction(SIGSEGV, &sa, NULL) < 0)
- panic("userspace_tramp - setting SIGSEGV handler "
- "failed - errno = %d\n", errno);
+ if (sigaction(SIGSEGV, &sa, NULL) < 0) {
+ printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV "
+ "handler failed - errno = %d\n", errno);
+ exit(1);
+ }
}
kill(os_getpid(), SIGSTOP);
@@ -246,13 +265,18 @@
{
void *stack;
unsigned long sp;
- int pid, status, n, flags;
+ int pid, status, n, flags, err;
stack = mmap(NULL, UM_KERN_PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (stack == MAP_FAILED)
- panic("start_userspace : mmap failed, errno = %d", errno);
+ if (stack == MAP_FAILED) {
+ err = -errno;
+ printk(UM_KERN_ERR "start_userspace : mmap failed, "
+ "errno = %d\n", errno);
+ return err;
+ }
+
sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
flags = CLONE_FILES;
@@ -262,29 +286,50 @@
flags |= SIGCHLD;
pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
- if (pid < 0)
- panic("start_userspace : clone failed, errno = %d", errno);
+ if (pid < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "start_userspace : clone failed, "
+ "errno = %d\n", errno);
+ return err;
+ }
do {
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
- if (n < 0)
- panic("start_userspace : wait failed, errno = %d",
- errno);
+ if (n < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "start_userspace : wait failed, "
+ "errno = %d\n", errno);
+ goto out_kill;
+ }
} while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
- if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
- panic("start_userspace : expected SIGSTOP, got status = %d",
- status);
+ if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
+ err = -EINVAL;
+ printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got "
+ "status = %d\n", status);
+ goto out_kill;
+ }
if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
- (void *) PTRACE_O_TRACESYSGOOD) < 0)
- panic("start_userspace : PTRACE_OLDSETOPTIONS failed, "
- "errno = %d\n", errno);
+ (void *) PTRACE_O_TRACESYSGOOD) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS "
+ "failed, errno = %d\n", errno);
+ goto out_kill;
+ }
- if (munmap(stack, UM_KERN_PAGE_SIZE) < 0)
- panic("start_userspace : munmap failed, errno = %d\n", errno);
+ if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "start_userspace : munmap failed, "
+ "errno = %d\n", errno);
+ goto out_kill;
+ }
return pid;
+
+ out_kill:
+ os_kill_ptraced_process(pid, 1);
+ return err;
}
void userspace(struct uml_pt_regs *regs)
@@ -302,7 +347,16 @@
nsecs += os_nsecs();
while (1) {
- restore_registers(pid, regs);
+ /*
+ * This can legitimately fail if the process loads a
+ * bogus value into a segment register. It will
+ * segfault and PTRACE_GETREGS will read that value
+ * out of the process. However, PTRACE_SETREGS will
+ * fail. In this case, there is nothing to do but
+ * just kill the process.
+ */
+ if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp))
+ fatal_sigsegv();
/* Now we set local_using_sysemu to be used for one loop */
local_using_sysemu = get_using_sysemu();
@@ -310,19 +364,26 @@
op = SELECT_PTRACE_OPERATION(local_using_sysemu,
singlestepping(NULL));
- err = ptrace(op, pid, 0, 0);
- if (err)
- panic("userspace - could not resume userspace process, "
- "pid=%d, ptrace operation = %d, errno = %d\n",
- pid, op, errno);
+ if (ptrace(op, pid, 0, 0)) {
+ printk(UM_KERN_ERR "userspace - ptrace continue "
+ "failed, op = %d, errno = %d\n", op, errno);
+ fatal_sigsegv();
+ }
CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
- if (err < 0)
- panic("userspace - waitpid failed, errno = %d\n",
- errno);
+ if (err < 0) {
+ printk(UM_KERN_ERR "userspace - wait failed, "
+ "errno = %d\n", errno);
+ fatal_sigsegv();
+ }
regs->is_user = 1;
- save_registers(pid, regs);
+ if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) {
+ printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, "
+ "errno = %d\n", errno);
+ fatal_sigsegv();
+ }
+
UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
if (WIFSTOPPED(status)) {
@@ -345,7 +406,7 @@
break;
case SIGVTALRM:
now = os_nsecs();
- if(now < nsecs)
+ if (now < nsecs)
break;
block_signals();
(*sig_info[sig])(sig, regs);
@@ -368,6 +429,7 @@
default:
printk(UM_KERN_ERR "userspace - child stopped "
"with signal %d\n", sig);
+ fatal_sigsegv();
}
pid = userspace_pid[0];
interrupt_end();
@@ -419,9 +481,12 @@
.it_interval = tv }) });
err = ptrace_setregs(pid, thread_regs);
- if (err < 0)
- panic("copy_context_skas0 : PTRACE_SETREGS failed, "
- "pid = %d, errno = %d\n", pid, -err);
+ if (err < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS "
+ "failed, pid = %d, errno = %d\n", pid, -err);
+ return err;
+ }
/* set a well known return code for detection of child write failure */
child_data->err = 12345678;
@@ -431,31 +496,47 @@
* parent's stack, and check, if bad result.
*/
err = ptrace(PTRACE_CONT, pid, 0, 0);
- if (err)
- panic("Failed to continue new process, pid = %d, "
- "errno = %d\n", pid, errno);
+ if (err) {
+ err = -errno;
+ printk(UM_KERN_ERR "Failed to continue new process, pid = %d, "
+ "errno = %d\n", pid, errno);
+ return err;
+ }
+
wait_stub_done(pid);
pid = data->err;
- if (pid < 0)
- panic("copy_context_skas0 - stub-parent reports error %d\n",
- -pid);
+ if (pid < 0) {
+ printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports "
+ "error %d\n", -pid);
+ return pid;
+ }
/*
* Wait, until child has finished too: read child's result from
* child's stack and check it.
*/
wait_stub_done(pid);
- if (child_data->err != STUB_DATA)
- panic("copy_context_skas0 - stub-child reports error %ld\n",
- child_data->err);
+ if (child_data->err != STUB_DATA) {
+ printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports "
+ "error %ld\n", child_data->err);
+ err = child_data->err;
+ goto out_kill;
+ }
if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
- (void *)PTRACE_O_TRACESYSGOOD) < 0)
- panic("copy_context_skas0 : PTRACE_OLDSETOPTIONS failed, "
- "errno = %d\n", errno);
+ (void *)PTRACE_O_TRACESYSGOOD) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS "
+ "failed, errno = %d\n", errno);
+ goto out_kill;
+ }
return pid;
+
+ out_kill:
+ os_kill_ptraced_process(pid, 1);
+ return err;
}
/*
@@ -463,8 +544,8 @@
* available. Opening /proc/mm creates a new mm_context, which lacks
* the stub-pages. Thus, we map them using /proc/mm-fd
*/
-void map_stub_pages(int fd, unsigned long code,
- unsigned long data, unsigned long stack)
+int map_stub_pages(int fd, unsigned long code, unsigned long data,
+ unsigned long stack)
{
struct proc_mm_op mmop;
int n;
@@ -488,8 +569,9 @@
printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, "
"offset = %llx\n", code, code_fd,
(unsigned long long) code_offset);
- panic("map_stub_pages : /proc/mm map for code failed, "
- "err = %d\n", n);
+ printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code "
+ "failed, err = %d\n", n);
+ return -n;
}
if (stack) {
@@ -507,10 +589,15 @@
.offset = map_offset
} } });
CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
- if (n != sizeof(mmop))
- panic("map_stub_pages : /proc/mm map for data failed, "
- "err = %d\n", errno);
+ if (n != sizeof(mmop)) {
+ n = errno;
+ printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for "
+ "data failed, err = %d\n", n);
+ return -n;
+ }
}
+
+ return 0;
}
void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
@@ -571,7 +658,9 @@
kmalloc_ok = 0;
return 1;
default:
- panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
+ printk(UM_KERN_ERR "Bad sigsetjmp return in "
+ "start_idle_thread - %d\n", n);
+ fatal_sigsegv();
}
longjmp(*switch_buf, 1);
}
@@ -614,9 +703,11 @@
if (proc_mm) {
err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
mm_idp->u.mm_fd);
- if (err)
- panic("__switch_mm - PTRACE_SWITCH_MM failed, "
- "errno = %d\n", errno);
+ if (err) {
+ printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM "
+ "failed, errno = %d\n", errno);
+ fatal_sigsegv();
+ }
}
else userspace_pid[0] = mm_idp->u.pid;
}
diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c
deleted file mode 100644
index 3b1b924..0000000
--- a/arch/um/os-Linux/skas/trap.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#if 0
-#include "kern_util.h"
-#include "skas.h"
-#include "ptrace_user.h"
-#include "sysdep/ptrace_user.h"
-#endif
-
-#include <errno.h>
-#include <signal.h>
-#include "sysdep/ptrace.h"
-#include "kern_constants.h"
-#include "as-layout.h"
-#include "os.h"
-#include "sigcontext.h"
-#include "task.h"
-
-static struct uml_pt_regs ksig_regs[UM_NR_CPUS];
-
-void sig_handler_common_skas(int sig, void *sc_ptr)
-{
- struct sigcontext *sc = sc_ptr;
- struct uml_pt_regs *r;
- void (*handler)(int, struct uml_pt_regs *);
- int save_user, save_errno = errno;
-
- /*
- * This is done because to allow SIGSEGV to be delivered inside a SEGV
- * handler. This can happen in copy_user, and if SEGV is disabled,
- * the process will die.
- * XXX Figure out why this is better than SA_NODEFER
- */
- if (sig == SIGSEGV) {
- change_sig(SIGSEGV, 1);
- /*
- * For segfaults, we want the data from the
- * sigcontext. In this case, we don't want to mangle
- * the process registers, so use a static set of
- * registers. For other signals, the process
- * registers are OK.
- */
- r = &ksig_regs[cpu()];
- copy_sc(r, sc_ptr);
- }
- else r = TASK_REGS(get_current());
-
- save_user = r->is_user;
- r->is_user = 0;
- if ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
- (sig == SIGILL) || (sig == SIGTRAP))
- GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
-
- change_sig(SIGUSR1, 1);
-
- handler = sig_info[sig];
-
- /* unblock SIGVTALRM, SIGIO if sig isn't IRQ signal */
- if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
- unblock_signals();
-
- handler(sig, r);
-
- errno = save_errno;
- r->is_user = save_user;
-}
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 7b81f6c..b616e15 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -60,10 +60,11 @@
* the UML code itself.
*/
ret = 2;
- _exit(ret);
+
+ exit(ret);
}
-static void fatal_perror(char *str)
+static void fatal_perror(const char *str)
{
perror(str);
exit(1);
@@ -341,6 +342,8 @@
void __init os_early_checks(void)
{
+ int pid;
+
/* Print out the core dump limits early */
check_coredump_limit();
@@ -350,6 +353,11 @@
* kernel is running.
*/
check_tmpexec();
+
+ pid = start_ptraced_child();
+ if (init_registers(pid))
+ fatal("Failed to initialize default registers");
+ stop_ptraced_child(pid, 1, 1);
}
static int __init noprocmm_cmd_param(char *str, int* add)
@@ -411,7 +419,6 @@
non_fatal("found\n");
}
- init_registers(pid);
stop_ptraced_child(pid, 1, 1);
}
@@ -466,7 +473,7 @@
else non_fatal("found\n");
}
-int can_do_skas(void)
+void can_do_skas(void)
{
non_fatal("Checking for the skas3 patch in the host:\n");
@@ -476,8 +483,6 @@
if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt)
skas_needs_stub = 1;
-
- return 1;
}
int __init parse_iomem(char *str, int *add)
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
deleted file mode 100644
index 2a1c984..0000000
--- a/arch/um/os-Linux/trap.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include "os.h"
-#include "sysdep/ptrace.h"
-
-/* Initialized from linux_main() */
-void (*sig_info[NSIG])(int, struct uml_pt_regs *);
-
-void os_fill_handlinfo(struct kern_handlers h)
-{
- sig_info[SIGTRAP] = h.relay_signal;
- sig_info[SIGFPE] = h.relay_signal;
- sig_info[SIGILL] = h.relay_signal;
- sig_info[SIGWINCH] = h.winch;
- sig_info[SIGBUS] = h.bus_handler;
- sig_info[SIGSEGV] = h.page_fault;
- sig_info[SIGIO] = h.sigio_handler;
- sig_info[SIGVTALRM] = h.timer_handler;
-}
diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
index 4cfdd18..b09ff66 100644
--- a/arch/um/os-Linux/tty.c
+++ b/arch/um/os-Linux/tty.c
@@ -1,13 +1,16 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include "kern_constants.h"
+#include "kern_util.h"
#include "os.h"
#include "user.h"
-#include "kern_util.h"
struct grantpt_info {
int fd;
@@ -26,36 +29,34 @@
int get_pty(void)
{
struct grantpt_info info;
- int fd;
+ int fd, err;
- fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
- if(fd < 0){
- printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
- return(fd);
+ fd = open("/dev/ptmx", O_RDWR);
+ if (fd < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "get_pty : Couldn't open /dev/ptmx - "
+ "err = %d\n", errno);
+ return err;
}
info.fd = fd;
initial_thread_cb(grantpt_cb, &info);
- if(info.res < 0){
- printk("get_pty : Couldn't grant pty - errno = %d\n",
- -info.err);
- return(-1);
+ if (info.res < 0) {
+ err = -info.err;
+ printk(UM_KERN_ERR "get_pty : Couldn't grant pty - "
+ "errno = %d\n", -info.err);
+ goto out;
}
- if(unlockpt(fd) < 0){
- printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
- return(-1);
- }
- return(fd);
-}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+ if (unlockpt(fd) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "get_pty : Couldn't unlock pty - "
+ "errno = %d\n", errno);
+ goto out;
+ }
+ return fd;
+out:
+ close(fd);
+ return err;
+}
diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c
index d11a55b..cc648e6 100644
--- a/arch/um/os-Linux/tty_log.c
+++ b/arch/um/os-Linux/tty_log.c
@@ -12,7 +12,6 @@
#include <sys/time.h>
#include "init.h"
#include "user.h"
-#include "kern_util.h"
#include "os.h"
#define TTY_LOG_DIR "./"
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 3e058ce..a6f31d4 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -88,21 +88,6 @@
host.release, host.version, host.machine);
}
-int setjmp_wrapper(void (*proc)(void *, void *), ...)
-{
- va_list args;
- jmp_buf buf;
- int n;
-
- n = UML_SETJMP(&buf);
- if(n == 0){
- va_start(args, proc);
- (*proc)(&buf, &args);
- }
- va_end(args);
- return n;
-}
-
void os_dump_core(void)
{
int pid;
diff --git a/arch/um/sys-i386/bug.c b/arch/um/sys-i386/bug.c
index a4360b5..8d4f273 100644
--- a/arch/um/sys-i386/bug.c
+++ b/arch/um/sys-i386/bug.c
@@ -4,6 +4,7 @@
*/
#include <linux/uaccess.h>
+#include <asm/errno.h>
/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
* that's not relevant in skas mode.
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
index 806895d..a74442d 100644
--- a/arch/um/sys-i386/bugs.c
+++ b/arch/um/sys-i386/bugs.c
@@ -3,171 +3,47 @@
* Licensed under the GPL
*/
-#include <errno.h>
#include <signal.h>
-#include <string.h>
#include "kern_constants.h"
-#include "os.h"
+#include "kern_util.h"
+#include "longjmp.h"
#include "task.h"
#include "user.h"
-
-#define MAXTOKEN 64
+#include "sysdep/ptrace.h"
/* Set during early boot */
int host_has_cmov = 1;
-int host_has_xmm = 0;
+static jmp_buf cmov_test_return;
-static char token(int fd, char *buf, int len, char stop)
+static void cmov_sigill_test_handler(int sig)
{
- int n;
- char *ptr, *end, c;
-
- ptr = buf;
- end = &buf[len];
- do {
- n = os_read_file(fd, ptr, sizeof(*ptr));
- c = *ptr++;
- if (n != sizeof(*ptr)) {
- if (n == 0)
- return 0;
- printk(UM_KERN_ERR "Reading /proc/cpuinfo failed, "
- "err = %d\n", -n);
- if (n < 0)
- return n;
- else return -EIO;
- }
- } while ((c != '\n') && (c != stop) && (ptr < end));
-
- if (ptr == end) {
- printk(UM_KERN_ERR "Failed to find '%c' in /proc/cpuinfo\n",
- stop);
- return -1;
- }
- *(ptr - 1) = '\0';
- return c;
-}
-
-static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
-{
- int n;
- char c;
-
- scratch[len - 1] = '\0';
- while (1) {
- c = token(fd, scratch, len - 1, ':');
- if (c <= 0)
- return 0;
- else if (c != ':') {
- printk(UM_KERN_ERR "Failed to find ':' in "
- "/proc/cpuinfo\n");
- return 0;
- }
-
- if (!strncmp(scratch, key, strlen(key)))
- return 1;
-
- do {
- n = os_read_file(fd, &c, sizeof(c));
- if (n != sizeof(c)) {
- printk(UM_KERN_ERR "Failed to find newline in "
- "/proc/cpuinfo, err = %d\n", -n);
- return 0;
- }
- } while (c != '\n');
- }
- return 0;
-}
-
-static int check_cpu_flag(char *feature, int *have_it)
-{
- char buf[MAXTOKEN], c;
- int fd, len = ARRAY_SIZE(buf);
-
- printk(UM_KERN_INFO "Checking for host processor %s support...",
- feature);
- fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
- if (fd < 0) {
- printk(UM_KERN_ERR "Couldn't open /proc/cpuinfo, err = %d\n",
- -fd);
- return 0;
- }
-
- *have_it = 0;
- if (!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf)))
- goto out;
-
- c = token(fd, buf, len - 1, ' ');
- if (c < 0)
- goto out;
- else if (c != ' ') {
- printk(UM_KERN_ERR "Failed to find ' ' in /proc/cpuinfo\n");
- goto out;
- }
-
- while (1) {
- c = token(fd, buf, len - 1, ' ');
- if (c < 0)
- goto out;
- else if (c == '\n')
- break;
-
- if (!strcmp(buf, feature)) {
- *have_it = 1;
- goto out;
- }
- }
- out:
- if (*have_it == 0)
- printk("No\n");
- else if (*have_it == 1)
- printk("Yes\n");
- os_close_file(fd);
- return 1;
-}
-
-#if 0 /*
- * This doesn't work in tt mode, plus it's causing compilation problems
- * for some people.
- */
-static void disable_lcall(void)
-{
- struct modify_ldt_ldt_s ldt;
- int err;
-
- bzero(&ldt, sizeof(ldt));
- ldt.entry_number = 7;
- ldt.base_addr = 0;
- ldt.limit = 0;
- err = modify_ldt(1, &ldt, sizeof(ldt));
- if (err)
- printk(UM_KERN_ERR "Failed to disable lcall7 - errno = %d\n",
- errno);
-}
-#endif
-
-void arch_init_thread(void)
-{
-#if 0
- disable_lcall();
-#endif
+ host_has_cmov = 0;
+ longjmp(cmov_test_return, 1);
}
void arch_check_bugs(void)
{
- int have_it;
+ struct sigaction old, new;
- if (os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0) {
- printk(UM_KERN_ERR "/proc/cpuinfo not available - skipping CPU "
- "capability checks\n");
- return;
- }
- if (check_cpu_flag("cmov", &have_it))
- host_has_cmov = have_it;
- if (check_cpu_flag("xmm", &have_it))
- host_has_xmm = have_it;
+ printk(UM_KERN_INFO "Checking for host processor cmov support...");
+ new.sa_handler = cmov_sigill_test_handler;
+
+ /* Make sure that SIGILL is enabled after the handler longjmps back */
+ new.sa_flags = SA_NODEFER;
+ sigemptyset(&new.sa_mask);
+ sigaction(SIGILL, &new, &old);
+
+ if (setjmp(cmov_test_return) == 0) {
+ unsigned long foo = 0;
+ __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo));
+ printk(UM_KERN_CONT "Yes\n");
+ } else
+ printk(UM_KERN_CONT "No\n");
+
+ sigaction(SIGILL, &old, &new);
}
-int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+void arch_examine_signal(int sig, struct uml_pt_regs *regs)
{
unsigned char tmp[2];
@@ -176,24 +52,25 @@
* SIGILL in init.
*/
if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
- return 0;
+ return;
- if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
- panic("SIGILL in init, could not read instructions!\n");
+ if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
+ printk(UM_KERN_ERR "SIGILL in init, could not read "
+ "instructions!\n");
+ return;
+ }
+
if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
- return 0;
+ return;
if (host_has_cmov == 0)
- panic("SIGILL caused by cmov, which this processor doesn't "
- "implement, boot a filesystem compiled for older "
- "processors");
+ printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+ "processor doesn't implement. Boot a filesystem "
+ "compiled for older processors");
else if (host_has_cmov == 1)
- panic("SIGILL caused by cmov, which this processor claims to "
- "implement");
- else if (host_has_cmov == -1)
- panic("SIGILL caused by cmov, couldn't tell if this processor "
- "implements it, boot a filesystem compiled for older "
- "processors");
- else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
- return 0;
+ printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+ "processor claims to implement");
+ else
+ printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)",
+ host_has_cmov);
}
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 67c0958..a34263e 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -3,8 +3,9 @@
* Licensed under the GPL
*/
-#include "linux/mm.h"
-#include "asm/unistd.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/unistd.h>
#include "os.h"
#include "proc_mm.h"
#include "skas.h"
@@ -146,7 +147,7 @@
if (ptrace_ldt)
return read_ldt_from_host(ptr, bytecount);
- down(&ldt->semaphore);
+ mutex_lock(&ldt->lock);
if (ldt->entry_count <= LDT_DIRECT_ENTRIES) {
size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES;
if (size > bytecount)
@@ -170,7 +171,7 @@
ptr += size;
}
}
- up(&ldt->semaphore);
+ mutex_unlock(&ldt->lock);
if (bytecount == 0 || err == -EFAULT)
goto out;
@@ -228,7 +229,7 @@
}
if (!ptrace_ldt)
- down(&ldt->semaphore);
+ mutex_lock(&ldt->lock);
err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1);
if (err)
@@ -288,7 +289,7 @@
err = 0;
out_unlock:
- up(&ldt->semaphore);
+ mutex_unlock(&ldt->lock);
out:
return err;
}
@@ -395,7 +396,7 @@
if (!ptrace_ldt)
- init_MUTEX(&new_mm->ldt.semaphore);
+ mutex_init(&new_mm->ldt.lock);
if (!from_mm) {
memset(&desc, 0, sizeof(desc));
@@ -455,7 +456,7 @@
* i.e., we have to use the stub for modify_ldt, which
* can't handle the big read buffer of up to 64kB.
*/
- down(&from_mm->ldt.semaphore);
+ mutex_lock(&from_mm->ldt.lock);
if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES)
memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries,
sizeof(new_mm->ldt.u.entries));
@@ -474,7 +475,7 @@
}
}
new_mm->ldt.entry_count = from_mm->ldt.entry_count;
- up(&from_mm->ldt.semaphore);
+ mutex_unlock(&from_mm->ldt.lock);
}
out:
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index bd3da8a..6b44999 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -8,11 +8,11 @@
#include "asm/uaccess.h"
#include "skas.h"
-extern int arch_switch_tls(struct task_struct *from, struct task_struct *to);
+extern int arch_switch_tls(struct task_struct *to);
-void arch_switch_to(struct task_struct *from, struct task_struct *to)
+void arch_switch_to(struct task_struct *to)
{
- int err = arch_switch_tls(from, to);
+ int err = arch_switch_tls(to);
if (!err)
return;
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 5cf97bc..0b10c3e 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -19,17 +19,3 @@
return -errno;
return 0;
}
-
-int ptrace_getfpregs(long pid, unsigned long *regs)
-{
- if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0)
- return -errno;
- return 0;
-}
-
-int ptrace_setfpregs(long pid, unsigned long *regs)
-{
- if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
- return -errno;
- return 0;
-}
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 19053d4..fd0c25a 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -168,12 +168,13 @@
struct sigcontext __user *from)
{
struct sigcontext sc;
- int err;
+ int err, pid;
err = copy_from_user(&sc, from, sizeof(sc));
if (err)
return err;
+ pid = userspace_pid[current_thread_info()->cpu];
copy_sc(®s->regs, &sc);
if (have_fpx_regs) {
struct user_fxsr_struct fpx;
@@ -187,8 +188,7 @@
if (err)
return 1;
- err = restore_fpx_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fpx);
+ err = restore_fpx_registers(pid, (unsigned long *) &fpx);
if (err < 0) {
printk(KERN_ERR "copy_sc_from_user - "
"restore_fpx_registers failed, errno = %d\n",
@@ -204,8 +204,7 @@
if (err)
return 1;
- err = restore_fp_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fp);
+ err = restore_fp_registers(pid, (unsigned long *) &fp);
if (err < 0) {
printk(KERN_ERR "copy_sc_from_user - "
"restore_fp_registers failed, errno = %d\n",
@@ -223,7 +222,7 @@
{
struct sigcontext sc;
struct faultinfo * fi = ¤t->thread.arch.faultinfo;
- int err;
+ int err, pid;
sc.gs = REGS_GS(regs->regs.gp);
sc.fs = REGS_FS(regs->regs.gp);
@@ -249,11 +248,11 @@
to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
sc.fpstate = to_fp;
+ pid = userspace_pid[current_thread_info()->cpu];
if (have_fpx_regs) {
struct user_fxsr_struct fpx;
- err = save_fpx_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fpx);
+ err = save_fpx_registers(pid, (unsigned long *) &fpx);
if (err < 0){
printk(KERN_ERR "copy_sc_to_user - save_fpx_registers "
"failed, errno = %d\n", err);
@@ -276,8 +275,7 @@
else {
struct user_i387_struct fp;
- err = save_fp_registers(userspace_pid[current_thread->cpu],
- (unsigned long *) &fp);
+ err = save_fp_registers(pid, (unsigned long *) &fp);
if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
return 1;
}
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
index e730772..7699e89 100644
--- a/arch/um/sys-i386/stub.S
+++ b/arch/um/sys-i386/stub.S
@@ -7,7 +7,7 @@
.globl batch_syscall_stub
batch_syscall_stub:
/* load pointer to first operation */
- mov $(ASM_STUB_DATA+8), %esp
+ mov $(STUB_DATA+8), %esp
again:
/* load length of additional data */
@@ -15,12 +15,12 @@
/* if(length == 0) : end of list */
/* write possible 0 to header */
- mov %eax, ASM_STUB_DATA+4
+ mov %eax, STUB_DATA+4
cmpl $0, %eax
jz done
/* save current pointer */
- mov %esp, ASM_STUB_DATA+4
+ mov %esp, STUB_DATA+4
/* skip additional data */
add %eax, %esp
@@ -46,7 +46,7 @@
done:
/* save return value */
- mov %eax, ASM_STUB_DATA
+ mov %eax, STUB_DATA
/* stop */
int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
index b3999cb..28ccf73 100644
--- a/arch/um/sys-i386/stub_segv.c
+++ b/arch/um/sys-i386/stub_segv.c
@@ -1,32 +1,17 @@
/*
- * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <signal.h>
-#include <sys/select.h> /* The only way I can see to get sigset_t */
-#include <asm/unistd.h>
-#include "as-layout.h"
-#include "uml-config.h"
#include "sysdep/stub.h"
#include "sysdep/sigcontext.h"
-#include "sysdep/faultinfo.h"
void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig)
{
struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
- int pid;
GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), sc);
- pid = stub_syscall0(__NR_getpid);
- stub_syscall2(__NR_kill, pid, SIGUSR1);
-
- /* Load pointer to sigcontext into esp, since we need to leave
- * the stack in its original form when we do the sigreturn here, by
- * hand.
- */
- __asm__ __volatile__("mov %0,%%esp ; movl %1, %%eax ; "
- "int $0x80" : : "a" (sc), "g" (__NR_sigreturn));
+ trap_myself();
}
diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S
index 12d4148..00e5f520 100644
--- a/arch/um/sys-i386/sys_call_table.S
+++ b/arch/um/sys-i386/sys_call_table.S
@@ -9,4 +9,9 @@
#define old_mmap old_mmap_i386
+.section .rodata,"a"
+
#include "../../x86/kernel/syscall_table_32.S"
+
+ENTRY(syscall_table_size)
+.long .-sys_call_table
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index fcaff86..c6c7131 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -26,6 +26,11 @@
cpu = get_cpu();
ret = os_set_thread_area(info, userspace_pid[cpu]);
put_cpu();
+
+ if (ret)
+ printk(KERN_ERR "PTRACE_SET_THREAD_AREA failed, err = %d, "
+ "index = %d\n", ret, info->entry_number);
+
return ret;
}
@@ -37,6 +42,11 @@
cpu = get_cpu();
ret = os_get_thread_area(info, userspace_pid[cpu]);
put_cpu();
+
+ if (ret)
+ printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, "
+ "index = %d\n", ret, info->entry_number);
+
return ret;
}
@@ -172,7 +182,7 @@
* SKAS patch.
*/
-int arch_switch_tls(struct task_struct *from, struct task_struct *to)
+int arch_switch_tls(struct task_struct *to)
{
if (!host_supports_tls)
return 0;
@@ -225,7 +235,8 @@
}
/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */
-static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx)
+static int get_tls_entry(struct task_struct *task, struct user_desc *info,
+ int idx)
{
struct thread_struct *t = &task->thread;
@@ -263,7 +274,7 @@
goto out;
}
-asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
+int sys_set_thread_area(struct user_desc __user *user_desc)
{
struct user_desc info;
int idx, ret;
@@ -298,7 +309,7 @@
* i386. However the only possible error are caused by bugs.
*/
int ptrace_set_thread_area(struct task_struct *child, int idx,
- struct user_desc __user *user_desc)
+ struct user_desc __user *user_desc)
{
struct user_desc info;
@@ -311,7 +322,7 @@
return set_tls_entry(child, &info, idx, 0);
}
-asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc)
+int sys_get_thread_area(struct user_desc __user *user_desc)
{
struct user_desc info;
int idx, ret;
@@ -355,10 +366,9 @@
return ret;
}
-
/*
- * XXX: This part is probably common to i386 and x86-64. Don't create a common
- * file for now, do that when implementing x86-64 support.
+ * This code is really i386-only, but it detects and logs x86_64 GDT indexes
+ * if a 32-bit UML is running on a 64-bit host.
*/
static int __init __setup_host_supports_tls(void)
{
@@ -367,13 +377,16 @@
printk(KERN_INFO "Host TLS support detected\n");
printk(KERN_INFO "Detected host type: ");
switch (host_gdt_entry_tls_min) {
- case GDT_ENTRY_TLS_MIN_I386:
- printk("i386\n");
- break;
- case GDT_ENTRY_TLS_MIN_X86_64:
- printk("x86_64\n");
- break;
+ case GDT_ENTRY_TLS_MIN_I386:
+ printk(KERN_CONT "i386");
+ break;
+ case GDT_ENTRY_TLS_MIN_X86_64:
+ printk(KERN_CONT "x86_64");
+ break;
}
+ printk(KERN_CONT " (GDT indexes %d to %d)\n",
+ host_gdt_entry_tls_min,
+ host_gdt_entry_tls_min + GDT_ENTRY_TLS_ENTRIES);
} else
printk(KERN_ERR " Host TLS support NOT detected! "
"TLS support inside UML will not work\n");
diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile
index a9814a7..0890152 100644
--- a/arch/um/sys-ppc/Makefile
+++ b/arch/um/sys-ppc/Makefile
@@ -6,7 +6,7 @@
OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
ptrace_user.o sysrq.o
-EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel
+EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel
all: $(OBJ)
@@ -22,25 +22,25 @@
semaphore.c:
rm -f $@
- ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+ ln -s $(srctree)/arch/ppc/kernel/$@ $@
checksum.S:
rm -f $@
- ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
+ ln -s $(srctree)/arch/ppc/lib/$@ $@
mk_defs.c:
rm -f $@
- ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+ ln -s $(srctree)/arch/ppc/kernel/$@ $@
ppc_defs.head:
rm -f $@
- ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+ ln -s $(srctree)/arch/ppc/kernel/$@ $@
ppc_defs.h: mk_defs.c ppc_defs.head \
- $(TOPDIR)/include/asm-ppc/mmu.h \
- $(TOPDIR)/include/asm-ppc/processor.h \
- $(TOPDIR)/include/asm-ppc/pgtable.h \
- $(TOPDIR)/include/asm-ppc/ptrace.h
+ $(srctree)/include/asm-ppc/mmu.h \
+ $(srctree)/include/asm-ppc/processor.h \
+ $(srctree)/include/asm-ppc/pgtable.h \
+ $(srctree)/include/asm-ppc/ptrace.h
# $(CC) $(CFLAGS) -S mk_defs.c
cp ppc_defs.head ppc_defs.h
# for bk, this way we can write to the file even if it's not checked out
@@ -56,13 +56,13 @@
checksum.o: checksum.S
rm -f asm
- ln -s $(TOPDIR)/include/asm-ppc asm
+ ln -s $(srctree)/include/asm-ppc asm
$(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
rm -f asm
misc.o: misc.S ppc_defs.h
rm -f asm
- ln -s $(TOPDIR)/include/asm-ppc asm
+ ln -s $(srctree)/include/asm-ppc asm
$(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
rm -f asm
diff --git a/arch/um/sys-x86_64/bug.c b/arch/um/sys-x86_64/bug.c
index a4360b5..e8034e3 100644
--- a/arch/um/sys-x86_64/bug.c
+++ b/arch/um/sys-x86_64/bug.c
@@ -5,7 +5,8 @@
#include <linux/uaccess.h>
-/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
+/*
+ * Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
* that's not relevant in skas mode.
*/
diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c
index 506b676..44e02ba 100644
--- a/arch/um/sys-x86_64/bugs.c
+++ b/arch/um/sys-x86_64/bugs.c
@@ -6,15 +6,10 @@
#include "sysdep/ptrace.h"
-void arch_init_thread(void)
-{
-}
-
void arch_check_bugs(void)
{
}
-int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+void arch_examine_signal(int sig, struct uml_pt_regs *regs)
{
- return 0;
}
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
index b7631b0..f3458d7 100644
--- a/arch/um/sys-x86_64/ptrace.c
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -5,13 +5,12 @@
* Licensed under the GPL
*/
-#define __FRAME_OFFSETS
-#include <asm/ptrace.h>
+#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/mm.h>
+#define __FRAME_OFFSETS
+#include <asm/ptrace.h>
#include <asm/uaccess.h>
-#include <asm/elf.h>
/*
* determines which flags the user has access to.
@@ -24,12 +23,14 @@
unsigned long tmp;
#ifdef TIF_IA32
- /* Some code in the 64bit emulation may not be 64bit clean.
- Don't take any chances. */
+ /*
+ * Some code in the 64bit emulation may not be 64bit clean.
+ * Don't take any chances.
+ */
if (test_tsk_thread_flag(child, TIF_IA32))
value &= 0xffffffff;
#endif
- switch (regno){
+ switch (regno) {
case FS:
case GS:
case DS:
@@ -66,7 +67,7 @@
if (addr < MAX_REG_OFFSET)
return putreg(child, addr, data);
else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
- (addr <= offsetof(struct user, u_debugreg[7]))){
+ (addr <= offsetof(struct user, u_debugreg[7]))) {
addr -= offsetof(struct user, u_debugreg[0]);
addr = addr >> 2;
if ((addr == 4) || (addr == 5))
@@ -108,11 +109,10 @@
return -EIO;
tmp = 0; /* Default return condition */
- if (addr < MAX_REG_OFFSET){
+ if (addr < MAX_REG_OFFSET)
tmp = getreg(child, addr);
- }
else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
- (addr <= offsetof(struct user, u_debugreg[7]))){
+ (addr <= offsetof(struct user, u_debugreg[7]))) {
addr -= offsetof(struct user, u_debugreg[0]);
addr = addr >> 2;
tmp = child->thread.arch.debugregs[addr];
@@ -127,8 +127,9 @@
int n;
n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
- if (n){
- /* access_process_vm() grants access to vsyscall and stub,
+ if (n) {
+ /*
+ * access_process_vm() grants access to vsyscall and stub,
* while copy_from_user doesn't. Maybe access_process_vm is
* slow, but that doesn't matter, since it will be called only
* in case of singlestepping, if copy_from_user failed.
@@ -155,7 +156,7 @@
return err;
n = copy_to_user(buf, fpregs, sizeof(fpregs));
- if(n > 0)
+ if (n > 0)
return -EFAULT;
return n;
diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c
index b5f9c33..c57a496 100644
--- a/arch/um/sys-x86_64/ptrace_user.c
+++ b/arch/um/sys-x86_64/ptrace_user.c
@@ -4,55 +4,19 @@
* Licensed under the GPL
*/
-#include <stddef.h>
#include <errno.h>
#include "ptrace_user.h"
-#include "user.h"
-#include "kern_constants.h"
int ptrace_getregs(long pid, unsigned long *regs_out)
{
- if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
- return(-errno);
- return(0);
-}
-
-int ptrace_setregs(long pid, unsigned long *regs)
-{
- if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0)
- return(-errno);
- return(0);
-}
-
-int ptrace_setfpregs(long pid, unsigned long *regs)
-{
- if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
+ if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
return -errno;
- return 0;
+ return(0);
}
-void ptrace_pokeuser(unsigned long addr, unsigned long data)
+int ptrace_setregs(long pid, unsigned long *regs_out)
{
- panic("ptrace_pokeuser");
-}
-
-#define DS 184
-#define ES 192
-#define __USER_DS 0x2b
-
-void arch_enter_kernel(void *task, int pid)
-{
-}
-
-void arch_leave_kernel(void *task, int pid)
-{
-#ifdef UM_USER_CS
- if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0)
- printk("POKEUSR CS failed");
-#endif
-
- if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0)
- printk("POKEUSR DS failed");
- if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0)
- printk("POKEUSR ES failed");
+ if (ptrace(PTRACE_SETREGS, pid, 0, regs_out) < 0)
+ return -errno;
+ return(0);
}
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 7457436..1a899a7 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -81,7 +81,7 @@
if (err)
return 1;
- err = restore_fp_registers(userspace_pid[current_thread->cpu],
+ err = restore_fp_registers(userspace_pid[current_thread_info()->cpu],
(unsigned long *) &fp);
if (err < 0) {
printk(KERN_ERR "copy_sc_from_user - "
@@ -112,7 +112,7 @@
err |= PUTREG(regs, RSI, to, si);
err |= PUTREG(regs, RBP, to, bp);
/*
- * Must use orignal RSP, which is passed in, rather than what's in
+ * Must use original RSP, which is passed in, rather than what's in
* the pt_regs, because that's already been updated to point at the
* signal frame.
*/
@@ -143,7 +143,7 @@
if (err)
return 1;
- err = save_fp_registers(userspace_pid[current_thread->cpu],
+ err = save_fp_registers(userspace_pid[current_thread_info()->cpu],
(unsigned long *) &fp);
if (err < 0) {
printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
index 4afe204..5687687 100644
--- a/arch/um/sys-x86_64/stub.S
+++ b/arch/um/sys-x86_64/stub.S
@@ -8,18 +8,18 @@
/* We don't have 64-bit constants, so this constructs the address
* we need.
*/
- movq $(ASM_STUB_DATA >> 32), %rbx
+ movq $(STUB_DATA >> 32), %rbx
salq $32, %rbx
- movq $(ASM_STUB_DATA & 0xffffffff), %rcx
+ movq $(STUB_DATA & 0xffffffff), %rcx
or %rcx, %rbx
movq %rax, (%rbx)
int3
.globl batch_syscall_stub
batch_syscall_stub:
- mov $(ASM_STUB_DATA >> 32), %rbx
+ mov $(STUB_DATA >> 32), %rbx
sal $32, %rbx
- mov $(ASM_STUB_DATA & 0xffffffff), %rax
+ mov $(STUB_DATA & 0xffffffff), %rax
or %rax, %rbx
/* load pointer to first operation */
mov %rbx, %rsp
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
index 3afb590..ced051a 100644
--- a/arch/um/sys-x86_64/stub_segv.c
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -1,51 +1,22 @@
/*
- * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <stddef.h>
#include <signal.h>
-#include <asm/unistd.h>
#include "as-layout.h"
-#include "uml-config.h"
-#include "sysdep/sigcontext.h"
-#include "sysdep/faultinfo.h"
#include "sysdep/stub.h"
-
-/* Copied from sys-x86_64/signal.c - Can't find an equivalent definition
- * in the libc headers anywhere.
- */
-struct rt_sigframe
-{
- char *pretcode;
- struct ucontext uc;
- struct siginfo info;
-};
-
-/* Copied here from <linux/kernel.h> - we're userspace. */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
+#include "sysdep/faultinfo.h"
+#include "sysdep/sigcontext.h"
void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig)
{
struct ucontext *uc;
- int pid;
__asm__ __volatile__("movq %%rdx, %0" : "=g" (uc) :);
GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA),
&uc->uc_mcontext);
-
- pid = stub_syscall0(__NR_getpid);
- stub_syscall2(__NR_kill, pid, SIGUSR1);
-
- /* sys_sigreturn expects that the stack pointer will be 8 bytes into
- * the signal frame. So, we use the ucontext pointer, which we know
- * already, to get the signal frame pointer, and add 8 to that.
- */
- __asm__ __volatile__("movq %0, %%rsp; movq %1, %%rax ; syscall": :
- "g" ((unsigned long)
- container_of(uc, struct rt_sigframe, uc) + 8),
- "g" (__NR_rt_sigreturn));
+ trap_myself();
}
+
diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c
index 71b2ae4..c128eb8 100644
--- a/arch/um/sys-x86_64/syscall_table.c
+++ b/arch/um/sys-x86_64/syscall_table.c
@@ -1,5 +1,7 @@
-/* System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c
- * with some changes for UML. */
+/*
+ * System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c
+ * with some changes for UML.
+ */
#include <linux/linkage.h>
#include <linux/sys.h>
@@ -8,22 +10,26 @@
#define __NO_STUBS
-/* Below you can see, in terms of #define's, the differences between the x86-64
- * and the UML syscall table. */
+/*
+ * Below you can see, in terms of #define's, the differences between the x86-64
+ * and the UML syscall table.
+ */
/* Not going to be implemented by UML, since we have no hardware. */
#define stub_iopl sys_ni_syscall
#define sys_ioperm sys_ni_syscall
-/* The UML TLS problem. Note that x86_64 does not implement this, so the below
- * is needed only for the ia32 compatibility. */
-/*#define sys_set_thread_area sys_ni_syscall
-#define sys_get_thread_area sys_ni_syscall*/
+/*
+ * The UML TLS problem. Note that x86_64 does not implement this, so the below
+ * is needed only for the ia32 compatibility.
+ */
/* On UML we call it this way ("old" means it's not mmap2) */
#define sys_mmap old_mmap
-/* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick.
- * See arch/x86_64/kernel/sys_x86_64.c */
+/*
+ * On x86-64 sys_uname is actually sys_newuname plus a compatibility trick.
+ * See arch/x86_64/kernel/sys_x86_64.c
+ */
#define sys_uname sys_uname64
#define stub_clone sys_clone
@@ -46,8 +52,19 @@
extern void sys_ni_syscall(void);
-sys_call_ptr_t sys_call_table[UM_NR_syscall_max+1] __cacheline_aligned = {
- /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */
- [0 ... UM_NR_syscall_max] = &sys_ni_syscall,
+/*
+ * We used to have a trick here which made sure that holes in the
+ * x86_64 table were filled in with sys_ni_syscall, but a comment in
+ * unistd_64.h says that holes aren't allowed, so the trick was
+ * removed.
+ * The trick looked like this
+ * [0 ... UM_NR_syscall_max] = &sys_ni_syscall
+ * before including unistd_64.h - the later initializations overwrote
+ * the sys_ni_syscall filler.
+ */
+
+sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
#include <asm-x86/unistd_64.h>
};
+
+int syscall_table_size = sizeof(sys_call_table);
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
index 86f6b18..f1199fd 100644
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -48,7 +48,9 @@
switch (code) {
case ARCH_SET_FS:
case ARCH_SET_GS:
- restore_registers(pid, ¤t->thread.regs.regs);
+ ret = restore_registers(pid, ¤t->thread.regs.regs);
+ if (ret)
+ return ret;
break;
case ARCH_GET_FS:
case ARCH_GET_GS:
@@ -70,10 +72,10 @@
switch (code) {
case ARCH_SET_FS:
current->thread.arch.fs = (unsigned long) ptr;
- save_registers(pid, ¤t->thread.regs.regs);
+ ret = save_registers(pid, ¤t->thread.regs.regs);
break;
case ARCH_SET_GS:
- save_registers(pid, ¤t->thread.regs.regs);
+ ret = save_registers(pid, ¤t->thread.regs.regs);
break;
case ARCH_GET_FS:
ret = put_user(tmp, addr);
@@ -105,7 +107,7 @@
return ret;
}
-void arch_switch_to(struct task_struct *from, struct task_struct *to)
+void arch_switch_to(struct task_struct *to)
{
if ((to->thread.arch.fs == 0) || (to->mm == NULL))
return;
diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c
index 7654440..f4f82be 100644
--- a/arch/um/sys-x86_64/sysrq.c
+++ b/arch/um/sys-x86_64/sysrq.c
@@ -4,32 +4,33 @@
* Licensed under the GPL
*/
-#include "linux/kernel.h"
-#include "linux/utsname.h"
-#include "linux/module.h"
-#include "asm/current.h"
-#include "asm/ptrace.h"
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <asm/current.h>
+#include <asm/ptrace.h>
#include "sysrq.h"
-void __show_regs(struct pt_regs * regs)
+void __show_regs(struct pt_regs *regs)
{
printk("\n");
print_modules();
- printk("Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
+ printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
current->comm, print_tainted(), init_utsname()->release);
- printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff,
+ printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
PT_REGS_RIP(regs));
- printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs),
+ printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs),
PT_REGS_EFLAGS(regs));
- printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
+ printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
- printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
+ printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n",
PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs));
- printk("RBP: %016lx R08: %016lx R09: %016lx\n",
+ printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n",
PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
- printk("R10: %016lx R11: %016lx R12: %016lx\n",
+ printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n",
PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs));
- printk("R13: %016lx R14: %016lx R15: %016lx\n",
+ printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n",
PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs));
}
diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c
index 8b8eff1..3dead39 100644
--- a/arch/um/sys-x86_64/um_module.c
+++ b/arch/um/sys-x86_64/um_module.c
@@ -1,7 +1,7 @@
#include <linux/vmalloc.h>
#include <linux/moduleloader.h>
-/*Copied from i386 arch/i386/kernel/module.c */
+/* Copied from i386 arch/i386/kernel/module.c */
void *module_alloc(unsigned long size)
{
if (size == 0)
@@ -13,7 +13,9 @@
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
- /* FIXME: If module_region == mod->init_region, trim exception
- table entries. */
+ /*
+ * FIXME: If module_region == mod->init_region, trim exception
+ * table entries.
+ */
}
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index b6a50b8..ace479a 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -331,8 +331,6 @@
source "drivers/usb/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/v850/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 93e6667..3954ae9 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -18,6 +18,8 @@
### Arch settings
config X86
def_bool y
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
config GENERIC_LOCKBREAK
def_bool n
@@ -96,6 +98,9 @@
config ARCH_HAS_ILOG2_U64
def_bool n
+config ARCH_HAS_CPU_IDLE_WAIT
+ def_bool y
+
config GENERIC_CALIBRATE_DELAY
def_bool y
@@ -103,15 +108,22 @@
bool
default X86_64
+config ARCH_HAS_CPU_RELAX
+ def_bool y
+
config HAVE_SETUP_PER_CPU_AREA
def_bool X86_64
-config ARCH_SUPPORTS_OPROFILE
- bool
- default y
-
select HAVE_KVM
+config ARCH_HIBERNATION_POSSIBLE
+ def_bool y
+ depends on !SMP || !X86_VOYAGER
+
+config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+ depends on !X86_VOYAGER
+
config ZONE_DMA32
bool
default X86_64
@@ -196,8 +208,7 @@
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
- See also the <file:Documentation/smp.txt>,
- <file:Documentation/i386/IO-APIC.txt>,
+ See also <file:Documentation/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
<http://www.tldp.org/docs.html#howto>.
@@ -301,6 +312,7 @@
select M486
select X86_REBOOTFIXUPS
select GENERIC_GPIO
+ select LEDS_CLASS
select LEDS_GPIO
help
This option is needed for RDC R-321x system-on-chip, also known
@@ -409,7 +421,7 @@
config HPET_EMULATE_RTC
def_bool y
- depends on HPET_TIMER && (RTC=y || RTC=m)
+ depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y)
# Mark as embedded because too many people got it wrong.
# The code disables itself when not needed.
@@ -459,6 +471,9 @@
Calgary anyway, pass 'iommu=calgary' on the kernel command line.
If unsure, say Y.
+config IOMMU_HELPER
+ def_bool (CALGARY_IOMMU || GART_IOMMU)
+
# need this always selected by IOMMU for the VIA workaround
config SWIOTLB
bool
@@ -1369,11 +1384,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't.
-
choice
prompt "PCI access mode"
depends on X86_32 && PCI && !X86_VISWS
@@ -1594,8 +1604,6 @@
source "fs/Kconfig"
-source "kernel/Kconfig.instrumentation"
-
source "arch/x86/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 2e1e3af..fa55514 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -220,9 +220,9 @@
This option will cause struct boot_params to be exported via debugfs.
config CPA_DEBUG
- bool "CPA self test code"
+ bool "CPA self-test code"
depends on DEBUG_KERNEL
help
- Do change_page_attr self tests at boot.
+ Do change_page_attr() self-tests every 30 seconds.
endmenu
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 8978e98..364865b 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -92,7 +92,6 @@
KBUILD_CFLAGS += $(cfi) $(cfi-sigframe)
LDFLAGS := -m elf_$(UTS_MACHINE)
-OBJCOPYFLAGS := -O binary -R .note -R .comment -S
# Speed up the build
KBUILD_CFLAGS += -pipe
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 349b81a..f88458e 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -26,7 +26,7 @@
#RAMDISK := -DRAMDISK=512
targets := vmlinux.bin setup.bin setup.elf zImage bzImage
-subdir- := compressed
+subdir- := compressed
setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
@@ -43,9 +43,17 @@
setup-y += video-bios.o
targets += $(setup-y)
-hostprogs-y := tools/build
+hostprogs-y := mkcpustr tools/build
-HOSTCFLAGS_build.o := $(LINUXINCLUDE)
+HOST_EXTRACFLAGS += $(LINUXINCLUDE)
+
+$(obj)/cpu.o: $(obj)/cpustr.h
+
+quiet_cmd_cpustr = CPUSTR $@
+ cmd_cpustr = $(obj)/mkcpustr > $@
+targets += cpustr.h
+$(obj)/cpustr.h: $(obj)/mkcpustr FORCE
+ $(call if_changed,cpustr)
# ---------------------------------------------------------------------------
@@ -80,6 +88,7 @@
$(call if_changed,image)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@@ -90,7 +99,6 @@
$(call if_changed,ld)
OBJCOPYFLAGS_setup.bin := -O binary
-
$(obj)/setup.bin: $(obj)/setup.elf FORCE
$(call if_changed,objcopy)
@@ -98,7 +106,7 @@
$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
-FDARGS =
+FDARGS =
# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
FDINITRD =
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index fe24cea..d2b9f3b 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -22,6 +22,7 @@
$(call if_changed,ld)
@:
+OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 1ccb38a..e8657b9 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -80,8 +80,8 @@
#ifdef CONFIG_RELOCATABLE
movl %ebp, %ebx
- addl $(LARGE_PAGE_SIZE -1), %ebx
- andl $LARGE_PAGE_MASK, %ebx
+ addl $(PMD_PAGE_SIZE -1), %ebx
+ andl $PMD_PAGE_MASK, %ebx
#else
movl $CONFIG_PHYSICAL_START, %ebx
#endif
@@ -220,8 +220,8 @@
/* Start with the delta to where the kernel will run at. */
#ifdef CONFIG_RELOCATABLE
leaq startup_32(%rip) /* - $startup_32 */, %rbp
- addq $(LARGE_PAGE_SIZE - 1), %rbp
- andq $LARGE_PAGE_MASK, %rbp
+ addq $(PMD_PAGE_SIZE - 1), %rbp
+ andq $PMD_PAGE_MASK, %rbp
movq %rbp, %rbx
#else
movq $CONFIG_PHYSICAL_START, %rbp
diff --git a/arch/x86/boot/cpu.c b/arch/x86/boot/cpu.c
index 2a5c32d..00e19ed 100644
--- a/arch/x86/boot/cpu.c
+++ b/arch/x86/boot/cpu.c
@@ -1,7 +1,7 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright 2007 rPath, Inc. - All Rights Reserved
+ * Copyright 2007-2008 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
@@ -9,7 +9,7 @@
* ----------------------------------------------------------------------- */
/*
- * arch/i386/boot/cpu.c
+ * arch/x86/boot/cpu.c
*
* Check for obligatory CPU features and abort if the features are not
* present.
@@ -19,6 +19,8 @@
#include "bitops.h"
#include <asm/cpufeature.h>
+#include "cpustr.h"
+
static char *cpu_name(int level)
{
static char buf[6];
@@ -35,6 +37,7 @@
{
u32 *err_flags;
int cpu_level, req_level;
+ const unsigned char *msg_strs;
check_cpu(&cpu_level, &req_level, &err_flags);
@@ -51,13 +54,26 @@
puts("This kernel requires the following features "
"not present on the CPU:\n");
+ msg_strs = (const unsigned char *)x86_cap_strs;
+
for (i = 0; i < NCAPINTS; i++) {
u32 e = err_flags[i];
for (j = 0; j < 32; j++) {
- if (e & 1)
- printf("%d:%d ", i, j);
-
+ int n = (i << 5)+j;
+ if (*msg_strs < n) {
+ /* Skip to the next string */
+ do {
+ msg_strs++;
+ } while (*msg_strs);
+ msg_strs++;
+ }
+ if (e & 1) {
+ if (*msg_strs == n && msg_strs[1])
+ printf("%s ", msg_strs+1);
+ else
+ printf("%d:%d ", i, j);
+ }
e >>= 1;
}
}
diff --git a/arch/x86/boot/mkcpustr.c b/arch/x86/boot/mkcpustr.c
new file mode 100644
index 0000000..bbe7695
--- /dev/null
+++ b/arch/x86/boot/mkcpustr.c
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2 or (at your
+ * option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * This is a host program to preprocess the CPU strings into a
+ * compact format suitable for the setup code.
+ */
+
+#include <stdio.h>
+
+#include "../kernel/cpu/feature_names.c"
+
+#if NCAPFLAGS > 8
+# error "Need to adjust the boot code handling of CPUID strings"
+#endif
+
+int main(void)
+{
+ int i;
+ const char *str;
+
+ printf("static const char x86_cap_strs[] = \n");
+
+ for (i = 0; i < NCAPINTS*32; i++) {
+ str = x86_cap_flags[i];
+
+ if (i == NCAPINTS*32-1) {
+ /* The last entry must be unconditional; this
+ also consumes the compiler-added null character */
+ if (!str)
+ str = "";
+ printf("\t\"\\x%02x\"\"%s\"\n", i, str);
+ } else if (str) {
+ printf("#if REQUIRED_MASK%d & (1 << %d)\n"
+ "\t\"\\x%02x\"\"%s\\0\"\n"
+ "#endif\n",
+ i >> 5, i & 31, i, str);
+ }
+ }
+ printf("\t;\n");
+ return 0;
+}
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 0db0a62..8022d3c 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -722,7 +722,9 @@
.quad sys_epoll_pwait
.quad compat_sys_utimensat /* 320 */
.quad compat_sys_signalfd
- .quad compat_sys_timerfd
+ .quad sys_timerfd_create
.quad sys_eventfd
.quad sys32_fallocate
+ .quad compat_sys_timerfd_settime /* 325 */
+ .quad compat_sys_timerfd_gettime
ia32_syscall_end:
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 6f81300..21dc1a0 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -37,7 +37,8 @@
obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_PCI) += early-quirks.o
-obj-$(CONFIG_APM) += apm_32.o
+apm-y := apm_32.o
+obj-$(CONFIG_APM) += apm.o
obj-$(CONFIG_X86_SMP) += smp_$(BITS).o smpboot_$(BITS).o tsc_sync.o
obj-$(CONFIG_X86_32_SMP) += smpcommon_32.o
obj-$(CONFIG_X86_64_SMP) += smp_64.o smpboot_64.o tsc_sync.o
@@ -74,7 +75,8 @@
obj-y += pcspeaker.o
endif
-obj-$(CONFIG_SCx200) += scx200_32.o
+obj-$(CONFIG_SCx200) += scx200.o
+scx200-y += scx200_32.o
###
# 64 bit specific files
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index d2a5843..f3e049e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -106,7 +106,7 @@
#ifdef CONFIG_X86_64
/* rely on all ACPI tables being in the direct mapping */
-char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
{
if (!phys_addr || !size)
return NULL;
@@ -131,7 +131,7 @@
* from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and
* count idx down while incrementing the phys address.
*/
-char *__acpi_map_table(unsigned long phys, unsigned long size)
+char *__init __acpi_map_table(unsigned long phys, unsigned long size)
{
unsigned long base, offset, mapped_size;
int idx;
@@ -587,25 +587,6 @@
EXPORT_SYMBOL(acpi_unregister_ioapic);
-static unsigned long __init
-acpi_scan_rsdp(unsigned long start, unsigned long length)
-{
- unsigned long offset = 0;
- unsigned long sig_len = sizeof("RSD PTR ") - 1;
-
- /*
- * Scan all 16-byte boundaries of the physical memory region for the
- * RSDP signature.
- */
- for (offset = 0; offset < length; offset += 16) {
- if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
- continue;
- return (start + offset);
- }
-
- return 0;
-}
-
static int __init acpi_parse_sbf(struct acpi_table_header *table)
{
struct acpi_table_boot *sb;
@@ -748,27 +729,6 @@
return 0;
}
-unsigned long __init acpi_find_rsdp(void)
-{
- unsigned long rsdp_phys = 0;
-
- if (efi_enabled) {
- if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- return efi.acpi20;
- else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- return efi.acpi;
- }
- /*
- * Scan memory looking for the RSDP signature. First search EBDA (low
- * memory) paragraphs and then search upper memory (E0000-FFFFF).
- */
- rsdp_phys = acpi_scan_rsdp(0, 0x400);
- if (!rsdp_phys)
- rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
-
- return rsdp_phys;
-}
-
#ifdef CONFIG_X86_LOCAL_APIC
/*
* Parse LAPIC entries in MADT
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index cfdb2f3b..a0c4d7c 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -3,6 +3,7 @@
#
obj-y := intel_cacheinfo.o addon_cpuid_features.o
+obj-y += feature_names.o
obj-$(CONFIG_X86_32) += common.o proc.o bugs.o
obj-$(CONFIG_X86_32) += amd.o
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index b7b2142..f86a3c4 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -623,16 +623,6 @@
* They will insert themselves into the cpu_devs structure.
* Then, when cpu_init() is called, we can just iterate over that array.
*/
-
-extern int intel_cpu_init(void);
-extern int cyrix_init_cpu(void);
-extern int nsc_init_cpu(void);
-extern int amd_init_cpu(void);
-extern int centaur_init_cpu(void);
-extern int transmeta_init_cpu(void);
-extern int nexgen_init_cpu(void);
-extern int umc_init_cpu(void);
-
void __init early_cpu_init(void)
{
intel_cpu_init();
@@ -647,7 +637,7 @@
}
/* Make sure %fs is initialized properly in idle threads */
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
{
memset(regs, 0, sizeof(struct pt_regs));
regs->fs = __KERNEL_PERCPU;
diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h
index ad6527a..e0b38c3 100644
--- a/arch/x86/kernel/cpu/cpu.h
+++ b/arch/x86/kernel/cpu/cpu.h
@@ -27,3 +27,12 @@
extern void early_init_intel(struct cpuinfo_x86 *c);
extern void early_init_amd(struct cpuinfo_x86 *c);
+/* Specific CPU type init functions */
+int intel_cpu_init(void);
+int amd_init_cpu(void);
+int cyrix_init_cpu(void);
+int nsc_init_cpu(void);
+int centaur_init_cpu(void);
+int transmeta_init_cpu(void);
+int nexgen_init_cpu(void);
+int umc_init_cpu(void);
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index a052273..5affe91 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -827,7 +827,6 @@
for (i = 0; i < data->acpi_data.state_count; i++) {
u32 index;
- u32 hi = 0, lo = 0;
index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
if (index > data->max_hw_pstate) {
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
index 76c3ab0..98d4fdb 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
@@ -189,10 +189,7 @@
printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n");
/* Multiplier. */
- if (c->x86_model < 2)
- mult = msr_lo >> 27;
- else
- mult = msr_lo >> 24;
+ mult = msr_lo >> 24;
dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult));
diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
index 404a6a2..7139b02 100644
--- a/arch/x86/kernel/cpu/cyrix.c
+++ b/arch/x86/kernel/cpu/cyrix.c
@@ -83,8 +83,6 @@
* FIXME: our newer udelay uses the tsc. We don't need to frob with SLOP
*/
-extern void calibrate_delay(void) __init;
-
static void __cpuinit check_cx686_slop(struct cpuinfo_x86 *c)
{
unsigned long flags;
diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c
new file mode 100644
index 0000000..ee975ac
--- /dev/null
+++ b/arch/x86/kernel/cpu/feature_names.c
@@ -0,0 +1,83 @@
+/*
+ * Strings for the various x86 capability flags.
+ *
+ * This file must not contain any executable code.
+ */
+
+#include "asm/cpufeature.h"
+
+/*
+ * These flag bits must match the definitions in <asm/cpufeature.h>.
+ * NULL means this bit is undefined or reserved; either way it doesn't
+ * have meaning as far as Linux is concerned. Note that it's important
+ * to realize there is a difference between this table and CPUID -- if
+ * applications want to get the raw CPUID data, they should access
+ * /dev/cpu/<cpu_nr>/cpuid instead.
+ */
+const char * const x86_cap_flags[NCAPINTS*32] = {
+ /* Intel-defined */
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
+
+ /* AMD-defined */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
+ NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
+ "3dnowext", "3dnow",
+
+ /* Transmeta-defined */
+ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Other (Linux-defined) */
+ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+ NULL, NULL, NULL, NULL,
+ "constant_tsc", "up", NULL, "arch_perfmon",
+ "pebs", "bts", NULL, NULL,
+ "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Intel-defined (#2) */
+ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+ "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
+ NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* VIA/Cyrix/Centaur-defined */
+ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
+ "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* AMD-defined (#2) */
+ "lahf_lm", "cmp_legacy", "svm", "extapic",
+ "cr8_legacy", "abm", "sse4a", "misalignsse",
+ "3dnowprefetch", "osvw", "ibs", "sse5",
+ "skinit", "wdt", NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Auxiliary (Linux-defined) */
+ "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+const char *const x86_power_flags[32] = {
+ "ts", /* temperature sensor */
+ "fid", /* frequency id control */
+ "vid", /* voltage id control */
+ "ttp", /* thermal trip */
+ "tm",
+ "stc",
+ "100mhzsteps",
+ "hwpstate",
+ "", /* tsc invariant mapped to constant_tsc */
+ /* nothing */
+};
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index d1c372b..fae31ce 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -13,6 +13,7 @@
#include <asm/uaccess.h>
#include <asm/ptrace.h>
#include <asm/ds.h>
+#include <asm/bugs.h>
#include "cpu.h"
diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c
index 8e139c7..ff14c32 100644
--- a/arch/x86/kernel/cpu/mtrr/cyrix.c
+++ b/arch/x86/kernel/cpu/mtrr/cyrix.c
@@ -7,8 +7,6 @@
#include <asm/processor-flags.h>
#include "mtrr.h"
-int arr3_protected;
-
static void
cyrix_get_arr(unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type * type)
@@ -99,8 +97,6 @@
case 4:
return replace_reg;
case 3:
- if (arr3_protected)
- break;
case 2:
case 1:
case 0:
@@ -115,8 +111,6 @@
} else {
for (i = 0; i < 7; i++) {
cyrix_get_arr(i, &lbase, &lsize, <ype);
- if ((i == 3) && arr3_protected)
- continue;
if (lsize == 0)
return i;
}
@@ -260,107 +254,6 @@
post_set();
}
-#if 0
-/*
- * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
- * with the SMM (System Management Mode) mode. So we need the following:
- * Check whether SMI_LOCK (CCR3 bit 0) is set
- * if it is set, write a warning message: ARR3 cannot be changed!
- * (it cannot be changed until the next processor reset)
- * if it is reset, then we can change it, set all the needed bits:
- * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
- * - disable access to SMM memory (CCR1 bit 2 reset)
- * - disable SMM mode (CCR1 bit 1 reset)
- * - disable write protection of ARR3 (CCR6 bit 1 reset)
- * - (maybe) disable ARR3
- * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
- */
-static void __init
-cyrix_arr_init(void)
-{
- struct set_mtrr_context ctxt;
- unsigned char ccr[7];
- int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
-#ifdef CONFIG_SMP
- int i;
-#endif
-
- /* flush cache and enable MAPEN */
- set_mtrr_prepare_save(&ctxt);
- set_mtrr_cache_disable(&ctxt);
-
- /* Save all CCRs locally */
- ccr[0] = getCx86(CX86_CCR0);
- ccr[1] = getCx86(CX86_CCR1);
- ccr[2] = getCx86(CX86_CCR2);
- ccr[3] = ctxt.ccr3;
- ccr[4] = getCx86(CX86_CCR4);
- ccr[5] = getCx86(CX86_CCR5);
- ccr[6] = getCx86(CX86_CCR6);
-
- if (ccr[3] & 1) {
- ccrc[3] = 1;
- arr3_protected = 1;
- } else {
- /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
- * access to SMM memory through ARR3 (bit 7).
- */
- if (ccr[1] & 0x80) {
- ccr[1] &= 0x7f;
- ccrc[1] |= 0x80;
- }
- if (ccr[1] & 0x04) {
- ccr[1] &= 0xfb;
- ccrc[1] |= 0x04;
- }
- if (ccr[1] & 0x02) {
- ccr[1] &= 0xfd;
- ccrc[1] |= 0x02;
- }
- arr3_protected = 0;
- if (ccr[6] & 0x02) {
- ccr[6] &= 0xfd;
- ccrc[6] = 1; /* Disable write protection of ARR3 */
- setCx86(CX86_CCR6, ccr[6]);
- }
- /* Disable ARR3. This is safe now that we disabled SMM. */
- /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
- }
- /* If we changed CCR1 in memory, change it in the processor, too. */
- if (ccrc[1])
- setCx86(CX86_CCR1, ccr[1]);
-
- /* Enable ARR usage by the processor */
- if (!(ccr[5] & 0x20)) {
- ccr[5] |= 0x20;
- ccrc[5] = 1;
- setCx86(CX86_CCR5, ccr[5]);
- }
-#ifdef CONFIG_SMP
- for (i = 0; i < 7; i++)
- ccr_state[i] = ccr[i];
- for (i = 0; i < 8; i++)
- cyrix_get_arr(i,
- &arr_state[i].base, &arr_state[i].size,
- &arr_state[i].type);
-#endif
-
- set_mtrr_done(&ctxt); /* flush cache and disable MAPEN */
-
- if (ccrc[5])
- printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n");
- if (ccrc[3])
- printk(KERN_INFO "mtrr: ARR3 cannot be changed\n");
-/*
- if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
- if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
- if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
-*/
- if (ccrc[6])
- printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
-}
-#endif
-
static struct mtrr_ops cyrix_mtrr_ops = {
.vendor = X86_VENDOR_CYRIX,
// .init = cyrix_arr_init,
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 7159195..b6e136f 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -59,12 +59,6 @@
static void set_mtrr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type);
-#ifndef CONFIG_X86_64
-extern int arr3_protected;
-#else
-#define arr3_protected 0
-#endif
-
void set_mtrr_ops(struct mtrr_ops * ops)
{
if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
@@ -513,12 +507,6 @@
printk(KERN_WARNING "mtrr: register: %d too big\n", reg);
goto out;
}
- if (is_cpu(CYRIX) && !use_intel()) {
- if ((reg == 3) && arr3_protected) {
- printk(KERN_WARNING "mtrr: ARR3 cannot be changed\n");
- goto out;
- }
- }
mtrr_if->get(reg, &lbase, &lsize, <ype);
if (lsize < 1) {
printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
@@ -566,10 +554,6 @@
* These should be called implicitly, but we can't yet until all the initcall
* stuff is done...
*/
-extern void amd_init_mtrr(void);
-extern void cyrix_init_mtrr(void);
-extern void centaur_init_mtrr(void);
-
static void __init init_ifs(void)
{
#ifndef CONFIG_X86_64
@@ -675,7 +659,7 @@
*/
int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
{
- unsigned long i, base, size, highest_addr = 0, def, dummy;
+ unsigned long i, base, size, highest_pfn = 0, def, dummy;
mtrr_type type;
u64 trim_start, trim_size;
@@ -698,28 +682,27 @@
mtrr_if->get(i, &base, &size, &type);
if (type != MTRR_TYPE_WRBACK)
continue;
- base <<= PAGE_SHIFT;
- size <<= PAGE_SHIFT;
- if (highest_addr < base + size)
- highest_addr = base + size;
+ if (highest_pfn < base + size)
+ highest_pfn = base + size;
}
/* kvm/qemu doesn't have mtrr set right, don't trim them all */
- if (!highest_addr) {
+ if (!highest_pfn) {
printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n");
WARN_ON(1);
return 0;
}
- if ((highest_addr >> PAGE_SHIFT) < end_pfn) {
+ if (highest_pfn < end_pfn) {
printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
- " all of memory, losing %LdMB of RAM.\n",
- (((u64)end_pfn << PAGE_SHIFT) - highest_addr) >> 20);
+ " all of memory, losing %luMB of RAM.\n",
+ (end_pfn - highest_pfn) >> (20 - PAGE_SHIFT));
WARN_ON(1);
printk(KERN_INFO "update e820 for mtrr\n");
- trim_start = highest_addr;
+ trim_start = highest_pfn;
+ trim_start <<= PAGE_SHIFT;
trim_size = end_pfn;
trim_size <<= PAGE_SHIFT;
trim_size -= trim_start;
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h
index fb74a2c..2cc77eb 100644
--- a/arch/x86/kernel/cpu/mtrr/mtrr.h
+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h
@@ -97,3 +97,7 @@
const char *mtrr_attrib_to_str(int x);
void mtrr_wrmsr(unsigned, unsigned, unsigned);
+/* CPU specific mtrr init functions */
+int amd_init_mtrr(void);
+int cyrix_init_mtrr(void);
+int centaur_init_mtrr(void);
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 02821326..af11d31 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -10,80 +10,6 @@
*/
static int show_cpuinfo(struct seq_file *m, void *v)
{
- /*
- * These flag bits must match the definitions in <asm/cpufeature.h>.
- * NULL means this bit is undefined or reserved; either way it doesn't
- * have meaning as far as Linux is concerned. Note that it's important
- * to realize there is a difference between this table and CPUID -- if
- * applications want to get the raw CPUID data, they should access
- * /dev/cpu/<cpu_nr>/cpuid instead.
- */
- static const char * const x86_cap_flags[] = {
- /* Intel-defined */
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
-
- /* AMD-defined */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
- NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
- "3dnowext", "3dnow",
-
- /* Transmeta-defined */
- "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Other (Linux-defined) */
- "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
- NULL, NULL, NULL, NULL,
- "constant_tsc", "up", NULL, "arch_perfmon",
- "pebs", "bts", NULL, "sync_rdtsc",
- "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Intel-defined (#2) */
- "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
- "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
- NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* VIA/Cyrix/Centaur-defined */
- NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
- "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* AMD-defined (#2) */
- "lahf_lm", "cmp_legacy", "svm", "extapic",
- "cr8_legacy", "abm", "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", "ibs", "sse5",
- "skinit", "wdt", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Auxiliary (Linux-defined) */
- "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- };
- static const char * const x86_power_flags[] = {
- "ts", /* temperature sensor */
- "fid", /* frequency id control */
- "vid", /* voltage id control */
- "ttp", /* thermal trip */
- "tm",
- "stc",
- "100mhzsteps",
- "hwpstate",
- "", /* constant_tsc - moved to flags */
- /* nothing */
- };
struct cpuinfo_x86 *c = v;
int i, n = 0;
int fpu_exception;
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index a63432d..288e7a6 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
- *
- * Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ * Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,10 @@
* and then read in chunks of 16 bytes. A larger size means multiple
* reads of consecutive levels.
*
+ * The lower 32 bits of the file position is used as the incoming %eax,
+ * and the upper 32 bits of the file position as the incoming %ecx,
+ * the latter intended for "counting" eax levels like eax=4.
+ *
* This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
* an SMP box will direct the access to CPU %d.
*/
@@ -43,35 +47,24 @@
static struct class *cpuid_class;
-struct cpuid_command {
- u32 reg;
- u32 *data;
+struct cpuid_regs {
+ u32 eax, ebx, ecx, edx;
};
static void cpuid_smp_cpuid(void *cmd_block)
{
- struct cpuid_command *cmd = cmd_block;
+ struct cpuid_regs *cmd = (struct cpuid_regs *)cmd_block;
- cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2],
- &cmd->data[3]);
-}
-
-static inline void do_cpuid(int cpu, u32 reg, u32 * data)
-{
- struct cpuid_command cmd;
-
- cmd.reg = reg;
- cmd.data = data;
-
- smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
+ cpuid_count(cmd->eax, cmd->ecx,
+ &cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx);
}
static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
+ struct inode *inode = file->f_mapping->host;
- lock_kernel();
-
+ mutex_lock(&inode->i_mutex);
switch (orig) {
case 0:
file->f_pos = offset;
@@ -84,8 +77,7 @@
default:
ret = -EINVAL;
}
-
- unlock_kernel();
+ mutex_unlock(&inode->i_mutex);
return ret;
}
@@ -93,19 +85,21 @@
size_t count, loff_t * ppos)
{
char __user *tmp = buf;
- u32 data[4];
- u32 reg = *ppos;
+ struct cpuid_regs cmd;
int cpu = iminor(file->f_path.dentry->d_inode);
+ u64 pos = *ppos;
if (count % 16)
return -EINVAL; /* Invalid chunk size */
for (; count; count -= 16) {
- do_cpuid(cpu, reg, data);
- if (copy_to_user(tmp, &data, 16))
+ cmd.eax = pos;
+ cmd.ecx = pos >> 32;
+ smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
+ if (copy_to_user(tmp, &cmd, 16))
return -EFAULT;
tmp += 16;
- *ppos = reg++;
+ *ppos = ++pos;
}
return tmp - buf;
@@ -193,7 +187,7 @@
}
for_each_online_cpu(i) {
err = cpuid_device_create(i);
- if (err != 0)
+ if (err != 0)
goto out_class;
}
register_hotcpu_notifier(&cpuid_class_cpu_notifier);
@@ -208,7 +202,7 @@
}
class_destroy(cpuid_class);
out_chrdev:
- unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
+ unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
out:
return err;
}
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
index 1411324..32dd62b 100644
--- a/arch/x86/kernel/efi.c
+++ b/arch/x86/kernel/efi.c
@@ -379,11 +379,9 @@
#endif
}
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
static void __init runtime_code_page_mkexec(void)
{
efi_memory_desc_t *md;
- unsigned long end;
void *p;
if (!(__supported_pte_mask & _PAGE_NX))
@@ -392,18 +390,13 @@
/* Make EFI runtime service code area executable */
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
- end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
- if (md->type == EFI_RUNTIME_SERVICES_CODE &&
- (end >> PAGE_SHIFT) <= max_pfn_mapped) {
- set_memory_x(md->virt_addr, md->num_pages);
- set_memory_uc(md->virt_addr, md->num_pages);
- }
+
+ if (md->type != EFI_RUNTIME_SERVICES_CODE)
+ continue;
+
+ set_memory_x(md->virt_addr, md->num_pages << EFI_PAGE_SHIFT);
}
- __flush_tlb_all();
}
-#else
-static inline void __init runtime_code_page_mkexec(void) { }
-#endif
/*
* This function will switch the EFI runtime services to virtual mode.
@@ -417,30 +410,40 @@
{
efi_memory_desc_t *md;
efi_status_t status;
- unsigned long end;
- void *p;
+ unsigned long size;
+ u64 end, systab;
+ void *p, *va;
efi.systab = NULL;
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
if (!(md->attribute & EFI_MEMORY_RUNTIME))
continue;
- end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
- if ((md->attribute & EFI_MEMORY_WB) &&
- ((end >> PAGE_SHIFT) <= max_pfn_mapped))
- md->virt_addr = (unsigned long)__va(md->phys_addr);
+
+ size = md->num_pages << EFI_PAGE_SHIFT;
+ end = md->phys_addr + size;
+
+ if ((end >> PAGE_SHIFT) <= max_pfn_mapped)
+ va = __va(md->phys_addr);
else
- md->virt_addr = (unsigned long)
- efi_ioremap(md->phys_addr,
- md->num_pages << EFI_PAGE_SHIFT);
- if (!md->virt_addr)
+ va = efi_ioremap(md->phys_addr, size);
+
+ if (md->attribute & EFI_MEMORY_WB)
+ set_memory_uc(md->virt_addr, size);
+
+ md->virt_addr = (u64) (unsigned long) va;
+
+ if (!va) {
printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
(unsigned long long)md->phys_addr);
- if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
- ((unsigned long)efi_phys.systab < end))
- efi.systab = (efi_system_table_t *)(unsigned long)
- (md->virt_addr - md->phys_addr +
- (unsigned long)efi_phys.systab);
+ continue;
+ }
+
+ systab = (u64) (unsigned long) efi_phys.systab;
+ if (md->phys_addr <= systab && systab < end) {
+ systab += md->virt_addr - md->phys_addr;
+ efi.systab = (efi_system_table_t *) (unsigned long) systab;
+ }
}
BUG_ON(!efi.systab);
diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c
index 674f237..09d5c23 100644
--- a/arch/x86/kernel/efi_64.c
+++ b/arch/x86/kernel/efi_64.c
@@ -54,10 +54,10 @@
else
set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
__supported_pte_mask));
- if (level == 4)
- start = (start + PMD_SIZE) & PMD_MASK;
- else
+ if (level == PG_LEVEL_4K)
start = (start + PAGE_SIZE) & PAGE_MASK;
+ else
+ start = (start + PMD_SIZE) & PMD_MASK;
}
}
@@ -109,23 +109,23 @@
memmap.nr_map * memmap.desc_size);
}
-void __iomem * __init efi_ioremap(unsigned long offset,
- unsigned long size)
+void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
{
static unsigned pages_mapped;
- unsigned long last_addr;
unsigned i, pages;
- last_addr = offset + size - 1;
- offset &= PAGE_MASK;
- pages = (PAGE_ALIGN(last_addr) - offset) >> PAGE_SHIFT;
+ /* phys_addr and size must be page aligned */
+ if ((phys_addr & ~PAGE_MASK) || (size & ~PAGE_MASK))
+ return NULL;
+
+ pages = size >> PAGE_SHIFT;
if (pages_mapped + pages > MAX_EFI_IO_PAGES)
return NULL;
for (i = 0; i < pages; i++) {
__set_fixmap(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
- offset, PAGE_KERNEL_EXEC_NOCACHE);
- offset += PAGE_SIZE;
+ phys_addr, PAGE_KERNEL);
+ phys_addr += PAGE_SIZE;
pages_mapped++;
}
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index bea8474..c7341e8 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -582,7 +582,6 @@
TRACE_IRQS_IRETQ
restore_args:
RESTORE_ARGS 0,8,0
-iret_label:
#ifdef CONFIG_PARAVIRT
INTERRUPT_RETURN
#endif
@@ -593,13 +592,22 @@
.quad native_iret, bad_iret
.previous
.section .fixup,"ax"
- /* force a signal here? this matches i386 behaviour */
- /* running with kernel gs */
bad_iret:
- movq $11,%rdi /* SIGSEGV */
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
- jmp do_exit
+ /*
+ * The iret traps when the %cs or %ss being restored is bogus.
+ * We've lost the original trap vector and error code.
+ * #GPF is the most likely one to get for an invalid selector.
+ * So pretend we completed the iret and took the #GPF in user mode.
+ *
+ * We are now running with the kernel GS after exception recovery.
+ * But error_entry expects us to have user GS to match the user %cs,
+ * so swap back.
+ */
+ pushq $0
+
+ SWAPGS
+ jmp general_protection
+
.previous
/* edi: workmask, edx: work */
@@ -911,7 +919,7 @@
iret run with kernel gs again, so don't set the user space flag.
B stepping K8s sometimes report an truncated RIP for IRET
exceptions returning to compat mode. Check for these here too. */
- leaq iret_label(%rip),%rbp
+ leaq native_iret(%rip),%rbp
cmpq %rbp,RIP(%rsp)
je error_swapgs
movl %ebp,%ebp /* zero extend */
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 1d5a7a3..09b38d5 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -63,7 +63,7 @@
/* Is the address not 2M aligned? */
movq %rbp, %rax
- andl $~LARGE_PAGE_MASK, %eax
+ andl $~PMD_PAGE_MASK, %eax
testl %eax, %eax
jnz bad_address
@@ -88,7 +88,7 @@
/* Add an Identity mapping if I am above 1G */
leaq _text(%rip), %rdi
- andq $LARGE_PAGE_MASK, %rdi
+ andq $PMD_PAGE_MASK, %rdi
movq %rdi, %rax
shrq $PUD_SHIFT, %rax
@@ -250,18 +250,13 @@
lretq
/* SMP bootup changes these two */
-#ifndef CONFIG_HOTPLUG_CPU
- .pushsection .init.data
-#endif
+ __CPUINITDATA
.align 8
- .globl initial_code
-initial_code:
+ ENTRY(initial_code)
.quad x86_64_start_kernel
-#ifndef CONFIG_HOTPLUG_CPU
- .popsection
-#endif
- .globl init_rsp
-init_rsp:
+ __FINITDATA
+
+ ENTRY(init_rsp)
.quad init_thread_union+THREAD_SIZE-8
bad_address:
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index 8a7660c..0224c36 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -35,7 +35,8 @@
if (mincount <= pc->size)
return 0;
oldsize = pc->size;
- mincount = (mincount + 511) & (~511);
+ mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) &
+ (~(PAGE_SIZE / LDT_ENTRY_SIZE - 1));
if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE)
newldt = vmalloc(mincount * LDT_ENTRY_SIZE);
else
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index bd82850..af51ea8 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
- *
- * Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ * Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,9 +45,10 @@
static loff_t msr_seek(struct file *file, loff_t offset, int orig)
{
- loff_t ret = -EINVAL;
+ loff_t ret;
+ struct inode *inode = file->f_mapping->host;
- lock_kernel();
+ mutex_lock(&inode->i_mutex);
switch (orig) {
case 0:
file->f_pos = offset;
@@ -56,8 +57,11 @@
case 1:
file->f_pos += offset;
ret = file->f_pos;
+ break;
+ default:
+ ret = -EINVAL;
}
- unlock_kernel();
+ mutex_unlock(&inode->i_mutex);
return ret;
}
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 1fe7f04..1b5464c 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -35,6 +35,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/scatterlist.h>
+#include <linux/iommu-helper.h>
#include <asm/gart.h>
#include <asm/calgary.h>
#include <asm/tce.h>
@@ -260,22 +261,28 @@
spin_unlock_irqrestore(&tbl->it_lock, flags);
}
-static unsigned long iommu_range_alloc(struct iommu_table *tbl,
- unsigned int npages)
+static unsigned long iommu_range_alloc(struct device *dev,
+ struct iommu_table *tbl,
+ unsigned int npages)
{
unsigned long flags;
unsigned long offset;
+ unsigned long boundary_size;
+
+ boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+ PAGE_SIZE) >> PAGE_SHIFT;
BUG_ON(npages == 0);
spin_lock_irqsave(&tbl->it_lock, flags);
- offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
- tbl->it_size, npages);
+ offset = iommu_area_alloc(tbl->it_map, tbl->it_size, tbl->it_hint,
+ npages, 0, boundary_size, 0);
if (offset == ~0UL) {
tbl->chip_ops->tce_cache_blast(tbl);
- offset = find_next_zero_string(tbl->it_map, 0,
- tbl->it_size, npages);
+
+ offset = iommu_area_alloc(tbl->it_map, tbl->it_size, 0,
+ npages, 0, boundary_size, 0);
if (offset == ~0UL) {
printk(KERN_WARNING "Calgary: IOMMU full.\n");
spin_unlock_irqrestore(&tbl->it_lock, flags);
@@ -286,7 +293,6 @@
}
}
- set_bit_string(tbl->it_map, offset, npages);
tbl->it_hint = offset + npages;
BUG_ON(tbl->it_hint > tbl->it_size);
@@ -295,13 +301,13 @@
return offset;
}
-static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
- unsigned int npages, int direction)
+static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
+ void *vaddr, unsigned int npages, int direction)
{
unsigned long entry;
dma_addr_t ret = bad_dma_address;
- entry = iommu_range_alloc(tbl, npages);
+ entry = iommu_range_alloc(dev, tbl, npages);
if (unlikely(entry == bad_dma_address))
goto error;
@@ -354,7 +360,7 @@
badbit, tbl, dma_addr, entry, npages);
}
- __clear_bit_string(tbl->it_map, entry, npages);
+ iommu_area_free(tbl->it_map, entry, npages);
spin_unlock_irqrestore(&tbl->it_lock, flags);
}
@@ -438,7 +444,7 @@
vaddr = (unsigned long) sg_virt(s);
npages = num_dma_pages(vaddr, s->length);
- entry = iommu_range_alloc(tbl, npages);
+ entry = iommu_range_alloc(dev, tbl, npages);
if (entry == bad_dma_address) {
/* makes sure unmap knows to stop */
s->dma_length = 0;
@@ -476,7 +482,7 @@
npages = num_dma_pages(uaddr, size);
if (translation_enabled(tbl))
- dma_handle = iommu_alloc(tbl, vaddr, npages, direction);
+ dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction);
else
dma_handle = virt_to_bus(vaddr);
@@ -516,7 +522,7 @@
if (translation_enabled(tbl)) {
/* set up tces to cover the allocated range */
- mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL);
+ mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL);
if (mapping == bad_dma_address)
goto free;
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c
index 4d5cc71..65f6acb 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/pci-gart_64.c
@@ -25,6 +25,7 @@
#include <linux/bitops.h>
#include <linux/kdebug.h>
#include <linux/scatterlist.h>
+#include <linux/iommu-helper.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/mtrr.h>
@@ -82,17 +83,24 @@
static unsigned long next_bit; /* protected by iommu_bitmap_lock */
static int need_flush; /* global flush state. set for each gart wrap */
-static unsigned long alloc_iommu(int size)
+static unsigned long alloc_iommu(struct device *dev, int size)
{
unsigned long offset, flags;
+ unsigned long boundary_size;
+ unsigned long base_index;
+
+ base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev),
+ PAGE_SIZE) >> PAGE_SHIFT;
+ boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+ PAGE_SIZE) >> PAGE_SHIFT;
spin_lock_irqsave(&iommu_bitmap_lock, flags);
- offset = find_next_zero_string(iommu_gart_bitmap, next_bit,
- iommu_pages, size);
+ offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit,
+ size, base_index, boundary_size, 0);
if (offset == -1) {
need_flush = 1;
- offset = find_next_zero_string(iommu_gart_bitmap, 0,
- iommu_pages, size);
+ offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0,
+ size, base_index, boundary_size, 0);
}
if (offset != -1) {
set_bit_string(iommu_gart_bitmap, offset, size);
@@ -114,7 +122,7 @@
unsigned long flags;
spin_lock_irqsave(&iommu_bitmap_lock, flags);
- __clear_bit_string(iommu_gart_bitmap, offset, size);
+ iommu_area_free(iommu_gart_bitmap, offset, size);
spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
}
@@ -235,7 +243,7 @@
size_t size, int dir)
{
unsigned long npages = to_pages(phys_mem, size);
- unsigned long iommu_page = alloc_iommu(npages);
+ unsigned long iommu_page = alloc_iommu(dev, npages);
int i;
if (iommu_page == -1) {
@@ -355,10 +363,11 @@
}
/* Map multiple scatterlist entries continuous into the first. */
-static int __dma_map_cont(struct scatterlist *start, int nelems,
- struct scatterlist *sout, unsigned long pages)
+static int __dma_map_cont(struct device *dev, struct scatterlist *start,
+ int nelems, struct scatterlist *sout,
+ unsigned long pages)
{
- unsigned long iommu_start = alloc_iommu(pages);
+ unsigned long iommu_start = alloc_iommu(dev, pages);
unsigned long iommu_page = iommu_start;
struct scatterlist *s;
int i;
@@ -394,8 +403,8 @@
}
static inline int
-dma_map_cont(struct scatterlist *start, int nelems, struct scatterlist *sout,
- unsigned long pages, int need)
+dma_map_cont(struct device *dev, struct scatterlist *start, int nelems,
+ struct scatterlist *sout, unsigned long pages, int need)
{
if (!need) {
BUG_ON(nelems != 1);
@@ -403,7 +412,7 @@
sout->dma_length = start->length;
return 0;
}
- return __dma_map_cont(start, nelems, sout, pages);
+ return __dma_map_cont(dev, start, nelems, sout, pages);
}
/*
@@ -416,6 +425,8 @@
struct scatterlist *s, *ps, *start_sg, *sgmap;
int need = 0, nextneed, i, out, start;
unsigned long pages = 0;
+ unsigned int seg_size;
+ unsigned int max_seg_size;
if (nents == 0)
return 0;
@@ -426,6 +437,8 @@
out = 0;
start = 0;
start_sg = sgmap = sg;
+ seg_size = 0;
+ max_seg_size = dma_get_max_seg_size(dev);
ps = NULL; /* shut up gcc */
for_each_sg(sg, s, nents, i) {
dma_addr_t addr = sg_phys(s);
@@ -443,11 +456,13 @@
* offset.
*/
if (!iommu_merge || !nextneed || !need || s->offset ||
+ (s->length + seg_size > max_seg_size) ||
(ps->offset + ps->length) % PAGE_SIZE) {
- if (dma_map_cont(start_sg, i - start, sgmap,
- pages, need) < 0)
+ if (dma_map_cont(dev, start_sg, i - start,
+ sgmap, pages, need) < 0)
goto error;
out++;
+ seg_size = 0;
sgmap = sg_next(sgmap);
pages = 0;
start = i;
@@ -455,11 +470,12 @@
}
}
+ seg_size += s->length;
need = nextneed;
pages += to_pages(s->offset, s->length);
ps = s;
}
- if (dma_map_cont(start_sg, i - start, sgmap, pages, need) < 0)
+ if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0)
goto error;
out++;
flush_gart();
@@ -501,7 +517,7 @@
}
a = aper + iommu_size;
- iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
+ iommu_size -= round_up(a, PMD_PAGE_SIZE) - a;
if (iommu_size < 64*1024*1024) {
printk(KERN_WARNING
@@ -731,7 +747,8 @@
* the backing memory. The GART address is only used by PCI
* devices.
*/
- clear_kernel_mapping((unsigned long)__va(iommu_bus_base), iommu_size);
+ set_memory_np((unsigned long)__va(iommu_bus_base),
+ iommu_size >> PAGE_SHIFT);
/*
* Try to workaround a bug (thanks to BenH)
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 968371a..dabdbef 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -251,7 +251,7 @@
* because it has nothing to do.
* Give all the remaining CPUS a kick.
*/
- smp_call_function_mask(map, do_nothing, 0, 0);
+ smp_call_function_mask(map, do_nothing, NULL, 0);
} while (!cpus_empty(map));
set_cpus_allowed(current, tmp);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 96286df..702c33ef 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -103,9 +103,26 @@
if (invalid_selector(value))
return -EIO;
- if (offset != offsetof(struct user_regs_struct, gs))
+ /*
+ * For %cs and %ss we cannot permit a null selector.
+ * We can permit a bogus selector as long as it has USER_RPL.
+ * Null selectors are fine for other segment registers, but
+ * we will never get back to user mode with invalid %cs or %ss
+ * and will take the trap in iret instead. Much code relies
+ * on user_mode() to distinguish a user trap frame (which can
+ * safely use invalid selectors) from a kernel trap frame.
+ */
+ switch (offset) {
+ case offsetof(struct user_regs_struct, cs):
+ case offsetof(struct user_regs_struct, ss):
+ if (unlikely(value == 0))
+ return -EIO;
+
+ default:
*pt_regs_access(task_pt_regs(task), offset) = value;
- else {
+ break;
+
+ case offsetof(struct user_regs_struct, gs):
task->thread.gs = value;
if (task == current)
/*
@@ -227,12 +244,16 @@
* Can't actually change these in 64-bit mode.
*/
case offsetof(struct user_regs_struct,cs):
+ if (unlikely(value == 0))
+ return -EIO;
#ifdef CONFIG_IA32_EMULATION
if (test_tsk_thread_flag(task, TIF_IA32))
task_pt_regs(task)->cs = value;
#endif
break;
case offsetof(struct user_regs_struct,ss):
+ if (unlikely(value == 0))
+ return -EIO;
#ifdef CONFIG_IA32_EMULATION
if (test_tsk_thread_flag(task, TIF_IA32))
task_pt_regs(task)->ss = value;
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 150ba29..6ba33ca 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -30,8 +30,8 @@
raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
if (!(word & (1 << 13))) {
- printk(KERN_INFO "Intel E7520/7320/7525 detected. "
- "Disabling irq balancing and affinity\n");
+ dev_info(&dev->dev, "Intel E7520/7320/7525 detected; "
+ "disabling irq balancing and affinity\n");
#ifdef CONFIG_IRQBALANCE
irqbalance_disable("");
#endif
@@ -104,14 +104,16 @@
pci_read_config_dword(dev, 0xF0, &rcba);
rcba &= 0xFFFFC000;
if (rcba == 0) {
- printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
+ dev_printk(KERN_DEBUG, &dev->dev, "RCBA disabled; "
+ "cannot force enable HPET\n");
return;
}
/* use bits 31:14, 16 kB aligned */
rcba_base = ioremap_nocache(rcba, 0x4000);
if (rcba_base == NULL) {
- printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
+ dev_printk(KERN_DEBUG, &dev->dev, "ioremap failed; "
+ "cannot force enable HPET\n");
return;
}
@@ -122,8 +124,8 @@
/* HPET is enabled in HPTC. Just not reported by BIOS */
val = val & 0x3;
force_hpet_address = 0xFED00000 | (val << 12);
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
+ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+ "0x%lx\n", force_hpet_address);
iounmap(rcba_base);
return;
}
@@ -142,11 +144,12 @@
if (err) {
force_hpet_address = 0;
iounmap(rcba_base);
- printk(KERN_DEBUG "Failed to force enable HPET\n");
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "Failed to force enable HPET\n");
} else {
force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
+ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+ "0x%lx\n", force_hpet_address);
}
}
@@ -208,8 +211,8 @@
if (val & 0x4) {
val &= 0x3;
force_hpet_address = 0xFED00000 | (val << 12);
- printk(KERN_DEBUG "HPET at base address 0x%lx\n",
- force_hpet_address);
+ dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n",
+ force_hpet_address);
return;
}
@@ -229,14 +232,14 @@
/* HPET is enabled in HPTC. Just not reported by BIOS */
val &= 0x3;
force_hpet_address = 0xFED00000 | (val << 12);
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
+ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+ "0x%lx\n", force_hpet_address);
cached_dev = dev;
force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
return;
}
- printk(KERN_DEBUG "Failed to force enable HPET\n");
+ dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n");
}
/*
@@ -294,8 +297,8 @@
*/
if (val & 0x80) {
force_hpet_address = (val & ~0x3ff);
- printk(KERN_DEBUG "HPET at base address 0x%lx\n",
- force_hpet_address);
+ dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n",
+ force_hpet_address);
return;
}
@@ -309,14 +312,14 @@
pci_read_config_dword(dev, 0x68, &val);
if (val & 0x80) {
force_hpet_address = (val & ~0x3ff);
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
- force_hpet_address);
+ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+ "0x%lx\n", force_hpet_address);
cached_dev = dev;
force_hpet_resume_type = VT8237_FORCE_HPET_RESUME;
return;
}
- printk(KERN_DEBUG "Failed to force enable HPET\n");
+ dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235,
@@ -344,7 +347,7 @@
pci_read_config_dword(dev, 0x44, &val);
force_hpet_address = val & 0xfffffffe;
force_hpet_resume_type = NVIDIA_FORCE_HPET_RESUME;
- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
force_hpet_address);
cached_dev = dev;
return;
@@ -377,19 +380,19 @@
void force_hpet_resume(void)
{
switch (force_hpet_resume_type) {
- case ICH_FORCE_HPET_RESUME:
- return ich_force_hpet_resume();
-
- case OLD_ICH_FORCE_HPET_RESUME:
- return old_ich_force_hpet_resume();
-
- case VT8237_FORCE_HPET_RESUME:
- return vt8237_force_hpet_resume();
-
- case NVIDIA_FORCE_HPET_RESUME:
- return nvidia_force_hpet_resume();
-
- default:
+ case ICH_FORCE_HPET_RESUME:
+ ich_force_hpet_resume();
+ return;
+ case OLD_ICH_FORCE_HPET_RESUME:
+ old_ich_force_hpet_resume();
+ return;
+ case VT8237_FORCE_HPET_RESUME:
+ vt8237_force_hpet_resume();
+ return;
+ case NVIDIA_FORCE_HPET_RESUME:
+ nvidia_force_hpet_resume();
+ return;
+ default:
break;
}
}
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 18df70c..c8939df 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -1068,82 +1068,6 @@
struct cpuinfo_x86 *c = v;
int cpu = 0, i;
- /*
- * These flag bits must match the definitions in <asm/cpufeature.h>.
- * NULL means this bit is undefined or reserved; either way it doesn't
- * have meaning as far as Linux is concerned. Note that it's important
- * to realize there is a difference between this table and CPUID -- if
- * applications want to get the raw CPUID data, they should access
- * /dev/cpu/<cpu_nr>/cpuid instead.
- */
- static const char *const x86_cap_flags[] = {
- /* Intel-defined */
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
-
- /* AMD-defined */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
- NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
- "3dnowext", "3dnow",
-
- /* Transmeta-defined */
- "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Other (Linux-defined) */
- "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
- NULL, NULL, NULL, NULL,
- "constant_tsc", "up", NULL, "arch_perfmon",
- "pebs", "bts", NULL, "sync_rdtsc",
- "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Intel-defined (#2) */
- "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
- "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
- NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* VIA/Cyrix/Centaur-defined */
- NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
- "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* AMD-defined (#2) */
- "lahf_lm", "cmp_legacy", "svm", "extapic",
- "cr8_legacy", "abm", "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", "ibs", "sse5",
- "skinit", "wdt", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
- /* Auxiliary (Linux-defined) */
- "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- };
- static const char *const x86_power_flags[] = {
- "ts", /* temperature sensor */
- "fid", /* frequency id control */
- "vid", /* voltage id control */
- "ttp", /* thermal trip */
- "tm",
- "stc",
- "100mhzsteps",
- "hwpstate",
- "", /* tsc invariant mapped to constant_tsc */
- /* nothing */
- };
-
-
#ifdef CONFIG_SMP
cpu = c->cpu_index;
#endif
diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c
index 5787a0c..579b9b7 100644
--- a/arch/x86/kernel/smpboot_32.c
+++ b/arch/x86/kernel/smpboot_32.c
@@ -202,8 +202,6 @@
;
}
-extern void calibrate_delay(void);
-
static atomic_t init_deasserted;
static void __cpuinit smp_callin(void)
diff --git a/arch/x86/kernel/srat_32.c b/arch/x86/kernel/srat_32.c
index 2bf6903..b72e613 100644
--- a/arch/x86/kernel/srat_32.c
+++ b/arch/x86/kernel/srat_32.c
@@ -274,7 +274,7 @@
int tables = 0;
int i = 0;
- rsdp_address = acpi_find_rsdp();
+ rsdp_address = acpi_os_get_root_pointer();
if (!rsdp_address) {
printk("%s: System description tables not found\n",
__FUNCTION__);
diff --git a/arch/x86/kernel/suspend_64.c b/arch/x86/kernel/suspend_64.c
index 0919951..7ac7130 100644
--- a/arch/x86/kernel/suspend_64.c
+++ b/arch/x86/kernel/suspend_64.c
@@ -140,7 +140,12 @@
int cpu = smp_processor_id();
struct tss_struct *t = &per_cpu(init_tss, cpu);
- set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
+ /*
+ * This just modifies memory; should not be necessary. But... This
+ * is necessary, because 386 hardware has concept of busy TSS or some
+ * similar stupidity.
+ */
+ set_tss_desc(cpu, t);
get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
@@ -160,7 +165,6 @@
loaddebug(¤t->thread, 6);
loaddebug(¤t->thread, 7);
}
-
}
#ifdef CONFIG_HIBERNATION
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index 8344c70..adff556 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -321,6 +321,8 @@
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
.long sys_signalfd
- .long sys_timerfd
+ .long sys_timerfd_create
.long sys_eventfd
.long sys_fallocate
+ .long sys_timerfd_settime /* 325 */
+ .long sys_timerfd_gettime
diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c
index ae0ef2e..10b8a6f 100644
--- a/arch/x86/kernel/test_nx.c
+++ b/arch/x86/kernel/test_nx.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/sort.h>
#include <asm/uaccess.h>
+#include <asm/asm.h>
extern int rodata_test_data;
@@ -89,16 +90,7 @@
"2: mov %[zero], %[rslt]\n"
" ret\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
-#ifdef CONFIG_X86_32
- " .long 0b\n"
- " .long 2b\n"
-#else
- " .quad 0b\n"
- " .quad 2b\n"
-#endif
- ".previous\n"
+ _ASM_EXTABLE(0b,2b)
: [rslt] "=r" (result)
: [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
);
@@ -147,7 +139,6 @@
* Until then, don't run them to avoid too many people getting scared
* by the error message
*/
-#if 0
#ifdef CONFIG_DEBUG_RODATA
/* Test 3: Check if the .rodata section is executable */
@@ -160,6 +151,7 @@
}
#endif
+#if 0
/* Test 4: Check if the .data section of a module is executable */
if (test_address(&test_data)) {
printk(KERN_ERR "test_nx: .data section is executable\n");
diff --git a/arch/x86/kernel/trampoline_32.S b/arch/x86/kernel/trampoline_32.S
index 9bcc1c6..6458067 100644
--- a/arch/x86/kernel/trampoline_32.S
+++ b/arch/x86/kernel/trampoline_32.S
@@ -11,12 +11,7 @@
* trampoline page to make our stack and everything else
* is a mystery.
*
- * In fact we don't actually need a stack so we don't
- * set one up.
- *
- * We jump into the boot/compressed/head.S code. So you'd
- * better be running a compressed kernel image or you
- * won't get very far.
+ * We jump into arch/x86/kernel/head_32.S.
*
* On entry to trampoline_data, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S
index e30b67c..4aedd0b 100644
--- a/arch/x86/kernel/trampoline_64.S
+++ b/arch/x86/kernel/trampoline_64.S
@@ -10,9 +10,6 @@
* trampoline page to make our stack and everything else
* is a mystery.
*
- * In fact we don't actually need a stack so we don't
- * set one up.
- *
* On entry to trampoline_data, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
* and IP is zero. Thus, data addresses need to be absolute
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index 3cf72977..b22c01e 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -1176,17 +1176,12 @@
#endif
set_trap_gate(19,&simd_coprocessor_error);
+ /*
+ * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
+ * Generate a build-time error if the alignment is wrong.
+ */
+ BUILD_BUG_ON(offsetof(struct task_struct, thread.i387.fxsave) & 15);
if (cpu_has_fxsr) {
- /*
- * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
- * Generates a compile-time "error: zero width for bit-field" if
- * the alignment is wrong.
- */
- struct fxsrAlignAssert {
- int _:!(offsetof(struct task_struct,
- thread.i387.fxsave) & 15);
- };
-
printk(KERN_INFO "Enabling fast FPU save and restore... ");
set_in_cr4(X86_CR4_OSFXSR);
printk("done.\n");
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c
index 4525bc2..12affe1 100644
--- a/arch/x86/kernel/vmi_32.c
+++ b/arch/x86/kernel/vmi_32.c
@@ -220,21 +220,21 @@
static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
{
u32 *idt_entry = (u32 *)g;
- vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[2]);
+ vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[1]);
}
static void vmi_write_gdt_entry(struct desc_struct *dt, int entry,
const void *desc, int type)
{
u32 *gdt_entry = (u32 *)desc;
- vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[2]);
+ vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[1]);
}
static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
const void *desc)
{
u32 *ldt_entry = (u32 *)desc;
- vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[2]);
+ vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
}
static void vmi_load_sp0(struct tss_struct *tss,
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index c83e1c9..41962e7 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -53,5 +53,6 @@
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
source drivers/lguest/Kconfig
+source drivers/virtio/Kconfig
endif # VIRTUALIZATION
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 8f94a0b..cf53081 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1739,7 +1739,7 @@
if (bytes == 8) {
gpa_t gpa;
struct page *page;
- char *addr;
+ char *kaddr;
u64 val;
down_read(¤t->mm->mmap_sem);
@@ -1754,9 +1754,9 @@
val = *(u64 *)new;
page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
- addr = kmap_atomic(page, KM_USER0);
- set_64bit((u64 *)(addr + offset_in_page(gpa)), val);
- kunmap_atomic(addr, KM_USER0);
+ kaddr = kmap_atomic(page, KM_USER0);
+ set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val);
+ kunmap_atomic(kaddr, KM_USER0);
kvm_release_page_dirty(page);
emul_write:
up_read(¤t->mm->mmap_sem);
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 4876182..25df1c1 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -21,7 +21,7 @@
lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
lib-y += thunk_64.o clear_page_64.o copy_page_64.o
- lib-y += bitstr_64.o bitops_64.o
+ lib-y += bitops_64.o
lib-y += memmove_64.o memset_64.o
lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o
endif
diff --git a/arch/x86/lib/bitops_32.c b/arch/x86/lib/bitops_32.c
index afd0045..b654404 100644
--- a/arch/x86/lib/bitops_32.c
+++ b/arch/x86/lib/bitops_32.c
@@ -2,7 +2,7 @@
#include <linux/module.h>
/**
- * find_next_bit - find the first set bit in a memory region
+ * find_next_bit - find the next set bit in a memory region
* @addr: The address to base the search on
* @offset: The bitnumber to start searching at
* @size: The maximum size to search
diff --git a/arch/x86/lib/bitops_64.c b/arch/x86/lib/bitops_64.c
index 95b6d96..0e8f491 100644
--- a/arch/x86/lib/bitops_64.c
+++ b/arch/x86/lib/bitops_64.c
@@ -58,7 +58,7 @@
}
/**
- * find_next_zero_bit - find the first zero bit in a memory region
+ * find_next_zero_bit - find the next zero bit in a memory region
* @addr: The address to base the search on
* @offset: The bitnumber to start searching at
* @size: The maximum size to search
diff --git a/arch/x86/lib/bitstr_64.c b/arch/x86/lib/bitstr_64.c
deleted file mode 100644
index 7445caf..0000000
--- a/arch/x86/lib/bitstr_64.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <linux/module.h>
-#include <linux/bitops.h>
-
-/* Find string of zero bits in a bitmap */
-unsigned long
-find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len)
-{
- unsigned long n, end, i;
-
- again:
- n = find_next_zero_bit(bitmap, nbits, start);
- if (n == -1)
- return -1;
-
- /* could test bitsliced, but it's hardly worth it */
- end = n+len;
- if (end > nbits)
- return -1;
- for (i = n+1; i < end; i++) {
- if (test_bit(i, bitmap)) {
- start = i+1;
- goto again;
- }
- }
- return n;
-}
-
-EXPORT_SYMBOL(find_next_zero_string);
diff --git a/arch/x86/lib/delay_32.c b/arch/x86/lib/delay_32.c
index aad9d95..4535e6d 100644
--- a/arch/x86/lib/delay_32.c
+++ b/arch/x86/lib/delay_32.c
@@ -12,8 +12,10 @@
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/timex.h>
#include <linux/preempt.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/processor.h>
#include <asm/delay.h>
@@ -63,7 +65,7 @@
delay_fn = delay_tsc;
}
-int read_current_timer(unsigned long *timer_val)
+int __devinit read_current_timer(unsigned long *timer_val)
{
if (delay_fn == delay_tsc) {
rdtscl(*timer_val);
diff --git a/arch/x86/lib/delay_64.c b/arch/x86/lib/delay_64.c
index 45cdd3f..bbc6105 100644
--- a/arch/x86/lib/delay_64.c
+++ b/arch/x86/lib/delay_64.c
@@ -10,8 +10,10 @@
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/timex.h>
#include <linux/preempt.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/delay.h>
#include <asm/msr.h>
@@ -20,7 +22,7 @@
#include <asm/smp.h>
#endif
-int read_current_timer(unsigned long *timer_value)
+int __devinit read_current_timer(unsigned long *timer_value)
{
rdtscll(*timer_value);
return 0;
diff --git a/arch/x86/lib/mmx_32.c b/arch/x86/lib/mmx_32.c
index 28084d2..cc9b4a4 100644
--- a/arch/x86/lib/mmx_32.c
+++ b/arch/x86/lib/mmx_32.c
@@ -4,6 +4,7 @@
#include <linux/hardirq.h>
#include <linux/module.h>
+#include <asm/asm.h>
#include <asm/i387.h>
@@ -50,10 +51,7 @@
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b, 3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: : "r" (from) );
@@ -81,10 +79,7 @@
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b, 3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: : "r" (from), "r" (to) : "memory");
from+=64;
to+=64;
@@ -181,10 +176,7 @@
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b, 3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: : "r" (from) );
for(i=0; i<(4096-320)/64; i++)
@@ -211,10 +203,7 @@
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b, 3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: : "r" (from), "r" (to) : "memory");
from+=64;
to+=64;
@@ -311,10 +300,7 @@
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b, 3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: : "r" (from) );
for(i=0; i<4096/64; i++)
@@ -341,10 +327,7 @@
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b, 3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: : "r" (from), "r" (to) : "memory");
from+=64;
to+=64;
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 9c4ffd5..e849b99 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -48,10 +48,7 @@
"3: movl %5,%0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(0b,3b) \
: "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
"=&D" (__d2) \
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
@@ -132,11 +129,8 @@
"3: lea 0(%2,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,3b\n" \
- " .long 1b,2b\n" \
- ".previous" \
+ _ASM_EXTABLE(0b,3b) \
+ _ASM_EXTABLE(1b,2b) \
: "=&c"(size), "=&D" (__d0) \
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
} while (0)
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c
index 893d43f..0c89d1b 100644
--- a/arch/x86/lib/usercopy_64.c
+++ b/arch/x86/lib/usercopy_64.c
@@ -31,10 +31,7 @@
"3: movq %5,%0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 0b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(0b,3b) \
: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
"=&D" (__d2) \
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
@@ -87,11 +84,8 @@
"3: lea 0(%[size1],%[size8],8),%[size8]\n"
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,3b\n"
- " .quad 1b,2b\n"
- ".previous"
+ _ASM_EXTABLE(0b,3b)
+ _ASM_EXTABLE(1b,2b)
: [size8] "=c"(size), [dst] "=&D" (__d0)
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
[zero] "r" (0UL), [eight] "r" (8UL));
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c
index dffa786..3cc8eb2 100644
--- a/arch/x86/mach-voyager/voyager_smp.c
+++ b/arch/x86/mach-voyager/voyager_smp.c
@@ -444,8 +444,6 @@
static void __init start_secondary(void *unused)
{
__u8 cpuid = hard_smp_processor_id();
- /* external functions not defined in the headers */
- extern void calibrate_delay(void);
cpu_init();
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index e4440d0..621afb6 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -240,7 +240,8 @@
pud = pud_offset(pgd, address);
if (bad_address(pud)) goto bad;
printk("PUD %lx ", pud_val(*pud));
- if (!pud_present(*pud)) goto ret;
+ if (!pud_present(*pud) || pud_large(*pud))
+ goto ret;
pmd = pmd_offset(pud, address);
if (bad_address(pmd)) goto bad;
@@ -427,6 +428,16 @@
}
#endif
+static int spurious_fault_check(unsigned long error_code, pte_t *pte)
+{
+ if ((error_code & PF_WRITE) && !pte_write(*pte))
+ return 0;
+ if ((error_code & PF_INSTR) && !pte_exec(*pte))
+ return 0;
+
+ return 1;
+}
+
/*
* Handle a spurious fault caused by a stale TLB entry. This allows
* us to lazily refresh the TLB when increasing the permissions of a
@@ -456,20 +467,21 @@
if (!pud_present(*pud))
return 0;
+ if (pud_large(*pud))
+ return spurious_fault_check(error_code, (pte_t *) pud);
+
pmd = pmd_offset(pud, address);
if (!pmd_present(*pmd))
return 0;
+ if (pmd_large(*pmd))
+ return spurious_fault_check(error_code, (pte_t *) pmd);
+
pte = pte_offset_kernel(pmd, address);
if (!pte_present(*pte))
return 0;
- if ((error_code & PF_WRITE) && !pte_write(*pte))
- return 0;
- if ((error_code & PF_INSTR) && !pte_exec(*pte))
- return 0;
-
- return 1;
+ return spurious_fault_check(error_code, pte);
}
/*
@@ -508,6 +520,10 @@
pmd_t *pmd, *pmd_ref;
pte_t *pte, *pte_ref;
+ /* Make sure we are in vmalloc area */
+ if (!(address >= VMALLOC_START && address < VMALLOC_END))
+ return -1;
+
/* Copy kernel mappings over when needed. This can also
happen within a race in page table update. In the later
case just flush. */
@@ -603,6 +619,9 @@
*/
#ifdef CONFIG_X86_32
if (unlikely(address >= TASK_SIZE)) {
+#else
+ if (unlikely(address >= TASK_SIZE64)) {
+#endif
if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
vmalloc_fault(address) >= 0)
return;
@@ -618,6 +637,8 @@
goto bad_area_nosemaphore;
}
+
+#ifdef CONFIG_X86_32
/* It's safe to allow irq's after cr2 has been saved and the vmalloc
fault has been handled. */
if (regs->flags & (X86_EFLAGS_IF|VM_MASK))
@@ -630,28 +651,6 @@
if (in_atomic() || !mm)
goto bad_area_nosemaphore;
#else /* CONFIG_X86_64 */
- if (unlikely(address >= TASK_SIZE64)) {
- /*
- * Don't check for the module range here: its PML4
- * is always initialized because it's shared with the main
- * kernel text. Only vmalloc may need PML4 syncups.
- */
- if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
- ((address >= VMALLOC_START && address < VMALLOC_END))) {
- if (vmalloc_fault(address) >= 0)
- return;
- }
-
- /* Can handle a stale RO->RW TLB */
- if (spurious_fault(address, error_code))
- return;
-
- /*
- * Don't take the mm semaphore here. If we fixup a prefetch
- * fault we could otherwise deadlock.
- */
- goto bad_area_nosemaphore;
- }
if (likely(regs->flags & X86_EFLAGS_IF))
local_irq_enable();
@@ -959,11 +958,12 @@
for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
if (!test_bit(pgd_index(address), insync)) {
const pgd_t *pgd_ref = pgd_offset_k(address);
+ unsigned long flags;
struct page *page;
if (pgd_none(*pgd_ref))
continue;
- spin_lock(&pgd_lock);
+ spin_lock_irqsave(&pgd_lock, flags);
list_for_each_entry(page, &pgd_list, lru) {
pgd_t *pgd;
pgd = (pgd_t *)page_address(page) + pgd_index(address);
@@ -972,7 +972,7 @@
else
BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
}
- spin_unlock(&pgd_lock);
+ spin_unlock_irqrestore(&pgd_lock, flags);
set_bit(pgd_index(address), insync);
}
if (address == start)
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index da524fb..d1bc040 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -31,6 +31,7 @@
#include <linux/initrd.h>
#include <linux/cpumask.h>
+#include <asm/asm.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -423,23 +424,23 @@
paravirt_pagetable_setup_done(pgd_base);
}
-#if defined(CONFIG_HIBERNATION) || defined(CONFIG_ACPI)
+#ifdef CONFIG_ACPI_SLEEP
/*
- * Swap suspend & friends need this for resume because things like the intel-agp
+ * ACPI suspend needs this for resume, because things like the intel-agp
* driver might have split up a kernel 4MB mapping.
*/
-char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+char swsusp_pg_dir[PAGE_SIZE]
__attribute__ ((aligned(PAGE_SIZE)));
static inline void save_pg_dir(void)
{
memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
}
-#else
+#else /* !CONFIG_ACPI_SLEEP */
static inline void save_pg_dir(void)
{
}
-#endif
+#endif /* !CONFIG_ACPI_SLEEP */
void zap_low_mappings(void)
{
@@ -718,10 +719,7 @@
"1: movb %1, %0 \n"
" xorl %2, %2 \n"
"2: \n"
- ".section __ex_table, \"a\"\n"
- " .align 4 \n"
- " .long 1b, 2b \n"
- ".previous \n"
+ _ASM_EXTABLE(1b,2b)
:"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
"=q" (tmp_reg),
"=r" (flag)
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index eabcaed..9b61c75 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -273,7 +273,6 @@
int i = pmd_index(address);
for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
- unsigned long entry;
pmd_t *pmd = pmd_page + pmd_index(address);
if (address >= end) {
@@ -287,9 +286,8 @@
if (pmd_val(*pmd))
continue;
- entry = __PAGE_KERNEL_LARGE|_PAGE_GLOBAL|address;
- entry &= __supported_pte_mask;
- set_pmd(pmd, __pmd(entry));
+ set_pte((pte_t *)pmd,
+ pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
}
}
@@ -435,49 +433,6 @@
#endif
/*
- * Unmap a kernel mapping if it exists. This is useful to avoid
- * prefetches from the CPU leading to inconsistent cache lines.
- * address and size must be aligned to 2MB boundaries.
- * Does nothing when the mapping doesn't exist.
- */
-void __init clear_kernel_mapping(unsigned long address, unsigned long size)
-{
- unsigned long end = address + size;
-
- BUG_ON(address & ~LARGE_PAGE_MASK);
- BUG_ON(size & ~LARGE_PAGE_MASK);
-
- for (; address < end; address += LARGE_PAGE_SIZE) {
- pgd_t *pgd = pgd_offset_k(address);
- pud_t *pud;
- pmd_t *pmd;
-
- if (pgd_none(*pgd))
- continue;
-
- pud = pud_offset(pgd, address);
- if (pud_none(*pud))
- continue;
-
- pmd = pmd_offset(pud, address);
- if (!pmd || pmd_none(*pmd))
- continue;
-
- if (!(pmd_val(*pmd) & _PAGE_PSE)) {
- /*
- * Could handle this, but it should not happen
- * currently:
- */
- printk(KERN_ERR "clear_kernel_mapping: "
- "mapping has been split. will leak memory\n");
- pmd_ERROR(*pmd);
- }
- set_pmd(pmd, __pmd(0));
- }
- __flush_tlb_all();
-}
-
-/*
* Memory hotplug specific functions
*/
void online_page(struct page *page)
@@ -636,10 +591,17 @@
if (end <= start)
return;
- set_memory_ro(start, (end - start) >> PAGE_SHIFT);
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
(end - start) >> 10);
+ set_memory_ro(start, (end - start) >> PAGE_SHIFT);
+
+ /*
+ * The rodata section (but not the kernel text!) should also be
+ * not-executable.
+ */
+ start = ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+ set_memory_nx(start, (end - start) >> PAGE_SHIFT);
rodata_test();
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index c004d94..ee6648f 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -70,25 +70,12 @@
* Fix up the linear direct mapping of the kernel to avoid cache attribute
* conflicts.
*/
-static int ioremap_change_attr(unsigned long paddr, unsigned long size,
+static int ioremap_change_attr(unsigned long vaddr, unsigned long size,
enum ioremap_mode mode)
{
- unsigned long vaddr = (unsigned long)__va(paddr);
unsigned long nrpages = size >> PAGE_SHIFT;
- unsigned int level;
int err;
- /* No change for pages after the last mapping */
- if ((paddr + size - 1) >= (max_pfn_mapped << PAGE_SHIFT))
- return 0;
-
- /*
- * If there is no identity map for this address,
- * change_page_attr_addr is unnecessary
- */
- if (!lookup_address(vaddr, &level))
- return 0;
-
switch (mode) {
case IOR_MODE_UNCACHED:
default:
@@ -114,9 +101,8 @@
static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
enum ioremap_mode mode)
{
- void __iomem *addr;
+ unsigned long pfn, offset, last_addr, vaddr;
struct vm_struct *area;
- unsigned long offset, last_addr;
pgprot_t prot;
/* Don't allow wraparound or zero size */
@@ -133,9 +119,10 @@
/*
* Don't allow anybody to remap normal RAM that we're using..
*/
- for (offset = phys_addr >> PAGE_SHIFT; offset < max_pfn_mapped &&
- (offset << PAGE_SHIFT) < last_addr; offset++) {
- if (page_is_ram(offset))
+ for (pfn = phys_addr >> PAGE_SHIFT; pfn < max_pfn_mapped &&
+ (pfn << PAGE_SHIFT) < last_addr; pfn++) {
+ if (page_is_ram(pfn) && pfn_valid(pfn) &&
+ !PageReserved(pfn_to_page(pfn)))
return NULL;
}
@@ -163,19 +150,18 @@
if (!area)
return NULL;
area->phys_addr = phys_addr;
- addr = (void __iomem *) area->addr;
- if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
- phys_addr, prot)) {
- remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
+ vaddr = (unsigned long) area->addr;
+ if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) {
+ remove_vm_area((void *)(vaddr & PAGE_MASK));
return NULL;
}
- if (ioremap_change_attr(phys_addr, size, mode) < 0) {
- vunmap(addr);
+ if (ioremap_change_attr(vaddr, size, mode) < 0) {
+ vunmap(area->addr);
return NULL;
}
- return (void __iomem *) (offset + (char __iomem *)addr);
+ return (void __iomem *) (vaddr + offset);
}
/**
@@ -254,9 +240,6 @@
return;
}
- /* Reset the direct mapping. Can block */
- ioremap_change_attr(p->phys_addr, p->size, IOR_MODE_CACHED);
-
/* Finally remove it */
o = remove_vm_area((void *)addr);
BUG_ON(p != o || o == NULL);
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index a920d09..5a02bf4c 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -202,6 +202,8 @@
if (node_data[nodeid] == NULL)
return;
nodedata_phys = __pa(node_data[nodeid]);
+ printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
+ nodedata_phys + pgdat_size - 1);
memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid];
@@ -225,12 +227,15 @@
return;
}
bootmap_start = __pa(bootmap);
- Dprintk("bootmap start %lu pages %lu\n", bootmap_start, bootmap_pages);
bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
bootmap_start >> PAGE_SHIFT,
start_pfn, end_pfn);
+ printk(KERN_INFO " bootmap [%016lx - %016lx] pages %lx\n",
+ bootmap_start, bootmap_start + bootmap_size - 1,
+ bootmap_pages);
+
free_bootmem_with_active_regions(nodeid, end);
reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index 7573e78..ed82016 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -5,6 +5,7 @@
* and compares page tables forwards and afterwards.
*/
#include <linux/bootmem.h>
+#include <linux/kthread.h>
#include <linux/random.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -14,8 +15,13 @@
#include <asm/pgtable.h>
#include <asm/kdebug.h>
+/*
+ * Only print the results of the first pass:
+ */
+static __read_mostly int print = 1;
+
enum {
- NTEST = 4000,
+ NTEST = 400,
#ifdef CONFIG_X86_64
LPS = (1 << PMD_SHIFT),
#elif defined(CONFIG_X86_PAE)
@@ -31,7 +37,7 @@
long min_exec, max_exec;
};
-static __init int print_split(struct split_state *s)
+static int print_split(struct split_state *s)
{
long i, expected, missed = 0;
int printed = 0;
@@ -82,10 +88,13 @@
s->max_exec = addr;
}
}
- printk(KERN_INFO
- "CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
- s->spg, s->lpg, s->gpg, s->exec,
- s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed);
+ if (print) {
+ printk(KERN_INFO
+ " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
+ s->spg, s->lpg, s->gpg, s->exec,
+ s->min_exec != ~0UL ? s->min_exec : 0,
+ s->max_exec, missed);
+ }
expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
if (expected != i) {
@@ -96,11 +105,11 @@
return err;
}
-static unsigned long __initdata addr[NTEST];
-static unsigned int __initdata len[NTEST];
+static unsigned long addr[NTEST];
+static unsigned int len[NTEST];
/* Change the global bit on random pages in the direct mapping */
-static __init int exercise_pageattr(void)
+static int pageattr_test(void)
{
struct split_state sa, sb, sc;
unsigned long *bm;
@@ -110,7 +119,8 @@
int i, k;
int err;
- printk(KERN_INFO "CPA exercising pageattr\n");
+ if (print)
+ printk(KERN_INFO "CPA self-test:\n");
bm = vmalloc((max_pfn_mapped + 7) / 8);
if (!bm) {
@@ -137,7 +147,8 @@
for (k = 0; k < len[i]; k++) {
pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
- if (!pte || pgprot_val(pte_pgprot(*pte)) == 0) {
+ if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 ||
+ !(pte_val(*pte) & _PAGE_PRESENT)) {
addr[i] = 0;
break;
}
@@ -185,7 +196,6 @@
failed += print_split(&sb);
- printk(KERN_INFO "CPA reverting everything\n");
for (i = 0; i < NTEST; i++) {
if (!addr[i])
continue;
@@ -213,12 +223,40 @@
failed += print_split(&sc);
if (failed) {
- printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n");
+ printk(KERN_ERR "NOT PASSED. Please report.\n");
WARN_ON(1);
+ return -EINVAL;
} else {
- printk(KERN_INFO "CPA selftests PASSED\n");
+ if (print)
+ printk(KERN_INFO "ok.\n");
}
return 0;
}
-module_init(exercise_pageattr);
+
+static int do_pageattr_test(void *__unused)
+{
+ while (!kthread_should_stop()) {
+ schedule_timeout_interruptible(HZ*30);
+ if (pageattr_test() < 0)
+ break;
+ if (print)
+ print--;
+ }
+ return 0;
+}
+
+static int start_pageattr_test(void)
+{
+ struct task_struct *p;
+
+ p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
+ if (!IS_ERR(p))
+ wake_up_process(p);
+ else
+ WARN_ON(1);
+
+ return 0;
+}
+
+module_init(start_pageattr_test);
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index e297bd6..8493c85 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -16,6 +16,17 @@
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
+/*
+ * The current flushing context - we pass it instead of 5 arguments:
+ */
+struct cpa_data {
+ unsigned long vaddr;
+ pgprot_t mask_set;
+ pgprot_t mask_clr;
+ int numpages;
+ int flushtlb;
+};
+
static inline int
within(unsigned long addr, unsigned long start, unsigned long end)
{
@@ -52,21 +63,23 @@
static void __cpa_flush_all(void *arg)
{
+ unsigned long cache = (unsigned long)arg;
+
/*
* Flush all to work around Errata in early athlons regarding
* large page flushing.
*/
__flush_tlb_all();
- if (boot_cpu_data.x86_model >= 4)
+ if (cache && boot_cpu_data.x86_model >= 4)
wbinvd();
}
-static void cpa_flush_all(void)
+static void cpa_flush_all(unsigned long cache)
{
BUG_ON(irqs_disabled());
- on_each_cpu(__cpa_flush_all, NULL, 1, 1);
+ on_each_cpu(__cpa_flush_all, (void *) cache, 1, 1);
}
static void __cpa_flush_range(void *arg)
@@ -79,7 +92,7 @@
__flush_tlb_all();
}
-static void cpa_flush_range(unsigned long start, int numpages)
+static void cpa_flush_range(unsigned long start, int numpages, int cache)
{
unsigned int i, level;
unsigned long addr;
@@ -89,6 +102,9 @@
on_each_cpu(__cpa_flush_range, NULL, 1, 1);
+ if (!cache)
+ return;
+
/*
* We only need to flush on one CPU,
* clflush is a MESI-coherent instruction that
@@ -101,11 +117,27 @@
/*
* Only flush present addresses:
*/
- if (pte && pte_present(*pte))
+ if (pte && (pte_val(*pte) & _PAGE_PRESENT))
clflush_cache_range((void *) addr, PAGE_SIZE);
}
}
+#define HIGH_MAP_START __START_KERNEL_map
+#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE)
+
+
+/*
+ * Converts a virtual address to a X86-64 highmap address
+ */
+static unsigned long virt_to_highmap(void *address)
+{
+#ifdef CONFIG_X86_64
+ return __pa((unsigned long)address) + HIGH_MAP_START - phys_base;
+#else
+ return (unsigned long)address;
+#endif
+}
+
/*
* Certain areas of memory on x86 require very specific protection flags,
* for example the BIOS area or kernel text. Callers don't always get this
@@ -129,19 +161,36 @@
*/
if (within(address, (unsigned long)_text, (unsigned long)_etext))
pgprot_val(forbidden) |= _PAGE_NX;
+ /*
+ * Do the same for the x86-64 high kernel mapping
+ */
+ if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
+ pgprot_val(forbidden) |= _PAGE_NX;
-#ifdef CONFIG_DEBUG_RODATA
/* The .rodata section needs to be read-only */
if (within(address, (unsigned long)__start_rodata,
(unsigned long)__end_rodata))
pgprot_val(forbidden) |= _PAGE_RW;
-#endif
+ /*
+ * Do the same for the x86-64 high kernel mapping
+ */
+ if (within(address, virt_to_highmap(__start_rodata),
+ virt_to_highmap(__end_rodata)))
+ pgprot_val(forbidden) |= _PAGE_RW;
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
return prot;
}
+/*
+ * Lookup the page table entry for a virtual address. Return a pointer
+ * to the entry and the level of the mapping.
+ *
+ * Note: We return pud and pmd either when the entry is marked large
+ * or when the present bit is not set. Otherwise we would return a
+ * pointer to a nonexisting mapping.
+ */
pte_t *lookup_address(unsigned long address, int *level)
{
pgd_t *pgd = pgd_offset_k(address);
@@ -152,21 +201,31 @@
if (pgd_none(*pgd))
return NULL;
+
pud = pud_offset(pgd, address);
if (pud_none(*pud))
return NULL;
+
+ *level = PG_LEVEL_1G;
+ if (pud_large(*pud) || !pud_present(*pud))
+ return (pte_t *)pud;
+
pmd = pmd_offset(pud, address);
if (pmd_none(*pmd))
return NULL;
*level = PG_LEVEL_2M;
- if (pmd_large(*pmd))
+ if (pmd_large(*pmd) || !pmd_present(*pmd))
return (pte_t *)pmd;
*level = PG_LEVEL_4K;
+
return pte_offset_kernel(pmd, address);
}
+/*
+ * Set the new pmd in all the pgds we know about:
+ */
static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
{
/* change init_mm */
@@ -189,18 +248,103 @@
#endif
}
+static int
+try_preserve_large_page(pte_t *kpte, unsigned long address,
+ struct cpa_data *cpa)
+{
+ unsigned long nextpage_addr, numpages, pmask, psize, flags;
+ pte_t new_pte, old_pte, *tmp;
+ pgprot_t old_prot, new_prot;
+ int level, do_split = 1;
+
+ spin_lock_irqsave(&pgd_lock, flags);
+ /*
+ * Check for races, another CPU might have split this page
+ * up already:
+ */
+ tmp = lookup_address(address, &level);
+ if (tmp != kpte)
+ goto out_unlock;
+
+ switch (level) {
+ case PG_LEVEL_2M:
+ psize = PMD_PAGE_SIZE;
+ pmask = PMD_PAGE_MASK;
+ break;
+#ifdef CONFIG_X86_64
+ case PG_LEVEL_1G:
+ psize = PMD_PAGE_SIZE;
+ pmask = PMD_PAGE_MASK;
+ break;
+#endif
+ default:
+ do_split = -EINVAL;
+ goto out_unlock;
+ }
+
+ /*
+ * Calculate the number of pages, which fit into this large
+ * page starting at address:
+ */
+ nextpage_addr = (address + psize) & pmask;
+ numpages = (nextpage_addr - address) >> PAGE_SHIFT;
+ if (numpages < cpa->numpages)
+ cpa->numpages = numpages;
+
+ /*
+ * We are safe now. Check whether the new pgprot is the same:
+ */
+ old_pte = *kpte;
+ old_prot = new_prot = pte_pgprot(old_pte);
+
+ pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
+ pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
+ new_prot = static_protections(new_prot, address);
+
+ /*
+ * If there are no changes, return. maxpages has been updated
+ * above:
+ */
+ if (pgprot_val(new_prot) == pgprot_val(old_prot)) {
+ do_split = 0;
+ goto out_unlock;
+ }
+
+ /*
+ * We need to change the attributes. Check, whether we can
+ * change the large page in one go. We request a split, when
+ * the address is not aligned and the number of pages is
+ * smaller than the number of pages in the large page. Note
+ * that we limited the number of possible pages already to
+ * the number of pages in the large page.
+ */
+ if (address == (nextpage_addr - psize) && cpa->numpages == numpages) {
+ /*
+ * The address is aligned and the number of pages
+ * covers the full page.
+ */
+ new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
+ __set_pmd_pte(kpte, address, new_pte);
+ cpa->flushtlb = 1;
+ do_split = 0;
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&pgd_lock, flags);
+
+ return do_split;
+}
+
static int split_large_page(pte_t *kpte, unsigned long address)
{
- pgprot_t ref_prot = pte_pgprot(pte_clrhuge(*kpte));
+ unsigned long flags, pfn, pfninc = 1;
gfp_t gfp_flags = GFP_KERNEL;
- unsigned long flags;
- unsigned long addr;
- pte_t *pbase, *tmp;
- struct page *base;
unsigned int i, level;
+ pte_t *pbase, *tmp;
+ pgprot_t ref_prot;
+ struct page *base;
#ifdef CONFIG_DEBUG_PAGEALLOC
- gfp_flags = __GFP_HIGH | __GFP_NOFAIL | __GFP_NOWARN;
gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
#endif
base = alloc_pages(gfp_flags, 0);
@@ -213,30 +357,41 @@
* up for us already:
*/
tmp = lookup_address(address, &level);
- if (tmp != kpte) {
- WARN_ON_ONCE(1);
+ if (tmp != kpte)
goto out_unlock;
- }
- address = __pa(address);
- addr = address & LARGE_PAGE_MASK;
pbase = (pte_t *)page_address(base);
#ifdef CONFIG_X86_32
paravirt_alloc_pt(&init_mm, page_to_pfn(base));
#endif
+ ref_prot = pte_pgprot(pte_clrhuge(*kpte));
- pgprot_val(ref_prot) &= ~_PAGE_NX;
- for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE)
- set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT, ref_prot));
+#ifdef CONFIG_X86_64
+ if (level == PG_LEVEL_1G) {
+ pfninc = PMD_PAGE_SIZE >> PAGE_SHIFT;
+ pgprot_val(ref_prot) |= _PAGE_PSE;
+ }
+#endif
/*
- * Install the new, split up pagetable. Important detail here:
+ * Get the target pfn from the original entry:
+ */
+ pfn = pte_pfn(*kpte);
+ for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
+ set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
+
+ /*
+ * Install the new, split up pagetable. Important details here:
*
* On Intel the NX bit of all levels must be cleared to make a
* page executable. See section 4.13.2 of Intel 64 and IA-32
* Architectures Software Developer's Manual).
+ *
+ * Mark the entry present. The current mapping might be
+ * set to not present, which we preserved above.
*/
ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
+ pgprot_val(ref_prot) |= _PAGE_PRESENT;
__set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
base = NULL;
@@ -249,18 +404,12 @@
return 0;
}
-static int
-__change_page_attr(unsigned long address, unsigned long pfn,
- pgprot_t mask_set, pgprot_t mask_clr)
+static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
{
+ int level, do_split, err;
struct page *kpte_page;
- int level, err = 0;
pte_t *kpte;
-#ifdef CONFIG_X86_32
- BUG_ON(pfn > max_low_pfn);
-#endif
-
repeat:
kpte = lookup_address(address, &level);
if (!kpte)
@@ -271,23 +420,62 @@
BUG_ON(PageCompound(kpte_page));
if (level == PG_LEVEL_4K) {
- pgprot_t new_prot = pte_pgprot(*kpte);
pte_t new_pte, old_pte = *kpte;
+ pgprot_t new_prot = pte_pgprot(old_pte);
- pgprot_val(new_prot) &= ~pgprot_val(mask_clr);
- pgprot_val(new_prot) |= pgprot_val(mask_set);
+ if(!pte_val(old_pte)) {
+ printk(KERN_WARNING "CPA: called for zero pte. "
+ "vaddr = %lx cpa->vaddr = %lx\n", address,
+ cpa->vaddr);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
+ pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
new_prot = static_protections(new_prot, address);
- new_pte = pfn_pte(pfn, canon_pgprot(new_prot));
- BUG_ON(pte_pfn(new_pte) != pte_pfn(old_pte));
+ /*
+ * We need to keep the pfn from the existing PTE,
+ * after all we're only going to change it's attributes
+ * not the memory it points to
+ */
+ new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
- set_pte_atomic(kpte, new_pte);
- } else {
- err = split_large_page(kpte, address);
- if (!err)
- goto repeat;
+ /*
+ * Do we really change anything ?
+ */
+ if (pte_val(old_pte) != pte_val(new_pte)) {
+ set_pte_atomic(kpte, new_pte);
+ cpa->flushtlb = 1;
+ }
+ cpa->numpages = 1;
+ return 0;
}
+
+ /*
+ * Check, whether we can keep the large page intact
+ * and just change the pte:
+ */
+ do_split = try_preserve_large_page(kpte, address, cpa);
+ /*
+ * When the range fits into the existing large page,
+ * return. cp->numpages and cpa->tlbflush have been updated in
+ * try_large_page:
+ */
+ if (do_split <= 0)
+ return do_split;
+
+ /*
+ * We have to split the large page:
+ */
+ err = split_large_page(kpte, address);
+ if (!err) {
+ cpa->flushtlb = 1;
+ goto repeat;
+ }
+
return err;
}
@@ -304,19 +492,14 @@
*
* Modules and drivers should use the set_memory_* APIs instead.
*/
-
-#define HIGH_MAP_START __START_KERNEL_map
-#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE)
-
-static int
-change_page_attr_addr(unsigned long address, pgprot_t mask_set,
- pgprot_t mask_clr)
+static int change_page_attr_addr(struct cpa_data *cpa)
{
- unsigned long phys_addr = __pa(address);
- unsigned long pfn = phys_addr >> PAGE_SHIFT;
int err;
+ unsigned long address = cpa->vaddr;
#ifdef CONFIG_X86_64
+ unsigned long phys_addr = __pa(address);
+
/*
* If we are inside the high mapped kernel range, then we
* fixup the low mapping first. __va() returns the virtual
@@ -326,7 +509,7 @@
address = (unsigned long) __va(phys_addr);
#endif
- err = __change_page_attr(address, pfn, mask_set, mask_clr);
+ err = __change_page_attr(address, cpa);
if (err)
return err;
@@ -339,42 +522,89 @@
/*
* Calc the high mapping address. See __phys_addr()
* for the non obvious details.
+ *
+ * Note that NX and other required permissions are
+ * checked in static_protections().
*/
address = phys_addr + HIGH_MAP_START - phys_base;
- /* Make sure the kernel mappings stay executable */
- pgprot_val(mask_clr) |= _PAGE_NX;
/*
* Our high aliases are imprecise, because we check
* everything between 0 and KERNEL_TEXT_SIZE, so do
* not propagate lookup failures back to users:
*/
- __change_page_attr(address, pfn, mask_set, mask_clr);
+ __change_page_attr(address, cpa);
}
#endif
return err;
}
-static int __change_page_attr_set_clr(unsigned long addr, int numpages,
- pgprot_t mask_set, pgprot_t mask_clr)
+static int __change_page_attr_set_clr(struct cpa_data *cpa)
{
- unsigned int i;
- int ret;
+ int ret, numpages = cpa->numpages;
- for (i = 0; i < numpages ; i++, addr += PAGE_SIZE) {
- ret = change_page_attr_addr(addr, mask_set, mask_clr);
+ while (numpages) {
+ /*
+ * Store the remaining nr of pages for the large page
+ * preservation check.
+ */
+ cpa->numpages = numpages;
+ ret = change_page_attr_addr(cpa);
if (ret)
return ret;
- }
+ /*
+ * Adjust the number of pages with the result of the
+ * CPA operation. Either a large page has been
+ * preserved or a single page update happened.
+ */
+ BUG_ON(cpa->numpages > numpages);
+ numpages -= cpa->numpages;
+ cpa->vaddr += cpa->numpages * PAGE_SIZE;
+ }
return 0;
}
+static inline int cache_attr(pgprot_t attr)
+{
+ return pgprot_val(attr) &
+ (_PAGE_PAT | _PAGE_PAT_LARGE | _PAGE_PWT | _PAGE_PCD);
+}
+
static int change_page_attr_set_clr(unsigned long addr, int numpages,
pgprot_t mask_set, pgprot_t mask_clr)
{
- int ret = __change_page_attr_set_clr(addr, numpages, mask_set,
- mask_clr);
+ struct cpa_data cpa;
+ int ret, cache;
+
+ /*
+ * Check, if we are requested to change a not supported
+ * feature:
+ */
+ mask_set = canon_pgprot(mask_set);
+ mask_clr = canon_pgprot(mask_clr);
+ if (!pgprot_val(mask_set) && !pgprot_val(mask_clr))
+ return 0;
+
+ cpa.vaddr = addr;
+ cpa.numpages = numpages;
+ cpa.mask_set = mask_set;
+ cpa.mask_clr = mask_clr;
+ cpa.flushtlb = 0;
+
+ ret = __change_page_attr_set_clr(&cpa);
+
+ /*
+ * Check whether we really changed something:
+ */
+ if (!cpa.flushtlb)
+ return ret;
+
+ /*
+ * No need to flush, when we did not set any of the caching
+ * attributes:
+ */
+ cache = cache_attr(mask_set);
/*
* On success we use clflush, when the CPU supports it to
@@ -383,9 +613,9 @@
* wbindv):
*/
if (!ret && cpu_has_clflush)
- cpa_flush_range(addr, numpages);
+ cpa_flush_range(addr, numpages, cache);
else
- cpa_flush_all();
+ cpa_flush_all(cache);
return ret;
}
@@ -489,37 +719,26 @@
return set_memory_rw(addr, numpages);
}
-
-#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_CPA_DEBUG)
-static inline int __change_page_attr_set(unsigned long addr, int numpages,
- pgprot_t mask)
-{
- return __change_page_attr_set_clr(addr, numpages, mask, __pgprot(0));
-}
-
-static inline int __change_page_attr_clear(unsigned long addr, int numpages,
- pgprot_t mask)
-{
- return __change_page_attr_set_clr(addr, numpages, __pgprot(0), mask);
-}
-#endif
-
#ifdef CONFIG_DEBUG_PAGEALLOC
static int __set_pages_p(struct page *page, int numpages)
{
- unsigned long addr = (unsigned long)page_address(page);
+ struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
+ .numpages = numpages,
+ .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
+ .mask_clr = __pgprot(0)};
- return __change_page_attr_set(addr, numpages,
- __pgprot(_PAGE_PRESENT | _PAGE_RW));
+ return __change_page_attr_set_clr(&cpa);
}
static int __set_pages_np(struct page *page, int numpages)
{
- unsigned long addr = (unsigned long)page_address(page);
+ struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
+ .numpages = numpages,
+ .mask_set = __pgprot(0),
+ .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};
- return __change_page_attr_clear(addr, numpages,
- __pgprot(_PAGE_PRESENT));
+ return __change_page_attr_set_clr(&cpa);
}
void kernel_map_pages(struct page *page, int numpages, int enable)
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index cb3aa47..6c19146 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -219,50 +219,39 @@
list_del(&page->lru);
}
+#define UNSHARED_PTRS_PER_PGD \
+ (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
-
-#if (PTRS_PER_PMD == 1)
-/* Non-PAE pgd constructor */
-static void pgd_ctor(void *pgd)
+static void pgd_ctor(void *p)
{
+ pgd_t *pgd = p;
unsigned long flags;
- /* !PAE, no pagetable sharing */
+ /* Clear usermode parts of PGD */
memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
spin_lock_irqsave(&pgd_lock, flags);
- /* must happen under lock */
- clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
- KERNEL_PGD_PTRS);
- paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
- __pa(swapper_pg_dir) >> PAGE_SHIFT,
- USER_PTRS_PER_PGD,
- KERNEL_PGD_PTRS);
- pgd_list_add(pgd);
- spin_unlock_irqrestore(&pgd_lock, flags);
-}
-#else /* PTRS_PER_PMD > 1 */
-/* PAE pgd constructor */
-static void pgd_ctor(void *pgd)
-{
- /* PAE, kernel PMD may be shared */
-
- if (SHARED_KERNEL_PMD) {
- clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
+ /* If the pgd points to a shared pagetable level (either the
+ ptes in non-PAE, or shared PMD in PAE), then just copy the
+ references from swapper_pg_dir. */
+ if (PAGETABLE_LEVELS == 2 ||
+ (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) {
+ clone_pgd_range(pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
KERNEL_PGD_PTRS);
- } else {
- unsigned long flags;
-
- memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
- spin_lock_irqsave(&pgd_lock, flags);
- pgd_list_add(pgd);
- spin_unlock_irqrestore(&pgd_lock, flags);
+ paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
+ __pa(swapper_pg_dir) >> PAGE_SHIFT,
+ USER_PTRS_PER_PGD,
+ KERNEL_PGD_PTRS);
}
+
+ /* list required to sync kernel mapping updates */
+ if (!SHARED_KERNEL_PMD)
+ pgd_list_add(pgd);
+
+ spin_unlock_irqrestore(&pgd_lock, flags);
}
-#endif /* PTRS_PER_PMD */
static void pgd_dtor(void *pgd)
{
@@ -276,9 +265,6 @@
spin_unlock_irqrestore(&pgd_lock, flags);
}
-#define UNSHARED_PTRS_PER_PGD \
- (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
-
#ifdef CONFIG_X86_PAE
/*
* Mop up any pmd pages which may still be attached to the pgd.
@@ -286,7 +272,7 @@
* preallocate which never got a corresponding vma will need to be
* freed manually.
*/
-static void pgd_mop_up_pmds(pgd_t *pgdp)
+static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
{
int i;
@@ -299,7 +285,7 @@
pgdp[i] = native_make_pgd(0);
paravirt_release_pd(pgd_val(pgd) >> PAGE_SHIFT);
- pmd_free(pmd);
+ pmd_free(mm, pmd);
}
}
}
@@ -327,7 +313,7 @@
pmd_t *pmd = pmd_alloc_one(mm, addr);
if (!pmd) {
- pgd_mop_up_pmds(pgd);
+ pgd_mop_up_pmds(mm, pgd);
return 0;
}
@@ -347,7 +333,7 @@
return 1;
}
-static void pgd_mop_up_pmds(pgd_t *pgd)
+static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
{
}
#endif /* CONFIG_X86_PAE */
@@ -366,9 +352,9 @@
return pgd;
}
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
- pgd_mop_up_pmds(pgd);
+ pgd_mop_up_pmds(mm, pgd);
quicklist_free(0, pgd_dtor, pgd);
}
@@ -387,13 +373,6 @@
void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
{
- /* This is called just after the pmd has been detached from
- the pgd, which requires a full tlb flush to be recognized
- by the CPU. Rather than incurring multiple tlb flushes
- while the address space is being pulled down, make the tlb
- gathering machinery do a full flush when we're done. */
- tlb->fullmm = 1;
-
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
tlb_remove_page(tlb, virt_to_page(pmd));
}
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index cb63007..74d30ff 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -17,7 +17,7 @@
int pxb, reg;
u8 busno, suba, subb;
- printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
+ dev_warn(&d->dev, "Searching for i450NX host bridges\n");
reg = 0xd0;
for(pxb = 0; pxb < 2; pxb++) {
pci_read_config_byte(d, reg++, &busno);
@@ -41,7 +41,7 @@
*/
u8 busno;
pci_read_config_byte(d, 0x4a, &busno);
- printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno);
+ dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno);
pci_scan_bus_with_sysdata(busno);
pcibios_last_bus = -1;
}
@@ -55,7 +55,7 @@
*/
int i;
- printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d));
+ dev_warn(&d->dev, "Fixing base address flags\n");
for(i = 0; i < 4; i++)
d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
}
@@ -68,7 +68,7 @@
* Fix class to be PCI_CLASS_STORAGE_SCSI
*/
if (!d->class) {
- printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d));
+ dev_warn(&d->dev, "Fixing NCR 53C810 class code\n");
d->class = PCI_CLASS_STORAGE_SCSI << 8;
}
}
@@ -80,7 +80,7 @@
* SiS 5597 and 5598 chipsets require latency timer set to
* at most 32 to avoid lockups.
*/
- DBG("PCI: Setting max latency to 32\n");
+ dev_dbg(&d->dev, "Setting max latency to 32\n");
pcibios_max_latency = 32;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency);
@@ -138,7 +138,7 @@
pci_read_config_byte(d, where, &v);
if (v & ~mask) {
- printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
+ dev_warn(&d->dev, "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
d->device, d->revision, where, v, mask, v & mask);
v &= mask;
pci_write_config_byte(d, where, v);
@@ -200,7 +200,7 @@
* Apply fixup if needed, but don't touch disconnect state
*/
if ((val & 0x00FF0000) != 0x00010000) {
- printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n");
+ dev_warn(&dev->dev, "nForce2 C1 Halt Disconnect fixup\n");
pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000);
}
}
@@ -348,7 +348,7 @@
pci_read_config_word(pdev, PCI_COMMAND, &config);
if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
- printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
+ dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
@@ -388,11 +388,11 @@
/* verify the change for status output */
pci_read_config_byte(dev, 0x50, &val);
if (val & 0x40)
- printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+ dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; "
"can't enable onboard soundcard!\n");
else
- printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
- "enabled onboard soundcard.\n");
+ dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; "
+ "enabled onboard soundcard\n");
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 42ba0e2..103b9dff 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -72,7 +72,7 @@
}
}
}
-
+EXPORT_SYMBOL(pcibios_align_resource);
/*
* Handle resources of PCI devices. If the world were perfect, we could
diff --git a/arch/x86/pci/numa.c b/arch/x86/pci/numa.c
index f5f165f..55270c2 100644
--- a/arch/x86/pci/numa.c
+++ b/arch/x86/pci/numa.c
@@ -5,36 +5,62 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/nodemask.h>
+#include <mach_apic.h>
#include "pci.h"
+#define XQUAD_PORTIO_BASE 0xfe400000
+#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
+
#define BUS2QUAD(global) (mp_bus_id_to_node[global])
#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
+extern void *xquad_portio; /* Where the IO area was mapped */
+#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
+
#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
(0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
+static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
+{
+ unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
+ if (xquad_portio)
+ writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
+ else
+ outl(val, 0xCF8);
+}
+
static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
+ void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
return -EINVAL;
spin_lock_irqsave(&pci_config_lock, flags);
- outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
+ write_cf8(bus, devfn, reg);
switch (len) {
case 1:
- *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+ if (xquad_portio)
+ *value = readb(adr + (reg & 3));
+ else
+ *value = inb(0xCFC + (reg & 3));
break;
case 2:
- *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+ if (xquad_portio)
+ *value = readw(adr + (reg & 2));
+ else
+ *value = inw(0xCFC + (reg & 2));
break;
case 4:
- *value = inl_quad(0xCFC, BUS2QUAD(bus));
+ if (xquad_portio)
+ *value = readl(adr);
+ else
+ *value = inl(0xCFC);
break;
}
@@ -47,23 +73,33 @@
unsigned int devfn, int reg, int len, u32 value)
{
unsigned long flags;
+ void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
return -EINVAL;
spin_lock_irqsave(&pci_config_lock, flags);
- outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
+ write_cf8(bus, devfn, reg);
switch (len) {
case 1:
- outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+ if (xquad_portio)
+ writeb(value, adr + (reg & 3));
+ else
+ outb((u8)value, 0xCFC + (reg & 3));
break;
case 2:
- outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+ if (xquad_portio)
+ writew(value, adr + (reg & 2));
+ else
+ outw((u16)value, 0xCFC + (reg & 2));
break;
case 4:
- outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+ if (xquad_portio)
+ writel(value, adr + reg);
+ else
+ outl((u32)value, 0xCFC);
break;
}
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index d3cb3d6..5d5546c 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -174,11 +174,6 @@
your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
VESA. If you have PCI, say Y, otherwise N.
- The PCI-HOWTO, available from
- <http://www.linuxdoc.org/docs.html#howto>, contains valuable
- information about which PCI hardware does work under Linux and which
- doesn't
-
source "drivers/pci/Kconfig"
config HOTPLUG
@@ -251,8 +246,6 @@
provide one yourself.
endmenu
-source "kernel/Kconfig.instrumentation"
-
source "arch/xtensa/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 60d29fe..8df1e842 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -204,7 +204,7 @@
}
#ifndef CONFIG_GENERIC_CALIBRATE_DELAY
-void __devinit calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
{
loops_per_jiffy = CCOUNT_PER_JIFFY;
printk("Calibrating delay loop (skipped)... "
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
index 047e533..0f62822 100644
--- a/crypto/async_tx/async_memcpy.c
+++ b/crypto/async_tx/async_memcpy.c
@@ -35,7 +35,7 @@
* @src: src page
* @offset: offset in pages to start transaction
* @len: length in bytes
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
* @depend_tx: memcpy depends on the result of this transaction
* @cb_fn: function to call when the memcpy completes
* @cb_param: parameter to pass to the callback routine
@@ -46,33 +46,29 @@
struct dma_async_tx_descriptor *depend_tx,
dma_async_tx_callback cb_fn, void *cb_param)
{
- struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY);
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY,
+ &dest, 1, &src, 1, len);
struct dma_device *device = chan ? chan->device : NULL;
- int int_en = cb_fn ? 1 : 0;
- struct dma_async_tx_descriptor *tx = device ?
- device->device_prep_dma_memcpy(chan, len,
- int_en) : NULL;
+ struct dma_async_tx_descriptor *tx = NULL;
- if (tx) { /* run the memcpy asynchronously */
- dma_addr_t addr;
- enum dma_data_direction dir;
+ if (device) {
+ dma_addr_t dma_dest, dma_src;
+ unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
+ dma_dest = dma_map_page(device->dev, dest, dest_offset, len,
+ DMA_FROM_DEVICE);
+
+ dma_src = dma_map_page(device->dev, src, src_offset, len,
+ DMA_TO_DEVICE);
+
+ tx = device->device_prep_dma_memcpy(chan, dma_dest, dma_src,
+ len, dma_prep_flags);
+ }
+
+ if (tx) {
pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
-
- dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
- DMA_NONE : DMA_FROM_DEVICE;
-
- addr = dma_map_page(device->dev, dest, dest_offset, len, dir);
- tx->tx_set_dest(addr, tx, 0);
-
- dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
- DMA_NONE : DMA_TO_DEVICE;
-
- addr = dma_map_page(device->dev, src, src_offset, len, dir);
- tx->tx_set_src(addr, tx, 0);
-
async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
- } else { /* run the memcpy synchronously */
+ } else {
void *dest_buf, *src_buf;
pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);
diff --git a/crypto/async_tx/async_memset.c b/crypto/async_tx/async_memset.c
index 66ef635..09c0e836 100644
--- a/crypto/async_tx/async_memset.c
+++ b/crypto/async_tx/async_memset.c
@@ -35,7 +35,7 @@
* @val: fill value
* @offset: offset in pages to start transaction
* @len: length in bytes
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
* @depend_tx: memset depends on the result of this transaction
* @cb_fn: function to call when the memcpy completes
* @cb_param: parameter to pass to the callback routine
@@ -46,24 +46,24 @@
struct dma_async_tx_descriptor *depend_tx,
dma_async_tx_callback cb_fn, void *cb_param)
{
- struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET);
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET,
+ &dest, 1, NULL, 0, len);
struct dma_device *device = chan ? chan->device : NULL;
- int int_en = cb_fn ? 1 : 0;
- struct dma_async_tx_descriptor *tx = device ?
- device->device_prep_dma_memset(chan, val, len,
- int_en) : NULL;
+ struct dma_async_tx_descriptor *tx = NULL;
- if (tx) { /* run the memset asynchronously */
- dma_addr_t dma_addr;
- enum dma_data_direction dir;
+ if (device) {
+ dma_addr_t dma_dest;
+ unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
+ dma_dest = dma_map_page(device->dev, dest, offset, len,
+ DMA_FROM_DEVICE);
+
+ tx = device->device_prep_dma_memset(chan, dma_dest, val, len,
+ dma_prep_flags);
+ }
+
+ if (tx) {
pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
- dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
- DMA_NONE : DMA_FROM_DEVICE;
-
- dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
- tx->tx_set_dest(dma_addr, tx, 0);
-
async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
} else { /* run the memset synchronously */
void *dest_buf;
diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c
index bc18cbb..56288218 100644
--- a/crypto/async_tx/async_tx.c
+++ b/crypto/async_tx/async_tx.c
@@ -57,8 +57,7 @@
*/
static spinlock_t async_tx_lock;
-static struct list_head
-async_tx_master_list = LIST_HEAD_INIT(async_tx_master_list);
+static LIST_HEAD(async_tx_master_list);
/* async_tx_issue_pending_all - start all transactions on all channels */
void async_tx_issue_pending_all(void)
@@ -362,13 +361,13 @@
}
/**
- * async_tx_find_channel - find a channel to carry out the operation or let
+ * __async_tx_find_channel - find a channel to carry out the operation or let
* the transaction execute synchronously
* @depend_tx: transaction dependency
* @tx_type: transaction type
*/
struct dma_chan *
-async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
enum dma_transaction_type tx_type)
{
/* see if we can keep the chain on one channel */
@@ -384,7 +383,7 @@
} else
return NULL;
}
-EXPORT_SYMBOL_GPL(async_tx_find_channel);
+EXPORT_SYMBOL_GPL(__async_tx_find_channel);
#else
static int __init async_tx_init(void)
{
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
index 2575f67..2259a4f 100644
--- a/crypto/async_tx/async_xor.c
+++ b/crypto/async_tx/async_xor.c
@@ -30,35 +30,51 @@
#include <linux/raid/xor.h>
#include <linux/async_tx.h>
-static void
-do_async_xor(struct dma_async_tx_descriptor *tx, struct dma_device *device,
+/* do_async_xor - dma map the pages and perform the xor with an engine.
+ * This routine is marked __always_inline so it can be compiled away
+ * when CONFIG_DMA_ENGINE=n
+ */
+static __always_inline struct dma_async_tx_descriptor *
+do_async_xor(struct dma_device *device,
struct dma_chan *chan, struct page *dest, struct page **src_list,
unsigned int offset, unsigned int src_cnt, size_t len,
enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
dma_async_tx_callback cb_fn, void *cb_param)
{
- dma_addr_t dma_addr;
- enum dma_data_direction dir;
+ dma_addr_t dma_dest;
+ dma_addr_t *dma_src = (dma_addr_t *) src_list;
+ struct dma_async_tx_descriptor *tx;
int i;
+ unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
pr_debug("%s: len: %zu\n", __FUNCTION__, len);
- dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
- DMA_NONE : DMA_FROM_DEVICE;
+ dma_dest = dma_map_page(device->dev, dest, offset, len,
+ DMA_FROM_DEVICE);
- dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
- tx->tx_set_dest(dma_addr, tx, 0);
+ for (i = 0; i < src_cnt; i++)
+ dma_src[i] = dma_map_page(device->dev, src_list[i], offset,
+ len, DMA_TO_DEVICE);
- dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
- DMA_NONE : DMA_TO_DEVICE;
+ /* Since we have clobbered the src_list we are committed
+ * to doing this asynchronously. Drivers force forward progress
+ * in case they can not provide a descriptor
+ */
+ tx = device->device_prep_dma_xor(chan, dma_dest, dma_src, src_cnt, len,
+ dma_prep_flags);
+ if (!tx) {
+ if (depend_tx)
+ dma_wait_for_async_tx(depend_tx);
- for (i = 0; i < src_cnt; i++) {
- dma_addr = dma_map_page(device->dev, src_list[i],
- offset, len, dir);
- tx->tx_set_src(dma_addr, tx, i);
+ while (!tx)
+ tx = device->device_prep_dma_xor(chan, dma_dest,
+ dma_src, src_cnt, len,
+ dma_prep_flags);
}
async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+
+ return tx;
}
static void
@@ -102,7 +118,7 @@
* @src_cnt: number of source pages
* @len: length in bytes
* @flags: ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DEST,
- * ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
* @depend_tx: xor depends on the result of this transaction.
* @cb_fn: function to call when the xor completes
* @cb_param: parameter to pass to the callback routine
@@ -113,14 +129,16 @@
struct dma_async_tx_descriptor *depend_tx,
dma_async_tx_callback cb_fn, void *cb_param)
{
- struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR);
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR,
+ &dest, 1, src_list,
+ src_cnt, len);
struct dma_device *device = chan ? chan->device : NULL;
struct dma_async_tx_descriptor *tx = NULL;
dma_async_tx_callback _cb_fn;
void *_cb_param;
unsigned long local_flags;
int xor_src_cnt;
- int i = 0, src_off = 0, int_en;
+ int i = 0, src_off = 0;
BUG_ON(src_cnt <= 1);
@@ -140,20 +158,11 @@
_cb_param = cb_param;
}
- int_en = _cb_fn ? 1 : 0;
-
- tx = device->device_prep_dma_xor(
- chan, xor_src_cnt, len, int_en);
-
- if (tx) {
- do_async_xor(tx, device, chan, dest,
- &src_list[src_off], offset, xor_src_cnt, len,
- local_flags, depend_tx, _cb_fn,
- _cb_param);
- } else /* fall through */
- goto xor_sync;
+ tx = do_async_xor(device, chan, dest,
+ &src_list[src_off], offset,
+ xor_src_cnt, len, local_flags,
+ depend_tx, _cb_fn, _cb_param);
} else { /* run the xor synchronously */
-xor_sync:
/* in the sync case the dest is an implied source
* (assumes the dest is at the src_off index)
*/
@@ -242,7 +251,7 @@
* @src_cnt: number of source pages
* @len: length in bytes
* @result: 0 if sum == 0 else non-zero
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
* @depend_tx: xor depends on the result of this transaction.
* @cb_fn: function to call when the xor completes
* @cb_param: parameter to pass to the callback routine
@@ -254,29 +263,36 @@
struct dma_async_tx_descriptor *depend_tx,
dma_async_tx_callback cb_fn, void *cb_param)
{
- struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM);
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM,
+ &dest, 1, src_list,
+ src_cnt, len);
struct dma_device *device = chan ? chan->device : NULL;
- int int_en = cb_fn ? 1 : 0;
- struct dma_async_tx_descriptor *tx = device ?
- device->device_prep_dma_zero_sum(chan, src_cnt, len, result,
- int_en) : NULL;
- int i;
+ struct dma_async_tx_descriptor *tx = NULL;
BUG_ON(src_cnt <= 1);
- if (tx) {
- dma_addr_t dma_addr;
- enum dma_data_direction dir;
+ if (device) {
+ dma_addr_t *dma_src = (dma_addr_t *) src_list;
+ unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
+ int i;
pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
- dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
- DMA_NONE : DMA_TO_DEVICE;
+ for (i = 0; i < src_cnt; i++)
+ dma_src[i] = dma_map_page(device->dev, src_list[i],
+ offset, len, DMA_TO_DEVICE);
- for (i = 0; i < src_cnt; i++) {
- dma_addr = dma_map_page(device->dev, src_list[i],
- offset, len, dir);
- tx->tx_set_src(dma_addr, tx, i);
+ tx = device->device_prep_dma_zero_sum(chan, dma_src, src_cnt,
+ len, result,
+ dma_prep_flags);
+ if (!tx) {
+ if (depend_tx)
+ dma_wait_for_async_tx(depend_tx);
+
+ while (!tx)
+ tx = device->device_prep_dma_zero_sum(chan,
+ dma_src, src_cnt, len, result,
+ dma_prep_flags);
}
async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
@@ -311,6 +327,16 @@
static int __init async_xor_init(void)
{
+ #ifdef CONFIG_DMA_ENGINE
+ /* To conserve stack space the input src_list (array of page pointers)
+ * is reused to hold the array of dma addresses passed to the driver.
+ * This conversion is only possible when dma_addr_t is less than the
+ * the size of a pointer. HIGHMEM64G is known to violate this
+ * assumption.
+ */
+ BUILD_BUG_ON(sizeof(dma_addr_t) > sizeof(struct page *));
+ #endif
+
return 0;
}
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 8e238cf..b86877b 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@
source "drivers/spi/Kconfig"
+source "drivers/gpio/Kconfig"
+
source "drivers/w1/Kconfig"
source "drivers/power/Kconfig"
@@ -93,6 +95,4 @@
source "drivers/auxdisplay/Kconfig"
source "drivers/uio/Kconfig"
-
-source "drivers/virtio/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index a516b8b..30ba97e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,6 +5,7 @@
# Rewritten to use lists instead of if-statements.
#
+obj-$(CONFIG_HAVE_GPIO_LIB) += gpio/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index d915fec..d25ef96 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -142,6 +142,7 @@
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
A4S, //Z81sp
//(Centrino)
+ F3Sa,
END_MODEL
} model; //Models currently supported
u16 event_count[128]; //count for each event TODO make this better
@@ -405,7 +406,20 @@
.brightness_get = "GPLV",
.mt_bt_switch = "BLED",
.mt_wled = "WLED"
- }
+ },
+
+ {
+ .name = "F3Sa",
+ .mt_bt_switch = "BLED",
+ .mt_wled = "WLED",
+ .mt_mled = "MLED",
+ .brightness_get = "GPLV",
+ .brightness_set = "SPLV",
+ .mt_lcd_switch = "\\_SB.PCI0.SBRG.EC0._Q10",
+ .lcd_status = "\\_SB.PCI0.SBRG.EC0.RPIN",
+ .display_get = "\\ADVG",
+ .display_set = "SDSP",
+ },
};
@@ -710,15 +724,8 @@
{
int lcd = 0;
- if (hotk->model != L3H) {
- /* We don't have to check anything if we are here */
- if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
- printk(KERN_WARNING
- "Asus ACPI: Error reading LCD status\n");
-
- if (hotk->model == L2D)
- lcd = ~lcd;
- } else { /* L3H and the like have to be handled differently */
+ if (hotk->model == L3H) {
+ /* L3H and the like have to be handled differently */
acpi_status status = 0;
struct acpi_object_list input;
union acpi_object mt_params[2];
@@ -745,6 +752,32 @@
if (out_obj.type == ACPI_TYPE_INTEGER)
/* That's what the AML code does */
lcd = out_obj.integer.value >> 8;
+ } else if (hotk->model == F3Sa) {
+ unsigned long tmp;
+ union acpi_object param;
+ struct acpi_object_list input;
+ acpi_status status;
+
+ /* Read pin 11 */
+ param.type = ACPI_TYPE_INTEGER;
+ param.integer.value = 0x11;
+ input.count = 1;
+ input.pointer = ¶m;
+
+ status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
+ &input, &tmp);
+ if (status != AE_OK)
+ return -1;
+
+ lcd = tmp;
+ } else {
+ /* We don't have to check anything if we are here */
+ if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
+ printk(KERN_WARNING
+ "Asus ACPI: Error reading LCD status\n");
+
+ if (hotk->model == L2D)
+ lcd = ~lcd;
}
return (lcd & 1);
@@ -1134,6 +1167,8 @@
return W5A;
else if (strncmp(model, "A4S", 3) == 0)
return A4S;
+ else if (strncmp(model, "F3Sa", 4) == 0)
+ return F3Sa;
else
return END_MODEL;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index c4a769d..f6215e8 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -194,6 +194,9 @@
case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = battery->oem_info;
break;
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ val->strval = battery->serial_number;
+ break;
default:
return -EINVAL;
}
@@ -212,6 +215,7 @@
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
static enum power_supply_property energy_battery_props[] = {
@@ -226,6 +230,7 @@
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
#endif
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 6daf6088..4777114 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -46,6 +46,12 @@
printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
static void bay_notify(acpi_handle handle, u32 event, void *data);
+static const struct acpi_device_id bay_device_ids[] = {
+ {"LNXIOBAY", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, bay_device_ids);
+
struct bay {
acpi_handle handle;
char *name;
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 8809654..6dbaa2d 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -70,8 +70,6 @@
/* IBM 600E - _ADR should return 7, but it returns 1 */
{"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1},
- {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
- "Bogus PCI routing", 1},
{""}
};
@@ -208,33 +206,35 @@
* Disable OSI(Linux) warnings on all "Acer, inc."
*
* _OSI(Linux) disables the latest Windows BIOS code:
+ * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
+ * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
* _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
*/
- {
- .callback = dmi_disable_osi_linux,
- .ident = "Acer, inc.",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
- },
- },
+ /*
+ * note that dmi_check_system() uses strstr()
+ * to match sub-strings rather than !strcmp(),
+ * so "Acer" below matches "Acer, inc." above.
+ */
/*
* Disable OSI(Linux) warnings on all "Acer"
*
* _OSI(Linux) effect unknown:
- * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
+ *
+ * _OSI(Linux) is a NOP:
+ * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
*/
{
- .callback = dmi_unknown_osi_linux,
+ .callback = dmi_disable_osi_linux,
.ident = "Acer",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -242,21 +242,22 @@
},
/*
* Disable OSI(Linux) warnings on all "Apple Computer, Inc."
+ * Disable OSI(Linux) warnings on all "Apple Inc."
*
* _OSI(Linux) confirmed to be a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+ * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
* _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
- * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
*/
{
.callback = dmi_disable_osi_linux,
.ident = "Apple",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
},
},
/*
@@ -294,13 +295,13 @@
* DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
*/
{
- .callback = dmi_unknown_osi_linux,
+ .callback = dmi_disable_osi_linux,
.ident = "Compal",
.matches = {
DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
},
},
- { /* OSI(Linux) touches USB, breaks suspend to disk */
+ { /* OSI(Linux) touches USB, unknown side-effect */
.callback = dmi_disable_osi_linux,
.ident = "Dell Dimension 5150",
.matches = {
@@ -310,7 +311,7 @@
},
{ /* OSI(Linux) is a NOP */
.callback = dmi_disable_osi_linux,
- .ident = "Dell",
+ .ident = "Dell i1501",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
@@ -318,7 +319,7 @@
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell Latitude D830",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
@@ -326,7 +327,7 @@
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell OP GX620",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
@@ -334,15 +335,23 @@
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell PE 1900",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
},
},
+ { /* OSI(Linux) is a NOP */
+ .callback = dmi_disable_osi_linux,
+ .ident = "Dell PE R200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R200"),
+ },
+ },
{ /* OSI(Linux) touches USB */
.callback = dmi_disable_osi_linux,
- .ident = "Dell",
+ .ident = "Dell PR 390",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
@@ -358,7 +367,7 @@
},
{ /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux,
- .ident = "Dell",
+ .ident = "Dell PE SC440",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
@@ -474,6 +483,11 @@
*
* _OSI(Linux) confirmed to be a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
+ * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
+ *
+ * unknown:
+ * DMI_MATCH(DMI_PRODUCT_NAME, "S1-MDGDG"),
+ * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
*/
{
.callback = dmi_disable_osi_linux,
@@ -516,7 +530,7 @@
* DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
*/
{
- .callback = dmi_unknown_osi_linux,
+ .callback = dmi_disable_osi_linux,
.ident = "Sony",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index bf513e0..6df564f 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -130,6 +130,63 @@
module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+static char trace_method_name[6];
+module_param_string(trace_method_name, trace_method_name, 6, 0644);
+static unsigned int trace_debug_layer;
+module_param(trace_debug_layer, uint, 0644);
+static unsigned int trace_debug_level;
+module_param(trace_debug_level, uint, 0644);
+
+static int param_set_trace_state(const char *val, struct kernel_param *kp)
+{
+ int result = 0;
+
+ if (!strncmp(val, "enable", strlen("enable") - 1)) {
+ result = acpi_debug_trace(trace_method_name, trace_debug_level,
+ trace_debug_layer, 0);
+ if (result)
+ result = -EBUSY;
+ goto exit;
+ }
+
+ if (!strncmp(val, "disable", strlen("disable") - 1)) {
+ int name = 0;
+ result = acpi_debug_trace((char *)&name, trace_debug_level,
+ trace_debug_layer, 0);
+ if (result)
+ result = -EBUSY;
+ goto exit;
+ }
+
+ if (!strncmp(val, "1", 1)) {
+ result = acpi_debug_trace(trace_method_name, trace_debug_level,
+ trace_debug_layer, 1);
+ if (result)
+ result = -EBUSY;
+ goto exit;
+ }
+
+ result = -EINVAL;
+exit:
+ return result;
+}
+
+static int param_get_trace_state(char *buffer, struct kernel_param *kp)
+{
+ if (!acpi_gbl_trace_method_name)
+ return sprintf(buffer, "disable");
+ else {
+ if (acpi_gbl_trace_flags & 1)
+ return sprintf(buffer, "1");
+ else
+ return sprintf(buffer, "enable");
+ }
+ return 0;
+}
+
+module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
+ NULL, 0644);
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 1dabdf4..b3dec21 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -51,6 +51,12 @@
static struct platform_device *dock_device;
static char dock_device_name[] = "dock";
+static const struct acpi_device_id dock_device_ids[] = {
+ {"LNXDOCK", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, dock_device_ids);
+
struct dock_station {
acpi_handle handle;
unsigned long last_dock_time;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 987b967..7222a18 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -573,7 +573,7 @@
void *handler_context, void *region_context)
{
struct acpi_ec *ec = handler_context;
- int result = 0, i = 0;
+ int result = 0, i;
u8 temp = 0;
if ((address > 0xFF) || !value || !handler_context)
@@ -585,7 +585,18 @@
if (bits != 8 && acpi_strict)
return AE_BAD_PARAMETER;
- while (bits - i > 0) {
+ acpi_ec_burst_enable(ec);
+
+ if (function == ACPI_READ) {
+ result = acpi_ec_read(ec, address, &temp);
+ *value = temp;
+ } else {
+ temp = 0xff & (*value);
+ result = acpi_ec_write(ec, address, temp);
+ }
+
+ for (i = 8; unlikely(bits - i > 0); i += 8) {
+ ++address;
if (function == ACPI_READ) {
result = acpi_ec_read(ec, address, &temp);
(*value) |= ((acpi_integer)temp) << i;
@@ -593,10 +604,10 @@
temp = 0xff & ((*value) >> i);
result = acpi_ec_write(ec, address, temp);
}
- i += 8;
- ++address;
}
+ acpi_ec_burst_disable(ec);
+
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index e412878..3048801 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -259,7 +259,7 @@
enable_bit_mask)) {
/* Found an active (signalled) event */
-
+ acpi_os_fixed_event_count(i);
int_status |= acpi_ev_fixed_event_dispatch((u32) i);
}
}
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index e22f4a9..0dadd2a 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -270,18 +270,18 @@
case ACPI_GPE_TYPE_WAKE_RUN:
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
- /*lint -fallthrough */
+ /* fallthrough */
case ACPI_GPE_TYPE_RUNTIME:
/* Disable the requested runtime GPE */
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
- status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
- break;
+
+ /* fallthrough */
default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ acpi_hw_write_gpe_enable_reg(gpe_event_info);
}
return_ACPI_STATUS(AE_OK);
@@ -501,6 +501,7 @@
* an interrupt handler.
*
******************************************************************************/
+static void acpi_ev_asynch_enable_gpe(void *context);
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
@@ -576,22 +577,30 @@
method_node)));
}
}
+ /* Defer enabling of GPE until all notify handlers are done */
+ acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
+ gpe_event_info);
+ return_VOID;
+}
- if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+static void acpi_ev_asynch_enable_gpe(void *context)
+{
+ struct acpi_gpe_event_info *gpe_event_info = context;
+ acpi_status status;
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
ACPI_GPE_LEVEL_TRIGGERED) {
/*
* GPE is level-triggered, we clear the GPE status bit after
* handling the event.
*/
- status = acpi_hw_clear_gpe(&local_gpe_event_info);
+ status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
return_VOID;
}
}
/* Enable this GPE */
-
- (void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
+ (void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
return_VOID;
}
@@ -618,7 +627,7 @@
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
- acpi_gpe_count++;
+ acpi_os_gpe_count(gpe_number);
/*
* If edge-triggered, clear the GPE status bit now. Note that
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 81b2484..058d0be5 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -192,18 +192,13 @@
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = sleep_state;
- /* Run the _PTS and _GTS methods */
+ /* Run the _PTS method */
status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
return_ACPI_STATUS(status);
}
- status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- return_ACPI_STATUS(status);
- }
-
/* Setup the argument to _SST */
switch (sleep_state) {
@@ -234,10 +229,6 @@
"While executing method _SST"));
}
- /* Disable/Clear all GPEs */
-
- status = acpi_hw_disable_all_gpes();
-
return_ACPI_STATUS(status);
}
@@ -262,6 +253,8 @@
struct acpi_bit_register_info *sleep_type_reg_info;
struct acpi_bit_register_info *sleep_enable_reg_info;
u32 in_value;
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
@@ -293,13 +286,13 @@
}
/*
+ * 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs
*/
status = acpi_hw_disable_all_gpes();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
acpi_gbl_system_awake_and_running = FALSE;
status = acpi_hw_enable_all_wakeup_gpes();
@@ -307,6 +300,18 @@
return_ACPI_STATUS(status);
}
+ /* Execute the _GTS method */
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = sleep_state;
+
+ status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ return_ACPI_STATUS(status);
+ }
+
/* Get current value of PM1A control */
status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
@@ -473,17 +478,18 @@
/*******************************************************************************
*
- * FUNCTION: acpi_leave_sleep_state
+ * FUNCTION: acpi_leave_sleep_state_prep
*
- * PARAMETERS: sleep_state - Which sleep state we just exited
+ * PARAMETERS: sleep_state - Which sleep state we are exiting
*
* RETURN: Status
*
- * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
- * Called with interrupts ENABLED.
+ * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
+ * sleep.
+ * Called with interrupts DISABLED.
*
******************************************************************************/
-acpi_status acpi_leave_sleep_state(u8 sleep_state)
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
{
struct acpi_object_list arg_list;
union acpi_object arg;
@@ -493,7 +499,7 @@
u32 PM1Acontrol;
u32 PM1Bcontrol;
- ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+ ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
/*
* Set SLP_TYPE and SLP_EN to state S0.
@@ -540,6 +546,41 @@
}
}
+ /* Execute the _BFS method */
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = sleep_state;
+
+ status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_leave_sleep_state
+ *
+ * PARAMETERS: sleep_state - Which sleep state we just exited
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+ * Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+acpi_status acpi_leave_sleep_state(u8 sleep_state)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
@@ -558,12 +599,6 @@
ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
}
- arg.integer.value = sleep_state;
- status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
- }
-
/*
* GPEs must be enabled before _WAK is called as GPEs
* might get fired there
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index f39fbc6..b92133f 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -443,6 +443,7 @@
struct acpica_device_id hid;
struct acpi_compatible_id_list *cid;
acpi_native_uint i;
+ int found;
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -496,16 +497,19 @@
/* Walk the CID list */
+ found = 0;
for (i = 0; i < cid->count; i++) {
if (ACPI_STRNCMP(cid->id[i].value, info->hid,
sizeof(struct
- acpi_compatible_id)) !=
+ acpi_compatible_id)) ==
0) {
- ACPI_FREE(cid);
- return (AE_OK);
+ found = 1;
+ break;
}
}
ACPI_FREE(cid);
+ if (!found)
+ return (AE_OK);
}
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e53fb51..3b8aef3 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -120,7 +120,7 @@
*/
#define OSI_LINUX_ENABLE 0
-struct osi_linux {
+static struct osi_linux {
unsigned int enable:1;
unsigned int dmi:1;
unsigned int cmdline:1;
@@ -250,11 +250,16 @@
"System description tables not found\n");
return 0;
}
- } else
- return acpi_find_rsdp();
+ } else {
+ acpi_physical_address pa = 0;
+
+ acpi_find_root_pointer(&pa);
+ return pa;
+ }
}
-void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+void __iomem *__init_refok
+acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -332,7 +337,15 @@
static irqreturn_t acpi_irq(int irq, void *dev_id)
{
- return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+ u32 handled;
+
+ handled = (*acpi_irq_handler) (acpi_irq_context);
+
+ if (handled) {
+ acpi_irq_handled++;
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
}
acpi_status
@@ -341,6 +354,8 @@
{
unsigned int irq;
+ acpi_irq_stats_init();
+
/*
* Ignore the GSI from the core, and use the value in our copy of the
* FADT. It may not be the same if an interrupt source override exists
@@ -661,25 +676,6 @@
dpc->function(dpc->context);
kfree(dpc);
- /* Yield cpu to notify thread */
- cond_resched();
-
- return;
-}
-
-static void acpi_os_execute_notify(struct work_struct *work)
-{
- struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
-
- if (!dpc) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- dpc->function(dpc->context);
-
- kfree(dpc);
-
return;
}
@@ -703,7 +699,7 @@
{
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
-
+ struct workqueue_struct *queue;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
function, context));
@@ -727,20 +723,13 @@
dpc->function = function;
dpc->context = context;
- if (type == OSL_NOTIFY_HANDLER) {
- INIT_WORK(&dpc->work, acpi_os_execute_notify);
- if (!queue_work(kacpi_notify_wq, &dpc->work)) {
- status = AE_ERROR;
- kfree(dpc);
- }
- } else {
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- if (!queue_work(kacpid_wq, &dpc->work)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Call to queue_work() failed.\n"));
- status = AE_ERROR;
- kfree(dpc);
- }
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+ queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
+ if (!queue_work(queue, &dpc->work)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Call to queue_work() failed.\n"));
+ status = AE_ERROR;
+ kfree(dpc);
}
return_ACPI_STATUS(status);
}
@@ -1213,24 +1202,24 @@
*
* Returns 0 on success
*/
-int acpi_dmi_dump(void)
+static int acpi_dmi_dump(void)
{
if (!dmi_available)
return -1;
printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
- dmi_get_slot(DMI_SYS_VENDOR));
+ dmi_get_system_info(DMI_SYS_VENDOR));
printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
- dmi_get_slot(DMI_PRODUCT_NAME));
+ dmi_get_system_info(DMI_PRODUCT_NAME));
printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
- dmi_get_slot(DMI_PRODUCT_VERSION));
+ dmi_get_system_info(DMI_PRODUCT_VERSION));
printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
- dmi_get_slot(DMI_BOARD_NAME));
+ dmi_get_system_info(DMI_BOARD_NAME));
printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
- dmi_get_slot(DMI_BIOS_VENDOR));
+ dmi_get_system_info(DMI_BIOS_VENDOR));
printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
- dmi_get_slot(DMI_BIOS_DATE));
+ dmi_get_system_info(DMI_BIOS_DATE));
return 0;
}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 62010c2..76d9c66 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -51,10 +51,8 @@
int bus,
int device, int pin)
{
- struct list_head *node = NULL;
struct acpi_prt_entry *entry = NULL;
-
if (!acpi_prt.count)
return NULL;
@@ -64,8 +62,7 @@
*
*/
spin_lock(&acpi_prt_lock);
- list_for_each(node, &acpi_prt.entries) {
- entry = list_entry(node, struct acpi_prt_entry, node);
+ list_for_each_entry(entry, &acpi_prt.entries, node) {
if ((segment == entry->id.segment)
&& (bus == entry->id.bus)
&& (device == entry->id.device)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index af1769a..76bf6d9 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -458,11 +458,9 @@
}
end:
- if (result) {
+ if (result)
device->power.state = ACPI_STATE_UNKNOWN;
- printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n",
- device->pnp.bus_id, state);
- } else {
+ else {
/* We shouldn't change the state till all above operations succeed */
device->power.state = state;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 5668c5e..315fd8f 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -835,11 +835,18 @@
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
- ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
- return 0;
- }
- return 1;
+ /*
+ * if a processor object does not have an _STA object,
+ * OSPM assumes that the processor is present.
+ */
+ if (status == AE_NOT_FOUND)
+ return 1;
+
+ if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
+ return 1;
+
+ ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
+ return 0;
}
static
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index eb1f82f..32003fd 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -38,7 +38,7 @@
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> /* need_resched() */
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
@@ -98,6 +98,9 @@
static int acpi_processor_set_power_policy(struct acpi_processor *pr);
+#else /* CONFIG_CPU_IDLE */
+static unsigned int latency_factor __read_mostly = 2;
+module_param(latency_factor, uint, 0644);
#endif
/*
@@ -201,6 +204,10 @@
return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
}
+/*
+ * Callers should disable interrupts before the call and enable
+ * interrupts after return.
+ */
static void acpi_safe_halt(void)
{
current_thread_info()->status &= ~TS_POLLING;
@@ -261,7 +268,7 @@
/* Common C-state entry for C2, C3, .. */
static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
{
- if (cstate->space_id == ACPI_CSTATE_FFH) {
+ if (cstate->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cstate);
} else {
@@ -413,6 +420,8 @@
pm_idle_save();
else
acpi_safe_halt();
+
+ local_irq_enable();
return;
}
@@ -521,6 +530,7 @@
* skew otherwise.
*/
sleep_ticks = 0xFFFFFFFF;
+ local_irq_enable();
break;
case ACPI_STATE_C2:
@@ -648,7 +658,8 @@
if (cx->promotion.state &&
((cx->promotion.state - pr->power.states) <= max_cstate)) {
if (sleep_ticks > cx->promotion.threshold.ticks &&
- cx->promotion.state->latency <= system_latency_constraint()) {
+ cx->promotion.state->latency <=
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
cx->promotion.count++;
cx->demotion.count = 0;
if (cx->promotion.count >=
@@ -692,7 +703,8 @@
* or if the latency of the current state is unacceptable
*/
if ((pr->power.state - pr->power.states) > max_cstate ||
- pr->power.state->latency > system_latency_constraint()) {
+ pr->power.state->latency >
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
if (cx->demotion.state)
next_state = cx->demotion.state;
}
@@ -920,20 +932,20 @@
cx.address = reg->address;
cx.index = current_count + 1;
- cx.space_id = ACPI_CSTATE_SYSTEMIO;
+ cx.entry_method = ACPI_CSTATE_SYSTEMIO;
if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
if (acpi_processor_ffh_cstate_probe
(pr->id, &cx, reg) == 0) {
- cx.space_id = ACPI_CSTATE_FFH;
- } else if (cx.type != ACPI_STATE_C1) {
+ cx.entry_method = ACPI_CSTATE_FFH;
+ } else if (cx.type == ACPI_STATE_C1) {
/*
* C1 is a special case where FIXED_HARDWARE
* can be handled in non-MWAIT way as well.
* In that case, save this _CST entry info.
- * That is, we retain space_id of SYSTEM_IO for
- * halt based C1.
* Otherwise, ignore this info and continue.
*/
+ cx.entry_method = ACPI_CSTATE_HALT;
+ } else {
continue;
}
}
@@ -1200,7 +1212,7 @@
"maximum allowed latency: %d usec\n",
pr->power.state ? pr->power.state - pr->power.states : 0,
max_cstate, (unsigned)pr->power.bm_activity,
- system_latency_constraint());
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY));
seq_puts(seq, "states:\n");
@@ -1367,12 +1379,16 @@
/**
* acpi_idle_do_entry - a helper function that does C2 and C3 type entry
* @cx: cstate data
+ *
+ * Caller disables interrupt before call and enables interrupt after return.
*/
static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
- if (cx->space_id == ACPI_CSTATE_FFH) {
+ if (cx->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx);
+ } else if (cx->entry_method == ACPI_CSTATE_HALT) {
+ acpi_safe_halt();
} else {
int unused;
/* IO port based C-state */
@@ -1394,21 +1410,27 @@
static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
+ u32 t1, t2;
struct acpi_processor *pr;
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+
pr = processors[smp_processor_id()];
if (unlikely(!pr))
return 0;
+ local_irq_disable();
if (pr->flags.bm_check)
acpi_idle_update_bm_rld(pr, cx);
- acpi_safe_halt();
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ acpi_idle_do_entry(cx);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ local_irq_enable();
cx->usage++;
- return 0;
+ return ticks_elapsed_in_us(t1, t2);
}
/**
@@ -1515,7 +1537,9 @@
if (dev->safe_state) {
return dev->safe_state->enter(dev, dev->safe_state);
} else {
+ local_irq_disable();
acpi_safe_halt();
+ local_irq_enable();
return 0;
}
}
@@ -1607,7 +1631,7 @@
*/
static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
{
- int i, count = 0;
+ int i, count = CPUIDLE_DRIVER_STATE_START;
struct acpi_processor_cx *cx;
struct cpuidle_state *state;
struct cpuidle_device *dev = &pr->power.dev;
@@ -1636,13 +1660,14 @@
snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
state->exit_latency = cx->latency;
- state->target_residency = cx->latency * 6;
+ state->target_residency = cx->latency * latency_factor;
state->power_usage = cx->power;
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
state->flags |= CPUIDLE_FLAG_SHALLOW;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_c1;
dev->safe_state = state;
break;
@@ -1665,6 +1690,8 @@
}
count++;
+ if (count == CPUIDLE_STATE_MAX)
+ break;
}
dev->state_count = count;
@@ -1718,8 +1745,9 @@
"ACPI: processor limited to max C-state %d\n",
max_cstate);
first_run++;
-#if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP)
- register_latency_notifier(&acpi_processor_latency_notifier);
+#if !defined(CONFIG_CPU_IDLE) && defined(CONFIG_SMP)
+ pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
+ &acpi_processor_latency_notifier);
#endif
}
@@ -1806,7 +1834,8 @@
*/
cpu_idle_wait();
#ifdef CONFIG_SMP
- unregister_latency_notifier(&acpi_processor_latency_notifier);
+ pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
+ &acpi_processor_latency_notifier);
#endif
}
#endif
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 463b024..f32010b 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -60,6 +60,11 @@
* policy is adjusted accordingly.
*/
+static unsigned int ignore_ppc = 0;
+module_param(ignore_ppc, uint, 0644);
+MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
+ "limited by BIOS, this should help");
+
#define PPC_REGISTERED 1
#define PPC_IN_USE 2
@@ -72,6 +77,9 @@
struct acpi_processor *pr;
unsigned int ppc = 0;
+ if (ignore_ppc)
+ return 0;
+
mutex_lock(&performance_mutex);
if (event != CPUFREQ_INCOMPATIBLE)
@@ -130,7 +138,13 @@
int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
{
- int ret = acpi_processor_get_platform_limit(pr);
+ int ret;
+
+ if (ignore_ppc)
+ return 0;
+
+ ret = acpi_processor_get_platform_limit(pr);
+
if (ret < 0)
return (ret);
else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index cbfe9ae..c7b0aa5 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -830,7 +830,7 @@
if (ACPI_SUCCESS(status))
device->flags.wake_capable = 1;
- /* TBD: Peformance management */
+ /* TBD: Performance management */
return 0;
}
@@ -941,6 +941,15 @@
return -ENODEV;
}
+/*
+ * acpi_dock_match - see if a device has a _DCK method
+ */
+static int acpi_dock_match(struct acpi_device *device)
+{
+ acpi_handle tmp;
+ return acpi_get_handle(device->handle, "_DCK", &tmp);
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
@@ -950,6 +959,7 @@
char *hid = NULL;
char *uid = NULL;
struct acpi_compatible_id_list *cid_list = NULL;
+ const char *cid_add = NULL;
acpi_status status;
switch (type) {
@@ -972,15 +982,18 @@
device->flags.bus_address = 1;
}
- if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
- status = acpi_video_bus_match(device);
- if(ACPI_SUCCESS(status))
- hid = ACPI_VIDEO_HID;
+ /* If we have a video/bay/dock device, add our selfdefined
+ HID to the CID list. Like that the video/bay/dock drivers
+ will get autoloaded and the device might still match
+ against another driver.
+ */
+ if (ACPI_SUCCESS(acpi_video_bus_match(device)))
+ cid_add = ACPI_VIDEO_HID;
+ else if (ACPI_SUCCESS(acpi_bay_match(device)))
+ cid_add = ACPI_BAY_HID;
+ else if (ACPI_SUCCESS(acpi_dock_match(device)))
+ cid_add = ACPI_DOCK_HID;
- status = acpi_bay_match(device);
- if (ACPI_SUCCESS(status))
- hid = ACPI_BAY_HID;
- }
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
@@ -1021,11 +1034,44 @@
strcpy(device->pnp.unique_id, uid);
device->flags.unique_id = 1;
}
- if (cid_list) {
- device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
- if (device->pnp.cid_list)
- memcpy(device->pnp.cid_list, cid_list, cid_list->size);
- else
+ if (cid_list || cid_add) {
+ struct acpi_compatible_id_list *list;
+ int size = 0;
+ int count = 0;
+
+ if (cid_list) {
+ size = cid_list->size;
+ } else if (cid_add) {
+ size = sizeof(struct acpi_compatible_id_list);
+ cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
+ if (!cid_list) {
+ printk(KERN_ERR "Memory allocation error\n");
+ kfree(buffer.pointer);
+ return;
+ } else {
+ cid_list->count = 0;
+ cid_list->size = size;
+ }
+ }
+ if (cid_add)
+ size += sizeof(struct acpi_compatible_id);
+ list = kmalloc(size, GFP_KERNEL);
+
+ if (list) {
+ if (cid_list) {
+ memcpy(list, cid_list, cid_list->size);
+ count = cid_list->count;
+ }
+ if (cid_add) {
+ strncpy(list->id[count].value, cid_add,
+ ACPI_MAX_CID_LENGTH);
+ count++;
+ device->flags.compatible_ids = 1;
+ }
+ list->size = size;
+ list->count = count;
+ device->pnp.cid_list = list;
+ } else
printk(KERN_ERR "Memory allocation error\n");
}
@@ -1081,6 +1127,20 @@
}
static int
+acpi_is_child_device(struct acpi_device *device,
+ int (*matcher)(struct acpi_device *))
+{
+ int result = -ENODEV;
+
+ do {
+ if (ACPI_SUCCESS(matcher(device)))
+ return AE_OK;
+ } while ((device = device->parent));
+
+ return result;
+}
+
+static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
@@ -1131,10 +1191,20 @@
case ACPI_BUS_TYPE_PROCESSOR:
case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device);
- if (ACPI_FAILURE(result) || !device->status.present) {
- result = -ENOENT;
+ if (ACPI_FAILURE(result)) {
+ result = -ENODEV;
goto end;
}
+ if (!device->status.present) {
+ /* Bay and dock should be handled even if absent */
+ if (!ACPI_SUCCESS(
+ acpi_is_child_device(device, acpi_bay_match)) &&
+ !ACPI_SUCCESS(
+ acpi_is_child_device(device, acpi_dock_match))) {
+ result = -ENODEV;
+ goto end;
+ }
+ }
break;
default:
STRUCT_TO_INT(device->status) =
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 2c0b663..293a1cb 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -26,9 +26,24 @@
#ifdef CONFIG_PM_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+static bool acpi_sleep_finish_wake_up;
+
+/*
+ * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we
+ * allow the user to request that behavior by using the 'acpi_new_pts_ordering'
+ * kernel command line option that causes the following variable to be set.
+ */
+static bool new_pts_ordering;
+
+static int __init acpi_new_pts_ordering(char *str)
+{
+ new_pts_ordering = true;
+ return 1;
+}
+__setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
#endif
-int acpi_sleep_prepare(u32 acpi_state)
+static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
/* do we have a wakeup address for S2 and S3? */
@@ -44,6 +59,8 @@
ACPI_FLUSH_CPU_CACHE();
acpi_enable_wakeup_device_prep(acpi_state);
#endif
+ printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
+ acpi_state);
acpi_enter_sleep_state_prep(acpi_state);
return 0;
}
@@ -63,17 +80,25 @@
static int init_8259A_after_S1;
/**
- * acpi_pm_set_target - Set the target system sleep state to the state
+ * acpi_pm_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported.
*/
-static int acpi_pm_set_target(suspend_state_t pm_state)
+static int acpi_pm_begin(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
if (sleep_states[acpi_state]) {
acpi_target_sleep_state = acpi_state;
+ if (new_pts_ordering)
+ return 0;
+
+ error = acpi_sleep_prepare(acpi_state);
+ if (error)
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ else
+ acpi_sleep_finish_wake_up = true;
} else {
printk(KERN_ERR "ACPI does not support this state: %d\n",
pm_state);
@@ -91,12 +116,17 @@
static int acpi_pm_prepare(void)
{
- int error = acpi_sleep_prepare(acpi_target_sleep_state);
+ if (new_pts_ordering) {
+ int error = acpi_sleep_prepare(acpi_target_sleep_state);
- if (error)
- acpi_target_sleep_state = ACPI_STATE_S0;
+ if (error) {
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ return error;
+ }
+ acpi_sleep_finish_wake_up = true;
+ }
- return error;
+ return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
}
/**
@@ -120,10 +150,8 @@
if (acpi_state == ACPI_STATE_S3) {
int error = acpi_save_state_mem();
- if (error) {
- acpi_target_sleep_state = ACPI_STATE_S0;
+ if (error)
return error;
- }
}
local_irq_save(flags);
@@ -139,13 +167,23 @@
break;
}
- /* ACPI 3.0 specs (P62) says that it's the responsabilty
+ /* Reprogram control registers and execute _BFS */
+ acpi_leave_sleep_state_prep(acpi_state);
+
+ /* ACPI 3.0 specs (P62) says that it's the responsibility
* of the OSPM to clear the status bit [ implying that the
* POWER_BUTTON event should not reach userspace ]
*/
if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
+ /*
+ * Disable and clear GPE status before interrupt is enabled. Some GPEs
+ * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
+ * acpi_leave_sleep_state will reenable specific GPEs later
+ */
+ acpi_hw_disable_all_gpes();
+
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
@@ -157,7 +195,7 @@
}
/**
- * acpi_pm_finish - Finish up suspend sequence.
+ * acpi_pm_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
@@ -174,6 +212,7 @@
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
acpi_target_sleep_state = ACPI_STATE_S0;
+ acpi_sleep_finish_wake_up = false;
#ifdef CONFIG_X86
if (init_8259A_after_S1) {
@@ -183,6 +222,20 @@
#endif
}
+/**
+ * acpi_pm_end - Finish up suspend sequence.
+ */
+
+static void acpi_pm_end(void)
+{
+ /*
+ * This is necessary in case acpi_pm_finish() is not called directly
+ * during a failing transition to a sleep state.
+ */
+ if (acpi_sleep_finish_wake_up)
+ acpi_pm_finish();
+}
+
static int acpi_pm_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -201,10 +254,11 @@
static struct platform_suspend_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid,
- .set_target = acpi_pm_set_target,
+ .begin = acpi_pm_begin,
.prepare = acpi_pm_prepare,
.enter = acpi_pm_enter,
.finish = acpi_pm_finish,
+ .end = acpi_pm_end,
};
/*
@@ -229,15 +283,36 @@
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
-static int acpi_hibernation_start(void)
+static int acpi_hibernation_begin(void)
{
+ int error;
+
acpi_target_sleep_state = ACPI_STATE_S4;
- return 0;
+ if (new_pts_ordering)
+ return 0;
+
+ error = acpi_sleep_prepare(ACPI_STATE_S4);
+ if (error)
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ else
+ acpi_sleep_finish_wake_up = true;
+
+ return error;
}
static int acpi_hibernation_prepare(void)
{
- return acpi_sleep_prepare(ACPI_STATE_S4);
+ if (new_pts_ordering) {
+ int error = acpi_sleep_prepare(ACPI_STATE_S4);
+
+ if (error) {
+ acpi_target_sleep_state = ACPI_STATE_S0;
+ return error;
+ }
+ acpi_sleep_finish_wake_up = true;
+ }
+
+ return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
}
static int acpi_hibernation_enter(void)
@@ -251,6 +326,8 @@
acpi_enable_wakeup_device(ACPI_STATE_S4);
/* This shouldn't return. If it returns, we have a problem */
status = acpi_enter_sleep_state(ACPI_STATE_S4);
+ /* Reprogram control registers and execute _BFS */
+ acpi_leave_sleep_state_prep(ACPI_STATE_S4);
local_irq_restore(flags);
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -263,15 +340,12 @@
* enable it here.
*/
acpi_enable();
+ /* Reprogram control registers and execute _BFS */
+ acpi_leave_sleep_state_prep(ACPI_STATE_S4);
}
static void acpi_hibernation_finish(void)
{
- /*
- * If ACPI is not enabled by the BIOS and the boot kernel, we need to
- * enable it here.
- */
- acpi_enable();
acpi_disable_wakeup_device(ACPI_STATE_S4);
acpi_leave_sleep_state(ACPI_STATE_S4);
@@ -279,6 +353,17 @@
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
acpi_target_sleep_state = ACPI_STATE_S0;
+ acpi_sleep_finish_wake_up = false;
+}
+
+static void acpi_hibernation_end(void)
+{
+ /*
+ * This is necessary in case acpi_hibernation_finish() is not called
+ * directly during a failing transition to the sleep state.
+ */
+ if (acpi_sleep_finish_wake_up)
+ acpi_hibernation_finish();
}
static int acpi_hibernation_pre_restore(void)
@@ -296,7 +381,8 @@
}
static struct platform_hibernation_ops acpi_hibernation_ops = {
- .start = acpi_hibernation_start,
+ .begin = acpi_hibernation_begin,
+ .end = acpi_hibernation_end,
.pre_snapshot = acpi_hibernation_prepare,
.finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
@@ -386,11 +472,20 @@
if (acpi_target_sleep_state == ACPI_STATE_S0 ||
(wake && adev->wakeup.state.enabled &&
adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
+ acpi_status status;
+
acpi_method[3] = 'W';
- acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
- /* Sanity check */
- if (d_max < d_min)
+ status = acpi_evaluate_integer(handle, acpi_method, NULL,
+ &d_max);
+ if (ACPI_FAILURE(status)) {
+ d_max = d_min;
+ } else if (d_max < d_min) {
+ /* Warn the user of the broken DSDT */
+ printk(KERN_WARNING "ACPI: Wrong value from %s\n",
+ acpi_method);
+ /* Sanitize it */
d_min = d_max;
+ }
}
if (d_min_p)
@@ -403,6 +498,7 @@
{
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
+ acpi_hw_disable_all_gpes();
}
static void acpi_power_off(void)
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 1538355..f8df521 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -178,6 +178,9 @@
* Try to find delimeter, only to insert null. The end of the
* string won't have one, but is still valid.
*/
+ if (*p == NULL)
+ return result;
+
next = strpbrk(*p, "- :");
if (next)
*next++ = '\0';
@@ -190,6 +193,8 @@
if (next)
*p = next;
+ else
+ *p = NULL;
return result;
}
@@ -251,27 +256,6 @@
if ((result = get_date_field(&p, &sec)))
goto end;
- if (sec > 59) {
- min += 1;
- sec -= 60;
- }
- if (min > 59) {
- hr += 1;
- min -= 60;
- }
- if (hr > 23) {
- day += 1;
- hr -= 24;
- }
- if (day > 31) {
- mo += 1;
- day -= 31;
- }
- if (mo > 12) {
- yr += 1;
- mo -= 12;
- }
-
spin_lock_irq(&rtc_lock);
rtc_control = CMOS_READ(RTC_CONTROL);
@@ -288,24 +272,24 @@
spin_unlock_irq(&rtc_lock);
if (sec > 59) {
- min++;
- sec -= 60;
+ min += sec/60;
+ sec = sec%60;
}
if (min > 59) {
- hr++;
- min -= 60;
+ hr += min/60;
+ min = min%60;
}
if (hr > 23) {
- day++;
- hr -= 24;
+ day += hr/24;
+ hr = hr%24;
}
if (day > 31) {
- mo++;
- day -= 31;
+ mo += day/32;
+ day = day%32;
}
if (mo > 12) {
- yr++;
- mo -= 12;
+ yr += mo/13;
+ mo = mo%13;
}
spin_lock_irq(&rtc_lock);
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
index a2ea125..cfaf8f5 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep/sleep.h
@@ -5,5 +5,3 @@
extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
extern void acpi_enable_wakeup_device(u8 sleep_state);
extern void acpi_disable_wakeup_device(u8 sleep_state);
-
-extern int acpi_sleep_prepare(u32 acpi_state);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 5ffe0ea..ce88171 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -40,6 +40,8 @@
#define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DEVICE_NAME "System"
+u32 acpi_irq_handled;
+
/*
* Make ACPICA version work as module param
*/
@@ -166,6 +168,212 @@
return 0;
}
+/*
+ * Detailed ACPI IRQ counters in /sys/firmware/acpi/interrupts/
+ * See Documentation/ABI/testing/sysfs-firmware-acpi
+ */
+
+#define COUNT_GPE 0
+#define COUNT_SCI 1 /* acpi_irq_handled */
+#define COUNT_ERROR 2 /* other */
+#define NUM_COUNTERS_EXTRA 3
+
+static u32 *all_counters;
+static u32 num_gpes;
+static u32 num_counters;
+static struct attribute **all_attrs;
+static u32 acpi_gpe_count;
+
+static struct attribute_group interrupt_stats_attr_group = {
+ .name = "interrupts",
+};
+static struct kobj_attribute *counter_attrs;
+
+static int count_num_gpes(void)
+{
+ int count = 0;
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+ struct acpi_gpe_block_info *gpe_block;
+ acpi_cpu_flags flags;
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+ while (gpe_xrupt_info) {
+ gpe_block = gpe_xrupt_info->gpe_block_list_head;
+ while (gpe_block) {
+ count += gpe_block->register_count *
+ ACPI_GPE_REGISTER_WIDTH;
+ gpe_block = gpe_block->next;
+ }
+ gpe_xrupt_info = gpe_xrupt_info->next;
+ }
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+ return count;
+}
+
+static void delete_gpe_attr_array(void)
+{
+ u32 *tmp = all_counters;
+
+ all_counters = NULL;
+ kfree(tmp);
+
+ if (counter_attrs) {
+ int i;
+
+ for (i = 0; i < num_gpes; i++)
+ kfree(counter_attrs[i].attr.name);
+
+ kfree(counter_attrs);
+ }
+ kfree(all_attrs);
+
+ return;
+}
+
+void acpi_os_gpe_count(u32 gpe_number)
+{
+ acpi_gpe_count++;
+
+ if (!all_counters)
+ return;
+
+ if (gpe_number < num_gpes)
+ all_counters[gpe_number]++;
+ else
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+
+ return;
+}
+
+void acpi_os_fixed_event_count(u32 event_number)
+{
+ if (!all_counters)
+ return;
+
+ if (event_number < ACPI_NUM_FIXED_EVENTS)
+ all_counters[num_gpes + event_number]++;
+ else
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+
+ return;
+}
+
+static ssize_t counter_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
+ acpi_irq_handled;
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
+ acpi_gpe_count;
+
+ return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
+}
+
+/*
+ * counter_set() sets the specified counter.
+ * setting the total "sci" file to any value clears all counters.
+ */
+static ssize_t counter_set(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t size)
+{
+ int index = attr - counter_attrs;
+
+ if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
+ int i;
+ for (i = 0; i < num_counters; ++i)
+ all_counters[i] = 0;
+ acpi_gpe_count = 0;
+ acpi_irq_handled = 0;
+
+ } else
+ all_counters[index] = strtoul(buf, NULL, 0);
+
+ return size;
+}
+
+void acpi_irq_stats_init(void)
+{
+ int i;
+
+ if (all_counters)
+ return;
+
+ num_gpes = count_num_gpes();
+ num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
+
+ all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1),
+ GFP_KERNEL);
+ if (all_attrs == NULL)
+ return;
+
+ all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
+ if (all_counters == NULL)
+ goto fail;
+
+ counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
+ GFP_KERNEL);
+ if (counter_attrs == NULL)
+ goto fail;
+
+ for (i = 0; i < num_counters; ++i) {
+ char buffer[10];
+ char *name;
+
+ if (i < num_gpes)
+ sprintf(buffer, "gpe%02X", i);
+ else if (i == num_gpes + ACPI_EVENT_PMTIMER)
+ sprintf(buffer, "ff_pmtimer");
+ else if (i == num_gpes + ACPI_EVENT_GLOBAL)
+ sprintf(buffer, "ff_gbl_lock");
+ else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
+ sprintf(buffer, "ff_pwr_btn");
+ else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
+ sprintf(buffer, "ff_slp_btn");
+ else if (i == num_gpes + ACPI_EVENT_RTC)
+ sprintf(buffer, "ff_rt_clk");
+ else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
+ sprintf(buffer, "gpe_all");
+ else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
+ sprintf(buffer, "sci");
+ else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
+ sprintf(buffer, "error");
+ else
+ sprintf(buffer, "bug%02X", i);
+
+ name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
+ if (name == NULL)
+ goto fail;
+ strncpy(name, buffer, strlen(buffer) + 1);
+
+ counter_attrs[i].attr.name = name;
+ counter_attrs[i].attr.mode = 0644;
+ counter_attrs[i].show = counter_show;
+ counter_attrs[i].store = counter_set;
+
+ all_attrs[i] = &counter_attrs[i].attr;
+ }
+
+ interrupt_stats_attr_group.attrs = all_attrs;
+ sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group);
+ return;
+
+fail:
+ delete_gpe_attr_array();
+ return;
+}
+
+static void __exit interrupt_stats_exit(void)
+{
+ sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
+
+ delete_gpe_attr_array();
+
+ return;
+}
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index 0a7d7af..7385efa 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,6 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories
#
-obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index cf8fa51..9ecb4b6 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -100,7 +100,7 @@
/*******************************************************************************
*
- * FUNCTION: acpi_tb_find_rsdp
+ * FUNCTION: acpi_find_root_pointer
*
* PARAMETERS: table_address - Where the table pointer is returned
*
@@ -219,8 +219,6 @@
return_ACPI_STATUS(AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
-
/*******************************************************************************
*
* FUNCTION: acpi_tb_scan_memory_for_rsdp
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 73f276b..8d4b79b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -539,7 +539,7 @@
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
- if (!tz || !tz->trips.critical.flags.valid || nocrt)
+ if (!tz || !tz->trips.critical.flags.valid)
return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) {
@@ -548,9 +548,6 @@
} else if (tz->trips.critical.flags.enabled)
tz->trips.critical.flags.enabled = 0;
- printk(KERN_EMERG
- "Critical temperature reached (%ld C), shutting down.\n",
- KELVIN_TO_CELSIUS(tz->temperature));
acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
@@ -558,14 +555,20 @@
ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
- orderly_poweroff(true);
+ /* take no action if nocrt is set */
+ if(!nocrt) {
+ printk(KERN_EMERG
+ "Critical temperature reached (%ld C), shutting down.\n",
+ KELVIN_TO_CELSIUS(tz->temperature));
+ orderly_poweroff(true);
+ }
return 0;
}
static int acpi_thermal_hot(struct acpi_thermal *tz)
{
- if (!tz || !tz->trips.hot.flags.valid || nocrt)
+ if (!tz || !tz->trips.hot.flags.valid)
return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) {
@@ -581,7 +584,7 @@
ACPI_THERMAL_NOTIFY_HOT,
tz->trips.hot.flags.enabled);
- /* TBD: Call user-mode "sleep(S4)" function */
+ /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
return 0;
}
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 93ea829..630c9a2 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -671,7 +671,6 @@
/* GPE support */
- acpi_gpe_count = 0;
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -735,4 +734,3 @@
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
- ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index cbbd331..b630ee1 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -1,6 +1,6 @@
/*******************************************************************************
*
- * Module Name: utresrc - Resource managment utilities
+ * Module Name: utresrc - Resource management utilities
*
******************************************************************************/
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index eab9c42..82815cf 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -294,18 +294,26 @@
static int acpi_video_get_brightness(struct backlight_device *bd)
{
unsigned long cur_level;
+ int i;
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_get_level_current(vd, &cur_level);
- return (int) cur_level;
+ for (i = 2; i < vd->brightness->count; i++) {
+ if (vd->brightness->levels[i] == cur_level)
+ /* The first two entries are special - see page 575
+ of the ACPI spec 3.0 */
+ return i-2;
+ }
+ return 0;
}
static int acpi_video_set_brightness(struct backlight_device *bd)
{
- int request_level = bd->props.brightness;
+ int request_level = bd->props.brightness+2;
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
- acpi_video_device_lcd_set_level(vd, request_level);
+ acpi_video_device_lcd_set_level(vd,
+ vd->brightness->levels[request_level]);
return 0;
}
@@ -702,7 +710,6 @@
kfree(obj);
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
- unsigned long tmp;
int result;
static int count = 0;
char *name;
@@ -711,11 +718,10 @@
return;
sprintf(name, "acpi_video%d", count++);
- acpi_video_device_lcd_get_level_current(device, &tmp);
device->backlight = backlight_device_register(name,
NULL, device, &acpi_backlight_ops);
- device->backlight->props.max_brightness = max_level;
- device->backlight->props.brightness = (int)tmp;
+ device->backlight->props.max_brightness = device->brightness->count-3;
+ device->backlight->props.brightness = acpi_video_get_brightness(device->backlight);
backlight_update_status(device->backlight);
kfree(name);
@@ -1324,8 +1330,37 @@
static int acpi_video_bus_add_fs(struct acpi_device *device)
{
+ long device_id;
+ int status;
struct proc_dir_entry *entry = NULL;
struct acpi_video_bus *video;
+ struct device *dev;
+
+ status =
+ acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+
+ if (!ACPI_SUCCESS(status))
+ return -ENODEV;
+
+ /* We need to attempt to determine whether the _ADR refers to a
+ PCI device or not. There's no terribly good way to do this,
+ so the best we can hope for is to assume that there'll never
+ be a video device in the host bridge */
+ if (device_id >= 0x10000) {
+ /* It looks like a PCI device. Does it exist? */
+ dev = acpi_get_physical_device(device->handle);
+ } else {
+ /* It doesn't look like a PCI device. Does its parent
+ exist? */
+ acpi_handle phandle;
+ if (acpi_get_parent(device->handle, &phandle))
+ return -ENODEV;
+ dev = acpi_get_physical_device(phandle);
+ }
+ if (!dev)
+ return -ENODEV;
+ put_device(dev);
+
video = acpi_driver_data(device);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 27c8d56..29e71bd 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -679,24 +679,20 @@
/* cross check port_map and cap.n_ports */
if (port_map) {
- u32 tmp_port_map = port_map;
- int n_ports = ahci_nr_ports(cap);
+ int map_ports = 0;
- for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
- if (tmp_port_map & (1 << i)) {
- n_ports--;
- tmp_port_map &= ~(1 << i);
- }
- }
+ for (i = 0; i < AHCI_MAX_PORTS; i++)
+ if (port_map & (1 << i))
+ map_ports++;
- /* If n_ports and port_map are inconsistent, whine and
- * clear port_map and let it be generated from n_ports.
+ /* If PI has more ports than n_ports, whine, clear
+ * port_map and let it be generated from n_ports.
*/
- if (n_ports || tmp_port_map) {
+ if (map_ports > ahci_nr_ports(cap)) {
dev_printk(KERN_WARNING, &pdev->dev,
- "nr_ports (%u) and implemented port map "
- "(0x%x) don't match, using nr_ports\n",
- ahci_nr_ports(cap), port_map);
+ "implemented port map (0x%x) contains more "
+ "ports than nr_ports (%u), using nr_ports\n",
+ port_map, ahci_nr_ports(cap));
port_map = 0;
}
}
@@ -2201,7 +2197,7 @@
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
- int i, rc;
+ int n_ports, i, rc;
VPRINTK("ENTER\n");
@@ -2255,7 +2251,14 @@
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
- host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
host->iomap = pcim_iomap_table(pdev);
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 47892e6..9c2515f 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -837,7 +837,7 @@
if (is_slave) {
/* clear TIME1|IE1|PPE1|DTE1 */
master_data &= 0xff0f;
- /* Enable SITRE (seperate slave timing register) */
+ /* Enable SITRE (separate slave timing register) */
master_data |= 0x4000;
/* enable PPE1, IE1 and TIME1 as needed */
master_data |= (control << 4);
@@ -1603,7 +1603,8 @@
* Zero on success, or -ERRNO value.
*/
-static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit piix_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
static int printed_version;
struct device *dev = &pdev->dev;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index bdbd55a..3011919 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3097,7 +3097,7 @@
/**
* ata_do_set_mode - Program timings and issue SET FEATURES - XFER
* @link: link on which timings will be programmed
- * @r_failed_dev: out paramter for failed device
+ * @r_failed_dev: out parameter for failed device
*
* Standard implementation of the function used to tune and set
* ATA device disk transfer mode (PIO3, UDMA6, etc.). If
@@ -4154,8 +4154,6 @@
/* NCQ is broken */
{ "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ },
{ "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ },
- { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ },
- { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ },
{ "ST380817AS", "3.42", ATA_HORKAGE_NONCQ },
{ "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ },
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 67e574d..db057b1 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -324,7 +324,7 @@
if (irq < 0)
return irq;
- /* Setup struct containing private infomation */
+ /* Setup struct containing private information */
info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index d4590f5..7ed279b 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -229,7 +229,7 @@
return -ENOMEM;
/* Perform set up for DMA */
- if (pci_enable_device_bars(pdev, 1<<2)) {
+ if (pci_enable_device_io(pdev)) {
printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
return -ENODEV;
}
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 043dcd3..dc33220 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -135,7 +135,7 @@
idetm_data &= 0xCC0F;
idetm_data |= (control << 4);
- /* Slave timing in seperate register */
+ /* Slave timing in separate register */
pci_read_config_byte(dev, 0x44, &slave_data);
slave_data &= 0x0F << shift;
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index 1eda821..e0c2cc2 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -128,7 +128,7 @@
idetm_data &= 0xCC0F;
idetm_data |= (control << 4);
- /* Slave timing in seperate register */
+ /* Slave timing in separate register */
pci_read_config_byte(dev, 0x44, &slave_data);
slave_data &= 0xF0;
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
index 938f48a..408da30 100644
--- a/drivers/ata/pata_of_platform.c
+++ b/drivers/ata/pata_of_platform.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
static int __devinit pata_of_platform_probe(struct of_device *ofdev,
const struct of_device_id *match)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 224bb6c..aad7adc 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -19,7 +19,7 @@
#include <linux/ata.h>
#include <linux/libata.h>
#include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#define DRV_NAME "pata_platform"
#define DRV_VERSION "1.2"
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 87546d9..dc7e915 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -345,7 +345,7 @@
if (adev->dma_mode < XFER_UDMA_0) {
/* bits 3-0 hold recovery timing bits 8-10 active timing and
- the higer bits are dependant on the device */
+ the higher bits are dependant on the device */
timing &= ~0x870F;
timing |= mwdma_bits[speed];
} else {
@@ -385,7 +385,7 @@
if (adev->dma_mode < XFER_UDMA_0) {
/* bits 3-0 hold recovery timing bits 8-10 active timing and
- the higer bits are dependant on the device, bit 15 udma */
+ the higher bits are dependant on the device, bit 15 udma */
timing &= ~0x870F;
timing |= mwdma_bits[speed];
} else {
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 922d7b2..efcb66b6 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -355,8 +355,8 @@
ata_port_printk(qc->ap, KERN_ERR,
"s/g len unaligned : 0x%x\n", sg_len);
- if ((num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1)) &&
- (qc->n_iter + 1 != qc->n_elem)) {
+ if (num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1) &&
+ sg_next(sg) != NULL) {
VPRINTK("setting indirect prde\n");
prd_ptr_to_indirect_ext = prd;
prd->dba = cpu_to_le32(indirect_ext_segment_paddr);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 96e614a..59e65ed 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -108,17 +108,6 @@
u8 cached_pirq_mask;
};
-static int inic_slave_config(struct scsi_device *sdev)
-{
- /* This controller is braindamaged. dma_boundary is 0xffff
- * like others but it will lock up the whole machine HARD if
- * 65536 byte PRD entry is fed. Reduce maximum segment size.
- */
- blk_queue_max_segment_size(sdev->request_queue, 65536 - 512);
-
- return ata_scsi_slave_config(sdev);
-}
-
static struct scsi_host_template inic_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -132,7 +121,7 @@
.use_clustering = ATA_SHT_USE_CLUSTERING,
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = inic_slave_config,
+ .slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
@@ -730,6 +719,18 @@
return rc;
}
+ /*
+ * This controller is braindamaged. dma_boundary is 0xffff
+ * like others but it will lock up the whole machine HARD if
+ * 65536 byte PRD entry is fed. Reduce maximum segment size.
+ */
+ rc = pci_set_dma_max_seg_size(pdev, 65536 - 512);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to set the maximum segment size.\n");
+ return rc;
+ }
+
rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 3c1b5c90..080b836 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -69,8 +69,11 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -179,6 +182,8 @@
HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
HC_MAIN_IRQ_MASK_OFS = 0x1d64,
+ HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
+ HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
PORT0_ERR = (1 << 0), /* shift by port # */
PORT0_DONE = (1 << 1), /* shift by port # */
HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
@@ -194,11 +199,13 @@
TWSI_INT = (1 << 24),
HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
+ HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */
HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
HC_MAIN_RSVD),
HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
HC_MAIN_RSVD_5),
+ HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
/* SATAHC registers */
HC_CFG_OFS = 0,
@@ -368,6 +375,7 @@
chip_608x,
chip_6042,
chip_7042,
+ chip_soc,
};
/* Command ReQuest Block: 32B */
@@ -424,6 +432,10 @@
u32 hp_flags;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
+ int n_ports;
+ void __iomem *base;
+ void __iomem *main_cause_reg_addr;
+ void __iomem *main_mask_reg_addr;
u32 irq_cause_ofs;
u32 irq_mask_ofs;
u32 unmask_all_irqs;
@@ -482,6 +494,15 @@
static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int n_hc);
static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv_soc_enable_leds(struct mv_host_priv *hpriv,
+ void __iomem *mmio);
+static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio);
+static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
+ void __iomem *mmio, unsigned int n_hc);
+static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
+ void __iomem *mmio);
+static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio);
static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no);
@@ -661,6 +682,12 @@
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
+ { /* chip_soc */
+ .flags = MV_COMMON_FLAGS | MV_FLAG_SOC,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &mv_iie_ops,
+ },
};
static const struct pci_device_id mv_pci_tbl[] = {
@@ -711,6 +738,15 @@
.reset_bus = mv_reset_pci_bus,
};
+static const struct mv_hw_ops mv_soc_ops = {
+ .phy_errata = mv6_phy_errata,
+ .enable_leds = mv_soc_enable_leds,
+ .read_preamp = mv_soc_read_preamp,
+ .reset_hc = mv_soc_reset_hc,
+ .reset_flash = mv_soc_reset_flash,
+ .reset_bus = mv_soc_reset_bus,
+};
+
/*
* Functions
*/
@@ -749,9 +785,15 @@
(mv_hardport_from_port(port) * MV_PORT_REG_SZ);
}
+static inline void __iomem *mv_host_base(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ return hpriv->base;
+}
+
static inline void __iomem *mv_ap_base(struct ata_port *ap)
{
- return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
+ return mv_port_base(mv_host_base(ap->host), ap->port_no);
}
static inline int mv_get_hc_count(unsigned long port_flags)
@@ -1649,16 +1691,21 @@
*/
static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
{
- void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
void __iomem *hc_mmio = mv_hc_base(mmio, hc);
u32 hc_irq_cause;
- int port, port0;
+ int port, port0, last_port;
if (hc == 0)
port0 = 0;
else
port0 = MV_PORTS_PER_HC;
+ if (HAS_PCI(host))
+ last_port = port0 + MV_PORTS_PER_HC;
+ else
+ last_port = port0 + hpriv->n_ports;
/* we'll need the HC success int register in most cases */
hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
if (!hc_irq_cause)
@@ -1669,7 +1716,7 @@
VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
hc, relevant, hc_irq_cause);
- for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+ for (port = port0; port < port0 + last_port; port++) {
struct ata_port *ap = host->ports[port];
struct mv_port_priv *pp = ap->private_data;
int have_err_bits, hard_port, shift;
@@ -1764,13 +1811,15 @@
static irqreturn_t mv_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
+ struct mv_host_priv *hpriv = host->private_data;
unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+ void __iomem *mmio = hpriv->base;
u32 irq_stat, irq_mask;
spin_lock(&host->lock);
- irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
- irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
+
+ irq_stat = readl(hpriv->main_cause_reg_addr);
+ irq_mask = readl(hpriv->main_mask_reg_addr);
/* check the cases where we either have nothing pending or have read
* a bogus register value which can indicate HW removal or PCI fault
@@ -1827,7 +1876,8 @@
static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
- void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->base;
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
@@ -1840,7 +1890,8 @@
static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
- void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->base;
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
@@ -2178,6 +2229,93 @@
writel(m2, port_mmio + PHY_MODE2);
}
+/* TODO: use the generic LED interface to configure the SATA Presence */
+/* & Acitivy LEDs on the board */
+static void mv_soc_enable_leds(struct mv_host_priv *hpriv,
+ void __iomem *mmio)
+{
+ return;
+}
+
+static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio)
+{
+ void __iomem *port_mmio;
+ u32 tmp;
+
+ port_mmio = mv_port_base(mmio, idx);
+ tmp = readl(port_mmio + PHY_MODE2);
+
+ hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */
+ hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */
+}
+
+#undef ZERO
+#define ZERO(reg) writel(0, port_mmio + (reg))
+static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
+ void __iomem *mmio, unsigned int port)
+{
+ void __iomem *port_mmio = mv_port_base(mmio, port);
+
+ writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+
+ mv_channel_reset(hpriv, mmio, port);
+
+ ZERO(0x028); /* command */
+ writel(0x101f, port_mmio + EDMA_CFG_OFS);
+ ZERO(0x004); /* timer */
+ ZERO(0x008); /* irq err cause */
+ ZERO(0x00c); /* irq err mask */
+ ZERO(0x010); /* rq bah */
+ ZERO(0x014); /* rq inp */
+ ZERO(0x018); /* rq outp */
+ ZERO(0x01c); /* respq bah */
+ ZERO(0x024); /* respq outp */
+ ZERO(0x020); /* respq inp */
+ ZERO(0x02c); /* test control */
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+}
+
+#undef ZERO
+
+#define ZERO(reg) writel(0, hc_mmio + (reg))
+static void mv_soc_reset_one_hc(struct mv_host_priv *hpriv,
+ void __iomem *mmio)
+{
+ void __iomem *hc_mmio = mv_hc_base(mmio, 0);
+
+ ZERO(0x00c);
+ ZERO(0x010);
+ ZERO(0x014);
+
+}
+
+#undef ZERO
+
+static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
+ void __iomem *mmio, unsigned int n_hc)
+{
+ unsigned int port;
+
+ for (port = 0; port < hpriv->n_ports; port++)
+ mv_soc_reset_hc_port(hpriv, mmio, port);
+
+ mv_soc_reset_one_hc(hpriv, mmio);
+
+ return 0;
+}
+
+static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
+ void __iomem *mmio)
+{
+ return;
+}
+
+static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
+{
+ return;
+}
+
static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no)
{
@@ -2342,7 +2480,7 @@
{
struct ata_port *ap = link->ap;
struct mv_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ void __iomem *mmio = hpriv->base;
mv_stop_dma(ap);
@@ -2383,7 +2521,7 @@
static void mv_eh_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int hc = (ap->port_no > 3) ? 1 : 0;
u32 tmp, mask;
unsigned int shift;
@@ -2397,13 +2535,14 @@
mask = 0x3 << shift;
/* disable assertion of portN err, done events */
- tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
- writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+ tmp = readl(hpriv->main_mask_reg_addr);
+ writelfl(tmp & ~mask, hpriv->main_mask_reg_addr);
}
static void mv_eh_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->base;
unsigned int hc = (ap->port_no > 3) ? 1 : 0;
void __iomem *hc_mmio = mv_hc_base(mmio, hc);
void __iomem *port_mmio = mv_ap_base(ap);
@@ -2430,8 +2569,8 @@
writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
/* enable assertion of portN err, done events */
- tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
- writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+ tmp = readl(hpriv->main_mask_reg_addr);
+ writelfl(tmp | mask, hpriv->main_mask_reg_addr);
}
/**
@@ -2598,9 +2737,13 @@
break;
}
break;
+ case chip_soc:
+ hpriv->ops = &mv_soc_ops;
+ hp_flags |= MV_HP_ERRATA_60X1C0;
+ break;
default:
- dev_printk(KERN_ERR, &pdev->dev,
+ dev_printk(KERN_ERR, host->dev,
"BUG: invalid board index %u\n", board_idx);
return 1;
}
@@ -2633,15 +2776,25 @@
static int mv_init_host(struct ata_host *host, unsigned int board_idx)
{
int rc = 0, n_hc, port, hc;
- void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
struct mv_host_priv *hpriv = host->private_data;
-
- /* global interrupt mask */
- writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
+ void __iomem *mmio = hpriv->base;
rc = mv_chip_id(host, board_idx);
if (rc)
- goto done;
+ goto done;
+
+ if (HAS_PCI(host)) {
+ hpriv->main_cause_reg_addr = hpriv->base +
+ HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS;
+ } else {
+ hpriv->main_cause_reg_addr = hpriv->base +
+ HC_SOC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_mask_reg_addr = hpriv->base +
+ HC_SOC_MAIN_IRQ_MASK_OFS;
+ }
+ /* global interrupt mask */
+ writel(0, hpriv->main_mask_reg_addr);
n_hc = mv_get_hc_count(host->ports[0]->flags);
@@ -2672,13 +2825,15 @@
for (port = 0; port < host->n_ports; port++) {
struct ata_port *ap = host->ports[port];
void __iomem *port_mmio = mv_port_base(mmio, port);
- unsigned int offset = port_mmio - mmio;
mv_port_init(&ap->ioaddr, port_mmio);
#ifdef CONFIG_PCI
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+ if (HAS_PCI(host)) {
+ unsigned int offset = port_mmio - mmio;
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+ }
#endif
}
@@ -2694,35 +2849,141 @@
writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
}
- /* Clear any currently outstanding host interrupt conditions */
- writelfl(0, mmio + hpriv->irq_cause_ofs);
+ if (HAS_PCI(host)) {
+ /* Clear any currently outstanding host interrupt conditions */
+ writelfl(0, mmio + hpriv->irq_cause_ofs);
- /* and unmask interrupt generation for host regs */
- writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+ /* and unmask interrupt generation for host regs */
+ writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+ if (IS_GEN_I(hpriv))
+ writelfl(~HC_MAIN_MASKED_IRQS_5,
+ hpriv->main_mask_reg_addr);
+ else
+ writelfl(~HC_MAIN_MASKED_IRQS,
+ hpriv->main_mask_reg_addr);
- if (IS_GEN_I(hpriv))
- writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
- else
- writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
-
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
- "PCI int cause/mask=0x%08x/0x%08x\n",
- readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
- readl(mmio + HC_MAIN_IRQ_MASK_OFS),
- readl(mmio + hpriv->irq_cause_ofs),
- readl(mmio + hpriv->irq_mask_ofs));
-
+ VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+ "PCI int cause/mask=0x%08x/0x%08x\n",
+ readl(hpriv->main_cause_reg_addr),
+ readl(hpriv->main_mask_reg_addr),
+ readl(mmio + hpriv->irq_cause_ofs),
+ readl(mmio + hpriv->irq_mask_ofs));
+ } else {
+ writelfl(~HC_MAIN_MASKED_IRQS_SOC,
+ hpriv->main_mask_reg_addr);
+ VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
+ readl(hpriv->main_cause_reg_addr),
+ readl(hpriv->main_mask_reg_addr));
+ }
done:
return rc;
}
+/**
+ * mv_platform_probe - handle a positive probe of an soc Marvell
+ * host
+ * @pdev: platform device found
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static int mv_platform_probe(struct platform_device *pdev)
+{
+ static int printed_version;
+ const struct mv_sata_platform_data *mv_platform_data;
+ const struct ata_port_info *ppi[] =
+ { &mv_port_info[chip_soc], NULL };
+ struct ata_host *host;
+ struct mv_host_priv *hpriv;
+ struct resource *res;
+ int n_ports, rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+ /*
+ * Simple resource validation ..
+ */
+ if (unlikely(pdev->num_resources != 2)) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Get the register base first
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ return -EINVAL;
+
+ /* allocate host */
+ mv_platform_data = pdev->dev.platform_data;
+ n_ports = mv_platform_data->n_ports;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+
+ if (!host || !hpriv)
+ return -ENOMEM;
+ host->private_data = hpriv;
+ hpriv->n_ports = n_ports;
+
+ host->iomap = NULL;
+ hpriv->base = ioremap(res->start, res->end - res->start + 1);
+ hpriv->base -= MV_SATAHC0_REG_BASE;
+
+ /* initialize adapter */
+ rc = mv_init_host(host, chip_soc);
+ if (rc)
+ return rc;
+
+ dev_printk(KERN_INFO, &pdev->dev,
+ "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
+ host->n_ports);
+
+ return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
+ IRQF_SHARED, &mv6_sht);
+}
+
+/*
+ *
+ * mv_platform_remove - unplug a platform interface
+ * @pdev: platform device
+ *
+ * A platform bus SATA device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit mv_platform_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *base = hpriv->base;
+
+ ata_host_detach(host);
+ iounmap(base);
+ return 0;
+}
+
+static struct platform_driver mv_platform_driver = {
+ .probe = mv_platform_probe,
+ .remove = __devexit_p(mv_platform_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
#ifdef CONFIG_PCI
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int mv_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+
static struct pci_driver mv_pci_driver = {
.name = DRV_NAME,
.id_table = mv_pci_tbl,
- .probe = mv_init_one,
+ .probe = mv_pci_init_one,
.remove = ata_pci_remove_one,
};
@@ -2828,14 +3089,15 @@
}
/**
- * mv_init_one - handle a positive probe of a Marvell host
+ * mv_pci_init_one - handle a positive probe of a PCI Marvell host
* @pdev: PCI device found
* @ent: PCI device ID entry for the matched host
*
* LOCKING:
* Inherited from caller.
*/
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int mv_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
static int printed_version;
unsigned int board_idx = (unsigned int)ent->driver_data;
@@ -2855,6 +3117,7 @@
if (!host || !hpriv)
return -ENOMEM;
host->private_data = hpriv;
+ hpriv->n_ports = n_ports;
/* acquire resources */
rc = pcim_enable_device(pdev);
@@ -2867,6 +3130,7 @@
if (rc)
return rc;
host->iomap = pcim_iomap_table(pdev);
+ hpriv->base = host->iomap[MV_PRIMARY_BAR];
rc = pci_go_64(pdev);
if (rc)
@@ -2895,11 +3159,22 @@
}
#endif
+static int mv_platform_probe(struct platform_device *pdev);
+static int __devexit mv_platform_remove(struct platform_device *pdev);
+
static int __init mv_init(void)
{
int rc = -ENODEV;
#ifdef CONFIG_PCI
rc = pci_register_driver(&mv_pci_driver);
+ if (rc < 0)
+ return rc;
+#endif
+ rc = platform_driver_register(&mv_platform_driver);
+
+#ifdef CONFIG_PCI
+ if (rc < 0)
+ pci_unregister_driver(&mv_pci_driver);
#endif
return rc;
}
@@ -2909,6 +3184,7 @@
#ifdef CONFIG_PCI
pci_unregister_driver(&mv_pci_driver);
#endif
+ platform_driver_unregister(&mv_platform_driver);
}
MODULE_AUTHOR("Brett Russ");
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index bfe92a4..ed5473b 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -247,6 +247,7 @@
void __iomem *ctl_block;
void __iomem *gen_block;
void __iomem *notifier_clear_block;
+ u64 adma_dma_mask;
u8 flags;
int last_issue_ncq;
};
@@ -715,9 +716,10 @@
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct nv_adma_port_priv *pp = ap->private_data;
+ struct nv_adma_port_priv *port0, *port1;
+ struct scsi_device *sdev0, *sdev1;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u64 bounce_limit;
- unsigned long segment_boundary;
+ unsigned long segment_boundary, flags;
unsigned short sg_tablesize;
int rc;
int adma_enable;
@@ -729,6 +731,8 @@
/* Not a proper libata device, ignore */
return rc;
+ spin_lock_irqsave(ap->lock, flags);
+
if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
/*
* NVIDIA reports that ADMA mode does not support ATAPI commands.
@@ -737,7 +741,6 @@
* Restrict DMA parameters as required by the legacy interface
* when an ATAPI device is connected.
*/
- bounce_limit = ATA_DMA_MASK;
segment_boundary = ATA_DMA_BOUNDARY;
/* Subtract 1 since an extra entry may be needed for padding, see
libata-scsi.c */
@@ -748,7 +751,6 @@
adma_enable = 0;
nv_adma_register_mode(ap);
} else {
- bounce_limit = *ap->dev->dma_mask;
segment_boundary = NV_ADMA_DMA_BOUNDARY;
sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
adma_enable = 1;
@@ -774,12 +776,49 @@
if (current_reg != new_reg)
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
- blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
+ port0 = ap->host->ports[0]->private_data;
+ port1 = ap->host->ports[1]->private_data;
+ sdev0 = ap->host->ports[0]->link.device[0].sdev;
+ sdev1 = ap->host->ports[1]->link.device[0].sdev;
+ if ((port0->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+ (port1->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+ /** We have to set the DMA mask to 32-bit if either port is in
+ ATAPI mode, since they are on the same PCI device which is
+ used for DMA mapping. If we set the mask we also need to set
+ the bounce limit on both ports to ensure that the block
+ layer doesn't feed addresses that cause DMA mapping to
+ choke. If either SCSI device is not allocated yet, it's OK
+ since that port will discover its correct setting when it
+ does get allocated.
+ Note: Setting 32-bit mask should not fail. */
+ if (sdev0)
+ blk_queue_bounce_limit(sdev0->request_queue,
+ ATA_DMA_MASK);
+ if (sdev1)
+ blk_queue_bounce_limit(sdev1->request_queue,
+ ATA_DMA_MASK);
+
+ pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ } else {
+ /** This shouldn't fail as it was set to this value before */
+ pci_set_dma_mask(pdev, pp->adma_dma_mask);
+ if (sdev0)
+ blk_queue_bounce_limit(sdev0->request_queue,
+ pp->adma_dma_mask);
+ if (sdev1)
+ blk_queue_bounce_limit(sdev1->request_queue,
+ pp->adma_dma_mask);
+ }
+
blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
ata_port_printk(ap, KERN_INFO,
- "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
- (unsigned long long)bounce_limit, segment_boundary, sg_tablesize);
+ "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
+ (unsigned long long)*ap->host->dev->dma_mask,
+ segment_boundary, sg_tablesize);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
return rc;
}
@@ -1140,10 +1179,20 @@
void *mem;
dma_addr_t mem_dma;
void __iomem *mmio;
+ struct pci_dev *pdev = to_pci_dev(dev);
u16 tmp;
VPRINTK("ENTER\n");
+ /* Ensure DMA mask is set to 32-bit before allocating legacy PRD and
+ pad buffers */
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
+
rc = ata_port_start(ap);
if (rc)
return rc;
@@ -1159,6 +1208,15 @@
pp->notifier_clear_block = pp->gen_block +
NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
+ /* Now that the legacy PRD and padding buffer are allocated we can
+ safely raise the DMA mask to allocate the CPB/APRD table.
+ These are allowed to fail since we store the value that ends up
+ being used to set as the bounce limit in slave_config later if
+ needed. */
+ pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ pp->adma_dma_mask = *dev->dma_mask;
+
mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
&mem_dma, GFP_KERNEL);
if (!mem)
@@ -2417,12 +2475,6 @@
hpriv->type = type;
host->private_data = hpriv;
- /* set 64bit dma masks, may fail */
- if (type == ADMA) {
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0)
- pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
- }
-
/* request and iomap NV_MMIO_BAR */
rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
if (rc)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 3ef072ff..30caa03 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -30,8 +30,6 @@
* Hardware documentation available under NDA.
*
*
- * To-do list:
- * - VT6421 PATA support
*
*/
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 63e09c0..c666373 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -5,7 +5,7 @@
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o
obj-y += power/
-obj-$(CONFIG_HAS_DMA) += dma-mapping.o dmapool.o
+obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/core.c b/drivers/base/core.c
index b172787..9c0070b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -423,10 +423,8 @@
int device_create_file(struct device *dev, struct device_attribute *attr)
{
int error = 0;
- if (get_device(dev)) {
+ if (dev)
error = sysfs_create_file(&dev->kobj, &attr->attr);
- put_device(dev);
- }
return error;
}
@@ -437,10 +435,8 @@
*/
void device_remove_file(struct device *dev, struct device_attribute *attr)
{
- if (get_device(dev)) {
+ if (dev)
sysfs_remove_file(&dev->kobj, &attr->attr);
- put_device(dev);
- }
}
/**
@@ -1144,25 +1140,11 @@
}
EXPORT_SYMBOL_GPL(device_create);
-/**
- * find_device - finds a device that was created with device_create()
- * @class: pointer to the struct class that this device was registered with
- * @devt: the dev_t of the device that was previously registered
- */
-static struct device *find_device(struct class *class, dev_t devt)
+static int __match_devt(struct device *dev, void *data)
{
- struct device *dev = NULL;
- struct device *dev_tmp;
+ dev_t *devt = data;
- down(&class->sem);
- list_for_each_entry(dev_tmp, &class->devices, node) {
- if (dev_tmp->devt == devt) {
- dev = dev_tmp;
- break;
- }
- }
- up(&class->sem);
- return dev;
+ return dev->devt == *devt;
}
/**
@@ -1177,9 +1159,11 @@
{
struct device *dev;
- dev = find_device(class, devt);
- if (dev)
+ dev = class_find_device(class, &devt, __match_devt);
+ if (dev) {
+ put_device(dev);
device_unregister(dev);
+ }
}
EXPORT_SYMBOL_GPL(device_destroy);
@@ -1203,9 +1187,11 @@
{
struct device *dev;
- dev = find_device(class, devt);
- if (dev)
+ dev = class_find_device(class, &devt, __match_devt);
+ if (dev) {
device_pm_schedule_removal(dev);
+ put_device(dev);
+ }
}
EXPORT_SYMBOL_GPL(destroy_suspended_device);
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index c5885f5..499b003 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -110,7 +110,7 @@
*
* Initialize and register the CPU device.
*/
-int __devinit register_cpu(struct cpu *cpu, int num)
+int __cpuinit register_cpu(struct cpu *cpu, int num)
{
int error;
cpu->node_id = cpu_to_node(num);
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
deleted file mode 100644
index b5034dc..0000000
--- a/drivers/base/dmapool.c
+++ /dev/null
@@ -1,481 +0,0 @@
-
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <asm/io.h> /* Needed for i386 to build */
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/poison.h>
-#include <linux/sched.h>
-
-/*
- * Pool allocator ... wraps the dma_alloc_coherent page allocator, so
- * small blocks are easily used by drivers for bus mastering controllers.
- * This should probably be sharing the guts of the slab allocator.
- */
-
-struct dma_pool { /* the pool */
- struct list_head page_list;
- spinlock_t lock;
- size_t blocks_per_page;
- size_t size;
- struct device *dev;
- size_t allocation;
- char name [32];
- wait_queue_head_t waitq;
- struct list_head pools;
-};
-
-struct dma_page { /* cacheable header for 'allocation' bytes */
- struct list_head page_list;
- void *vaddr;
- dma_addr_t dma;
- unsigned in_use;
- unsigned long bitmap [0];
-};
-
-#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
-
-static DEFINE_MUTEX (pools_lock);
-
-static ssize_t
-show_pools (struct device *dev, struct device_attribute *attr, char *buf)
-{
- unsigned temp;
- unsigned size;
- char *next;
- struct dma_page *page;
- struct dma_pool *pool;
-
- next = buf;
- size = PAGE_SIZE;
-
- temp = scnprintf(next, size, "poolinfo - 0.1\n");
- size -= temp;
- next += temp;
-
- mutex_lock(&pools_lock);
- list_for_each_entry(pool, &dev->dma_pools, pools) {
- unsigned pages = 0;
- unsigned blocks = 0;
-
- list_for_each_entry(page, &pool->page_list, page_list) {
- pages++;
- blocks += page->in_use;
- }
-
- /* per-pool info, no real statistics yet */
- temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
- pool->name,
- blocks, pages * pool->blocks_per_page,
- pool->size, pages);
- size -= temp;
- next += temp;
- }
- mutex_unlock(&pools_lock);
-
- return PAGE_SIZE - size;
-}
-static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL);
-
-/**
- * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
- * @name: name of pool, for diagnostics
- * @dev: device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- * Context: !in_interrupt()
- *
- * Returns a dma allocation pool with the requested characteristics, or
- * null if one can't be created. Given one of these pools, dma_pool_alloc()
- * may be used to allocate memory. Such memory will all have "consistent"
- * DMA mappings, accessible by the device and its driver without using
- * cache flushing primitives. The actual size of blocks allocated may be
- * larger than requested because of alignment.
- *
- * If allocation is nonzero, objects returned from dma_pool_alloc() won't
- * cross that size boundary. This is useful for devices which have
- * addressing restrictions on individual DMA transfers, such as not crossing
- * boundaries of 4KBytes.
- */
-struct dma_pool *
-dma_pool_create (const char *name, struct device *dev,
- size_t size, size_t align, size_t allocation)
-{
- struct dma_pool *retval;
-
- if (align == 0)
- align = 1;
- if (size == 0)
- return NULL;
- else if (size < align)
- size = align;
- else if ((size % align) != 0) {
- size += align + 1;
- size &= ~(align - 1);
- }
-
- if (allocation == 0) {
- if (PAGE_SIZE < size)
- allocation = size;
- else
- allocation = PAGE_SIZE;
- // FIXME: round up for less fragmentation
- } else if (allocation < size)
- return NULL;
-
- if (!(retval = kmalloc_node (sizeof *retval, GFP_KERNEL, dev_to_node(dev))))
- return retval;
-
- strlcpy (retval->name, name, sizeof retval->name);
-
- retval->dev = dev;
-
- INIT_LIST_HEAD (&retval->page_list);
- spin_lock_init (&retval->lock);
- retval->size = size;
- retval->allocation = allocation;
- retval->blocks_per_page = allocation / size;
- init_waitqueue_head (&retval->waitq);
-
- if (dev) {
- int ret;
-
- mutex_lock(&pools_lock);
- if (list_empty (&dev->dma_pools))
- ret = device_create_file (dev, &dev_attr_pools);
- else
- ret = 0;
- /* note: not currently insisting "name" be unique */
- if (!ret)
- list_add (&retval->pools, &dev->dma_pools);
- else {
- kfree(retval);
- retval = NULL;
- }
- mutex_unlock(&pools_lock);
- } else
- INIT_LIST_HEAD (&retval->pools);
-
- return retval;
-}
-
-
-static struct dma_page *
-pool_alloc_page (struct dma_pool *pool, gfp_t mem_flags)
-{
- struct dma_page *page;
- int mapsize;
-
- mapsize = pool->blocks_per_page;
- mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
- mapsize *= sizeof (long);
-
- page = kmalloc(mapsize + sizeof *page, mem_flags);
- if (!page)
- return NULL;
- page->vaddr = dma_alloc_coherent (pool->dev,
- pool->allocation,
- &page->dma,
- mem_flags);
- if (page->vaddr) {
- memset (page->bitmap, 0xff, mapsize); // bit set == free
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
-#endif
- list_add (&page->page_list, &pool->page_list);
- page->in_use = 0;
- } else {
- kfree (page);
- page = NULL;
- }
- return page;
-}
-
-
-static inline int
-is_page_busy (int blocks, unsigned long *bitmap)
-{
- while (blocks > 0) {
- if (*bitmap++ != ~0UL)
- return 1;
- blocks -= BITS_PER_LONG;
- }
- return 0;
-}
-
-static void
-pool_free_page (struct dma_pool *pool, struct dma_page *page)
-{
- dma_addr_t dma = page->dma;
-
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
-#endif
- dma_free_coherent (pool->dev, pool->allocation, page->vaddr, dma);
- list_del (&page->page_list);
- kfree (page);
-}
-
-
-/**
- * dma_pool_destroy - destroys a pool of dma memory blocks.
- * @pool: dma pool that will be destroyed
- * Context: !in_interrupt()
- *
- * Caller guarantees that no more memory from the pool is in use,
- * and that nothing will try to use the pool after this call.
- */
-void
-dma_pool_destroy (struct dma_pool *pool)
-{
- mutex_lock(&pools_lock);
- list_del (&pool->pools);
- if (pool->dev && list_empty (&pool->dev->dma_pools))
- device_remove_file (pool->dev, &dev_attr_pools);
- mutex_unlock(&pools_lock);
-
- while (!list_empty (&pool->page_list)) {
- struct dma_page *page;
- page = list_entry (pool->page_list.next,
- struct dma_page, page_list);
- if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_destroy %s, %p busy\n",
- pool->name, page->vaddr);
- else
- printk (KERN_ERR "dma_pool_destroy %s, %p busy\n",
- pool->name, page->vaddr);
- /* leak the still-in-use consistent memory */
- list_del (&page->page_list);
- kfree (page);
- } else
- pool_free_page (pool, page);
- }
-
- kfree (pool);
-}
-
-
-/**
- * dma_pool_alloc - get a block of consistent memory
- * @pool: dma pool that will produce the block
- * @mem_flags: GFP_* bitmask
- * @handle: pointer to dma address of block
- *
- * This returns the kernel virtual address of a currently unused block,
- * and reports its dma address through the handle.
- * If such a memory block can't be allocated, null is returned.
- */
-void *
-dma_pool_alloc (struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
-{
- unsigned long flags;
- struct dma_page *page;
- int map, block;
- size_t offset;
- void *retval;
-
-restart:
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each_entry(page, &pool->page_list, page_list) {
- int i;
- /* only cachable accesses here ... */
- for (map = 0, i = 0;
- i < pool->blocks_per_page;
- i += BITS_PER_LONG, map++) {
- if (page->bitmap [map] == 0)
- continue;
- block = ffz (~ page->bitmap [map]);
- if ((i + block) < pool->blocks_per_page) {
- clear_bit (block, &page->bitmap [map]);
- offset = (BITS_PER_LONG * map) + block;
- offset *= pool->size;
- goto ready;
- }
- }
- }
- if (!(page = pool_alloc_page (pool, GFP_ATOMIC))) {
- if (mem_flags & __GFP_WAIT) {
- DECLARE_WAITQUEUE (wait, current);
-
- __set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue (&pool->waitq, &wait);
- spin_unlock_irqrestore (&pool->lock, flags);
-
- schedule_timeout (POOL_TIMEOUT_JIFFIES);
-
- remove_wait_queue (&pool->waitq, &wait);
- goto restart;
- }
- retval = NULL;
- goto done;
- }
-
- clear_bit (0, &page->bitmap [0]);
- offset = 0;
-ready:
- page->in_use++;
- retval = offset + page->vaddr;
- *handle = offset + page->dma;
-#ifdef CONFIG_DEBUG_SLAB
- memset (retval, POOL_POISON_ALLOCATED, pool->size);
-#endif
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return retval;
-}
-
-
-static struct dma_page *
-pool_find_page (struct dma_pool *pool, dma_addr_t dma)
-{
- unsigned long flags;
- struct dma_page *page;
-
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each_entry(page, &pool->page_list, page_list) {
- if (dma < page->dma)
- continue;
- if (dma < (page->dma + pool->allocation))
- goto done;
- }
- page = NULL;
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return page;
-}
-
-
-/**
- * dma_pool_free - put block back into dma pool
- * @pool: the dma pool holding the block
- * @vaddr: virtual address of block
- * @dma: dma address of block
- *
- * Caller promises neither device nor driver will again touch this block
- * unless it is first re-allocated.
- */
-void
-dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
-{
- struct dma_page *page;
- unsigned long flags;
- int map, block;
-
- if ((page = pool_find_page(pool, dma)) == NULL) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_free %s, %p/%lx (bad dma)\n",
- pool->name, vaddr, (unsigned long) dma);
- else
- printk (KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n",
- pool->name, vaddr, (unsigned long) dma);
- return;
- }
-
- block = dma - page->dma;
- block /= pool->size;
- map = block / BITS_PER_LONG;
- block %= BITS_PER_LONG;
-
-#ifdef CONFIG_DEBUG_SLAB
- if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
- pool->name, vaddr, (unsigned long long) dma);
- else
- printk (KERN_ERR "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
- pool->name, vaddr, (unsigned long long) dma);
- return;
- }
- if (page->bitmap [map] & (1UL << block)) {
- if (pool->dev)
- dev_err(pool->dev, "dma_pool_free %s, dma %Lx already free\n",
- pool->name, (unsigned long long)dma);
- else
- printk (KERN_ERR "dma_pool_free %s, dma %Lx already free\n",
- pool->name, (unsigned long long)dma);
- return;
- }
- memset (vaddr, POOL_POISON_FREED, pool->size);
-#endif
-
- spin_lock_irqsave (&pool->lock, flags);
- page->in_use--;
- set_bit (block, &page->bitmap [map]);
- if (waitqueue_active (&pool->waitq))
- wake_up (&pool->waitq);
- /*
- * Resist a temptation to do
- * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
- * Better have a few empty pages hang around.
- */
- spin_unlock_irqrestore (&pool->lock, flags);
-}
-
-/*
- * Managed DMA pool
- */
-static void dmam_pool_release(struct device *dev, void *res)
-{
- struct dma_pool *pool = *(struct dma_pool **)res;
-
- dma_pool_destroy(pool);
-}
-
-static int dmam_pool_match(struct device *dev, void *res, void *match_data)
-{
- return *(struct dma_pool **)res == match_data;
-}
-
-/**
- * dmam_pool_create - Managed dma_pool_create()
- * @name: name of pool, for diagnostics
- * @dev: device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- *
- * Managed dma_pool_create(). DMA pool created with this function is
- * automatically destroyed on driver detach.
- */
-struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
- size_t size, size_t align, size_t allocation)
-{
- struct dma_pool **ptr, *pool;
-
- ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
- if (pool)
- devres_add(dev, ptr);
- else
- devres_free(ptr);
-
- return pool;
-}
-
-/**
- * dmam_pool_destroy - Managed dma_pool_destroy()
- * @pool: dma pool that will be destroyed
- *
- * Managed dma_pool_destroy().
- */
-void dmam_pool_destroy(struct dma_pool *pool)
-{
- struct device *dev = pool->dev;
-
- dma_pool_destroy(pool);
- WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
-}
-
-EXPORT_SYMBOL (dma_pool_create);
-EXPORT_SYMBOL (dma_pool_destroy);
-EXPORT_SYMBOL (dma_pool_alloc);
-EXPORT_SYMBOL (dma_pool_free);
-EXPORT_SYMBOL (dmam_pool_create);
-EXPORT_SYMBOL (dmam_pool_destroy);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index a35f041..ba75184 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -97,10 +97,9 @@
struct driver_attribute *attr)
{
int error;
- if (get_driver(drv)) {
+ if (drv)
error = sysfs_create_file(&drv->p->kobj, &attr->attr);
- put_driver(drv);
- } else
+ else
error = -EINVAL;
return error;
}
@@ -114,10 +113,8 @@
void driver_remove_file(struct device_driver *drv,
struct driver_attribute *attr)
{
- if (get_driver(drv)) {
+ if (drv)
sysfs_remove_file(&drv->p->kobj, &attr->attr);
- put_driver(drv);
- }
}
EXPORT_SYMBOL_GPL(driver_remove_file);
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index de28dfd..911208b 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o
-obj-$(CONFIG_PM_TRACE) += trace.o
+obj-$(CONFIG_PM_TRACE_RTC) += trace.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 200ed5f..bdc03f7 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -129,6 +129,7 @@
list_move_tail(&dev->power.entry, &dpm_destroy);
mutex_unlock(&dpm_list_mtx);
}
+EXPORT_SYMBOL_GPL(device_pm_schedule_removal);
/**
* pm_sleep_lock - mutual exclusion for registration and suspend
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 6f0dfca..e32d3bd 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -13,7 +13,6 @@
extern void device_pm_add(struct device *);
extern void device_pm_remove(struct device *);
-extern void device_pm_schedule_removal(struct device *);
extern int pm_sleep_lock(void);
extern void pm_sleep_unlock(void);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index f212285..64e5148 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -440,6 +440,7 @@
tristate "Virtio block driver (EXPERIMENTAL)"
depends on EXPERIMENTAL && VIRTIO
---help---
- This is the virtual block driver for lguest. Say Y or M.
+ This is the virtual block driver for virtio. It can be used with
+ lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
endif # BLK_DEV
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 94268c7..4249950 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -90,7 +90,7 @@
unsigned blocks; /* total number of blocks */
unsigned fdc_speed; /* fdc_speed setting */
unsigned stretch; /* track doubling ? */
-} disk_type[] = {
+} atari_disk_type[] = {
{ "d360", 9, 720, 0, 0}, /* 0: 360kB diskette */
{ "D360", 9, 720, 0, 1}, /* 1: 360kb in 720k or 1.2MB drive */
{ "D720", 9,1440, 0, 0}, /* 2: 720kb in 720k or 1.2MB drive */
@@ -658,7 +658,7 @@
return -EINVAL;
}
type = minor2disktype[type].index;
- UDT = &disk_type[type];
+ UDT = &atari_disk_type[type];
}
if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
@@ -1064,7 +1064,7 @@
searched for a non-existent sector! */
!(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
if (Probing) {
- if (SUDT > disk_type) {
+ if (SUDT > atari_disk_type) {
if (SUDT[-1].blocks > ReqBlock) {
/* try another disk type */
SUDT--;
@@ -1082,7 +1082,7 @@
} else {
/* record not found, but not probing. Maybe stretch wrong ? Restart probing */
if (SUD.autoprobe) {
- SUDT = disk_type + StartDiskType[DriveType];
+ SUDT = atari_disk_type + StartDiskType[DriveType];
set_capacity(unit[SelectedDrive].disk,
SUDT->blocks);
Probing = 1;
@@ -1421,7 +1421,7 @@
if (type == 0) {
if (!UDT) {
Probing = 1;
- UDT = disk_type + StartDiskType[DriveType];
+ UDT = atari_disk_type + StartDiskType[DriveType];
set_capacity(floppy->disk, UDT->blocks);
UD.autoprobe = 1;
}
@@ -1439,7 +1439,7 @@
goto repeat;
}
type = minor2disktype[type].index;
- UDT = &disk_type[type];
+ UDT = &atari_disk_type[type];
set_capacity(floppy->disk, UDT->blocks);
UD.autoprobe = 0;
}
@@ -1505,7 +1505,7 @@
if (minor2disktype[type].drive_types > DriveType)
return -ENODEV;
type = minor2disktype[type].index;
- dtp = &disk_type[type];
+ dtp = &atari_disk_type[type];
if (UD.flags & FTD_MSG)
printk (KERN_ERR "floppy%d: found dtp %p name %s!\n",
drive, dtp, dtp->name);
@@ -1576,7 +1576,7 @@
continue;
}
setidx = minor2disktype[settype].index;
- dtp = &disk_type[setidx];
+ dtp = &atari_disk_type[setidx];
/* found matching entry ?? */
if ( dtp->blocks == setprm.size
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 855ce8e..9715be3 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -2630,12 +2630,14 @@
c->Request.CDB[8] = creq->nr_sectors & 0xff;
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
} else {
+ u32 upper32 = upper_32_bits(start_blk);
+
c->Request.CDBLen = 16;
c->Request.CDB[1]= 0;
- c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
- c->Request.CDB[3]= (start_blk >> 48) & 0xff;
- c->Request.CDB[4]= (start_blk >> 40) & 0xff;
- c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+ c->Request.CDB[2]= (upper32 >> 24) & 0xff; //MSB
+ c->Request.CDB[3]= (upper32 >> 16) & 0xff;
+ c->Request.CDB[4]= (upper32 >> 8) & 0xff;
+ c->Request.CDB[5]= upper32 & 0xff;
c->Request.CDB[6]= (start_blk >> 24) & 0xff;
c->Request.CDB[7]= (start_blk >> 16) & 0xff;
c->Request.CDB[8]= (start_blk >> 8) & 0xff;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 63ee6c0..55178e9 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -1453,7 +1453,7 @@
rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0,
(unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0],
TYPE_MSG);
- /* sendcmd turned off interrputs on the board, turn 'em back on. */
+ /* sendcmd turned off interrupts on the board, turn 'em back on. */
(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
if (rc == 0)
return SUCCESS;
@@ -1483,7 +1483,7 @@
0, 2, 0, 0,
(unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0],
TYPE_MSG);
- /* sendcmd turned off interrputs on the board, turn 'em back on. */
+ /* sendcmd turned off interrupts on the board, turn 'em back on. */
(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
if (rc == 0)
return SUCCESS;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index b8af22e..91ebb00 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -973,6 +973,10 @@
lo->transfer = xfer->transfer;
lo->ioctl = xfer->ioctl;
+ if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) !=
+ (info->lo_flags & LO_FLAGS_AUTOCLEAR))
+ lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
+
lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
lo->lo_init[0] = info->lo_init[0];
lo->lo_init[1] = info->lo_init[1];
@@ -1331,6 +1335,10 @@
mutex_lock(&lo->lo_ctl_mutex);
--lo->lo_refcnt;
+
+ if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt)
+ loop_clr_fd(lo, inode->i_bdev);
+
mutex_unlock(&lo->lo_ctl_mutex);
return 0;
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 76096ca..8b9549a 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -660,7 +660,7 @@
pt_identify(tape);
err = -ENODEV;
- if (!tape->flags & PT_MEDIA)
+ if (!(tape->flags & PT_MEDIA))
goto out;
err = -EROFS;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index e9de171..674cd66 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2212,11 +2212,11 @@
return ret;
}
- if (!buf[6] & 0x40) {
+ if (!(buf[6] & 0x40)) {
printk(DRIVER_NAME": Disc type is not CD-RW\n");
return 1;
}
- if (!buf[6] & 0x4) {
+ if (!(buf[6] & 0x4)) {
printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
return 1;
}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 82f4eec..06e23be 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -56,6 +56,7 @@
#include <linux/backing-dev.h>
#include <linux/blkpg.h>
#include <linux/writeback.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
@@ -450,7 +451,7 @@
err = -ENOMEM;
if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
- (rd_blocksize & (rd_blocksize-1))) {
+ !is_power_of_2(rd_blocksize)) {
printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
rd_blocksize);
rd_blocksize = BLOCK_SIZE;
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index c6179d6..a70c1c2 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -922,11 +922,6 @@
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
- /* Fill what we shouldn't be filling, because usb-storage did so. */
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
-
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
ub_complete(&sc->work_done);
@@ -1313,9 +1308,6 @@
sc->last_pipe = pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
sg->length, ub_urb_complete, sc);
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
@@ -1356,9 +1348,6 @@
sc->last_pipe = sc->recv_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
&sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
@@ -1473,9 +1462,6 @@
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
ub_complete(&sc->work_done);
@@ -1953,9 +1939,6 @@
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
printk(KERN_WARNING
@@ -2007,9 +1990,6 @@
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
(unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
goto err_submit;
@@ -2077,9 +2057,6 @@
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
printk(KERN_WARNING
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 924ddd8..3b1a68d 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -7,8 +7,10 @@
#include <linux/scatterlist.h>
#define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS)
+#define PART_BITS 4
-static unsigned char virtblk_index = 'a';
+static int major, index;
+
struct virtio_blk
{
spinlock_t lock;
@@ -36,7 +38,7 @@
struct virtio_blk_inhdr in_hdr;
};
-static bool blk_done(struct virtqueue *vq)
+static void blk_done(struct virtqueue *vq)
{
struct virtio_blk *vblk = vq->vdev->priv;
struct virtblk_req *vbr;
@@ -65,7 +67,6 @@
/* In case queue is stopped waiting for more buffers. */
blk_start_queue(vblk->disk->queue);
spin_unlock_irqrestore(&vblk->lock, flags);
- return true;
}
static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
@@ -153,20 +154,37 @@
(void __user *)data);
}
+/* We provide getgeo only to please some old bootloader/partitioning tools */
+static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
+{
+ /* some standard values, similar to sd */
+ geo->heads = 1 << 6;
+ geo->sectors = 1 << 5;
+ geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ return 0;
+}
+
static struct block_device_operations virtblk_fops = {
- .ioctl = virtblk_ioctl,
- .owner = THIS_MODULE,
+ .ioctl = virtblk_ioctl,
+ .owner = THIS_MODULE,
+ .getgeo = virtblk_getgeo,
};
+static int index_to_minor(int index)
+{
+ return index << PART_BITS;
+}
+
static int virtblk_probe(struct virtio_device *vdev)
{
struct virtio_blk *vblk;
- int err, major;
- void *token;
- unsigned int len;
+ int err;
u64 cap;
u32 v;
+ if (index_to_minor(index) >= 1 << MINORBITS)
+ return -ENOSPC;
+
vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
if (!vblk) {
err = -ENOMEM;
@@ -178,7 +196,7 @@
vblk->vdev = vdev;
/* We expect one virtqueue, for output. */
- vblk->vq = vdev->config->find_vq(vdev, blk_done);
+ vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
if (IS_ERR(vblk->vq)) {
err = PTR_ERR(vblk->vq);
goto out_free_vblk;
@@ -190,17 +208,11 @@
goto out_free_vq;
}
- major = register_blkdev(0, "virtblk");
- if (major < 0) {
- err = major;
- goto out_mempool;
- }
-
/* FIXME: How many partitions? How long is a piece of string? */
- vblk->disk = alloc_disk(1 << 4);
+ vblk->disk = alloc_disk(1 << PART_BITS);
if (!vblk->disk) {
err = -ENOMEM;
- goto out_unregister_blkdev;
+ goto out_mempool;
}
vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
@@ -209,22 +221,32 @@
goto out_put_disk;
}
- sprintf(vblk->disk->disk_name, "vd%c", virtblk_index++);
+ if (index < 26) {
+ sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
+ } else if (index < (26 + 1) * 26) {
+ sprintf(vblk->disk->disk_name, "vd%c%c",
+ 'a' + index / 26 - 1, 'a' + index % 26);
+ } else {
+ const unsigned int m1 = (index / 26 - 1) / 26 - 1;
+ const unsigned int m2 = (index / 26 - 1) % 26;
+ const unsigned int m3 = index % 26;
+ sprintf(vblk->disk->disk_name, "vd%c%c%c",
+ 'a' + m1, 'a' + m2, 'a' + m3);
+ }
+
vblk->disk->major = major;
- vblk->disk->first_minor = 0;
+ vblk->disk->first_minor = index_to_minor(index);
vblk->disk->private_data = vblk;
vblk->disk->fops = &virtblk_fops;
+ index++;
/* If barriers are supported, tell block layer that queue is ordered */
- token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len);
- if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER))
+ if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
- err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap);
- if (err) {
- dev_err(&vdev->dev, "Bad/missing capacity in config\n");
- goto out_cleanup_queue;
- }
+ /* Host must always specify the capacity. */
+ __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
+ &cap);
/* If capacity is too big, truncate with warning. */
if ((sector_t)cap != cap) {
@@ -234,31 +256,25 @@
}
set_capacity(vblk->disk, cap);
- err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v);
+ /* Host can optionally specify maximum segment size and number of
+ * segments. */
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
+ offsetof(struct virtio_blk_config, size_max),
+ &v);
if (!err)
blk_queue_max_segment_size(vblk->disk->queue, v);
- else if (err != -ENOENT) {
- dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
- goto out_cleanup_queue;
- }
- err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v);
+ err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
+ offsetof(struct virtio_blk_config, seg_max),
+ &v);
if (!err)
blk_queue_max_hw_segments(vblk->disk->queue, v);
- else if (err != -ENOENT) {
- dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
- goto out_cleanup_queue;
- }
add_disk(vblk->disk);
return 0;
-out_cleanup_queue:
- blk_cleanup_queue(vblk->disk->queue);
out_put_disk:
put_disk(vblk->disk);
-out_unregister_blkdev:
- unregister_blkdev(major, "virtblk");
out_mempool:
mempool_destroy(vblk->pool);
out_free_vq:
@@ -274,12 +290,16 @@
struct virtio_blk *vblk = vdev->priv;
int major = vblk->disk->major;
+ /* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));
+
+ /* Stop all the virtqueues. */
+ vdev->config->reset(vdev);
+
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
unregister_blkdev(major, "virtblk");
mempool_destroy(vblk->pool);
- /* There should be nothing in the queue now, so no need to shutdown */
vdev->config->del_vq(vblk->vq);
kfree(vblk);
}
@@ -299,11 +319,15 @@
static int __init init(void)
{
+ major = register_blkdev(0, "virtblk");
+ if (major < 0)
+ return major;
return register_virtio_driver(&virtio_blk);
}
static void __exit fini(void)
{
+ unregister_blkdev(major, "virtblk");
unregister_virtio_driver(&virtio_blk);
}
module_init(init);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 1375b53..3b28658 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -423,6 +423,7 @@
break;
default:
+ usb_free_urb(urb);
return -EILSEQ;
}
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index a18f9b8..7703d6e 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -704,7 +704,7 @@
static int bt3c_config(struct pcmcia_device *link)
{
- static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+ static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
bt3c_info_t *info = link->priv;
tuple_t tuple;
u_short buf[256];
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index b786f61..58630cc 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -162,10 +162,8 @@
bt_cb(skb)->pkt_type = hdr[3];
err = hci_recv_frame(skb);
- if (err < 0) {
- kfree(skb);
+ if (err < 0)
return err;
- }
sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 08f48d5..68d1d25 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -383,7 +383,7 @@
outb(lcr, iobase + UART_LCR); /* Set 8N1 */
outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
- /* Turn on interrups */
+ /* Turn on interrupts */
outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
spin_unlock_irqrestore(&(info->lock), flags);
@@ -634,7 +634,7 @@
static int btuart_config(struct pcmcia_device *link)
{
- static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+ static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
btuart_info_t *info = link->priv;
tuple_t tuple;
u_short buf[256];
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 98a9cde..372c7ef6 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -111,6 +111,7 @@
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
/* Broadcom BCM2035 */
+ { USB_DEVICE(0x0a5c, 0x2035), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 47e5b40..db259e6 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1206,25 +1206,26 @@
return 0;
}
-/* Admittedly, the logic below could be performed in a nicer way. */
int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
{
struct cdrom_device_ops *cdo = cdi->ops;
int opened_for_data;
- cdinfo(CD_CLOSE, "entering cdrom_release\n");
+ cdinfo(CD_CLOSE, "entering cdrom_release\n");
if (cdi->use_count > 0)
cdi->use_count--;
- if (cdi->use_count == 0)
+
+ if (cdi->use_count == 0) {
cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
- if (cdi->use_count == 0)
cdrom_dvd_rw_close_write(cdi);
- if (cdi->use_count == 0 &&
- (cdo->capability & CDC_LOCK) && !keeplocked) {
- cdinfo(CD_CLOSE, "Unlocking door!\n");
- cdo->lock_door(cdi, 0);
+
+ if ((cdo->capability & CDC_LOCK) && !keeplocked) {
+ cdinfo(CD_CLOSE, "Unlocking door!\n");
+ cdo->lock_door(cdi, 0);
+ }
}
+
opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
!(fp && fp->f_flags & O_NONBLOCK);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 4666295..85bf9b2 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -276,7 +276,7 @@
config RISCOM8
tristate "SDL RISCom/8 card support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD
help
This is a driver for the SDL Communications RISCom/8 multiport card,
which gives you many serial ports. You would need something like
@@ -765,7 +765,7 @@
config SGI_DS1286
tristate "SGI DS1286 RTC support"
- depends on SGI_IP22
+ depends on SGI_HAS_DS1286
help
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index b83824c4..c69f795 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -117,7 +117,8 @@
void (*free_by_type)(struct agp_memory *);
void *(*agp_alloc_page)(struct agp_bridge_data *);
void (*agp_destroy_page)(void *, int flags);
- int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
+ int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
+ void (*chipset_flush)(struct agp_bridge_data *);
};
struct agp_bridge_data {
@@ -235,6 +236,9 @@
#define I965_PGETBL_SIZE_512KB (0 << 1)
#define I965_PGETBL_SIZE_256KB (1 << 1)
#define I965_PGETBL_SIZE_128KB (2 << 1)
+#define I965_PGETBL_SIZE_1MB (3 << 1)
+#define I965_PGETBL_SIZE_2MB (4 << 1)
+#define I965_PGETBL_SIZE_1_5MB (5 << 1)
#define G33_PGETBL_SIZE_MASK (3 << 8)
#define G33_PGETBL_SIZE_1M (1 << 8)
#define G33_PGETBL_SIZE_2M (2 << 8)
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index aa8f3a3..e77c178 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -11,29 +11,28 @@
#include "agp.h"
-static struct page *alpha_core_agp_vm_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int *type)
+static int alpha_core_agp_vm_fault(struct vm_area_struct *vma,
+ struct vm_fault *vmf)
{
alpha_agp_info *agp = agp_bridge->dev_private_data;
dma_addr_t dma_addr;
unsigned long pa;
struct page *page;
- dma_addr = address - vma->vm_start + agp->aperture.bus_base;
+ dma_addr = (unsigned long)vmf->virtual_address - vma->vm_start
+ + agp->aperture.bus_base;
pa = agp->ops->translate(agp, dma_addr);
if (pa == (unsigned long)-EINVAL)
- return NULL; /* no translation */
+ return VM_FAULT_SIGBUS; /* no translation */
/*
* Get the page, inc the use count, and return it
*/
page = virt_to_page(__va(pa));
get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = page;
+ return 0;
}
static struct aper_size_info_fixed alpha_core_agp_sizes[] =
@@ -42,7 +41,7 @@
};
struct vm_operations_struct alpha_core_agp_vm_ops = {
- .nopage = alpha_core_agp_vm_nopage,
+ .fault = alpha_core_agp_vm_fault,
};
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 1405a42..87be464 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -436,10 +436,6 @@
return -ENODEV;
}
cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP);
- if (!cap_ptr) {
- pci_dev_put(gfxcard);
- continue;
- }
}
/* With so many variants of NVidia cards, it's simpler just
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 2720882..b1bdd01 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -43,7 +43,7 @@
* fix some real stupidity. It's only by chance we can bump
* past 0.99 at all due to some boolean logic error. */
#define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 102
+#define AGPGART_VERSION_MINOR 103
static const struct agp_version agp_current_version =
{
.major = AGPGART_VERSION_MAJOR,
diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c
index ecd4248..3927579 100644
--- a/drivers/char/agp/compat_ioctl.c
+++ b/drivers/char/agp/compat_ioctl.c
@@ -273,6 +273,10 @@
case AGPIOC_UNBIND32:
ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg);
break;
+
+ case AGPIOC_CHIPSET_FLUSH32:
+ ret_val = agpioc_chipset_flush_wrap(curr_priv);
+ break;
}
ioctl_out:
diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h
index 71939d6..0c9678a 100644
--- a/drivers/char/agp/compat_ioctl.h
+++ b/drivers/char/agp/compat_ioctl.h
@@ -39,6 +39,7 @@
#define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t)
#define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t)
#define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t)
+#define AGPIOC_CHIPSET_FLUSH32 _IO (AGPIOC_BASE, 10)
struct agp_info32 {
struct agp_version version; /* version of the driver */
@@ -101,5 +102,6 @@
struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type);
struct agp_memory *agp_find_mem_by_key(int key);
struct agp_client *agp_find_client_by_pid(pid_t id);
+int agpioc_chipset_flush_wrap(struct agp_file_private *priv);
#endif /* _AGP_COMPAT_H */
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 7791e98..55d7a82 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -689,7 +689,7 @@
set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
priv->my_pid = current->pid;
- if ((current->uid == 0) || (current->suid == 0)) {
+ if (capable(CAP_SYS_RAWIO)) {
/* Root priv, can be controller */
set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
}
@@ -960,6 +960,13 @@
return agp_unbind_memory(memory);
}
+int agpioc_chipset_flush_wrap(struct agp_file_private *priv)
+{
+ DBG("");
+ agp_flush_chipset(agp_bridge);
+ return 0;
+}
+
static int agp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1033,6 +1040,10 @@
case AGPIOC_UNBIND:
ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg);
break;
+
+ case AGPIOC_CHIPSET_FLUSH:
+ ret_val = agpioc_chipset_flush_wrap(curr_priv);
+ break;
}
ioctl_out:
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 1a4674c..7484bc7 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -80,6 +80,13 @@
return -1;
}
+void agp_flush_chipset(struct agp_bridge_data *bridge)
+{
+ if (bridge->driver->chipset_flush)
+ bridge->driver->chipset_flush(bridge);
+}
+EXPORT_SYMBOL(agp_flush_chipset);
+
/*
* Use kmalloc if possible for the page list. Otherwise fall back to
* vmalloc. This speeds things up and also saves memory for small AGP
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 189efb6..eeea50a 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -14,8 +14,8 @@
#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a
#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972
-#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980
-#define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982
+#define PCI_DEVICE_ID_INTEL_82G35_HB 0x2980
+#define PCI_DEVICE_ID_INTEL_82G35_IG 0x2982
#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990
#define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992
#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0
@@ -32,13 +32,24 @@
#define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2
#define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0
#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2
+#define PCI_DEVICE_ID_INTEL_IGD_HB 0x2A40
+#define PCI_DEVICE_ID_INTEL_IGD_IG 0x2A42
+
+/* cover 915 and 945 variants */
+#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB)
#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
@@ -71,9 +82,11 @@
#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)
#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4)
+#define I915_IFPADDR 0x60
/* Intel 965G registers */
#define I965_MSAC 0x62
+#define I965_IFPADDR 0x70
/* Intel 7505 registers */
#define INTEL_I7505_APSIZE 0x74
@@ -115,6 +128,13 @@
* popup and for the GTT.
*/
int gtt_entries; /* i830+ */
+ union {
+ void __iomem *i9xx_flush_page;
+ void *i8xx_flush_page;
+ };
+ struct page *i8xx_page;
+ struct resource ifp_resource;
+ int resource_valid;
} intel_private;
static int intel_i810_fetch_size(void)
@@ -204,7 +224,7 @@
/* Exists to support ARGB cursors */
static void *i8xx_alloc_pages(void)
{
- struct page * page;
+ struct page *page;
page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
if (page == NULL)
@@ -433,7 +453,7 @@
static const int ddt[4] = { 0, 16, 32, 64 };
int size; /* reserved space (in kb) at the top of stolen memory */
- pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+ pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
if (IS_I965) {
u32 pgetbl_ctl;
@@ -453,6 +473,15 @@
case I965_PGETBL_SIZE_512KB:
size = 512;
break;
+ case I965_PGETBL_SIZE_1MB:
+ size = 1024;
+ break;
+ case I965_PGETBL_SIZE_2MB:
+ size = 2048;
+ break;
+ case I965_PGETBL_SIZE_1_5MB:
+ size = 1024 + 512;
+ break;
default:
printk(KERN_INFO PFX "Unknown page table size, "
"assuming 512KB\n");
@@ -523,26 +552,14 @@
break;
case I915_GMCH_GMS_STOLEN_48M:
/* Check it's really I915G */
- if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
- IS_I965 || IS_G33)
+ if (IS_I915 || IS_I965 || IS_G33)
gtt_entries = MB(48) - KB(size);
else
gtt_entries = 0;
break;
case I915_GMCH_GMS_STOLEN_64M:
/* Check it's really I915G */
- if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
- IS_I965 || IS_G33)
+ if (IS_I915 || IS_I965 || IS_G33)
gtt_entries = MB(64) - KB(size);
else
gtt_entries = 0;
@@ -575,6 +592,45 @@
intel_private.gtt_entries = gtt_entries;
}
+static void intel_i830_fini_flush(void)
+{
+ kunmap(intel_private.i8xx_page);
+ intel_private.i8xx_flush_page = NULL;
+ unmap_page_from_agp(intel_private.i8xx_page);
+
+ __free_page(intel_private.i8xx_page);
+ intel_private.i8xx_page = NULL;
+}
+
+static void intel_i830_setup_flush(void)
+{
+ /* return if we've already set the flush mechanism up */
+ if (intel_private.i8xx_page)
+ return;
+
+ intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+ if (!intel_private.i8xx_page)
+ return;
+
+ /* make page uncached */
+ map_page_into_agp(intel_private.i8xx_page);
+
+ intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
+ if (!intel_private.i8xx_flush_page)
+ intel_i830_fini_flush();
+}
+
+static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+{
+ unsigned int *pg = intel_private.i8xx_flush_page;
+ int i;
+
+ for (i = 0; i < 256; i += 2)
+ *(pg + i) = i;
+
+ wmb();
+}
+
/* The intel i830 automatically initializes the agp aperture during POST.
* Use the memory already set aside for in the GTT.
*/
@@ -590,10 +646,10 @@
num_entries = size->num_entries;
agp_bridge->gatt_table_real = NULL;
- pci_read_config_dword(intel_private.pcidev,I810_MMADDR,&temp);
+ pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
temp &= 0xfff80000;
- intel_private.registers = ioremap(temp,128 * 4096);
+ intel_private.registers = ioremap(temp, 128 * 4096);
if (!intel_private.registers)
return -ENOMEM;
@@ -633,7 +689,7 @@
return values[0].size;
}
- pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+ pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
@@ -657,12 +713,12 @@
current_size = A_SIZE_FIX(agp_bridge->current_size);
- pci_read_config_dword(intel_private.pcidev,I810_GMADDR,&temp);
+ pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+ pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
gmch_ctrl |= I830_GMCH_ENABLED;
- pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
+ pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
@@ -675,6 +731,8 @@
}
global_cache_flush();
+
+ intel_i830_setup_flush();
return 0;
}
@@ -683,9 +741,10 @@
iounmap(intel_private.registers);
}
-static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type)
+static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
+ int type)
{
- int i,j,num_entries;
+ int i, j, num_entries;
void *temp;
int ret = -EINVAL;
int mask_type;
@@ -697,10 +756,10 @@
num_entries = A_SIZE_FIX(temp)->num_entries;
if (pg_start < intel_private.gtt_entries) {
- printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
- pg_start,intel_private.gtt_entries);
+ printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
+ pg_start, intel_private.gtt_entries);
- printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
+ printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n");
goto out_err;
}
@@ -738,8 +797,8 @@
return ret;
}
-static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
- int type)
+static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
+ int type)
{
int i;
@@ -747,7 +806,7 @@
return 0;
if (pg_start < intel_private.gtt_entries) {
- printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
+ printk(KERN_INFO PFX "Trying to disable local/stolen memory\n");
return -EINVAL;
}
@@ -760,7 +819,7 @@
return 0;
}
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
+static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
{
if (type == AGP_PHYS_MEMORY)
return alloc_agpphysmem_i8xx(pg_count, type);
@@ -768,6 +827,95 @@
return NULL;
}
+static int intel_alloc_chipset_flush_resource(void)
+{
+ int ret;
+ ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+ PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
+ pcibios_align_resource, agp_bridge->dev);
+
+ return ret;
+}
+
+static void intel_i915_setup_chipset_flush(void)
+{
+ int ret;
+ u32 temp;
+
+ pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+ if (!(temp & 0x1)) {
+ intel_alloc_chipset_flush_resource();
+ intel_private.resource_valid = 1;
+ pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+ } else {
+ temp &= ~1;
+
+ intel_private.resource_valid = 1;
+ intel_private.ifp_resource.start = temp;
+ intel_private.ifp_resource.end = temp + PAGE_SIZE;
+ ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+ /* some BIOSes reserve this area in a pnp some don't */
+ if (ret)
+ intel_private.resource_valid = 0;
+ }
+}
+
+static void intel_i965_g33_setup_chipset_flush(void)
+{
+ u32 temp_hi, temp_lo;
+ int ret;
+
+ pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
+ pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+
+ if (!(temp_lo & 0x1)) {
+
+ intel_alloc_chipset_flush_resource();
+
+ intel_private.resource_valid = 1;
+ pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+ upper_32_bits(intel_private.ifp_resource.start));
+ pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+ } else {
+ u64 l64;
+
+ temp_lo &= ~0x1;
+ l64 = ((u64)temp_hi << 32) | temp_lo;
+
+ intel_private.resource_valid = 1;
+ intel_private.ifp_resource.start = l64;
+ intel_private.ifp_resource.end = l64 + PAGE_SIZE;
+ ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+ /* some BIOSes reserve this area in a pnp some don't */
+ if (ret)
+ intel_private.resource_valid = 0;
+ }
+}
+
+static void intel_i9xx_setup_flush(void)
+{
+ /* return if already configured */
+ if (intel_private.ifp_resource.start)
+ return;
+
+ /* setup a resource for this object */
+ intel_private.ifp_resource.name = "Intel Flush Page";
+ intel_private.ifp_resource.flags = IORESOURCE_MEM;
+
+ /* Setup chipset flush for 915 */
+ if (IS_I965 || IS_G33) {
+ intel_i965_g33_setup_chipset_flush();
+ } else {
+ intel_i915_setup_chipset_flush();
+ }
+
+ if (intel_private.ifp_resource.start) {
+ intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
+ if (!intel_private.i9xx_flush_page)
+ printk(KERN_INFO "unable to ioremap flush page - no chipset flushing");
+ }
+}
+
static int intel_i915_configure(void)
{
struct aper_size_info_fixed *current_size;
@@ -781,9 +929,9 @@
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+ pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
gmch_ctrl |= I830_GMCH_ENABLED;
- pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
+ pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
@@ -796,19 +944,34 @@
}
global_cache_flush();
+
+ intel_i9xx_setup_flush();
+
return 0;
}
static void intel_i915_cleanup(void)
{
+ if (intel_private.i9xx_flush_page)
+ iounmap(intel_private.i9xx_flush_page);
+ if (intel_private.resource_valid)
+ release_resource(&intel_private.ifp_resource);
+ intel_private.ifp_resource.start = 0;
+ intel_private.resource_valid = 0;
iounmap(intel_private.gtt);
iounmap(intel_private.registers);
}
-static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
- int type)
+static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
{
- int i,j,num_entries;
+ if (intel_private.i9xx_flush_page)
+ writel(1, intel_private.i9xx_flush_page);
+}
+
+static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
+ int type)
+{
+ int i, j, num_entries;
void *temp;
int ret = -EINVAL;
int mask_type;
@@ -820,10 +983,10 @@
num_entries = A_SIZE_FIX(temp)->num_entries;
if (pg_start < intel_private.gtt_entries) {
- printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
- pg_start,intel_private.gtt_entries);
+ printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
+ pg_start, intel_private.gtt_entries);
- printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
+ printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n");
goto out_err;
}
@@ -861,8 +1024,8 @@
return ret;
}
-static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
- int type)
+static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
+ int type)
{
int i;
@@ -870,13 +1033,13 @@
return 0;
if (pg_start < intel_private.gtt_entries) {
- printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
+ printk(KERN_INFO PFX "Trying to disable local/stolen memory\n");
return -EINVAL;
}
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+ for (i = pg_start; i < (mem->page_count + pg_start); i++)
writel(agp_bridge->scratch_page, intel_private.gtt+i);
- }
+
readl(intel_private.gtt+i-1);
agp_bridge->driver->tlb_flush(mem);
@@ -923,7 +1086,7 @@
agp_bridge->gatt_table_real = NULL;
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
- pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2);
+ pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
if (IS_G33)
gtt_map_size = 1024 * 1024; /* 1M on G33 */
@@ -933,7 +1096,7 @@
temp &= 0xfff80000;
- intel_private.registers = ioremap(temp,128 * 4096);
+ intel_private.registers = ioremap(temp, 128 * 4096);
if (!intel_private.registers) {
iounmap(intel_private.gtt);
return -ENOMEM;
@@ -980,6 +1143,7 @@
struct aper_size_info_fixed *size;
int num_entries;
u32 temp;
+ int gtt_offset, gtt_size;
size = agp_bridge->current_size;
page_order = size->page_order;
@@ -989,13 +1153,18 @@
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
temp &= 0xfff00000;
- intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024);
- if (!intel_private.gtt)
- return -ENOMEM;
+ if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB)
+ gtt_offset = gtt_size = MB(2);
+ else
+ gtt_offset = gtt_size = KB(512);
+ intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
- intel_private.registers = ioremap(temp,128 * 4096);
+ if (!intel_private.gtt)
+ return -ENOMEM;
+
+ intel_private.registers = ioremap(temp, 128 * 4096);
if (!intel_private.registers) {
iounmap(intel_private.gtt);
return -ENOMEM;
@@ -1154,7 +1323,7 @@
/* the Intel 815 chipset spec. says that bits 29-31 in the
* ATTBASE register are reserved -> try not to write them */
if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) {
- printk (KERN_EMERG PFX "gatt bus addr too high");
+ printk(KERN_EMERG PFX "gatt bus addr too high");
return -EINVAL;
}
@@ -1296,6 +1465,8 @@
pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
/* clear any possible error conditions */
pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c);
+
+ intel_i830_setup_flush();
return 0;
}
@@ -1552,6 +1723,7 @@
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .chipset_flush = intel_i830_chipset_flush,
};
static const struct agp_bridge_driver intel_820_driver = {
@@ -1648,6 +1820,7 @@
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
+ .chipset_flush = intel_i830_chipset_flush,
};
static const struct agp_bridge_driver intel_850_driver = {
@@ -1721,6 +1894,7 @@
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .chipset_flush = intel_i915_chipset_flush,
};
static const struct agp_bridge_driver intel_i965_driver = {
@@ -1746,6 +1920,7 @@
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .chipset_flush = intel_i915_chipset_flush,
};
static const struct agp_bridge_driver intel_7505_driver = {
@@ -1795,6 +1970,7 @@
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .chipset_flush = intel_i915_chipset_flush,
};
static int find_gmch(u16 device)
@@ -1804,7 +1980,7 @@
gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
- device, gmch_device);
+ device, gmch_device);
}
if (!gmch_device)
@@ -1867,7 +2043,7 @@
NULL, &intel_915_driver },
{ PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
NULL, &intel_i965_driver },
- { PCI_DEVICE_ID_INTEL_82965G_1_HB, PCI_DEVICE_ID_INTEL_82965G_1_IG, 0, "965G",
+ { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35",
NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q",
NULL, &intel_i965_driver },
@@ -1885,6 +2061,8 @@
NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
NULL, &intel_g33_driver },
+ { PCI_DEVICE_ID_INTEL_IGD_HB, PCI_DEVICE_ID_INTEL_IGD_IG, 0,
+ "Intel Integrated Graphics Device", NULL, &intel_i965_driver },
{ 0, 0, 0, NULL, NULL, NULL }
};
@@ -1924,7 +2102,7 @@
if (intel_agp_chipsets[i].name == NULL) {
if (cap_ptr)
printk(KERN_WARNING PFX "Unsupported Intel chipset"
- "(device id: %04x)\n", pdev->device);
+ "(device id: %04x)\n", pdev->device);
agp_put_bridge(bridge);
return -ENODEV;
}
@@ -1937,7 +2115,7 @@
intel_agp_chipsets[i].gmch_chip_id);
agp_put_bridge(bridge);
return -ENODEV;
- }
+ }
bridge->dev = pdev;
bridge->capndx = cap_ptr;
@@ -2067,7 +2245,7 @@
ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
- ID(PCI_DEVICE_ID_INTEL_82965G_1_HB),
+ ID(PCI_DEVICE_ID_INTEL_82G35_HB),
ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
ID(PCI_DEVICE_ID_INTEL_82965G_HB),
ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
@@ -2075,6 +2253,7 @@
ID(PCI_DEVICE_ID_INTEL_G33_HB),
ID(PCI_DEVICE_ID_INTEL_Q35_HB),
ID(PCI_DEVICE_ID_INTEL_Q33_HB),
+ ID(PCI_DEVICE_ID_INTEL_IGD_HB),
{ }
};
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index e8d50af..ef5e6b1 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -506,6 +506,7 @@
vma->vm_ops = &drm_vm_dma_ops;
vma->vm_flags |= VM_RESERVED; /* Don't swap */
+ vma->vm_flags |= VM_DONTEXPAND;
vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma);
@@ -655,6 +656,7 @@
return -EINVAL; /* This should never happen. */
}
vma->vm_flags |= VM_RESERVED; /* Don't swap */
+ vma->vm_flags |= VM_DONTEXPAND;
vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma);
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index 3ae57ec..fa194a4 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -584,7 +584,7 @@
#define R300_RE_FOG_START 0x4298
/* Not sure why there are duplicate of factor and constant values.
- * My best guess so far is that there are seperate zbiases for test and write.
+ * My best guess so far is that there are separate zbiases for test and write.
* Ordering might be wrong.
* Some of the tests indicate that fgl has a fallback implementation of zbias
* via pixel shaders.
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index 75d6b74..7009dbd 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -400,7 +400,7 @@
}
/*
- * This function is used internally by ring buffer mangement code.
+ * This function is used internally by ring buffer management code.
*
* Returns virtual pointer to ring buffer.
*/
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 004141d..49233f5 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -18,7 +18,7 @@
*
* NOTES:
* - Locking is required for safe execution of EFI calls with regards
- * to interrrupts and SMP.
+ * to interrupts and SMP.
*
* TODO (December 1999):
* - provide the API to set/get the WakeUp Alarm (different from the
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index ffcecde..ffd747c 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1797,7 +1797,7 @@
res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
/*
* This gets a little confusing. The Digi cards have their own
- * representation of c_cflags controling baud rate. For the most part
+ * representation of c_cflags controlling baud rate. For the most part
* this is identical to the Linux implementation. However; Digi
* supports one rate (76800) that Linux doesn't. This means that the
* c_cflag entry that would normally mean 76800 for Digi actually means
@@ -2068,7 +2068,7 @@
{
/*
* This call is made by the apps to complete the
- * initilization of the board(s). This routine is
+ * initialization of the board(s). This routine is
* responsible for setting the card to its initial
* state and setting the drivers control fields to the
* sutianle settings for the card in question.
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index 0e8ceea..712d9f2 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -26,7 +26,7 @@
* The hangcheck-timer driver uses the TSC to catch delays that
* jiffies does not notice. A timer is set. When the timer fires, it
* checks whether it was delayed and if that delay exceeds a given
- * margin of error. The hangcheck_tick module paramter takes the timer
+ * margin of error. The hangcheck_tick module parameter takes the timer
* duration in seconds. The hangcheck_margin parameter defines the
* margin of error, in seconds. The defaults are 60 seconds for the
* timer and 180 seconds for the margin of error. IOW, a timer is set
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 480fae2..44160d5 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -93,7 +93,7 @@
};
/* dynamic list of hvc_struct instances */
-static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
+static LIST_HEAD(hvc_structs);
/*
* Protect the list of hvc_struct instances from inserts and removals during
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index fd75590..786d518 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -306,7 +306,7 @@
/* Required to back map a kref to its containing object */
#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
+static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
static void hvcs_unthrottle(struct tty_struct *tty);
@@ -838,7 +838,7 @@
if (!hvcsd)
return -ENODEV;
- /* By this time the vty-server won't be getting any more interrups */
+ /* By this time the vty-server won't be getting any more interrupts */
spin_lock_irqsave(&hvcsd->lock, flags);
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 0118b98..84cdf90 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -234,11 +234,11 @@
NULL);
-static void unregister_miscdev(void)
+static void unregister_miscdev(bool suspended)
{
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
- misc_deregister(&rng_miscdev);
+ __misc_deregister(&rng_miscdev, suspended);
}
static int register_miscdev(void)
@@ -313,7 +313,7 @@
}
EXPORT_SYMBOL_GPL(hwrng_register);
-void hwrng_unregister(struct hwrng *rng)
+void __hwrng_unregister(struct hwrng *rng, bool suspended)
{
int err;
@@ -332,11 +332,11 @@
}
}
if (list_empty(&rng_list))
- unregister_miscdev();
+ unregister_miscdev(suspended);
mutex_unlock(&rng_mutex);
}
-EXPORT_SYMBOL_GPL(hwrng_unregister);
+EXPORT_SYMBOL_GPL(__hwrng_unregister);
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 868e39f..f7feae4 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -42,6 +42,8 @@
VIA_STRFILT_ENABLE = (1 << 14),
VIA_RAWBITS_ENABLE = (1 << 13),
VIA_RNG_ENABLE = (1 << 6),
+ VIA_NOISESRC1 = (1 << 8),
+ VIA_NOISESRC2 = (1 << 9),
VIA_XSTORE_CNT_MASK = 0x0F,
VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */
@@ -119,6 +121,7 @@
static int via_rng_init(struct hwrng *rng)
{
+ struct cpuinfo_x86 *c = &cpu_data(0);
u32 lo, hi, old_lo;
/* Control the RNG via MSR. Tread lightly and pay very close
@@ -134,6 +137,17 @@
lo &= ~VIA_XSTORE_CNT_MASK;
lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
lo |= VIA_RNG_ENABLE;
+ lo |= VIA_NOISESRC1;
+
+ /* Enable secondary noise source on CPUs where it is present. */
+
+ /* Nehemiah stepping 8 and higher */
+ if ((c->x86_model == 9) && (c->x86_mask > 7))
+ lo |= VIA_NOISESRC2;
+
+ /* Esther */
+ if (c->x86_model >= 10)
+ lo |= VIA_NOISESRC2;
if (lo != old_lo)
wrmsr(MSR_VIA_RNG, lo, hi);
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 30e5645..179223a 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -439,6 +439,13 @@
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
},
},
+ { /* UK Inspiron 6400 */
+ .ident = "Dell Inspiron 3",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
+ },
+ },
{ }
};
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index e46120d..d6567b3 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -661,7 +661,7 @@
if (!in_interrupt()) {
schedule_timeout_interruptible(1); // short nap
} else {
- // we cannot sched/sleep in interrrupt silly
+ // we cannot sched/sleep in interrupt silly
return 0;
}
if (signal_pending(current)) {
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index e04e66cf..0f49ccf0 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -1251,7 +1251,7 @@
// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
// It will NOT poll boards handled by hard interrupts.
- // The issue of queued BH interrups is handled in ip2_interrupt().
+ // The issue of queued BH interrupts is handled in ip2_interrupt().
ip2_polled_interrupt();
PollTimer.expires = POLL_TIMEOUT;
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index 932264a..86e6538 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -46,8 +46,8 @@
#include <asm/sn/sn0/hub.h>
#include <asm/sn/sn_private.h>
-static int rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+static long rtc_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
static int rtc_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data);
@@ -75,8 +75,7 @@
static const unsigned char days_in_mo[] =
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct rtc_time wtime;
@@ -197,7 +196,7 @@
static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
- .ioctl = rtc_ioctl,
+ .unlocked_ioctl = rtc_ioctl,
.open = rtc_open,
.release = rtc_release,
};
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 5dc1265..32b2b22 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -365,12 +365,12 @@
};
static DEFINE_MUTEX(ipmidriver_mutex);
-static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
+static LIST_HEAD(ipmi_interfaces);
static DEFINE_MUTEX(ipmi_interfaces_mutex);
/* List of watchers that want to know when smi's are added and
deleted. */
-static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static LIST_HEAD(smi_watchers);
static DEFINE_MUTEX(smi_watchers_mutex);
@@ -441,7 +441,7 @@
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{
ipmi_smi_t intf;
- struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
+ LIST_HEAD(to_deliver);
struct watcher_entry *e, *e2;
mutex_lock(&smi_watchers_mutex);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 81674d7..60ac642 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -312,7 +312,7 @@
if (copy_size > LP_BUFFER_SIZE)
copy_size = LP_BUFFER_SIZE;
- if (down_interruptible (&lp_table[minor].port_mutex))
+ if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
return -EINTR;
if (copy_from_user (kbuf, buf, copy_size)) {
@@ -399,7 +399,7 @@
lp_release_parport (&lp_table[minor]);
}
out_unlock:
- up (&lp_table[minor].port_mutex);
+ mutex_unlock(&lp_table[minor].port_mutex);
return retv;
}
@@ -421,7 +421,7 @@
if (count > LP_BUFFER_SIZE)
count = LP_BUFFER_SIZE;
- if (down_interruptible (&lp_table[minor].port_mutex))
+ if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
return -EINTR;
lp_claim_parport_or_block (&lp_table[minor]);
@@ -479,7 +479,7 @@
if (retval > 0 && copy_to_user (buf, kbuf, retval))
retval = -EFAULT;
- up (&lp_table[minor].port_mutex);
+ mutex_unlock(&lp_table[minor].port_mutex);
return retval;
}
@@ -888,7 +888,7 @@
lp_table[i].last_error = 0;
init_waitqueue_head (&lp_table[i].waitq);
init_waitqueue_head (&lp_table[i].dataq);
- init_MUTEX (&lp_table[i].port_mutex);
+ mutex_init(&lp_table[i].port_mutex);
lp_table[i].timeout = 10 * HZ;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 71c8cd7..a39101f 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -232,8 +232,9 @@
}
/**
- * misc_deregister - unregister a miscellaneous device
+ * __misc_deregister - unregister a miscellaneous device
* @misc: device to unregister
+ * @suspended: to be set if the function is used during suspend/resume
*
* Unregister a miscellaneous device that was previously
* successfully registered with misc_register(). Success
@@ -241,7 +242,7 @@
* indicates an error.
*/
-int misc_deregister(struct miscdevice * misc)
+int __misc_deregister(struct miscdevice *misc, bool suspended)
{
int i = misc->minor;
@@ -250,7 +251,11 @@
mutex_lock(&misc_mtx);
list_del(&misc->list);
- device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
+ if (suspended)
+ destroy_suspended_device(misc_class,
+ MKDEV(MISC_MAJOR, misc->minor));
+ else
+ device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
@@ -259,7 +264,7 @@
}
EXPORT_SYMBOL(misc_register);
-EXPORT_SYMBOL(misc_deregister);
+EXPORT_SYMBOL(__misc_deregister);
static int __init misc_init(void)
{
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 82f2e27..ff146c2 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -283,7 +283,7 @@
vdata->refcnt = ATOMIC_INIT(1);
vma->vm_private_data = vdata;
- vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP);
+ vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &mspec_vm_ops;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index fd0abef..47420787 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
-#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index 081c84c..bf1bee4 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 596c717..90c3969 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -695,17 +695,16 @@
return;
}
- if (tty->stopped && !tty->flow_stopped &&
- I_IXON(tty) && I_IXANY(tty)) {
- start_tty(tty);
- return;
- }
-
if (I_ISTRIP(tty))
c &= 0x7f;
if (I_IUCLC(tty) && L_IEXTEN(tty))
c=tolower(c);
+ if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+ ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
+ c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+ start_tty(tty);
+
if (tty->closing) {
if (I_IXON(tty)) {
if (c == START_CHAR(tty))
@@ -769,7 +768,21 @@
signal = SIGTSTP;
if (c == SUSP_CHAR(tty)) {
send_signal:
- isig(signal, tty, 0);
+ /*
+ * Echo character, and then send the signal.
+ * Note that we do not use isig() here because we want
+ * the order to be:
+ * 1) flush, 2) echo, 3) signal
+ */
+ if (!L_NOFLSH(tty)) {
+ n_tty_flush_buffer(tty);
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ }
+ if (L_ECHO(tty))
+ echo_char(c, tty);
+ if (tty->pgrp)
+ kill_pgrp(tty->pgrp, signal, 1);
return;
}
}
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 6076e66..dfaab23 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -2,7 +2,7 @@
* nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter
*
* Written by: Ulf Jakobsson,
- * Jan �erfeldt,
+ * Jan Åkerfeldt,
* Stefan Thomasson,
*
* Maintained by: Paul Hardwick (p.hardwick@option.com)
@@ -38,60 +38,6 @@
* --------------------------------------------------------------------------
*/
-/*
- * CHANGELOG
- * Version 2.1d
- * 11-November-2007 Jiri Slaby, Frank Seidel
- * - Big rework of multicard support by Jiri
- * - Major cleanups (semaphore to mutex, endianess, no major reservation)
- * - Optimizations
- *
- * Version 2.1c
- * 30-October-2007 Frank Seidel
- * - Completed multicard support
- * - Minor cleanups
- *
- * Version 2.1b
- * 07-August-2007 Frank Seidel
- * - Minor cleanups
- * - theoretical multicard support
- *
- * Version 2.1
- * 03-July-2006 Paul Hardwick
- *
- * - Stability Improvements. Incorporated spinlock wraps patch.
- * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room)
- * - using __devexit macro for tty
- *
- *
- * Version 2.0
- * 08-feb-2006 15:34:10:Ulf
- *
- * -Fixed issue when not waking up line disipine layer, could probably result
- * in better uplink performance for 2.4.
- *
- * -Fixed issue with big endian during initalization, now proper toggle flags
- * are handled between preloader and maincode.
- *
- * -Fixed flow control issue.
- *
- * -Added support for setting DTR.
- *
- * -For 2.4 kernels, removing temporary buffer that's not needed.
- *
- * -Reading CTS only for modem port (only port that supports it).
- *
- * -Return 0 in write_room instead of netative value, it's not handled in
- * upper layer.
- *
- * --------------------------------------------------------------------------
- * Version 1.0
- *
- * First version of driver, only tested with card of type F32_2.
- * Works fine with 2.4 and 2.6 kernels.
- * Driver also support big endian architecture.
- */
-
/* Enable this to have a lot of debug printouts */
#define DEBUG
@@ -143,8 +89,9 @@
/* Do we need this settable at runtime? */
static int debug = NOZOMI_DEBUG_LEVEL;
-#define D(lvl, args...) do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
- while (0)
+#define D(lvl, args...) do \
+ {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
+ while (0)
#define D_(lvl, args...) D(lvl, ##args)
/* These printouts are always printed */
@@ -273,13 +220,13 @@
/* Big endian */
struct toggles {
- unsigned enabled:5; /*
+ unsigned int enabled:5; /*
* Toggle fields are valid if enabled is 0,
* else A-channels must always be used.
*/
- unsigned diag_dl:1;
- unsigned mdm_dl:1;
- unsigned mdm_ul:1;
+ unsigned int diag_dl:1;
+ unsigned int mdm_dl:1;
+ unsigned int mdm_ul:1;
} __attribute__ ((packed));
/* Configuration table to read at startup of card */
@@ -320,19 +267,19 @@
/* This stores all control downlink flags */
struct ctrl_dl {
u8 port;
- unsigned reserved:4;
- unsigned CTS:1;
- unsigned RI:1;
- unsigned DCD:1;
- unsigned DSR:1;
+ unsigned int reserved:4;
+ unsigned int CTS:1;
+ unsigned int RI:1;
+ unsigned int DCD:1;
+ unsigned int DSR:1;
} __attribute__ ((packed));
/* This stores all control uplink flags */
struct ctrl_ul {
u8 port;
- unsigned reserved:6;
- unsigned RTS:1;
- unsigned DTR:1;
+ unsigned int reserved:6;
+ unsigned int RTS:1;
+ unsigned int DTR:1;
} __attribute__ ((packed));
#else
@@ -340,10 +287,10 @@
/* This represents the toggle information */
struct toggles {
- unsigned mdm_ul:1;
- unsigned mdm_dl:1;
- unsigned diag_dl:1;
- unsigned enabled:5; /*
+ unsigned int mdm_ul:1;
+ unsigned int mdm_dl:1;
+ unsigned int diag_dl:1;
+ unsigned int enabled:5; /*
* Toggle fields are valid if enabled is 0,
* else A-channels must always be used.
*/
@@ -379,19 +326,19 @@
/* This stores all control downlink flags */
struct ctrl_dl {
- unsigned DSR:1;
- unsigned DCD:1;
- unsigned RI:1;
- unsigned CTS:1;
- unsigned reserverd:4;
+ unsigned int DSR:1;
+ unsigned int DCD:1;
+ unsigned int RI:1;
+ unsigned int CTS:1;
+ unsigned int reserverd:4;
u8 port;
} __attribute__ ((packed));
/* This stores all control uplink flags */
struct ctrl_ul {
- unsigned DTR:1;
- unsigned RTS:1;
- unsigned reserved:6;
+ unsigned int DTR:1;
+ unsigned int RTS:1;
+ unsigned int reserved:6;
u8 port;
} __attribute__ ((packed));
#endif
@@ -448,7 +395,7 @@
} __attribute__ ((packed));
/* Global variables */
-static struct pci_device_id nozomi_pci_tbl[] = {
+static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = {
{PCI_DEVICE(VENDOR1, DEVICE1)},
{},
};
@@ -524,12 +471,12 @@
* -Optimize
* -Rewrite cleaner
*/
-static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf,
+static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf,
u32 size_bytes)
{
u32 i = 0;
u32 *ptr = (__force u32 *) mem_addr_start;
- u16 *buf16;
+ const u16 *buf16;
if (unlikely(!ptr || !buf))
return 0;
@@ -537,7 +484,7 @@
/* shortcut for extremely often used cases */
switch (size_bytes) {
case 2: /* 2 bytes */
- buf16 = (u16 *) buf;
+ buf16 = (const u16 *)buf;
writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
return 2;
break;
@@ -554,7 +501,7 @@
while (i < size_bytes) {
if (size_bytes - i == 2) {
/* 2 bytes */
- buf16 = (u16 *) buf;
+ buf16 = (const u16 *)buf;
writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
i += 2;
} else {
@@ -694,7 +641,7 @@
dc->config_table.ul_ctrl_len);
}
#else
-static __inline__ void dump_table(const struct nozomi *dc) { }
+static inline void dump_table(const struct nozomi *dc) { }
#endif
/*
@@ -776,8 +723,7 @@
/* Enable uplink interrupts */
static void enable_transmit_ul(enum port_type port, struct nozomi *dc)
{
- u16 mask[NOZOMI_MAX_PORTS] = \
- {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL};
+ static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL};
if (port < NOZOMI_MAX_PORTS) {
dc->last_ier |= mask[port];
@@ -790,8 +736,8 @@
/* Disable uplink interrupts */
static void disable_transmit_ul(enum port_type port, struct nozomi *dc)
{
- u16 mask[NOZOMI_MAX_PORTS] = \
- {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL};
+ static const u16 mask[] =
+ {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL};
if (port < NOZOMI_MAX_PORTS) {
dc->last_ier &= mask[port];
@@ -804,8 +750,7 @@
/* Enable downlink interrupts */
static void enable_transmit_dl(enum port_type port, struct nozomi *dc)
{
- u16 mask[NOZOMI_MAX_PORTS] = \
- {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL};
+ static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL};
if (port < NOZOMI_MAX_PORTS) {
dc->last_ier |= mask[port];
@@ -818,8 +763,8 @@
/* Disable downlink interrupts */
static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
{
- u16 mask[NOZOMI_MAX_PORTS] = \
- {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL};
+ static const u16 mask[] =
+ {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL};
if (port < NOZOMI_MAX_PORTS) {
dc->last_ier &= mask[port];
@@ -833,13 +778,13 @@
* Return 1 - send buffer to card and ack.
* Return 0 - don't ack, don't send buffer to card.
*/
-static int send_data(enum port_type index, struct nozomi *dc)
+static int send_data(enum port_type index, const struct nozomi *dc)
{
u32 size = 0;
- struct port *port = &dc->port[index];
- u8 toggle = port->toggle_ul;
+ const struct port *port = &dc->port[index];
+ const u8 toggle = port->toggle_ul;
void __iomem *addr = port->ul_addr[toggle];
- u32 ul_size = port->ul_size[toggle];
+ const u32 ul_size = port->ul_size[toggle];
struct tty_struct *tty = port->tty;
/* Get data from tty and place in buf for now */
@@ -1102,7 +1047,7 @@
}
/*
- * Handle donlink data, ports that are handled are modem and diagnostics
+ * Handle downlink data, ports that are handled are modem and diagnostics
* Return 1 - ok
* Return 0 - toggle fields are out of sync
*/
@@ -1359,20 +1304,20 @@
static ssize_t card_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+ const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
return sprintf(buf, "%d\n", dc->card_type);
}
-static DEVICE_ATTR(card_type, 0444, card_type_show, NULL);
+static DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL);
static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+ const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
return sprintf(buf, "%u\n", dc->open_ttys);
}
-static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL);
+static DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL);
static void make_sysfs_files(struct nozomi *dc)
{
@@ -1735,7 +1680,7 @@
{
struct port *port = tty->driver_data;
int room = 0;
- struct nozomi *dc = get_dc_by_tty(tty);
+ const struct nozomi *dc = get_dc_by_tty(tty);
if (!dc || !port)
return 0;
@@ -1755,9 +1700,9 @@
/* Gets io control parameters */
static int ntty_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct port *port = tty->driver_data;
- struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
- struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+ const struct port *port = tty->driver_data;
+ const struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
+ const struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
return (ctrl_ul->RTS ? TIOCM_RTS : 0) |
(ctrl_ul->DTR ? TIOCM_DTR : 0) |
@@ -1787,7 +1732,7 @@
static int ntty_cflags_changed(struct port *port, unsigned long flags,
struct async_icount *cprev)
{
- struct async_icount cnow = port->tty_icount;
+ const struct async_icount cnow = port->tty_icount;
int ret;
ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
@@ -1802,7 +1747,7 @@
static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
{
- struct async_icount cnow = port->tty_icount;
+ const struct async_icount cnow = port->tty_icount;
struct serial_icounter_struct icount;
icount.cts = cnow.cts;
@@ -1882,7 +1827,10 @@
/* just to discard single character writes */
static void ntty_put_char(struct tty_struct *tty, unsigned char c)
{
- /* FIXME !!! */
+ /*
+ * card does not react correct when we write single chars
+ * to the card, so we discard them
+ */
DBG2("PUT CHAR Function: %c", c);
}
@@ -1910,7 +1858,7 @@
return rval;
}
-static struct tty_operations tty_ops = {
+static const struct tty_operations tty_ops = {
.ioctl = ntty_ioctl,
.open = ntty_open,
.close = ntty_close,
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 02518da..454d732 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -308,7 +308,8 @@
return (wcrcf / wbrcf);
}
-static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s)
+static unsigned short io_read_num_rec_bytes(unsigned int iobase,
+ unsigned short *s)
{
unsigned short tmp;
@@ -426,7 +427,7 @@
static void set_cardparameter(struct cm4000_dev *dev)
{
int i;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->io.BasePort1;
u_int8_t stopbits = 0x02; /* ISO default */
DEBUGP(3, dev, "-> set_cardparameter\n");
@@ -459,7 +460,7 @@
unsigned short num_bytes_read;
unsigned char pts_reply[4];
ssize_t rc;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->io.BasePort1;
rc = 0;
@@ -610,7 +611,7 @@
return rc;
}
-static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev)
+static int io_detect_cm4000(unsigned int iobase, struct cm4000_dev *dev)
{
/* note: statemachine is assumed to be reset */
@@ -671,7 +672,7 @@
static void monitor_card(unsigned long p)
{
struct cm4000_dev *dev = (struct cm4000_dev *) p;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->io.BasePort1;
unsigned short s;
struct ptsreq ptsreq;
int i, atrc;
@@ -933,7 +934,7 @@
loff_t *ppos)
{
struct cm4000_dev *dev = filp->private_data;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->io.BasePort1;
ssize_t rc;
int i, j, k;
@@ -1054,7 +1055,7 @@
size_t count, loff_t *ppos)
{
struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->io.BasePort1;
unsigned short s;
unsigned char tmp;
unsigned char infolen;
@@ -1408,7 +1409,7 @@
unsigned long arg)
{
struct cm4000_dev *dev = filp->private_data;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->io.BasePort1;
struct pcmcia_device *link;
int size;
int rc;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 8caff0c..279ff50 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -57,6 +57,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
+#include <linux/synclink.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -87,8 +88,6 @@
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
static MGSL_PARAMS default_params = {
MGSL_MODE_HDLC, /* unsigned long mode */
0, /* unsigned char loopback; */
diff --git a/drivers/char/random.c b/drivers/char/random.c
index c511a83..f43c89f 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1039,6 +1039,7 @@
p += bytes;
add_entropy_words(r, buf, (bytes + 3) / 4);
+ cond_resched();
}
return 0;
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 102ece4..d130b87 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -47,6 +47,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/tty_flip.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
@@ -81,6 +82,8 @@
static struct tty_driver *riscom_driver;
+static DEFINE_SPINLOCK(riscom_lock);
+
static struct riscom_board rc_board[RC_NBOARD] = {
{
.base = RC_IOBASE1,
@@ -217,13 +220,14 @@
{
unsigned long flags;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
rc_wait_CCR(bp); /* Wait for CCR ready */
rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
- sti();
+ spin_unlock_irqrestore(&riscom_lock, flags);
msleep(50); /* Delay 0.05 sec */
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
rc_out(bp, CD180_GICR, 0); /* Clear all bits */
rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
@@ -234,7 +238,7 @@
rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
/* Main probing routine, also sets irq. */
@@ -812,9 +816,9 @@
}
port->xmit_buf = (unsigned char *) tmp;
}
-
- save_flags(flags); cli();
-
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
@@ -825,7 +829,7 @@
rc_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
return 0;
}
@@ -901,6 +905,7 @@
int retval;
int do_clocal = 0;
int CD;
+ unsigned long flags;
/*
* If the device is in the middle of being closed, then block
@@ -936,19 +941,26 @@
*/
retval = 0;
add_wait_queue(&port->open_wait, &wait);
- cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (!tty_hung_up_p(filp))
port->count--;
- sti();
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
port->blocked_open++;
while (1) {
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
rc_out(bp, CD180_CAR, port_No(port));
CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
rc_out(bp, CD180_MSVR, MSVR_RTS);
bp->DTR &= ~(1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
- sti();
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
@@ -1020,8 +1032,9 @@
if (!port || rc_paranoia_check(port, tty->name, "close"))
return;
-
- save_flags(flags); cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (tty_hung_up_p(filp))
goto out;
@@ -1088,7 +1101,9 @@
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
-out: restore_flags(flags);
+
+out:
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static int rc_write(struct tty_struct * tty,
@@ -1107,34 +1122,33 @@
if (!tty || !port->xmit_buf)
return 0;
- save_flags(flags);
while (1) {
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
SERIAL_XMIT_SIZE - port->xmit_head));
- if (c <= 0) {
- restore_flags(flags);
- break;
- }
+ if (c <= 0)
+ break; /* lock continues to be held */
memcpy(port->xmit_buf + port->xmit_head, buf, c);
port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
port->xmit_cnt += c;
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
buf += c;
count -= c;
total += c;
}
- cli();
if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
return total;
}
@@ -1150,7 +1164,7 @@
if (!tty || !port->xmit_buf)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
goto out;
@@ -1158,7 +1172,9 @@
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
-out: restore_flags(flags);
+
+out:
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_flush_chars(struct tty_struct * tty)
@@ -1173,11 +1189,13 @@
!port->xmit_buf)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->IER |= IER_TXRDY;
rc_out(port_Board(port), CD180_CAR, port_No(port));
rc_out(port_Board(port), CD180_IER, port->IER);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static int rc_write_room(struct tty_struct * tty)
@@ -1212,9 +1230,11 @@
if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
tty_wakeup(tty);
}
@@ -1231,11 +1251,15 @@
return -ENODEV;
bp = port_Board(port);
- save_flags(flags); cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
rc_out(bp, CD180_CAR, port_No(port));
status = rc_in(bp, CD180_MSVR);
result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
| ((status & MSVR_DTR) ? TIOCM_DTR : 0)
| ((status & MSVR_CD) ? TIOCM_CAR : 0)
@@ -1256,7 +1280,8 @@
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (set & TIOCM_RTS)
port->MSVR |= MSVR_RTS;
if (set & TIOCM_DTR)
@@ -1270,7 +1295,9 @@
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_MSVR, port->MSVR);
rc_out(bp, RC_DTR, bp->DTR);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
return 0;
}
@@ -1279,7 +1306,8 @@
struct riscom_board *bp = port_Board(port);
unsigned long flags;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->break_length = RISCOM_TPS / HZ * length;
port->COR2 |= COR2_ETC;
port->IER |= IER_TXRDY;
@@ -1289,7 +1317,8 @@
rc_wait_CCR(bp);
rc_out(bp, CD180_CCR, CCR_CORCHG2);
rc_wait_CCR(bp);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static inline int rc_set_serial_info(struct riscom_port * port,
@@ -1298,7 +1327,6 @@
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
int change_speed;
- unsigned long flags;
if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
return -EFAULT;
@@ -1332,9 +1360,11 @@
port->closing_wait = tmp.closing_wait;
}
if (change_speed) {
- save_flags(flags); cli();
+ unsigned long flags;
+
+ spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(bp, port);
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
return 0;
}
@@ -1414,17 +1444,19 @@
return;
bp = port_Board(port);
-
- save_flags(flags); cli();
+
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->MSVR &= ~MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
- if (I_IXOFF(tty)) {
+ if (I_IXOFF(tty)) {
rc_wait_CCR(bp);
rc_out(bp, CD180_CCR, CCR_SSCH2);
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_unthrottle(struct tty_struct * tty)
@@ -1438,7 +1470,8 @@
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->MSVR |= MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1447,7 +1480,8 @@
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_stop(struct tty_struct * tty)
@@ -1461,11 +1495,13 @@
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
static void rc_start(struct tty_struct * tty)
@@ -1479,13 +1515,15 @@
bp = port_Board(port);
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
/*
@@ -1537,9 +1575,9 @@
tty->termios->c_iflag == old_termios->c_iflag)
return;
- save_flags(flags); cli();
+ spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(port_Board(port), port);
- restore_flags(flags);
+ spin_unlock_irqrestore(&riscom_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -1627,11 +1665,12 @@
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&riscom_lock, flags);
+
tty_unregister_driver(riscom_driver);
put_tty_driver(riscom_driver);
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&riscom_lock, flags);
}
#ifndef MODULE
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 3c86914..4ba3aec 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -653,7 +653,7 @@
port->gs.closing_wait = 30 * HZ;
port->gs.rd = &a2232_real_driver;
#ifdef NEW_WRITE_LOCKING
- init_MUTEX(&(port->gs.port_write_mutex));
+ mutex_init(&(port->gs.port_write_mutex));
#endif
init_waitqueue_head(&port->gs.open_wait);
init_waitqueue_head(&port->gs.close_wait);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 905d1f5..ddc74d1 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -85,6 +85,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/ioctl.h>
+#include <linux/synclink.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -110,8 +111,6 @@
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
#define RCLRVALUE 0xffff
static MGSL_PARAMS default_params = {
@@ -1544,7 +1543,7 @@
/* mgsl_isr_misc()
*
- * Service a miscellaneos interrupt source.
+ * Service a miscellaneous interrupt source.
*
* Arguments: info pointer to device extension (instance data)
* Return Value: None
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 64e835f..1f954ac 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -73,6 +73,7 @@
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/hdlc.h>
+#include <linux/synclink.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -81,8 +82,6 @@
#include <asm/types.h>
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
#define SYNCLINK_GENERIC_HDLC 1
#else
@@ -2040,37 +2039,41 @@
tty_wakeup(tty);
}
-static void dsr_change(struct slgt_info *info)
+static void dsr_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT3) {
+ info->signals |= SerialSignal_DSR;
+ info->input_signal_events.dsr_up++;
+ } else {
+ info->signals &= ~SerialSignal_DSR;
+ info->input_signal_events.dsr_down++;
+ }
DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_DSR);
return;
}
info->icount.dsr++;
- if (info->signals & SerialSignal_DSR)
- info->input_signal_events.dsr_up++;
- else
- info->input_signal_events.dsr_down++;
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
}
-static void cts_change(struct slgt_info *info)
+static void cts_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT2) {
+ info->signals |= SerialSignal_CTS;
+ info->input_signal_events.cts_up++;
+ } else {
+ info->signals &= ~SerialSignal_CTS;
+ info->input_signal_events.cts_down++;
+ }
DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_CTS);
return;
}
info->icount.cts++;
- if (info->signals & SerialSignal_CTS)
- info->input_signal_events.cts_up++;
- else
- info->input_signal_events.cts_down++;
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
@@ -2091,20 +2094,21 @@
}
}
-static void dcd_change(struct slgt_info *info)
+static void dcd_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT1) {
+ info->signals |= SerialSignal_DCD;
+ info->input_signal_events.dcd_up++;
+ } else {
+ info->signals &= ~SerialSignal_DCD;
+ info->input_signal_events.dcd_down++;
+ }
DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_DCD);
return;
}
info->icount.dcd++;
- if (info->signals & SerialSignal_DCD) {
- info->input_signal_events.dcd_up++;
- } else {
- info->input_signal_events.dcd_down++;
- }
#if SYNCLINK_GENERIC_HDLC
if (info->netcount) {
if (info->signals & SerialSignal_DCD)
@@ -2127,20 +2131,21 @@
}
}
-static void ri_change(struct slgt_info *info)
+static void ri_change(struct slgt_info *info, unsigned short status)
{
- get_signals(info);
+ if (status & BIT0) {
+ info->signals |= SerialSignal_RI;
+ info->input_signal_events.ri_up++;
+ } else {
+ info->signals &= ~SerialSignal_RI;
+ info->input_signal_events.ri_down++;
+ }
DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
slgt_irq_off(info, IRQ_RI);
return;
}
- info->icount.dcd++;
- if (info->signals & SerialSignal_RI) {
- info->input_signal_events.ri_up++;
- } else {
- info->input_signal_events.ri_down++;
- }
+ info->icount.rng++;
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
@@ -2191,13 +2196,13 @@
}
if (status & IRQ_DSR)
- dsr_change(info);
+ dsr_change(info, status);
if (status & IRQ_CTS)
- cts_change(info);
+ cts_change(info, status);
if (status & IRQ_DCD)
- dcd_change(info);
+ dcd_change(info, status);
if (status & IRQ_RI)
- ri_change(info);
+ ri_change(info, status);
}
static void isr_rdma(struct slgt_info *info)
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index c63013b..f3e7807 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -66,6 +66,7 @@
#include <linux/termios.h>
#include <linux/workqueue.h>
#include <linux/hdlc.h>
+#include <linux/synclink.h>
#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE))
#define SYNCLINK_GENERIC_HDLC 1
@@ -80,8 +81,6 @@
#include <asm/uaccess.h>
-#include "linux/synclink.h"
-
static MGSL_PARAMS default_params = {
MGSL_MODE_HDLC, /* unsigned long mode */
0, /* unsigned char loopback; */
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index 5422f99..ce5ebe3 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -505,7 +505,7 @@
if (tosh_probe())
return -ENODEV;
- printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n");
+ printk(KERN_INFO "Toshiba System Management Mode driver v" TOSH_VERSION "\n");
/* set the port to use for Fn status if not specified as a parameter */
if (tosh_fn==0x00)
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index c88424a..a5d8bcb 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1031,18 +1031,13 @@
spin_unlock(&driver_lock);
- dev_set_drvdata(dev, NULL);
misc_deregister(&chip->vendor.miscdev);
- kfree(chip->vendor.miscdev.name);
sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
tpm_bios_log_teardown(chip->bios_dir);
- clear_bit(chip->dev_num, dev_mask);
-
- kfree(chip);
-
- put_device(dev);
+ /* write it this way to be explicit (chip->dev == dev) */
+ put_device(chip->dev);
}
EXPORT_SYMBOL_GPL(tpm_remove_hardware);
@@ -1083,6 +1078,26 @@
EXPORT_SYMBOL_GPL(tpm_pm_resume);
/*
+ * Once all references to platform device are down to 0,
+ * release all allocated structures.
+ * In case vendor provided release function,
+ * call it too.
+ */
+static void tpm_dev_release(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ if (chip->vendor.release)
+ chip->vendor.release(dev);
+
+ chip->release(dev);
+
+ clear_bit(chip->dev_num, dev_mask);
+ kfree(chip->vendor.miscdev.name);
+ kfree(chip);
+}
+
+/*
* Called from tpm_<specific>.c probe function only for devices
* the driver has determined it should claim. Prior to calling
* this function the specific probe function has called pci_enable_device
@@ -1136,23 +1151,21 @@
chip->vendor.miscdev.parent = dev;
chip->dev = get_device(dev);
+ chip->release = dev->release;
+ dev->release = tpm_dev_release;
+ dev_set_drvdata(dev, chip);
if (misc_register(&chip->vendor.miscdev)) {
dev_err(chip->dev,
"unable to misc_register %s, minor %d\n",
chip->vendor.miscdev.name,
chip->vendor.miscdev.minor);
- put_device(dev);
- clear_bit(chip->dev_num, dev_mask);
- kfree(chip);
- kfree(devname);
+ put_device(chip->dev);
return NULL;
}
spin_lock(&driver_lock);
- dev_set_drvdata(dev, chip);
-
list_add(&chip->list, &tpm_chip_list);
spin_unlock(&driver_lock);
@@ -1160,10 +1173,7 @@
if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
list_del(&chip->list);
misc_deregister(&chip->vendor.miscdev);
- put_device(dev);
- clear_bit(chip->dev_num, dev_mask);
- kfree(chip);
- kfree(devname);
+ put_device(chip->dev);
return NULL;
}
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index d15ccdd..e885148 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -74,6 +74,7 @@
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
u8 (*status) (struct tpm_chip *);
+ void (*release) (struct device *);
struct miscdevice miscdev;
struct attribute_group *attr_group;
struct list_head list;
@@ -106,6 +107,7 @@
struct dentry **bios_dir;
struct list_head list;
+ void (*release) (struct device *);
};
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 967002a..726ee8a 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -611,7 +611,7 @@
}
}
-static struct pnp_driver tpm_inf_pnp = {
+static struct pnp_driver tpm_inf_pnp_driver = {
.name = "tpm_inf_pnp",
.driver = {
.owner = THIS_MODULE,
@@ -625,12 +625,12 @@
static int __init init_inf(void)
{
- return pnp_register_driver(&tpm_inf_pnp);
+ return pnp_register_driver(&tpm_inf_pnp_driver);
}
static void __exit cleanup_inf(void)
{
- pnp_unregister_driver(&tpm_inf_pnp);
+ pnp_unregister_driver(&tpm_inf_pnp_driver);
}
module_init(init_inf);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index f36fecd..79c86c4 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -138,7 +138,7 @@
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
extern int pty_limit; /* Config limit on Unix98 ptys */
static DEFINE_IDR(allocated_ptys);
-static DECLARE_MUTEX(allocated_ptys_lock);
+static DEFINE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
@@ -2571,9 +2571,9 @@
#ifdef CONFIG_UNIX98_PTYS
/* Make this pty number available for reallocation */
if (devpts) {
- down(&allocated_ptys_lock);
+ mutex_lock(&allocated_ptys_lock);
idr_remove(&allocated_ptys, idx);
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
}
#endif
@@ -2737,24 +2737,24 @@
nonseekable_open(inode, filp);
/* find a device that is not in use. */
- down(&allocated_ptys_lock);
+ mutex_lock(&allocated_ptys_lock);
if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
return -ENOMEM;
}
idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
if (idr_ret < 0) {
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
if (idr_ret == -EAGAIN)
return -ENOMEM;
return -EIO;
}
if (index >= pty_limit) {
idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
return -EIO;
}
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
mutex_lock(&tty_mutex);
retval = init_dev(ptm_driver, index, &tty);
@@ -2781,9 +2781,9 @@
release_dev(filp);
return retval;
out:
- down(&allocated_ptys_lock);
+ mutex_lock(&allocated_ptys_lock);
idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
+ mutex_unlock(&allocated_ptys_lock);
return retval;
}
#endif
@@ -3721,7 +3721,6 @@
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
- init_MUTEX(&tty->buf.pty_sem);
mutex_init(&tty->termios_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
@@ -4048,10 +4047,6 @@
}
}
-#ifdef CONFIG_VT
-extern int vty_init(void);
-#endif
-
static int __init tty_class_init(void)
{
tty_class = class_create(THIS_MODULE, "tty");
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index e34da5c..dc17fe3 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -158,13 +158,13 @@
/* Find the input queue. */
/* FIXME: This is why we want to wean off hvc: we do nothing
* when input comes in. */
- in_vq = vdev->config->find_vq(vdev, NULL);
+ in_vq = vdev->config->find_vq(vdev, 0, NULL);
if (IS_ERR(in_vq)) {
err = PTR_ERR(in_vq);
goto free;
}
- out_vq = vdev->config->find_vq(vdev, NULL);
+ out_vq = vdev->config->find_vq(vdev, 1, NULL);
if (IS_ERR(out_vq)) {
err = PTR_ERR(out_vq);
goto free_in_vq;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 7a5badf..367be91 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2400,13 +2400,15 @@
{
struct vc_data *vc = vc_cons[fg_console].d;
unsigned char c;
- static unsigned long printing;
+ static DEFINE_SPINLOCK(printing_lock);
const ushort *start;
ushort cnt = 0;
ushort myx;
/* console busy or not yet initialized */
- if (!printable || test_and_set_bit(0, &printing))
+ if (!printable)
+ return;
+ if (!spin_trylock(&printing_lock))
return;
if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
@@ -2481,7 +2483,7 @@
notify_update(vc);
quit:
- clear_bit(0, &printing);
+ spin_unlock(&printing_lock);
}
static struct tty_driver *vt_console_device(struct console *c, int *index)
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 3bed412..7dbc4a8 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -1,13 +1,13 @@
config CPU_IDLE
bool "CPU idle PM support"
+ default ACPI
help
CPU idle is a generic framework for supporting software-controlled
idle processor power management. It includes modular cross-platform
governors that can be swapped during runtime.
- If you're using a mobile platform that supports CPU idle PM (e.g.
- an ACPI-capable notebook), you should say Y here.
+ If you're using an ACPI-enabled platform, you should say Y here.
config CPU_IDLE_GOV_LADDER
bool
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index d2fabe7..d868d73 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -12,9 +12,10 @@
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/notifier.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include <linux/cpu.h>
#include <linux/cpuidle.h>
+#include <linux/ktime.h>
#include "cpuidle.h"
@@ -82,7 +83,7 @@
{
if (enabled_devices && (pm_idle != pm_idle_old)) {
pm_idle = pm_idle_old;
- cpu_idle_wait();
+ cpuidle_kick_cpus();
}
}
@@ -180,6 +181,44 @@
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+
+ t1 = ktime_get();
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+
+ t2 = ktime_get();
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ ret = (int) diff;
+ return ret;
+}
+
+static void poll_idle_init(struct cpuidle_device *dev)
+{
+ struct cpuidle_state *state = &dev->states[0];
+
+ cpuidle_set_statedata(state, NULL);
+
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)");
+ state->exit_latency = 0;
+ state->target_residency = 0;
+ state->power_usage = -1;
+ state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID;
+ state->enter = poll_idle;
+}
+#else
+static void poll_idle_init(struct cpuidle_device *dev) {}
+#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
+
/**
* cpuidle_register_device - registers a CPU's idle PM feature
* @dev: the cpu
@@ -198,6 +237,8 @@
mutex_lock(&cpuidle_lock);
+ poll_idle_init(dev);
+
per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);
if ((ret = cpuidle_add_sysfs(sys_dev))) {
@@ -265,7 +306,10 @@
.notifier_call = cpuidle_latency_notify,
};
-#define latency_notifier_init(x) do { register_latency_notifier(x); } while (0)
+static inline void latency_notifier_init(struct notifier_block *n)
+{
+ pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n);
+}
#else /* CONFIG_SMP */
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index eb666ec..ba7b9a6 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/cpuidle.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include <linux/moduleparam.h>
#include <linux/jiffies.h>
@@ -81,7 +81,8 @@
/* consider promotion */
if (last_idx < dev->state_count - 1 &&
last_residency > last_state->threshold.promotion_time &&
- dev->states[last_idx + 1].exit_latency <= system_latency_constraint()) {
+ dev->states[last_idx + 1].exit_latency <=
+ pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
last_state->stats.promotion_count++;
last_state->stats.demotion_count = 0;
if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 299d45c..78d77c5 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -8,7 +8,7 @@
#include <linux/kernel.h>
#include <linux/cpuidle.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include <linux/time.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
@@ -48,7 +48,7 @@
break;
if (s->target_residency > data->predicted_us)
break;
- if (s->exit_latency > system_latency_constraint())
+ if (s->exit_latency > pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY))
break;
}
diff --git a/drivers/dio/dio-driver.c b/drivers/dio/dio-driver.c
index e4c48e3..8cd8507 100644
--- a/drivers/dio/dio-driver.c
+++ b/drivers/dio/dio-driver.c
@@ -15,16 +15,15 @@
#include <linux/dio.h>
- /**
- * dio_match_device - Tell if a DIO device structure has a matching
- * DIO device id structure
- * @ids: array of DIO device id structures to search in
- * @dev: the DIO device structure to match against
- *
- * Used by a driver to check whether a DIO device present in the
- * system is in its list of supported devices. Returns the matching
- * dio_device_id structure or %NULL if there is no match.
- */
+/**
+ * dio_match_device - Tell if a DIO device structure has a matching DIO device id structure
+ * @ids: array of DIO device id structures to search in
+ * @d: the DIO device structure to match against
+ *
+ * Used by a driver to check whether a DIO device present in the
+ * system is in its list of supported devices. Returns the matching
+ * dio_device_id structure or %NULL if there is no match.
+ */
const struct dio_device_id *
dio_match_device(const struct dio_device_id *ids,
@@ -66,13 +65,13 @@
}
- /**
- * dio_register_driver - register a new DIO driver
- * @drv: the driver structure to register
- *
- * Adds the driver structure to the list of registered drivers
- * Returns zero or a negative error value.
- */
+/**
+ * dio_register_driver - register a new DIO driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns zero or a negative error value.
+ */
int dio_register_driver(struct dio_driver *drv)
{
@@ -85,15 +84,15 @@
}
- /**
- * dio_unregister_driver - unregister a DIO driver
- * @drv: the driver structure to unregister
- *
- * Deletes the driver structure from the list of registered DIO drivers,
- * gives it a chance to clean up by calling its remove() function for
- * each device it was responsible for, and marks those devices as
- * driverless.
- */
+/**
+ * dio_unregister_driver - unregister a DIO driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered DIO drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
void dio_unregister_driver(struct dio_driver *drv)
{
@@ -101,16 +100,15 @@
}
- /**
- * dio_bus_match - Tell if a DIO device structure has a matching DIO
- * device id structure
- * @ids: array of DIO device id structures to search in
- * @dev: the DIO device structure to match against
- *
- * Used by a driver to check whether a DIO device present in the
- * system is in its list of supported devices. Returns the matching
- * dio_device_id structure or %NULL if there is no match.
- */
+/**
+ * dio_bus_match - Tell if a DIO device structure has a matching DIO device id structure
+ * @dev: the DIO device structure to match against
+ * @drv: the &device_driver that points to the array of DIO device id structures to search
+ *
+ * Used by a driver to check whether a DIO device present in the
+ * system is in its list of supported devices. Returns the matching
+ * dio_device_id structure or %NULL if there is no match.
+ */
static int dio_bus_match(struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c
index 17502d6..07f274f 100644
--- a/drivers/dio/dio.c
+++ b/drivers/dio/dio.c
@@ -88,8 +88,6 @@
#undef DIONAME
#undef DIOFBNAME
-#define NUMNAMES (sizeof(names) / sizeof(struct dioname))
-
static const char *unknowndioname
= "unknown DIO board -- please email <linux-m68k@lists.linux-m68k.org>!";
@@ -97,7 +95,7 @@
{
/* return pointer to a constant string describing the board with given ID */
unsigned int i;
- for (i = 0; i < NUMNAMES; i++)
+ for (i = 0; i < ARRAY_SIZE(names); i++)
if (names[i].id == id)
return names[i].name;
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index c46b7c2..a703def 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -5,6 +5,7 @@
menuconfig DMADEVICES
bool "DMA Engine support"
depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
+ depends on !HIGHMEM64G
help
DMA engines can do asynchronous data transfers without
involving the host CPU. Currently, this framework can be
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index bcf52df..2996523 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -473,20 +473,22 @@
{
struct dma_device *dev = chan->device;
struct dma_async_tx_descriptor *tx;
- dma_addr_t addr;
+ dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
int cpu;
- tx = dev->device_prep_dma_memcpy(chan, len, 0);
- if (!tx)
+ dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
+ dma_dest = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
+ tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+ if (!tx) {
+ dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
+ dma_unmap_single(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
return -ENOMEM;
+ }
tx->ack = 1;
tx->callback = NULL;
- addr = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
- tx->tx_set_src(addr, tx, 0);
- addr = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
- tx->tx_set_dest(addr, tx, 0);
cookie = tx->tx_submit(tx);
cpu = get_cpu();
@@ -517,20 +519,22 @@
{
struct dma_device *dev = chan->device;
struct dma_async_tx_descriptor *tx;
- dma_addr_t addr;
+ dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
int cpu;
- tx = dev->device_prep_dma_memcpy(chan, len, 0);
- if (!tx)
+ dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
+ dma_dest = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
+ tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+ if (!tx) {
+ dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
+ dma_unmap_page(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
return -ENOMEM;
+ }
tx->ack = 1;
tx->callback = NULL;
- addr = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
- tx->tx_set_src(addr, tx, 0);
- addr = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
- tx->tx_set_dest(addr, tx, 0);
cookie = tx->tx_submit(tx);
cpu = get_cpu();
@@ -563,20 +567,23 @@
{
struct dma_device *dev = chan->device;
struct dma_async_tx_descriptor *tx;
- dma_addr_t addr;
+ dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
int cpu;
- tx = dev->device_prep_dma_memcpy(chan, len, 0);
- if (!tx)
+ dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
+ dma_dest = dma_map_page(dev->dev, dest_pg, dest_off, len,
+ DMA_FROM_DEVICE);
+ tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+ if (!tx) {
+ dma_unmap_page(dev->dev, dma_src, len, DMA_TO_DEVICE);
+ dma_unmap_page(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
return -ENOMEM;
+ }
tx->ack = 1;
tx->callback = NULL;
- addr = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
- tx->tx_set_src(addr, tx, 0);
- addr = dma_map_page(dev->dev, dest_pg, dest_off, len, DMA_FROM_DEVICE);
- tx->tx_set_dest(addr, tx, 0);
cookie = tx->tx_submit(tx);
cpu = get_cpu();
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
index 45e7b46..dff38ac 100644
--- a/drivers/dma/ioat_dma.c
+++ b/drivers/dma/ioat_dma.c
@@ -159,20 +159,6 @@
return device->common.chancnt;
}
-static void ioat_set_src(dma_addr_t addr,
- struct dma_async_tx_descriptor *tx,
- int index)
-{
- tx_to_ioat_desc(tx)->src = addr;
-}
-
-static void ioat_set_dest(dma_addr_t addr,
- struct dma_async_tx_descriptor *tx,
- int index)
-{
- tx_to_ioat_desc(tx)->dst = addr;
-}
-
/**
* ioat_dma_memcpy_issue_pending - push potentially unrecognized appended
* descriptors to hw
@@ -415,8 +401,6 @@
memset(desc, 0, sizeof(*desc));
dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
- desc_sw->async_tx.tx_set_src = ioat_set_src;
- desc_sw->async_tx.tx_set_dest = ioat_set_dest;
switch (ioat_chan->device->version) {
case IOAT_VER_1_2:
desc_sw->async_tx.tx_submit = ioat1_tx_submit;
@@ -714,8 +698,10 @@
static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
struct dma_chan *chan,
+ dma_addr_t dma_dest,
+ dma_addr_t dma_src,
size_t len,
- int int_en)
+ unsigned long flags)
{
struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
struct ioat_desc_sw *new;
@@ -726,6 +712,8 @@
if (new) {
new->len = len;
+ new->dst = dma_dest;
+ new->src = dma_src;
return &new->async_tx;
} else
return NULL;
@@ -733,8 +721,10 @@
static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
struct dma_chan *chan,
+ dma_addr_t dma_dest,
+ dma_addr_t dma_src,
size_t len,
- int int_en)
+ unsigned long flags)
{
struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
struct ioat_desc_sw *new;
@@ -749,6 +739,8 @@
if (new) {
new->len = len;
+ new->dst = dma_dest;
+ new->src = dma_src;
return &new->async_tx;
} else
return NULL;
@@ -1045,7 +1037,7 @@
u8 *dest;
struct dma_chan *dma_chan;
struct dma_async_tx_descriptor *tx;
- dma_addr_t addr;
+ dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
int err = 0;
@@ -1073,7 +1065,12 @@
goto out;
}
- tx = device->common.device_prep_dma_memcpy(dma_chan, IOAT_TEST_SIZE, 0);
+ dma_src = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
+ DMA_TO_DEVICE);
+ dma_dest = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
+ DMA_FROM_DEVICE);
+ tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src,
+ IOAT_TEST_SIZE, 0);
if (!tx) {
dev_err(&device->pdev->dev,
"Self-test prep failed, disabling\n");
@@ -1082,12 +1079,6 @@
}
async_tx_ack(tx);
- addr = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
- DMA_TO_DEVICE);
- tx->tx_set_src(addr, tx, 0);
- addr = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
- DMA_FROM_DEVICE);
- tx->tx_set_dest(addr, tx, 0);
tx->callback = ioat_dma_test_callback;
tx->callback_param = (void *)0x8086;
cookie = tx->tx_submit(tx);
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index e5c62b7..3986d54 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -284,7 +284,7 @@
int slots_per_op)
{
struct iop_adma_desc_slot *iter, *_iter, *alloc_start = NULL;
- struct list_head chain = LIST_HEAD_INIT(chain);
+ LIST_HEAD(chain);
int slots_found, retry = 0;
/* start search from the last allocated descrtiptor
@@ -443,17 +443,6 @@
return cookie;
}
-static void
-iop_adma_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
- int index)
-{
- struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
- struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan);
-
- /* to do: support transfers lengths > IOP_ADMA_MAX_BYTE_COUNT */
- iop_desc_set_dest_addr(sw_desc->group_head, iop_chan, addr);
-}
-
static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan);
static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan);
@@ -486,7 +475,6 @@
dma_async_tx_descriptor_init(&slot->async_tx, chan);
slot->async_tx.tx_submit = iop_adma_tx_submit;
- slot->async_tx.tx_set_dest = iop_adma_set_dest;
INIT_LIST_HEAD(&slot->chain_node);
INIT_LIST_HEAD(&slot->slot_node);
INIT_LIST_HEAD(&slot->async_tx.tx_list);
@@ -547,18 +535,9 @@
return sw_desc ? &sw_desc->async_tx : NULL;
}
-static void
-iop_adma_memcpy_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
- int index)
-{
- struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
- struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
- iop_desc_set_memcpy_src_addr(grp_start, addr);
-}
-
static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
+iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
+ dma_addr_t dma_src, size_t len, unsigned long flags)
{
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -576,11 +555,12 @@
sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
if (sw_desc) {
grp_start = sw_desc->group_head;
- iop_desc_init_memcpy(grp_start, int_en);
+ iop_desc_init_memcpy(grp_start, flags);
iop_desc_set_byte_count(grp_start, iop_chan, len);
+ iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
+ iop_desc_set_memcpy_src_addr(grp_start, dma_src);
sw_desc->unmap_src_cnt = 1;
sw_desc->unmap_len = len;
- sw_desc->async_tx.tx_set_src = iop_adma_memcpy_set_src;
}
spin_unlock_bh(&iop_chan->lock);
@@ -588,8 +568,8 @@
}
static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
- int int_en)
+iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
+ int value, size_t len, unsigned long flags)
{
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -607,9 +587,10 @@
sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
if (sw_desc) {
grp_start = sw_desc->group_head;
- iop_desc_init_memset(grp_start, int_en);
+ iop_desc_init_memset(grp_start, flags);
iop_desc_set_byte_count(grp_start, iop_chan, len);
iop_desc_set_block_fill_val(grp_start, value);
+ iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
sw_desc->unmap_src_cnt = 1;
sw_desc->unmap_len = len;
}
@@ -618,19 +599,10 @@
return sw_desc ? &sw_desc->async_tx : NULL;
}
-static void
-iop_adma_xor_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
- int index)
-{
- struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
- struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
- iop_desc_set_xor_src_addr(grp_start, index, addr);
-}
-
static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_xor(struct dma_chan *chan, unsigned int src_cnt, size_t len,
- int int_en)
+iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
+ dma_addr_t *dma_src, unsigned int src_cnt, size_t len,
+ unsigned long flags)
{
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -641,39 +613,32 @@
BUG_ON(unlikely(len > IOP_ADMA_XOR_MAX_BYTE_COUNT));
dev_dbg(iop_chan->device->common.dev,
- "%s src_cnt: %d len: %u int_en: %d\n",
- __FUNCTION__, src_cnt, len, int_en);
+ "%s src_cnt: %d len: %u flags: %lx\n",
+ __FUNCTION__, src_cnt, len, flags);
spin_lock_bh(&iop_chan->lock);
slot_cnt = iop_chan_xor_slot_count(len, src_cnt, &slots_per_op);
sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
if (sw_desc) {
grp_start = sw_desc->group_head;
- iop_desc_init_xor(grp_start, src_cnt, int_en);
+ iop_desc_init_xor(grp_start, src_cnt, flags);
iop_desc_set_byte_count(grp_start, iop_chan, len);
+ iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
sw_desc->unmap_src_cnt = src_cnt;
sw_desc->unmap_len = len;
- sw_desc->async_tx.tx_set_src = iop_adma_xor_set_src;
+ while (src_cnt--)
+ iop_desc_set_xor_src_addr(grp_start, src_cnt,
+ dma_src[src_cnt]);
}
spin_unlock_bh(&iop_chan->lock);
return sw_desc ? &sw_desc->async_tx : NULL;
}
-static void
-iop_adma_xor_zero_sum_set_src(dma_addr_t addr,
- struct dma_async_tx_descriptor *tx,
- int index)
-{
- struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
- struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
- iop_desc_set_zero_sum_src_addr(grp_start, index, addr);
-}
-
static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_zero_sum(struct dma_chan *chan, unsigned int src_cnt,
- size_t len, u32 *result, int int_en)
+iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src,
+ unsigned int src_cnt, size_t len, u32 *result,
+ unsigned long flags)
{
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -690,14 +655,16 @@
sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
if (sw_desc) {
grp_start = sw_desc->group_head;
- iop_desc_init_zero_sum(grp_start, src_cnt, int_en);
+ iop_desc_init_zero_sum(grp_start, src_cnt, flags);
iop_desc_set_zero_sum_byte_count(grp_start, len);
grp_start->xor_check_result = result;
pr_debug("\t%s: grp_start->xor_check_result: %p\n",
__FUNCTION__, grp_start->xor_check_result);
sw_desc->unmap_src_cnt = src_cnt;
sw_desc->unmap_len = len;
- sw_desc->async_tx.tx_set_src = iop_adma_xor_zero_sum_set_src;
+ while (src_cnt--)
+ iop_desc_set_zero_sum_src_addr(grp_start, src_cnt,
+ dma_src[src_cnt]);
}
spin_unlock_bh(&iop_chan->lock);
@@ -882,13 +849,12 @@
goto out;
}
- tx = iop_adma_prep_dma_memcpy(dma_chan, IOP_ADMA_TEST_SIZE, 1);
dest_dma = dma_map_single(dma_chan->device->dev, dest,
IOP_ADMA_TEST_SIZE, DMA_FROM_DEVICE);
- iop_adma_set_dest(dest_dma, tx, 0);
src_dma = dma_map_single(dma_chan->device->dev, src,
IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE);
- iop_adma_memcpy_set_src(src_dma, tx, 0);
+ tx = iop_adma_prep_dma_memcpy(dma_chan, dest_dma, src_dma,
+ IOP_ADMA_TEST_SIZE, 1);
cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan);
@@ -929,6 +895,7 @@
struct page *dest;
struct page *xor_srcs[IOP_ADMA_NUM_SRC_TEST];
struct page *zero_sum_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
+ dma_addr_t dma_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
dma_addr_t dma_addr, dest_dma;
struct dma_async_tx_descriptor *tx;
struct dma_chan *dma_chan;
@@ -981,17 +948,13 @@
}
/* test xor */
- tx = iop_adma_prep_dma_xor(dma_chan, IOP_ADMA_NUM_SRC_TEST,
- PAGE_SIZE, 1);
dest_dma = dma_map_page(dma_chan->device->dev, dest, 0,
PAGE_SIZE, DMA_FROM_DEVICE);
- iop_adma_set_dest(dest_dma, tx, 0);
-
- for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++) {
- dma_addr = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0,
- PAGE_SIZE, DMA_TO_DEVICE);
- iop_adma_xor_set_src(dma_addr, tx, i);
- }
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++)
+ dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i],
+ 0, PAGE_SIZE, DMA_TO_DEVICE);
+ tx = iop_adma_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
+ IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE, 1);
cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan);
@@ -1032,13 +995,13 @@
zero_sum_result = 1;
- tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
- PAGE_SIZE, &zero_sum_result, 1);
- for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
- dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
- 0, PAGE_SIZE, DMA_TO_DEVICE);
- iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
- }
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
+ dma_srcs[i] = dma_map_page(dma_chan->device->dev,
+ zero_sum_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
+ IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
+ &zero_sum_result, 1);
cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan);
@@ -1060,10 +1023,9 @@
}
/* test memset */
- tx = iop_adma_prep_dma_memset(dma_chan, 0, PAGE_SIZE, 1);
dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
PAGE_SIZE, DMA_FROM_DEVICE);
- iop_adma_set_dest(dma_addr, tx, 0);
+ tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE, 1);
cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan);
@@ -1089,13 +1051,13 @@
/* test for non-zero parity sum */
zero_sum_result = 0;
- tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
- PAGE_SIZE, &zero_sum_result, 1);
- for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
- dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
- 0, PAGE_SIZE, DMA_TO_DEVICE);
- iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
- }
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
+ dma_srcs[i] = dma_map_page(dma_chan->device->dev,
+ zero_sum_srcs[i], 0, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
+ IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
+ &zero_sum_result, 1);
cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan);
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index 5dee9f50..e0b47b7 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -73,7 +73,7 @@
*
* Last action on the pci control structure.
*
- * call the remove sysfs informaton, which will unregister
+ * call the remove sysfs information, which will unregister
* this control struct's kobj. When that kobj's ref count
* goes to zero, its release function will be call and then
* kfree() the memory.
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index a1f24c4..5a85201 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -351,7 +351,7 @@
u16 b1_ambpresent0; /* Branch 1, Channel 8 */
u16 b1_ambpresent1; /* Branch 1, Channel 1 */
- /* DIMM infomation matrix, allocating architecture maximums */
+ /* DIMM information matrix, allocating architecture maximums */
struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
/* Actual values for this controller */
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 18cdcb3..1636806 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -658,4 +658,5 @@
MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR("Dell Inc.");
MODULE_LICENSE("GPL");
-
+/* Any System or BIOS claiming to be by Dell */
+MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*");
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 313c99c..e880d6c 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/device.h>
-#include <linux/autoconf.h>
struct dmi_device_attribute{
struct device_attribute dev_attr;
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 9008ed5..e0bade7 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -489,12 +489,3 @@
return year;
}
-
-/**
- * dmi_get_slot - return dmi_ident[slot]
- * @slot: index into dmi_ident[]
- */
-char *dmi_get_slot(int slot)
-{
- return(dmi_ident[slot]);
-}
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index d168223..74401198 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -11,7 +11,7 @@
*
* This code takes information provided by BIOS EDD calls
* fn41 - Check Extensions Present and
- * fn48 - Get Device Parametes with EDD extensions
+ * fn48 - Get Device Parameters with EDD extensions
* made in setup.S, copied to safe structures in setup.c,
* and presents it in sysfs.
*
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
new file mode 100644
index 0000000..bbd2834
--- /dev/null
+++ b/drivers/gpio/Kconfig
@@ -0,0 +1,73 @@
+#
+# GPIO infrastructure and expanders
+#
+
+config HAVE_GPIO_LIB
+ bool
+ help
+ Platforms select gpiolib if they use this infrastructure
+ for all their GPIOs, usually starting with ones integrated
+ into SOC processors.
+
+menu "GPIO Support"
+ depends on HAVE_GPIO_LIB
+
+config DEBUG_GPIO
+ bool "Debug GPIO calls"
+ depends on DEBUG_KERNEL
+ help
+ Say Y here to add some extra checks and diagnostics to GPIO calls.
+ The checks help ensure that GPIOs have been properly initialized
+ before they are used and that sleeping calls aren not made from
+ nonsleeping contexts. They can make bitbanged serial protocols
+ slower. The diagnostics help catch the type of setup errors
+ that are most common when setting up new platforms or boards.
+
+# put expanders in the right section, in alphabetical order
+
+comment "I2C GPIO expanders:"
+
+config GPIO_PCA953X
+ tristate "PCA953x I/O ports"
+ depends on I2C
+ help
+ Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
+ PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
+ (16-bit) I/O ports. These parts are made by NXP and TI.
+
+ This driver can also be built as a module. If so, the module
+ will be called pca953x.
+
+config GPIO_PCF857X
+ tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders"
+ depends on I2C
+ help
+ Say yes here to provide access to most "quasi-bidirectional" I2C
+ GPIO expanders used for additional digital outputs or inputs.
+ Most of these parts are from NXP, though TI is a second source for
+ some of them. Compatible models include:
+
+ 8 bits: pcf8574, pcf8574a, pca8574, pca8574a,
+ pca9670, pca9672, pca9674, pca9674a
+
+ 16 bits: pcf8575, pcf8575c, pca8575,
+ pca9671, pca9673, pca9675
+
+ Your board setup code will need to declare the expanders in
+ use, and assign numbers to the GPIOs they expose. Those GPIOs
+ can then be used from drivers and other kernel code, just like
+ other GPIOs, but only accessible from task contexts.
+
+ This driver provides an in-kernel interface to those GPIOs using
+ platform-neutral GPIO calls.
+
+comment "SPI GPIO expanders:"
+
+config GPIO_MCP23S08
+ tristate "Microchip MCP23S08 I/O expander"
+ depends on SPI_MASTER
+ help
+ SPI driver for Microchip MCP23S08 I/O expander. This provides
+ a GPIO interface supporting inputs and outputs.
+
+endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
new file mode 100644
index 0000000..fdde992
--- /dev/null
+++ b/drivers/gpio/Makefile
@@ -0,0 +1,9 @@
+# gpio support: dedicated expander chips, etc
+
+ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
+
+obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o
+
+obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
+obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
+obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
new file mode 100644
index 0000000..d8db2f8e
--- /dev/null
+++ b/drivers/gpio/gpiolib.c
@@ -0,0 +1,567 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+
+#include <asm/gpio.h>
+
+
+/* Optional implementation infrastructure for GPIO interfaces.
+ *
+ * Platforms may want to use this if they tend to use very many GPIOs
+ * that aren't part of a System-On-Chip core; or across I2C/SPI/etc.
+ *
+ * When kernel footprint or instruction count is an issue, simpler
+ * implementations may be preferred. The GPIO programming interface
+ * allows for inlining speed-critical get/set operations for common
+ * cases, so that access to SOC-integrated GPIOs can sometimes cost
+ * only an instruction or two per bit.
+ */
+
+
+/* When debugging, extend minimal trust to callers and platform code.
+ * Also emit diagnostic messages that may help initial bringup, when
+ * board setup or driver bugs are most common.
+ *
+ * Otherwise, minimize overhead in what may be bitbanging codepaths.
+ */
+#ifdef DEBUG
+#define extra_checks 1
+#else
+#define extra_checks 0
+#endif
+
+/* gpio_lock prevents conflicts during gpio_desc[] table updates.
+ * While any GPIO is requested, its gpio_chip is not removable;
+ * each GPIO's "requested" flag serves as a lock and refcount.
+ */
+static DEFINE_SPINLOCK(gpio_lock);
+
+struct gpio_desc {
+ struct gpio_chip *chip;
+ unsigned long flags;
+/* flag symbols are bit numbers */
+#define FLAG_REQUESTED 0
+#define FLAG_IS_OUT 1
+
+#ifdef CONFIG_DEBUG_FS
+ const char *label;
+#endif
+};
+static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
+
+static inline void desc_set_label(struct gpio_desc *d, const char *label)
+{
+#ifdef CONFIG_DEBUG_FS
+ d->label = label;
+#endif
+}
+
+/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
+ * when setting direction, and otherwise illegal. Until board setup code
+ * and drivers use explicit requests everywhere (which won't happen when
+ * those calls have no teeth) we can't avoid autorequesting. This nag
+ * message should motivate switching to explicit requests...
+ */
+static void gpio_ensure_requested(struct gpio_desc *desc)
+{
+ if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
+ pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
+ desc_set_label(desc, "[auto]");
+ }
+}
+
+/* caller holds gpio_lock *OR* gpio is marked as requested */
+static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
+{
+ return gpio_desc[gpio].chip;
+}
+
+/**
+ * gpiochip_add() - register a gpio_chip
+ * @chip: the chip to register, with chip->base initialized
+ * Context: potentially before irqs or kmalloc will work
+ *
+ * Returns a negative errno if the chip can't be registered, such as
+ * because the chip->base is invalid or already associated with a
+ * different chip. Otherwise it returns zero as a success code.
+ */
+int gpiochip_add(struct gpio_chip *chip)
+{
+ unsigned long flags;
+ int status = 0;
+ unsigned id;
+
+ /* NOTE chip->base negative is reserved to mean a request for
+ * dynamic allocation. We don't currently support that.
+ */
+
+ if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) {
+ status = -EINVAL;
+ goto fail;
+ }
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ /* these GPIO numbers must not be managed by another gpio_chip */
+ for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+ if (gpio_desc[id].chip != NULL) {
+ status = -EBUSY;
+ break;
+ }
+ }
+ if (status == 0) {
+ for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+ gpio_desc[id].chip = chip;
+ gpio_desc[id].flags = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+fail:
+ /* failures here can mean systems won't boot... */
+ if (status)
+ pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
+ chip->base, chip->base + chip->ngpio,
+ chip->label ? : "generic");
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add);
+
+/**
+ * gpiochip_remove() - unregister a gpio_chip
+ * @chip: the chip to unregister
+ *
+ * A gpio_chip with any GPIOs still requested may not be removed.
+ */
+int gpiochip_remove(struct gpio_chip *chip)
+{
+ unsigned long flags;
+ int status = 0;
+ unsigned id;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+ if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
+ status = -EBUSY;
+ break;
+ }
+ }
+ if (status == 0) {
+ for (id = chip->base; id < chip->base + chip->ngpio; id++)
+ gpio_desc[id].chip = NULL;
+ }
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove);
+
+
+/* These "optional" allocation calls help prevent drivers from stomping
+ * on each other, and help provide better diagnostics in debugfs.
+ * They're called even less than the "set direction" calls.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+ struct gpio_desc *desc;
+ int status = -EINVAL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ if (gpio >= ARCH_NR_GPIOS)
+ goto done;
+ desc = &gpio_desc[gpio];
+ if (desc->chip == NULL)
+ goto done;
+
+ /* NOTE: gpio_request() can be called in early boot,
+ * before IRQs are enabled.
+ */
+
+ if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
+ desc_set_label(desc, label ? : "?");
+ status = 0;
+ } else
+ status = -EBUSY;
+
+done:
+ if (status)
+ pr_debug("gpio_request: gpio-%d (%s) status %d\n",
+ gpio, label ? : "?", status);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_desc *desc;
+
+ if (gpio >= ARCH_NR_GPIOS) {
+ WARN_ON(extra_checks);
+ return;
+ }
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ desc = &gpio_desc[gpio];
+ if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags))
+ desc_set_label(desc, NULL);
+ else
+ WARN_ON(extra_checks);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gpio_free);
+
+
+/**
+ * gpiochip_is_requested - return string iff signal was requested
+ * @chip: controller managing the signal
+ * @offset: of signal within controller's 0..(ngpio - 1) range
+ *
+ * Returns NULL if the GPIO is not currently requested, else a string.
+ * If debugfs support is enabled, the string returned is the label passed
+ * to gpio_request(); otherwise it is a meaningless constant.
+ *
+ * This function is for use by GPIO controller drivers. The label can
+ * help with diagnostics, and knowing that the signal is used as a GPIO
+ * can help avoid accidentally multiplexing it to another controller.
+ */
+const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned gpio = chip->base + offset;
+
+ if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip)
+ return NULL;
+ if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
+ return NULL;
+#ifdef CONFIG_DEBUG_FS
+ return gpio_desc[gpio].label;
+#else
+ return "?";
+#endif
+}
+EXPORT_SYMBOL_GPL(gpiochip_is_requested);
+
+
+/* Drivers MUST set GPIO direction before making get/set calls. In
+ * some cases this is done in early boot, before IRQs are enabled.
+ *
+ * As a rule these aren't called more than once (except for drivers
+ * using the open-drain emulation idiom) so these are natural places
+ * to accumulate extra debugging checks. Note that we can't (yet)
+ * rely on gpio_request() having been called beforehand.
+ */
+
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+ struct gpio_desc *desc = &gpio_desc[gpio];
+ int status = -EINVAL;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ if (gpio >= ARCH_NR_GPIOS)
+ goto fail;
+ chip = desc->chip;
+ if (!chip || !chip->get || !chip->direction_input)
+ goto fail;
+ gpio -= chip->base;
+ if (gpio >= chip->ngpio)
+ goto fail;
+ gpio_ensure_requested(desc);
+
+ /* now we know the gpio is valid and chip won't vanish */
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ might_sleep_if(extra_checks && chip->can_sleep);
+
+ status = chip->direction_input(chip, gpio);
+ if (status == 0)
+ clear_bit(FLAG_IS_OUT, &desc->flags);
+ return status;
+fail:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ if (status)
+ pr_debug("%s: gpio-%d status %d\n",
+ __FUNCTION__, gpio, status);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned long flags;
+ struct gpio_chip *chip;
+ struct gpio_desc *desc = &gpio_desc[gpio];
+ int status = -EINVAL;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ if (gpio >= ARCH_NR_GPIOS)
+ goto fail;
+ chip = desc->chip;
+ if (!chip || !chip->set || !chip->direction_output)
+ goto fail;
+ gpio -= chip->base;
+ if (gpio >= chip->ngpio)
+ goto fail;
+ gpio_ensure_requested(desc);
+
+ /* now we know the gpio is valid and chip won't vanish */
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ might_sleep_if(extra_checks && chip->can_sleep);
+
+ status = chip->direction_output(chip, gpio, value);
+ if (status == 0)
+ set_bit(FLAG_IS_OUT, &desc->flags);
+ return status;
+fail:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ if (status)
+ pr_debug("%s: gpio-%d status %d\n",
+ __FUNCTION__, gpio, status);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_output);
+
+
+/* I/O calls are only valid after configuration completed; the relevant
+ * "is this a valid GPIO" error checks should already have been done.
+ *
+ * "Get" operations are often inlinable as reading a pin value register,
+ * and masking the relevant bit in that register.
+ *
+ * When "set" operations are inlinable, they involve writing that mask to
+ * one register to set a low value, or a different register to set it high.
+ * Otherwise locking is needed, so there may be little value to inlining.
+ *
+ *------------------------------------------------------------------------
+ *
+ * IMPORTANT!!! The hot paths -- get/set value -- assume that callers
+ * have requested the GPIO. That can include implicit requesting by
+ * a direction setting call. Marking a gpio as requested locks its chip
+ * in memory, guaranteeing that these table lookups need no more locking
+ * and that gpiochip_remove() will fail.
+ *
+ * REVISIT when debugging, consider adding some instrumentation to ensure
+ * that the GPIO was actually requested.
+ */
+
+/**
+ * __gpio_get_value() - return a gpio's value
+ * @gpio: gpio whose value will be returned
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_get_value().
+ * It returns the zero or nonzero value provided by the associated
+ * gpio_chip.get() method; or zero if no such method is provided.
+ */
+int __gpio_get_value(unsigned gpio)
+{
+ struct gpio_chip *chip;
+
+ chip = gpio_to_chip(gpio);
+ WARN_ON(extra_checks && chip->can_sleep);
+ return chip->get ? chip->get(chip, gpio - chip->base) : 0;
+}
+EXPORT_SYMBOL_GPL(__gpio_get_value);
+
+/**
+ * __gpio_set_value() - assign a gpio's value
+ * @gpio: gpio whose value will be assigned
+ * @value: value to assign
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_set_value().
+ * It invokes the associated gpio_chip.set() method.
+ */
+void __gpio_set_value(unsigned gpio, int value)
+{
+ struct gpio_chip *chip;
+
+ chip = gpio_to_chip(gpio);
+ WARN_ON(extra_checks && chip->can_sleep);
+ chip->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL_GPL(__gpio_set_value);
+
+/**
+ * __gpio_cansleep() - report whether gpio value access will sleep
+ * @gpio: gpio in question
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_cansleep(). It
+ * returns nonzero if access reading or writing the GPIO value can sleep.
+ */
+int __gpio_cansleep(unsigned gpio)
+{
+ struct gpio_chip *chip;
+
+ /* only call this on GPIOs that are valid! */
+ chip = gpio_to_chip(gpio);
+
+ return chip->can_sleep;
+}
+EXPORT_SYMBOL_GPL(__gpio_cansleep);
+
+
+
+/* There's no value in making it easy to inline GPIO calls that may sleep.
+ * Common examples include ones connected to I2C or SPI chips.
+ */
+
+int gpio_get_value_cansleep(unsigned gpio)
+{
+ struct gpio_chip *chip;
+
+ might_sleep_if(extra_checks);
+ chip = gpio_to_chip(gpio);
+ return chip->get(chip, gpio - chip->base);
+}
+EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
+
+void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+ struct gpio_chip *chip;
+
+ might_sleep_if(extra_checks);
+ chip = gpio_to_chip(gpio);
+ chip->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+
+static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned i;
+ unsigned gpio = chip->base;
+ struct gpio_desc *gdesc = &gpio_desc[gpio];
+ int is_out;
+
+ for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
+ if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
+ continue;
+
+ is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
+ seq_printf(s, " gpio-%-3d (%-12s) %s %s",
+ gpio, gdesc->label,
+ is_out ? "out" : "in ",
+ chip->get
+ ? (chip->get(chip, i) ? "hi" : "lo")
+ : "? ");
+
+ if (!is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_desc + irq;
+
+ /* This races with request_irq(), set_irq_type(),
+ * and set_irq_wake() ... but those are "rare".
+ *
+ * More significantly, trigger type flags aren't
+ * currently maintained by genirq.
+ */
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+
+ switch (desc->status & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ trigger = "(default)";
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = "edge-falling";
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = "edge-rising";
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = "edge-both";
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = "level-high";
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = "level-low";
+ break;
+ default:
+ trigger = "?trigger?";
+ break;
+ }
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ (desc->status & IRQ_WAKEUP)
+ ? " wakeup" : "");
+ }
+ }
+
+ seq_printf(s, "\n");
+ }
+}
+
+static int gpiolib_show(struct seq_file *s, void *unused)
+{
+ struct gpio_chip *chip = NULL;
+ unsigned gpio;
+ int started = 0;
+
+ /* REVISIT this isn't locked against gpio_chip removal ... */
+
+ for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
+ if (chip == gpio_desc[gpio].chip)
+ continue;
+ chip = gpio_desc[gpio].chip;
+ if (!chip)
+ continue;
+
+ seq_printf(s, "%sGPIOs %d-%d, %s%s:\n",
+ started ? "\n" : "",
+ chip->base, chip->base + chip->ngpio - 1,
+ chip->label ? : "generic",
+ chip->can_sleep ? ", can sleep" : "");
+ started = 1;
+ if (chip->dbg_show)
+ chip->dbg_show(s, chip);
+ else
+ gpiolib_dbg_show(s, chip);
+ }
+ return 0;
+}
+
+static int gpiolib_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gpiolib_show, NULL);
+}
+
+static struct file_operations gpiolib_operations = {
+ .open = gpiolib_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init gpiolib_debugfs_init(void)
+{
+ /* /sys/kernel/debug/gpio */
+ (void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,
+ NULL, NULL, &gpiolib_operations);
+ return 0;
+}
+subsys_initcall(gpiolib_debugfs_init);
+
+#endif /* DEBUG_FS */
diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c
new file mode 100644
index 0000000..bb60e8c
--- /dev/null
+++ b/drivers/gpio/mcp23s08.c
@@ -0,0 +1,357 @@
+/*
+ * mcp23s08.c - SPI gpio expander driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mcp23s08.h>
+
+#include <asm/gpio.h>
+
+
+/* Registers are all 8 bits wide.
+ *
+ * The mcp23s17 has twice as many bits, and can be configured to work
+ * with either 16 bit registers or with two adjacent 8 bit banks.
+ *
+ * Also, there are I2C versions of both chips.
+ */
+#define MCP_IODIR 0x00 /* init/reset: all ones */
+#define MCP_IPOL 0x01
+#define MCP_GPINTEN 0x02
+#define MCP_DEFVAL 0x03
+#define MCP_INTCON 0x04
+#define MCP_IOCON 0x05
+# define IOCON_SEQOP (1 << 5)
+# define IOCON_HAEN (1 << 3)
+# define IOCON_ODR (1 << 2)
+# define IOCON_INTPOL (1 << 1)
+#define MCP_GPPU 0x06
+#define MCP_INTF 0x07
+#define MCP_INTCAP 0x08
+#define MCP_GPIO 0x09
+#define MCP_OLAT 0x0a
+
+struct mcp23s08 {
+ struct spi_device *spi;
+ u8 addr;
+
+ /* lock protects the cached values */
+ struct mutex lock;
+ u8 cache[11];
+
+ struct gpio_chip chip;
+
+ struct work_struct work;
+};
+
+static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
+{
+ u8 tx[2], rx[1];
+ int status;
+
+ tx[0] = mcp->addr | 0x01;
+ tx[1] = reg;
+ status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx);
+ return (status < 0) ? status : rx[0];
+}
+
+static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val)
+{
+ u8 tx[3];
+
+ tx[0] = mcp->addr;
+ tx[1] = reg;
+ tx[2] = val;
+ return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
+}
+
+static int
+mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u8 *vals, unsigned n)
+{
+ u8 tx[2];
+
+ if ((n + reg) > sizeof mcp->cache)
+ return -EINVAL;
+ tx[0] = mcp->addr | 0x01;
+ tx[1] = reg;
+ return spi_write_then_read(mcp->spi, tx, sizeof tx, vals, n);
+}
+
+/*----------------------------------------------------------------------*/
+
+static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ int status;
+
+ mutex_lock(&mcp->lock);
+ mcp->cache[MCP_IODIR] |= (1 << offset);
+ status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
+ mutex_unlock(&mcp->lock);
+ return status;
+}
+
+static int mcp23s08_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ int status;
+
+ mutex_lock(&mcp->lock);
+
+ /* REVISIT reading this clears any IRQ ... */
+ status = mcp23s08_read(mcp, MCP_GPIO);
+ if (status < 0)
+ status = 0;
+ else {
+ mcp->cache[MCP_GPIO] = status;
+ status = !!(status & (1 << offset));
+ }
+ mutex_unlock(&mcp->lock);
+ return status;
+}
+
+static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value)
+{
+ u8 olat = mcp->cache[MCP_OLAT];
+
+ if (value)
+ olat |= mask;
+ else
+ olat &= ~mask;
+ mcp->cache[MCP_OLAT] = olat;
+ return mcp23s08_write(mcp, MCP_OLAT, olat);
+}
+
+static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ u8 mask = 1 << offset;
+
+ mutex_lock(&mcp->lock);
+ __mcp23s08_set(mcp, mask, value);
+ mutex_unlock(&mcp->lock);
+}
+
+static int
+mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+ u8 mask = 1 << offset;
+ int status;
+
+ mutex_lock(&mcp->lock);
+ status = __mcp23s08_set(mcp, mask, value);
+ if (status == 0) {
+ mcp->cache[MCP_IODIR] &= ~mask;
+ status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
+ }
+ mutex_unlock(&mcp->lock);
+ return status;
+}
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+/*
+ * This shows more info than the generic gpio dump code:
+ * pullups, deglitching, open drain drive.
+ */
+static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct mcp23s08 *mcp;
+ char bank;
+ unsigned t;
+ unsigned mask;
+
+ mcp = container_of(chip, struct mcp23s08, chip);
+
+ /* NOTE: we only handle one bank for now ... */
+ bank = '0' + ((mcp->addr >> 1) & 0x3);
+
+ mutex_lock(&mcp->lock);
+ t = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache);
+ if (t < 0) {
+ seq_printf(s, " I/O ERROR %d\n", t);
+ goto done;
+ }
+
+ for (t = 0, mask = 1; t < 8; t++, mask <<= 1) {
+ const char *label;
+
+ label = gpiochip_is_requested(chip, t);
+ if (!label)
+ continue;
+
+ seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s",
+ chip->base + t, bank, t, label,
+ (mcp->cache[MCP_IODIR] & mask) ? "in " : "out",
+ (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
+ (mcp->cache[MCP_GPPU] & mask) ? " " : "up");
+ /* NOTE: ignoring the irq-related registers */
+ seq_printf(s, "\n");
+ }
+done:
+ mutex_unlock(&mcp->lock);
+}
+
+#else
+#define mcp23s08_dbg_show NULL
+#endif
+
+/*----------------------------------------------------------------------*/
+
+static int mcp23s08_probe(struct spi_device *spi)
+{
+ struct mcp23s08 *mcp;
+ struct mcp23s08_platform_data *pdata;
+ int status;
+ int do_update = 0;
+
+ pdata = spi->dev.platform_data;
+ if (!pdata || pdata->slave > 3 || !pdata->base)
+ return -ENODEV;
+
+ mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
+ if (!mcp)
+ return -ENOMEM;
+
+ mutex_init(&mcp->lock);
+
+ mcp->spi = spi;
+ mcp->addr = 0x40 | (pdata->slave << 1);
+
+ mcp->chip.label = "mcp23s08",
+
+ mcp->chip.direction_input = mcp23s08_direction_input;
+ mcp->chip.get = mcp23s08_get;
+ mcp->chip.direction_output = mcp23s08_direction_output;
+ mcp->chip.set = mcp23s08_set;
+ mcp->chip.dbg_show = mcp23s08_dbg_show;
+
+ mcp->chip.base = pdata->base;
+ mcp->chip.ngpio = 8;
+ mcp->chip.can_sleep = 1;
+
+ spi_set_drvdata(spi, mcp);
+
+ /* verify MCP_IOCON.SEQOP = 0, so sequential reads work */
+ status = mcp23s08_read(mcp, MCP_IOCON);
+ if (status < 0)
+ goto fail;
+ if (status & IOCON_SEQOP) {
+ status &= ~IOCON_SEQOP;
+ status = mcp23s08_write(mcp, MCP_IOCON, (u8) status);
+ if (status < 0)
+ goto fail;
+ }
+
+ /* configure ~100K pullups */
+ status = mcp23s08_write(mcp, MCP_GPPU, pdata->pullups);
+ if (status < 0)
+ goto fail;
+
+ status = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache);
+ if (status < 0)
+ goto fail;
+
+ /* disable inverter on input */
+ if (mcp->cache[MCP_IPOL] != 0) {
+ mcp->cache[MCP_IPOL] = 0;
+ do_update = 1;
+ }
+
+ /* disable irqs */
+ if (mcp->cache[MCP_GPINTEN] != 0) {
+ mcp->cache[MCP_GPINTEN] = 0;
+ do_update = 1;
+ }
+
+ if (do_update) {
+ u8 tx[4];
+
+ tx[0] = mcp->addr;
+ tx[1] = MCP_IPOL;
+ memcpy(&tx[2], &mcp->cache[MCP_IPOL], sizeof(tx) - 2);
+ status = spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
+
+ /* FIXME check status... */
+ }
+
+ status = gpiochip_add(&mcp->chip);
+
+ /* NOTE: these chips have a relatively sane IRQ framework, with
+ * per-signal masking and level/edge triggering. It's not yet
+ * handled here...
+ */
+
+ if (pdata->setup) {
+ status = pdata->setup(spi, mcp->chip.base,
+ mcp->chip.ngpio, pdata->context);
+ if (status < 0)
+ dev_dbg(&spi->dev, "setup --> %d\n", status);
+ }
+
+ return 0;
+
+fail:
+ kfree(mcp);
+ return status;
+}
+
+static int mcp23s08_remove(struct spi_device *spi)
+{
+ struct mcp23s08 *mcp = spi_get_drvdata(spi);
+ struct mcp23s08_platform_data *pdata = spi->dev.platform_data;
+ int status = 0;
+
+ if (pdata->teardown) {
+ status = pdata->teardown(spi,
+ mcp->chip.base, mcp->chip.ngpio,
+ pdata->context);
+ if (status < 0) {
+ dev_err(&spi->dev, "%s --> %d\n", "teardown", status);
+ return status;
+ }
+ }
+
+ status = gpiochip_remove(&mcp->chip);
+ if (status == 0)
+ kfree(mcp);
+ else
+ dev_err(&spi->dev, "%s --> %d\n", "remove", status);
+ return status;
+}
+
+static struct spi_driver mcp23s08_driver = {
+ .probe = mcp23s08_probe,
+ .remove = mcp23s08_remove,
+ .driver = {
+ .name = "mcp23s08",
+ .owner = THIS_MODULE,
+ },
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __init mcp23s08_init(void)
+{
+ return spi_register_driver(&mcp23s08_driver);
+}
+module_init(mcp23s08_init);
+
+static void __exit mcp23s08_exit(void)
+{
+ spi_unregister_driver(&mcp23s08_driver);
+}
+module_exit(mcp23s08_exit);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
new file mode 100644
index 0000000..92583cd
--- /dev/null
+++ b/drivers/gpio/pca953x.c
@@ -0,0 +1,308 @@
+/*
+ * pca953x.c - 4/8/16 bit I/O ports
+ *
+ * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+ * Copyright (C) 2007 Marvell International Ltd.
+ *
+ * Derived from drivers/i2c/chips/pca9539.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/gpio.h>
+
+#define PCA953X_INPUT 0
+#define PCA953X_OUTPUT 1
+#define PCA953X_INVERT 2
+#define PCA953X_DIRECTION 3
+
+/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
+struct pca953x_desc {
+ char name[I2C_NAME_SIZE];
+ unsigned long driver_data;
+};
+
+static const struct pca953x_desc pca953x_descs[] = {
+ { "pca9534", 8, },
+ { "pca9535", 16, },
+ { "pca9536", 4, },
+ { "pca9537", 4, },
+ { "pca9538", 8, },
+ { "pca9539", 16, },
+ /* REVISIT several pca955x parts should work here too */
+};
+
+struct pca953x_chip {
+ unsigned gpio_start;
+ uint16_t reg_output;
+ uint16_t reg_direction;
+
+ struct i2c_client *client;
+ struct gpio_chip gpio_chip;
+};
+
+/* NOTE: we can't currently rely on fault codes to come from SMBus
+ * calls, so we map all errors to EIO here and return zero otherwise.
+ */
+static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
+{
+ int ret;
+
+ if (chip->gpio_chip.ngpio <= 8)
+ ret = i2c_smbus_write_byte_data(chip->client, reg, val);
+ else
+ ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "failed writing register\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
+{
+ int ret;
+
+ if (chip->gpio_chip.ngpio <= 8)
+ ret = i2c_smbus_read_byte_data(chip->client, reg);
+ else
+ ret = i2c_smbus_read_word_data(chip->client, reg << 1);
+
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "failed reading register\n");
+ return -EIO;
+ }
+
+ *val = (uint16_t)ret;
+ return 0;
+}
+
+static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ reg_val = chip->reg_direction | (1u << off);
+ ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+ if (ret)
+ return ret;
+
+ chip->reg_direction = reg_val;
+ return 0;
+}
+
+static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+ unsigned off, int val)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ /* set output level */
+ if (val)
+ reg_val = chip->reg_output | (1u << off);
+ else
+ reg_val = chip->reg_output & ~(1u << off);
+
+ ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+ if (ret)
+ return ret;
+
+ chip->reg_output = reg_val;
+
+ /* then direction */
+ reg_val = chip->reg_direction & ~(1u << off);
+ ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+ if (ret)
+ return ret;
+
+ chip->reg_direction = reg_val;
+ return 0;
+}
+
+static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val);
+ if (ret < 0) {
+ /* NOTE: diagnostic already emitted; that's all we should
+ * do unless gpio_*_value_cansleep() calls become different
+ * from their nonsleeping siblings (and report faults).
+ */
+ return 0;
+ }
+
+ return (reg_val & (1u << off)) ? 1 : 0;
+}
+
+static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+{
+ struct pca953x_chip *chip;
+ uint16_t reg_val;
+ int ret;
+
+ chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+ if (val)
+ reg_val = chip->reg_output | (1u << off);
+ else
+ reg_val = chip->reg_output & ~(1u << off);
+
+ ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+ if (ret)
+ return;
+
+ chip->reg_output = reg_val;
+}
+
+static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+{
+ struct gpio_chip *gc;
+
+ gc = &chip->gpio_chip;
+
+ gc->direction_input = pca953x_gpio_direction_input;
+ gc->direction_output = pca953x_gpio_direction_output;
+ gc->get = pca953x_gpio_get_value;
+ gc->set = pca953x_gpio_set_value;
+
+ gc->base = chip->gpio_start;
+ gc->ngpio = gpios;
+ gc->label = chip->client->name;
+}
+
+static int __devinit pca953x_probe(struct i2c_client *client)
+{
+ struct pca953x_platform_data *pdata;
+ struct pca953x_chip *chip;
+ int ret, i;
+ const struct pca953x_desc *id = NULL;
+
+ pdata = client->dev.platform_data;
+ if (pdata == NULL)
+ return -ENODEV;
+
+ /* this loop vanishes when we get i2c_device_id */
+ for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
+ if (!strcmp(pca953x_descs[i].name, client->name)) {
+ id = pca953x_descs + i;
+ break;
+ }
+ if (!id)
+ return -ENODEV;
+
+ chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->client = client;
+
+ chip->gpio_start = pdata->gpio_base;
+
+ /* initialize cached registers from their original values.
+ * we can't share this chip with another i2c master.
+ */
+ pca953x_setup_gpio(chip, id->driver_data);
+
+ ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+ if (ret)
+ goto out_failed;
+
+ ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
+ if (ret)
+ goto out_failed;
+
+ /* set platform specific polarity inversion */
+ ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
+ if (ret)
+ goto out_failed;
+
+
+ ret = gpiochip_add(&chip->gpio_chip);
+ if (ret)
+ goto out_failed;
+
+ if (pdata->setup) {
+ ret = pdata->setup(client, chip->gpio_chip.base,
+ chip->gpio_chip.ngpio, pdata->context);
+ if (ret < 0)
+ dev_warn(&client->dev, "setup failed, %d\n", ret);
+ }
+
+ i2c_set_clientdata(client, chip);
+ return 0;
+
+out_failed:
+ kfree(chip);
+ return ret;
+}
+
+static int pca953x_remove(struct i2c_client *client)
+{
+ struct pca953x_platform_data *pdata = client->dev.platform_data;
+ struct pca953x_chip *chip = i2c_get_clientdata(client);
+ int ret = 0;
+
+ if (pdata->teardown) {
+ ret = pdata->teardown(client, chip->gpio_chip.base,
+ chip->gpio_chip.ngpio, pdata->context);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s failed, %d\n",
+ "teardown", ret);
+ return ret;
+ }
+ }
+
+ ret = gpiochip_remove(&chip->gpio_chip);
+ if (ret) {
+ dev_err(&client->dev, "%s failed, %d\n",
+ "gpiochip_remove()", ret);
+ return ret;
+ }
+
+ kfree(chip);
+ return 0;
+}
+
+static struct i2c_driver pca953x_driver = {
+ .driver = {
+ .name = "pca953x",
+ },
+ .probe = pca953x_probe,
+ .remove = pca953x_remove,
+};
+
+static int __init pca953x_init(void)
+{
+ return i2c_add_driver(&pca953x_driver);
+}
+module_init(pca953x_init);
+
+static void __exit pca953x_exit(void)
+{
+ i2c_del_driver(&pca953x_driver);
+}
+module_exit(pca953x_exit);
+
+MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("GPIO expander driver for PCA953x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
new file mode 100644
index 0000000..c6b3b53
--- /dev/null
+++ b/drivers/gpio/pcf857x.c
@@ -0,0 +1,330 @@
+/*
+ * pcf857x - driver for pcf857x, pca857x, and pca967x I2C GPIO expanders
+ *
+ * Copyright (C) 2007 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+
+#include <asm/gpio.h>
+
+
+/*
+ * The pcf857x, pca857x, and pca967x chips only expose one read and one
+ * write register. Writing a "one" bit (to match the reset state) lets
+ * that pin be used as an input; it's not an open-drain model, but acts
+ * a bit like one. This is described as "quasi-bidirectional"; read the
+ * chip documentation for details.
+ *
+ * Many other I2C GPIO expander chips (like the pca953x models) have
+ * more complex register models and more conventional circuitry using
+ * push/pull drivers. They often use the same 0x20..0x27 addresses as
+ * pcf857x parts, making the "legacy" I2C driver model problematic.
+ */
+struct pcf857x {
+ struct gpio_chip chip;
+ struct i2c_client *client;
+ unsigned out; /* software latch */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Talk to 8-bit I/O expander */
+
+static int pcf857x_input8(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+
+ gpio->out |= (1 << offset);
+ return i2c_smbus_write_byte(gpio->client, gpio->out);
+}
+
+static int pcf857x_get8(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ s32 value;
+
+ value = i2c_smbus_read_byte(gpio->client);
+ return (value < 0) ? 0 : (value & (1 << offset));
+}
+
+static int pcf857x_output8(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ unsigned bit = 1 << offset;
+
+ if (value)
+ gpio->out |= bit;
+ else
+ gpio->out &= ~bit;
+ return i2c_smbus_write_byte(gpio->client, gpio->out);
+}
+
+static void pcf857x_set8(struct gpio_chip *chip, unsigned offset, int value)
+{
+ pcf857x_output8(chip, offset, value);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Talk to 16-bit I/O expander */
+
+static int i2c_write_le16(struct i2c_client *client, u16 word)
+{
+ u8 buf[2] = { word & 0xff, word >> 8, };
+ int status;
+
+ status = i2c_master_send(client, buf, 2);
+ return (status < 0) ? status : 0;
+}
+
+static int i2c_read_le16(struct i2c_client *client)
+{
+ u8 buf[2];
+ int status;
+
+ status = i2c_master_recv(client, buf, 2);
+ if (status < 0)
+ return status;
+ return (buf[1] << 8) | buf[0];
+}
+
+static int pcf857x_input16(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+
+ gpio->out |= (1 << offset);
+ return i2c_write_le16(gpio->client, gpio->out);
+}
+
+static int pcf857x_get16(struct gpio_chip *chip, unsigned offset)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ int value;
+
+ value = i2c_read_le16(gpio->client);
+ return (value < 0) ? 0 : (value & (1 << offset));
+}
+
+static int pcf857x_output16(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
+ unsigned bit = 1 << offset;
+
+ if (value)
+ gpio->out |= bit;
+ else
+ gpio->out &= ~bit;
+ return i2c_write_le16(gpio->client, gpio->out);
+}
+
+static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value)
+{
+ pcf857x_output16(chip, offset, value);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int pcf857x_probe(struct i2c_client *client)
+{
+ struct pcf857x_platform_data *pdata;
+ struct pcf857x *gpio;
+ int status;
+
+ pdata = client->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ /* Allocate, initialize, and register this gpio_chip. */
+ gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+
+ gpio->chip.base = pdata->gpio_base;
+ gpio->chip.can_sleep = 1;
+
+ /* NOTE: the OnSemi jlc1562b is also largely compatible with
+ * these parts, notably for output. It has a low-resolution
+ * DAC instead of pin change IRQs; and its inputs can be the
+ * result of comparators.
+ */
+
+ /* 8574 addresses are 0x20..0x27; 8574a uses 0x38..0x3f;
+ * 9670, 9672, 9764, and 9764a use quite a variety.
+ *
+ * NOTE: we don't distinguish here between *4 and *4a parts.
+ */
+ if (strcmp(client->name, "pcf8574") == 0
+ || strcmp(client->name, "pca8574") == 0
+ || strcmp(client->name, "pca9670") == 0
+ || strcmp(client->name, "pca9672") == 0
+ || strcmp(client->name, "pca9674") == 0
+ ) {
+ gpio->chip.ngpio = 8;
+ gpio->chip.direction_input = pcf857x_input8;
+ gpio->chip.get = pcf857x_get8;
+ gpio->chip.direction_output = pcf857x_output8;
+ gpio->chip.set = pcf857x_set8;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE))
+ status = -EIO;
+
+ /* fail if there's no chip present */
+ else
+ status = i2c_smbus_read_byte(client);
+
+ /* '75/'75c addresses are 0x20..0x27, just like the '74;
+ * the '75c doesn't have a current source pulling high.
+ * 9671, 9673, and 9765 use quite a variety of addresses.
+ *
+ * NOTE: we don't distinguish here between '75 and '75c parts.
+ */
+ } else if (strcmp(client->name, "pcf8575") == 0
+ || strcmp(client->name, "pca8575") == 0
+ || strcmp(client->name, "pca9671") == 0
+ || strcmp(client->name, "pca9673") == 0
+ || strcmp(client->name, "pca9675") == 0
+ ) {
+ gpio->chip.ngpio = 16;
+ gpio->chip.direction_input = pcf857x_input16;
+ gpio->chip.get = pcf857x_get16;
+ gpio->chip.direction_output = pcf857x_output16;
+ gpio->chip.set = pcf857x_set16;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ status = -EIO;
+
+ /* fail if there's no chip present */
+ else
+ status = i2c_read_le16(client);
+
+ } else
+ status = -ENODEV;
+
+ if (status < 0)
+ goto fail;
+
+ gpio->chip.label = client->name;
+
+ gpio->client = client;
+ i2c_set_clientdata(client, gpio);
+
+ /* NOTE: these chips have strange "quasi-bidirectional" I/O pins.
+ * We can't actually know whether a pin is configured (a) as output
+ * and driving the signal low, or (b) as input and reporting a low
+ * value ... without knowing the last value written since the chip
+ * came out of reset (if any). We can't read the latched output.
+ *
+ * In short, the only reliable solution for setting up pin direction
+ * is to do it explicitly. The setup() method can do that, but it
+ * may cause transient glitching since it can't know the last value
+ * written (some pins may need to be driven low).
+ *
+ * Using pdata->n_latch avoids that trouble. When left initialized
+ * to zero, our software copy of the "latch" then matches the chip's
+ * all-ones reset state. Otherwise it flags pins to be driven low.
+ */
+ gpio->out = ~pdata->n_latch;
+
+ status = gpiochip_add(&gpio->chip);
+ if (status < 0)
+ goto fail;
+
+ /* NOTE: these chips can issue "some pin-changed" IRQs, which we
+ * don't yet even try to use. Among other issues, the relevant
+ * genirq state isn't available to modular drivers; and most irq
+ * methods can't be called from sleeping contexts.
+ */
+
+ dev_info(&client->dev, "gpios %d..%d on a %s%s\n",
+ gpio->chip.base,
+ gpio->chip.base + gpio->chip.ngpio - 1,
+ client->name,
+ client->irq ? " (irq ignored)" : "");
+
+ /* Let platform code set up the GPIOs and their users.
+ * Now is the first time anyone could use them.
+ */
+ if (pdata->setup) {
+ status = pdata->setup(client,
+ gpio->chip.base, gpio->chip.ngpio,
+ pdata->context);
+ if (status < 0)
+ dev_warn(&client->dev, "setup --> %d\n", status);
+ }
+
+ return 0;
+
+fail:
+ dev_dbg(&client->dev, "probe error %d for '%s'\n",
+ status, client->name);
+ kfree(gpio);
+ return status;
+}
+
+static int pcf857x_remove(struct i2c_client *client)
+{
+ struct pcf857x_platform_data *pdata = client->dev.platform_data;
+ struct pcf857x *gpio = i2c_get_clientdata(client);
+ int status = 0;
+
+ if (pdata->teardown) {
+ status = pdata->teardown(client,
+ gpio->chip.base, gpio->chip.ngpio,
+ pdata->context);
+ if (status < 0) {
+ dev_err(&client->dev, "%s --> %d\n",
+ "teardown", status);
+ return status;
+ }
+ }
+
+ status = gpiochip_remove(&gpio->chip);
+ if (status == 0)
+ kfree(gpio);
+ else
+ dev_err(&client->dev, "%s --> %d\n", "remove", status);
+ return status;
+}
+
+static struct i2c_driver pcf857x_driver = {
+ .driver = {
+ .name = "pcf857x",
+ .owner = THIS_MODULE,
+ },
+ .probe = pcf857x_probe,
+ .remove = pcf857x_remove,
+};
+
+static int __init pcf857x_init(void)
+{
+ return i2c_add_driver(&pcf857x_driver);
+}
+module_init(pcf857x_init);
+
+static void __exit pcf857x_exit(void)
+{
+ i2c_del_driver(&pcf857x_driver);
+}
+module_exit(pcf857x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Brownell");
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index e6c4a2b..f5e7a70 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -492,7 +492,7 @@
iface->pdev = pdev;
iface->bar = bar;
- rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar);
+ rc = pci_enable_device_io(iface->pdev);
if (rc)
goto errout_free;
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index bd7082c..b21593f 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -54,8 +54,8 @@
hardware. If unsure, say N.
config SENSORS_PCA9539
- tristate "Philips PCA9539 16-bit I/O port"
- depends on EXPERIMENTAL
+ tristate "Philips PCA9539 16-bit I/O port (DEPRECATED)"
+ depends on EXPERIMENTAL && GPIO_PCA9539 = "n"
help
If you say yes here you get support for the Philips PCA9539
16-bit I/O port.
@@ -63,6 +63,9 @@
This driver can also be built as a module. If so, the module
will be called pca9539.
+ This driver is deprecated and will be dropped soon. Use
+ drivers/gpio/pca9539.c instead.
+
config SENSORS_PCF8591
tristate "Philips PCF8591"
depends on EXPERIMENTAL
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index e42a465..ab8fb25 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -216,8 +216,7 @@
memory, though.
config BLK_DEV_IDETAPE
- tristate "Include IDE/ATAPI TAPE support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "Include IDE/ATAPI TAPE support"
help
If you have an IDE tape drive using the ATAPI protocol, say Y.
ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
@@ -1010,6 +1009,15 @@
normally be on; disable it only if you are running a custom hard
drive subsystem through an expansion card.
+config BLK_DEV_PALMCHIP_BK3710
+ tristate "Palmchip bk3710 IDE controller support"
+ depends on ARCH_DAVINCI
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Say Y here if you want to support the onchip IDE controller on the
+ TI DaVinci SoC
+
+
config BLK_DEV_MPC8xx_IDE
tristate "MPC8xx IDE support"
depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
index 5f63ad2..936e7b0 100644
--- a/drivers/ide/arm/Makefile
+++ b/drivers/ide/arm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o
+obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
ifeq ($(CONFIG_IDE_ARM), m)
obj-m += ide_arm.o
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index 037300f..0e7574c 100644
--- a/drivers/ide/arm/bast-ide.c
+++ b/drivers/ide/arm/bast-ide.c
@@ -28,8 +28,10 @@
bastide_register(unsigned int base, unsigned int aux, int irq,
ide_hwif_t **hwif)
{
+ ide_hwif_t *hwif;
hw_regs_t hw;
int i;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
memset(&hw, 0, sizeof(hw));
@@ -44,8 +46,24 @@
hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
hw.irq = irq;
- ide_register_hw(&hw, NULL, hwif);
+ hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ if (hwif == NULL)
+ goto out;
+ i = hwif->index;
+
+ if (hwif->present)
+ ide_unregister(i, 0, 0);
+ else if (!hwif->hold)
+ ide_init_port_data(hwif, i);
+
+ ide_init_port_hw(hwif, &hw);
+ hwif->quirkproc = NULL;
+
+ idx[0] = i;
+
+ ide_device_add(idx, NULL);
+out:
return 0;
}
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 8d2cc47..e816b0f 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -365,7 +365,7 @@
if (icside_dma_test_irq(drive))
return;
- ide_dump_status(drive, "DMA timeout", HWIF(drive)->INB(IDE_STATUS_REG));
+ ide_dump_status(drive, "DMA timeout", ide_read_status(drive));
icside_dma_end(drive);
}
@@ -377,9 +377,6 @@
static void icside_dma_init(ide_hwif_t *hwif)
{
- hwif->mwdma_mask = 7; /* MW0..2 */
- hwif->swdma_mask = 7; /* SW0..2 */
-
hwif->dmatable_cpu = NULL;
hwif->dmatable_dma = 0;
hwif->set_dma_mode = icside_set_dma_mode;
@@ -459,11 +456,19 @@
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
return 0;
}
+static const struct ide_port_info icside_v6_port_info __initdata = {
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+ IDE_HFLAG_NO_AUTOTUNE,
+ .mwdma_mask = ATA_MWDMA2,
+ .swdma_mask = ATA_SWDMA2,
+};
+
static int __init
icside_register_v6(struct icside_state *state, struct expansion_card *ec)
{
@@ -472,6 +477,7 @@
unsigned int sel = 0;
int ret;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ struct ide_port_info d = icside_v6_port_info;
ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
if (!ioc_base) {
@@ -521,30 +527,25 @@
state->hwif[1] = mate;
hwif->maskproc = icside_maskproc;
- hwif->channel = 0;
hwif->hwif_data = state;
- hwif->mate = mate;
- hwif->serialized = 1;
hwif->config_data = (unsigned long)ioc_base;
hwif->select_data = sel;
mate->maskproc = icside_maskproc;
- mate->channel = 1;
mate->hwif_data = state;
- mate->mate = hwif;
- mate->serialized = 1;
mate->config_data = (unsigned long)ioc_base;
mate->select_data = sel | 1;
if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
icside_dma_init(hwif);
icside_dma_init(mate);
- }
+ } else
+ d.mwdma_mask = d.swdma_mask = 0;
idx[0] = hwif->index;
idx[1] = mate->index;
- ide_device_add(idx);
+ ide_device_add(idx, &d);
return 0;
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index 60f2497..43a70e9 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -39,7 +39,7 @@
ide_init_port_hw(hwif, &hw);
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
}
return 0;
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
new file mode 100644
index 0000000..c306997
--- /dev/null
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -0,0 +1,395 @@
+/*
+ * Palmchip bk3710 IDE controller
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/* Offset of the primary interface registers */
+#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
+
+/* Primary Control Offset */
+#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
+
+/*
+ * PalmChip 3710 IDE Controller UDMA timing structure Definition
+ */
+struct palm_bk3710_udmatiming {
+ unsigned int rptime; /* Ready to pause time */
+ unsigned int cycletime; /* Cycle Time */
+};
+
+#define BK3710_BMICP 0x00
+#define BK3710_BMISP 0x02
+#define BK3710_BMIDTP 0x04
+#define BK3710_BMICS 0x08
+#define BK3710_BMISS 0x0A
+#define BK3710_BMIDTS 0x0C
+#define BK3710_IDETIMP 0x40
+#define BK3710_IDETIMS 0x42
+#define BK3710_SIDETIM 0x44
+#define BK3710_SLEWCTL 0x45
+#define BK3710_IDESTATUS 0x47
+#define BK3710_UDMACTL 0x48
+#define BK3710_UDMATIM 0x4A
+#define BK3710_MISCCTL 0x50
+#define BK3710_REGSTB 0x54
+#define BK3710_REGRCVR 0x58
+#define BK3710_DATSTB 0x5C
+#define BK3710_DATRCVR 0x60
+#define BK3710_DMASTB 0x64
+#define BK3710_DMARCVR 0x68
+#define BK3710_UDMASTB 0x6C
+#define BK3710_UDMATRP 0x70
+#define BK3710_UDMAENV 0x74
+#define BK3710_IORDYTMP 0x78
+#define BK3710_IORDYTMS 0x7C
+
+#include "../ide-timing.h"
+
+static long ide_palm_clk;
+
+static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
+ {160, 240}, /* UDMA Mode 0 */
+ {125, 160}, /* UDMA Mode 1 */
+ {100, 120}, /* UDMA Mode 2 */
+ {100, 90}, /* UDMA Mode 3 */
+ {85, 60}, /* UDMA Mode 4 */
+};
+
+static struct clk *ideclkp;
+
+static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
+ unsigned int mode)
+{
+ u8 tenv, trp, t0;
+ u32 val32;
+ u16 val16;
+
+ /* DMA Data Setup */
+ t0 = (palm_bk3710_udmatimings[mode].cycletime + ide_palm_clk - 1)
+ / ide_palm_clk - 1;
+ tenv = (20 + ide_palm_clk - 1) / ide_palm_clk - 1;
+ trp = (palm_bk3710_udmatimings[mode].rptime + ide_palm_clk - 1)
+ / ide_palm_clk - 1;
+
+ /* udmatim Register */
+ val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
+ val16 |= (mode << (dev ? 4 : 0));
+ writew(val16, base + BK3710_UDMATIM);
+
+ /* udmastb Ultra DMA Access Strobe Width */
+ val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t0 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMASTB);
+
+ /* udmatrp Ultra DMA Ready to Pause Time */
+ val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
+ val32 |= (trp << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMATRP);
+
+ /* udmaenv Ultra DMA envelop Time */
+ val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
+ val32 |= (tenv << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMAENV);
+
+ /* Enable UDMA for Device */
+ val16 = readw(base + BK3710_UDMACTL) | (1 << dev);
+ writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
+ unsigned short min_cycle,
+ unsigned int mode)
+{
+ u8 td, tkw, t0;
+ u32 val32;
+ u16 val16;
+ struct ide_timing *t;
+ int cycletime;
+
+ t = ide_timing_find_mode(mode);
+ cycletime = max_t(int, t->cycle, min_cycle);
+
+ /* DMA Data Setup */
+ t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
+ td = (t->active + ide_palm_clk - 1) / ide_palm_clk;
+ tkw = t0 - td - 1;
+ td -= 1;
+
+ val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (td << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DMASTB);
+
+ val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (tkw << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DMARCVR);
+
+ /* Disable UDMA for Device */
+ val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev);
+ writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
+ unsigned int dev, unsigned int cycletime,
+ unsigned int mode)
+{
+ u8 t2, t2i, t0;
+ u32 val32;
+ struct ide_timing *t;
+
+ /* PIO Data Setup */
+ t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
+ t2 = (ide_timing_find_mode(XFER_PIO_0 + mode)->active +
+ ide_palm_clk - 1) / ide_palm_clk;
+
+ t2i = t0 - t2 - 1;
+ t2 -= 1;
+
+ val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DATSTB);
+
+ val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2i << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DATRCVR);
+
+ if (mate && mate->present) {
+ u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
+
+ if (mode2 < mode)
+ mode = mode2;
+ }
+
+ /* TASKFILE Setup */
+ t = ide_timing_find_mode(XFER_PIO_0 + mode);
+ t0 = (t->cyc8b + ide_palm_clk - 1) / ide_palm_clk;
+ t2 = (t->act8b + ide_palm_clk - 1) / ide_palm_clk;
+
+ t2i = t0 - t2 - 1;
+ t2 -= 1;
+
+ val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_REGSTB);
+
+ val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2i << (dev ? 8 : 0));
+ writel(val32, base + BK3710_REGRCVR);
+}
+
+static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
+{
+ int is_slave = drive->dn & 1;
+ void __iomem *base = (void *)drive->hwif->dma_base;
+
+ if (xferspeed >= XFER_UDMA_0) {
+ palm_bk3710_setudmamode(base, is_slave,
+ xferspeed - XFER_UDMA_0);
+ } else {
+ palm_bk3710_setdmamode(base, is_slave, drive->id->eide_dma_min,
+ xferspeed);
+ }
+}
+
+static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio)
+{
+ unsigned int cycle_time;
+ int is_slave = drive->dn & 1;
+ ide_drive_t *mate;
+ void __iomem *base = (void *)drive->hwif->dma_base;
+
+ /*
+ * Obtain the drive PIO data for tuning the Palm Chip registers
+ */
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ mate = ide_get_paired_drive(drive);
+ palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
+}
+
+static void __devinit palm_bk3710_chipinit(void __iomem *base)
+{
+ /*
+ * enable the reset_en of ATA controller so that when ata signals
+ * are brought out, by writing into device config. at that
+ * time por_n signal should not be 'Z' and have a stable value.
+ */
+ writel(0x0300, base + BK3710_MISCCTL);
+
+ /* wait for some time and deassert the reset of ATA Device. */
+ mdelay(100);
+
+ /* Deassert the Reset */
+ writel(0x0200, base + BK3710_MISCCTL);
+
+ /*
+ * Program the IDETIMP Register Value based on the following assumptions
+ *
+ * (ATA_IDETIMP_IDEEN , ENABLE ) |
+ * (ATA_IDETIMP_SLVTIMEN , DISABLE) |
+ * (ATA_IDETIMP_RDYSMPL , 70NS) |
+ * (ATA_IDETIMP_RDYRCVRY , 50NS) |
+ * (ATA_IDETIMP_DMAFTIM1 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST1 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN1 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM1 , DISABLE) |
+ * (ATA_IDETIMP_DMAFTIM0 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST0 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN0 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM0 , DISABLE)
+ */
+ writew(0xB388, base + BK3710_IDETIMP);
+
+ /*
+ * Configure SIDETIM Register
+ * (ATA_SIDETIM_RDYSMPS1 ,120NS ) |
+ * (ATA_SIDETIM_RDYRCYS1 ,120NS )
+ */
+ writeb(0, base + BK3710_SIDETIM);
+
+ /*
+ * UDMACTL Ultra-ATA DMA Control
+ * (ATA_UDMACTL_UDMAP1 , 0 ) |
+ * (ATA_UDMACTL_UDMAP0 , 0 )
+ *
+ */
+ writew(0, base + BK3710_UDMACTL);
+
+ /*
+ * MISCCTL Miscellaneous Conrol Register
+ * (ATA_MISCCTL_RSTMODEP , 1) |
+ * (ATA_MISCCTL_RESETP , 0) |
+ * (ATA_MISCCTL_TIMORIDE , 1)
+ */
+ writel(0x201, base + BK3710_MISCCTL);
+
+ /*
+ * IORDYTMP IORDY Timer for Primary Register
+ * (ATA_IORDYTMP_IORDYTMP , 0xffff )
+ */
+ writel(0xFFFF, base + BK3710_IORDYTMP);
+
+ /*
+ * Configure BMISP Register
+ * (ATA_BMISP_DMAEN1 , DISABLE ) |
+ * (ATA_BMISP_DMAEN0 , DISABLE ) |
+ * (ATA_BMISP_IORDYINT , CLEAR) |
+ * (ATA_BMISP_INTRSTAT , CLEAR) |
+ * (ATA_BMISP_DMAERROR , CLEAR)
+ */
+ writew(0, base + BK3710_BMISP);
+
+ palm_bk3710_setpiomode(base, NULL, 0, 600, 0);
+ palm_bk3710_setpiomode(base, NULL, 1, 600, 0);
+}
+static int __devinit palm_bk3710_probe(struct platform_device *pdev)
+{
+ hw_regs_t ide_ctlr_info;
+ int index = 0;
+ int pribase;
+ struct clk *clkp;
+ struct resource *mem, *irq;
+ ide_hwif_t *hwif;
+ void __iomem *base;
+
+ clkp = clk_get(NULL, "IDECLK");
+ if (IS_ERR(clkp))
+ return -ENODEV;
+
+ ideclkp = clkp;
+ clk_enable(ideclkp);
+ ide_palm_clk = clk_get_rate(ideclkp)/100000;
+ ide_palm_clk = (10000/ide_palm_clk) + 1;
+ /* Register the IDE interface with Linux ATA Interface */
+ memset(&ide_ctlr_info, 0, sizeof(ide_ctlr_info));
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem == NULL) {
+ printk(KERN_ERR "failed to get memory region resource\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq == NULL) {
+ printk(KERN_ERR "failed to get IRQ resource\n");
+ return -ENODEV;
+ }
+
+ base = (void *)mem->start;
+
+ /* Configure the Palm Chip controller */
+ palm_bk3710_chipinit(base);
+
+ pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET;
+ for (index = 0; index < IDE_NR_PORTS - 2; index++)
+ ide_ctlr_info.io_ports[index] = pribase + index;
+ ide_ctlr_info.io_ports[IDE_CONTROL_OFFSET] = mem->start +
+ IDE_PALM_ATA_PRI_CTL_OFFSET;
+ ide_ctlr_info.irq = irq->start;
+ ide_ctlr_info.chipset = ide_palm3710;
+
+ if (ide_register_hw(&ide_ctlr_info, NULL, &hwif) < 0) {
+ printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
+ return -ENODEV;
+ }
+
+ hwif->set_pio_mode = &palm_bk3710_set_pio_mode;
+ hwif->set_dma_mode = &palm_bk3710_set_dma_mode;
+ hwif->mmio = 1;
+ default_hwif_mmiops(hwif);
+ hwif->cbl = ATA_CBL_PATA80;
+ hwif->ultra_mask = 0x1f; /* Ultra DMA Mode 4 Max
+ (input clk 99MHz) */
+ hwif->mwdma_mask = 0x7;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ ide_setup_dma(hwif, mem->start);
+
+ return 0;
+}
+
+static struct platform_driver platform_bk_driver = {
+ .driver = {
+ .name = "palm_bk3710",
+ },
+ .probe = palm_bk3710_probe,
+ .remove = NULL,
+};
+
+static int __init palm_bk3710_init(void)
+{
+ return platform_driver_register(&platform_bk_driver);
+}
+
+module_init(palm_bk3710_init);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index c8b6581..efba00d 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -58,7 +58,7 @@
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
ecard_set_drvdata(ec, hwif);
goto out;
@@ -76,7 +76,7 @@
ecard_set_drvdata(ec, NULL);
- ide_unregister(hwif->index);
+ ide_unregister(hwif->index, 0, 0);
ecard_release_resources(ec);
}
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 0640a38..e79bf8f 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -753,34 +753,53 @@
cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
}
+static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ for (i = 0; i <= 7; i++)
+ hw->io_ports[i] = base + cris_ide_reg_addr(i, 0, 1);
+
+ /*
+ * the IDE control register is at ATA address 6,
+ * with CS1 active instead of CS0
+ */
+ hw->io_ports[IDE_CONTROL_OFFSET] = base + cris_ide_reg_addr(6, 1, 0);
+
+ hw->irq = ide_default_irq(0);
+ hw->ack_intr = cris_ide_ack_intr;
+}
+
+static const struct ide_port_info cris_port_info __initdata = {
+ .chipset = ide_etrax100,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_NO_DMA, /* no SFF-style DMA */
+ .pio_mask = ATA_PIO4,
+ .udma_mask = cris_ultra_mask,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
static int __init init_e100_ide(void)
{
hw_regs_t hw;
- int ide_offsets[IDE_NR_PORTS], h, i;
+ int h;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
printk("ide: ETRAX FS built-in ATA DMA controller\n");
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- ide_offsets[i] = cris_ide_reg_addr(i, 0, 1);
-
- /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */
- ide_offsets[IDE_CONTROL_OFFSET] = cris_ide_reg_addr(6, 1, 0);
-
for (h = 0; h < 4; h++) {
ide_hwif_t *hwif = NULL;
- ide_setup_ports(&hw, cris_ide_base_address(h),
- ide_offsets,
- 0, 0, cris_ide_ack_intr,
- ide_default_irq(0));
+ cris_setup_ports(&hw, cris_ide_base_address(h));
+
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif == NULL)
continue;
ide_init_port_data(hwif, hwif->index);
ide_init_port_hw(hwif, &hw);
hwif->mmio = 1;
- hwif->chipset = ide_etrax100;
hwif->set_pio_mode = &cris_set_pio_mode;
hwif->set_dma_mode = &cris_set_dma_mode;
hwif->ata_input_data = &cris_ide_input_data;
@@ -799,12 +818,6 @@
hwif->INB = &cris_ide_inb;
hwif->INW = &cris_ide_inw;
hwif->cbl = ATA_CBL_PATA40;
- hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
- hwif->pio_mask = ATA_PIO4,
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- hwif->ultra_mask = cris_ultra_mask;
- hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
idx[h] = hwif->index;
}
@@ -820,7 +833,7 @@
cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
- ide_device_add(idx);
+ ide_device_add(idx, &cris_port_info);
return 0;
}
@@ -1032,11 +1045,7 @@
static void cris_dma_exec_cmd(ide_drive_t *drive, u8 command)
{
- /* set the irq handler which will finish the request when DMA is done */
- ide_set_handler(drive, &cris_dma_intr, WAIT_CMD, NULL);
-
- /* issue cmd to drive */
- cris_ide_outb(command, IDE_COMMAND_REG);
+ ide_execute_command(drive, command, &cris_dma_intr, WAIT_CMD, NULL);
}
static void cris_dma_start(ide_drive_t *drive)
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 0243295..520aec0 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -114,7 +114,7 @@
idx[0] = index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
return 0;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 68bc618..e07b189 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -39,7 +39,6 @@
};
struct ide_acpi_drive_link {
- ide_drive_t *drive;
acpi_handle obj_handle;
u8 idbuff[512];
};
@@ -172,7 +171,7 @@
static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
{
struct device *dev = hwif->gendev.parent;
- acpi_handle dev_handle;
+ acpi_handle uninitialized_var(dev_handle);
acpi_integer pcidevfn;
acpi_handle chan_handle;
int err;
@@ -280,16 +279,6 @@
port = hwif->channel ? drive->dn - 2: drive->dn;
- if (!drive->acpidata) {
- if (port == 0) {
- drive->acpidata = &hwif->acpidata->master;
- hwif->acpidata->master.drive = drive;
- } else {
- drive->acpidata = &hwif->acpidata->slave;
- hwif->acpidata->slave.drive = drive;
- }
- }
-
DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
hwif->name, dev->bus_id, port, hwif->channel);
@@ -494,7 +483,6 @@
return ret;
}
-EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
/**
* ide_acpi_get_timing - get the channel (controller) timings
@@ -580,7 +568,6 @@
kfree(output.pointer);
}
-EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
/**
* ide_acpi_push_timing - set the channel (controller) timings
@@ -634,7 +621,6 @@
}
DEBPRINT("_STM status: %d\n", status);
}
-EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
/**
* ide_acpi_set_state - set the channel power state
@@ -688,11 +674,6 @@
*/
void ide_acpi_init(ide_hwif_t *hwif)
{
- int unit;
- int err;
- struct ide_acpi_drive_link *master;
- struct ide_acpi_drive_link *slave;
-
ide_acpi_blacklist();
hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
@@ -704,40 +685,38 @@
DEBPRINT("no ACPI object for %s found\n", hwif->name);
kfree(hwif->acpidata);
hwif->acpidata = NULL;
- return;
}
+}
+
+void ide_acpi_port_init_devices(ide_hwif_t *hwif)
+{
+ ide_drive_t *drive;
+ int i, err;
+
+ if (hwif->acpidata == NULL)
+ return;
/*
* The ACPI spec mandates that we send information
* for both drives, regardless whether they are connected
* or not.
*/
- hwif->acpidata->master.drive = &hwif->drives[0];
hwif->drives[0].acpidata = &hwif->acpidata->master;
- master = &hwif->acpidata->master;
-
- hwif->acpidata->slave.drive = &hwif->drives[1];
hwif->drives[1].acpidata = &hwif->acpidata->slave;
- slave = &hwif->acpidata->slave;
-
/*
* Send IDENTIFY for each drive
*/
- if (master->drive->present) {
- err = taskfile_lib_get_identify(master->drive, master->idbuff);
- if (err) {
- DEBPRINT("identify device %s failed (%d)\n",
- master->drive->name, err);
- }
- }
+ for (i = 0; i < MAX_DRIVES; i++) {
+ drive = &hwif->drives[i];
- if (slave->drive->present) {
- err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
- if (err) {
+ if (!drive->present)
+ continue;
+
+ err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
+ if (err)
DEBPRINT("identify device %s failed (%d)\n",
- slave->drive->name, err);
- }
+ drive->name, err);
}
if (ide_noacpionboot) {
@@ -753,13 +732,11 @@
ide_acpi_get_timing(hwif);
ide_acpi_push_timing(hwif);
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t *drive = &hwif->drives[unit];
+ for (i = 0; i < MAX_DRIVES; i++) {
+ drive = &hwif->drives[i];
- if (drive->present) {
+ if (drive->present)
/* Execute ACPI startup code */
ide_acpi_exec_tfs(drive);
- }
}
}
-EXPORT_SYMBOL_GPL(ide_acpi_init);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 23074e8..5e42c19 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -295,7 +295,8 @@
int stat, err, sense_key;
/* Check for errors. */
- stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
+
if (stat_ret)
*stat_ret = stat;
@@ -303,7 +304,7 @@
return 0;
/* Get the IDE error register. */
- err = HWIF(drive)->INB(IDE_ERROR_REG);
+ err = ide_read_error(drive);
sense_key = err >> 4;
if (rq == NULL) {
@@ -604,8 +605,6 @@
* Block read functions.
*/
-typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
-
static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len)
{
while (len > 0) {
@@ -694,7 +693,7 @@
/* Some drives (ASUS) seem to tell us that status
* info is available. just get it and ignore.
*/
- (void) HWIF(drive)->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
return 0;
} else {
/* Drive wants a command packet, or invalid ireason... */
@@ -1328,7 +1327,7 @@
if (blk_fs_request(rq)) {
if (info->cd_flags & IDE_CD_FLAG_SEEKING) {
unsigned long elapsed = jiffies - info->start_seek;
- int stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ int stat = ide_read_status(drive);
if ((stat & SEEK_STAT) != SEEK_STAT) {
if (elapsed < IDECD_SEEK_TIMEOUT) {
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 7beaf1e..a4bb328 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -147,7 +147,8 @@
u8 stat = 0, dma_stat = 0;
dma_stat = HWIF(drive)->ide_dma_end(drive);
- stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */
+ stat = ide_read_status(drive);
+
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
struct request *rq = HWGROUP(drive)->rq;
@@ -819,6 +820,26 @@
return 0;
}
+void ide_check_dma_crc(ide_drive_t *drive)
+{
+ u8 mode;
+
+ ide_dma_off_quietly(drive);
+ drive->crc_count = 0;
+ mode = drive->current_speed;
+ /*
+ * Don't try non Ultra-DMA modes without iCRC's. Force the
+ * device to PIO and make the user enable SWDMA/MWDMA modes.
+ */
+ if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
+ mode--;
+ else
+ mode = XFER_PIO_4;
+ ide_set_xfer_rate(drive, mode);
+ if (drive->current_speed >= XFER_SW_DMA_0)
+ ide_dma_on(drive);
+}
+
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
void ide_dma_lost_irq (ide_drive_t *drive)
{
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 3512637..faf22d7 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -4,11 +4,6 @@
* Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il>
* Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net>
* Copyright (C) 2005 Bartlomiej Zolnierkiewicz
- */
-
-/*
- * The driver currently doesn't have any fancy features, just the bare
- * minimum read/write support.
*
* This driver supports the following IDE floppy drives:
*
@@ -20,7 +15,7 @@
* Documentation/ide/ChangeLog.ide-floppy.1996-2002
*/
-#define IDEFLOPPY_VERSION "0.99.newide"
+#define IDEFLOPPY_VERSION "1.00"
#include <linux/module.h>
#include <linux/types.h>
@@ -42,179 +37,91 @@
#include <scsi/scsi_ioctl.h>
#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/unaligned.h>
-/*
- * The following are used to debug the driver.
- */
+/* define to see debug info */
#define IDEFLOPPY_DEBUG_LOG 0
-#define IDEFLOPPY_DEBUG_INFO 0
-#define IDEFLOPPY_DEBUG_BUGS 1
/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
-#define IDEFLOPPY_DEBUG( fmt, args... )
+#define IDEFLOPPY_DEBUG(fmt, args...)
#if IDEFLOPPY_DEBUG_LOG
-#define debug_log printk
+#define debug_log(fmt, args...) \
+ printk(KERN_INFO "ide-floppy: " fmt, ## args)
#else
-#define debug_log(fmt, args... ) do {} while(0)
+#define debug_log(fmt, args...) do {} while (0)
#endif
-/*
- * Some drives require a longer irq timeout.
- */
+/* Some drives require a longer irq timeout. */
#define IDEFLOPPY_WAIT_CMD (5 * WAIT_CMD)
/*
- * After each failed packet command we issue a request sense command
- * and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times.
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
*/
#define IDEFLOPPY_MAX_PC_RETRIES 3
/*
- * With each packet command, we allocate a buffer of
- * IDEFLOPPY_PC_BUFFER_SIZE bytes.
+ * With each packet command, we allocate a buffer of IDEFLOPPY_PC_BUFFER_SIZE
+ * bytes.
*/
#define IDEFLOPPY_PC_BUFFER_SIZE 256
/*
- * In various places in the driver, we need to allocate storage
- * for packet commands and requests, which will remain valid while
- * we leave the driver to wait for an interrupt or a timeout event.
+ * In various places in the driver, we need to allocate storage for packet
+ * commands and requests, which will remain valid while we leave the driver to
+ * wait for an interrupt or a timeout event.
*/
#define IDEFLOPPY_PC_STACK (10 + IDEFLOPPY_MAX_PC_RETRIES)
-/*
- * Our view of a packet command.
- */
typedef struct idefloppy_packet_command_s {
u8 c[12]; /* Actual packet bytes */
- int retries; /* On each retry, we increment retries */
+ int retries; /* On each retry, we increment
+ retries */
int error; /* Error code */
int request_transfer; /* Bytes to transfer */
int actually_transferred; /* Bytes actually transferred */
int buffer_size; /* Size of our data buffer */
- int b_count; /* Missing/Available data on the current buffer */
+ int b_count; /* Missing/Available data on
+ the current buffer */
struct request *rq; /* The corresponding request */
u8 *buffer; /* Data buffer */
- u8 *current_position; /* Pointer into the above buffer */
- void (*callback) (ide_drive_t *); /* Called when this packet command is completed */
+ u8 *current_position; /* Pointer into above buffer */
+ void (*callback) (ide_drive_t *); /* Called when this packet
+ command is completed */
u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE]; /* Temporary buffer */
- unsigned long flags; /* Status/Action bit flags: long for set_bit */
+ unsigned long flags; /* Status/Action bit flags: long
+ for set_bit */
} idefloppy_pc_t;
-/*
- * Packet command flag bits.
- */
-#define PC_ABORT 0 /* Set when an error is considered normal - We won't retry */
-#define PC_DMA_RECOMMENDED 2 /* 1 when we prefer to use DMA if possible */
-#define PC_DMA_IN_PROGRESS 3 /* 1 while DMA in progress */
-#define PC_DMA_ERROR 4 /* 1 when encountered problem during DMA */
-#define PC_WRITING 5 /* Data direction */
+/* Packet command flag bits. */
+enum {
+ /* 1 when we prefer to use DMA if possible */
+ PC_FLAG_DMA_RECOMMENDED = (1 << 0),
+ /* 1 while DMA in progress */
+ PC_FLAG_DMA_IN_PROGRESS = (1 << 1),
+ /* 1 when encountered problem during DMA */
+ PC_FLAG_DMA_ERROR = (1 << 2),
+ /* Data direction */
+ PC_FLAG_WRITING = (1 << 3),
+ /* Suppress error reporting */
+ PC_FLAG_SUPPRESS_ERROR = (1 << 4),
+};
-#define PC_SUPPRESS_ERROR 6 /* Suppress error reporting */
-
-/*
- * Removable Block Access Capabilities Page
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x1b */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned ps :1; /* Should be 0 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1; /* Should be 0 */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned page_code :6; /* Page code - Should be 0x1b */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u8 page_length; /* Page Length - Should be 0xa */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved2 :6;
- unsigned srfp :1; /* Supports reporting progress of format */
- unsigned sflp :1; /* System floppy type device */
- unsigned tlun :3; /* Total logical units supported by the device */
- unsigned reserved3 :3;
- unsigned sml :1; /* Single / Multiple lun supported */
- unsigned ncd :1; /* Non cd optical device */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned sflp :1; /* System floppy type device */
- unsigned srfp :1; /* Supports reporting progress of format */
- unsigned reserved2 :6;
- unsigned ncd :1; /* Non cd optical device */
- unsigned sml :1; /* Single / Multiple lun supported */
- unsigned reserved3 :3;
- unsigned tlun :3; /* Total logical units supported by the device */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u8 reserved[8];
-} idefloppy_capabilities_page_t;
-
-/*
- * Flexible disk page.
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x5 */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned ps :1; /* The device is capable of saving the page */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1; /* The device is capable of saving the page */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned page_code :6; /* Page code - Should be 0x5 */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u8 page_length; /* Page Length - Should be 0x1e */
- u16 transfer_rate; /* In kilobits per second */
- u8 heads, sectors; /* Number of heads, Number of sectors per track */
- u16 sector_size; /* Byes per sector */
- u16 cyls; /* Number of cylinders */
- u8 reserved10[10];
- u8 motor_delay; /* Motor off delay */
- u8 reserved21[7];
- u16 rpm; /* Rotations per minute */
- u8 reserved30[2];
-} idefloppy_flexible_disk_page_t;
-
-/*
- * Format capacity
- */
-typedef struct {
- u8 reserved[3];
- u8 length; /* Length of the following descriptors in bytes */
-} idefloppy_capacity_header_t;
-
-typedef struct {
- u32 blocks; /* Number of blocks */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned dc :2; /* Descriptor Code */
- unsigned reserved :6;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved :6;
- unsigned dc :2; /* Descriptor Code */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u8 length_msb; /* Block Length (MSB)*/
- u16 length; /* Block Length */
-} idefloppy_capacity_descriptor_t;
-
+/* format capacities descriptor codes */
#define CAPACITY_INVALID 0x00
#define CAPACITY_UNFORMATTED 0x01
#define CAPACITY_CURRENT 0x02
#define CAPACITY_NO_CARTRIDGE 0x03
/*
- * Most of our global data which we need to save even as we leave the
- * driver due to an interrupt or a timer event is stored in a variable
- * of type idefloppy_floppy_t, defined below.
+ * Most of our global data which we need to save even as we leave the driver
+ * due to an interrupt or a timer event is stored in a variable of type
+ * idefloppy_floppy_t, defined below.
*/
typedef struct ide_floppy_obj {
ide_drive_t *drive;
@@ -235,23 +142,19 @@
/* We implement a circular array */
int rq_stack_index;
- /*
- * Last error information
- */
+ /* Last error information */
u8 sense_key, asc, ascq;
/* delay this long before sending packet command */
u8 ticks;
int progress_indication;
- /*
- * Device information
- */
+ /* Device information */
/* Current format */
int blocks, block_size, bs_factor;
- /* Last format capacity */
- idefloppy_capacity_descriptor_t capacity;
+ /* Last format capacity descriptor */
+ u8 cap_desc[8];
/* Copy of the flexible disk page */
- idefloppy_flexible_disk_page_t flexible_disk_page;
+ u8 flexible_disk_page[32];
/* Write protect */
int wp;
/* Supports format progress report */
@@ -262,64 +165,40 @@
#define IDEFLOPPY_TICKS_DELAY HZ/20 /* default delay for ZIP 100 (50ms) */
-/*
- * Floppy flag bits values.
- */
-#define IDEFLOPPY_DRQ_INTERRUPT 0 /* DRQ interrupt device */
-#define IDEFLOPPY_MEDIA_CHANGED 1 /* Media may have changed */
-#define IDEFLOPPY_USE_READ12 2 /* Use READ12/WRITE12 or READ10/WRITE10 */
-#define IDEFLOPPY_FORMAT_IN_PROGRESS 3 /* Format in progress */
-#define IDEFLOPPY_CLIK_DRIVE 4 /* Avoid commands not supported in Clik drive */
-#define IDEFLOPPY_ZIP_DRIVE 5 /* Requires BH algorithm for packets */
+/* Floppy flag bits values. */
+enum {
+ /* DRQ interrupt device */
+ IDEFLOPPY_FLAG_DRQ_INTERRUPT = (1 << 0),
+ /* Media may have changed */
+ IDEFLOPPY_FLAG_MEDIA_CHANGED = (1 << 1),
+ /* Format in progress */
+ IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS = (1 << 2),
+ /* Avoid commands not supported in Clik drive */
+ IDEFLOPPY_FLAG_CLIK_DRIVE = (1 << 3),
+ /* Requires BH algorithm for packets */
+ IDEFLOPPY_FLAG_ZIP_DRIVE = (1 << 4),
+};
-/*
- * ATAPI floppy drive packet commands
- */
-#define IDEFLOPPY_FORMAT_UNIT_CMD 0x04
-#define IDEFLOPPY_INQUIRY_CMD 0x12
-#define IDEFLOPPY_MODE_SELECT_CMD 0x55
-#define IDEFLOPPY_MODE_SENSE_CMD 0x5a
-#define IDEFLOPPY_READ10_CMD 0x28
-#define IDEFLOPPY_READ12_CMD 0xa8
-#define IDEFLOPPY_READ_CAPACITY_CMD 0x23
-#define IDEFLOPPY_REQUEST_SENSE_CMD 0x03
-#define IDEFLOPPY_PREVENT_REMOVAL_CMD 0x1e
-#define IDEFLOPPY_SEEK_CMD 0x2b
-#define IDEFLOPPY_START_STOP_CMD 0x1b
-#define IDEFLOPPY_TEST_UNIT_READY_CMD 0x00
-#define IDEFLOPPY_VERIFY_CMD 0x2f
-#define IDEFLOPPY_WRITE10_CMD 0x2a
-#define IDEFLOPPY_WRITE12_CMD 0xaa
-#define IDEFLOPPY_WRITE_VERIFY_CMD 0x2e
-
-/*
- * Defines for the mode sense command
- */
+/* Defines for the MODE SENSE command */
#define MODE_SENSE_CURRENT 0x00
#define MODE_SENSE_CHANGEABLE 0x01
-#define MODE_SENSE_DEFAULT 0x02
+#define MODE_SENSE_DEFAULT 0x02
#define MODE_SENSE_SAVED 0x03
-/*
- * IOCTLs used in low-level formatting.
- */
-
+/* IOCTLs used in low-level formatting. */
#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600
#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601
#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602
#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603
-/*
- * Error codes which are returned in rq->errors to the higher part
- * of the driver.
- */
+/* Error code returned in rq->errors to the higher part of the driver. */
#define IDEFLOPPY_ERROR_GENERAL 101
/*
- * The following is used to format the general configuration word of
- * the ATAPI IDENTIFY DEVICE command.
+ * The following is used to format the general configuration word of the
+ * ATAPI IDENTIFY DEVICE command.
*/
-struct idefloppy_id_gcw {
+struct idefloppy_id_gcw {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned packet_size :2; /* Packet Size */
unsigned reserved234 :3; /* Reserved */
@@ -342,103 +221,12 @@
};
/*
- * INQUIRY packet command - Data Format
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned device_type :5; /* Peripheral Device Type */
- unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
- unsigned reserved1_6t0 :7; /* Reserved */
- unsigned rmb :1; /* Removable Medium Bit */
- unsigned ansi_version :3; /* ANSI Version */
- unsigned ecma_version :3; /* ECMA Version */
- unsigned iso_version :2; /* ISO Version */
- unsigned response_format :4; /* Response Data Format */
- unsigned reserved3_45 :2; /* Reserved */
- unsigned reserved3_6 :1; /* TrmIOP - Reserved */
- unsigned reserved3_7 :1; /* AENC - Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
- unsigned device_type :5; /* Peripheral Device Type */
- unsigned rmb :1; /* Removable Medium Bit */
- unsigned reserved1_6t0 :7; /* Reserved */
- unsigned iso_version :2; /* ISO Version */
- unsigned ecma_version :3; /* ECMA Version */
- unsigned ansi_version :3; /* ANSI Version */
- unsigned reserved3_7 :1; /* AENC - Reserved */
- unsigned reserved3_6 :1; /* TrmIOP - Reserved */
- unsigned reserved3_45 :2; /* Reserved */
- unsigned response_format :4; /* Response Data Format */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u8 additional_length; /* Additional Length (total_length-4) */
- u8 rsv5, rsv6, rsv7; /* Reserved */
- u8 vendor_id[8]; /* Vendor Identification */
- u8 product_id[16]; /* Product Identification */
- u8 revision_level[4]; /* Revision Level */
- u8 vendor_specific[20]; /* Vendor Specific - Optional */
- u8 reserved56t95[40]; /* Reserved - Optional */
- /* Additional information may be returned */
-} idefloppy_inquiry_result_t;
-
-/*
- * REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned error_code :7; /* Current error (0x70) */
- unsigned valid :1; /* The information field conforms to SFF-8070i */
- u8 reserved1 :8; /* Reserved */
- unsigned sense_key :4; /* Sense Key */
- unsigned reserved2_4 :1; /* Reserved */
- unsigned ili :1; /* Incorrect Length Indicator */
- unsigned reserved2_67 :2;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned valid :1; /* The information field conforms to SFF-8070i */
- unsigned error_code :7; /* Current error (0x70) */
- u8 reserved1 :8; /* Reserved */
- unsigned reserved2_67 :2;
- unsigned ili :1; /* Incorrect Length Indicator */
- unsigned reserved2_4 :1; /* Reserved */
- unsigned sense_key :4; /* Sense Key */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u32 information __attribute__ ((packed));
- u8 asl; /* Additional sense length (n-7) */
- u32 command_specific; /* Additional command specific information */
- u8 asc; /* Additional Sense Code */
- u8 ascq; /* Additional Sense Code Qualifier */
- u8 replaceable_unit_code; /* Field Replaceable Unit Code */
- u8 sksv[3];
- u8 pad[2]; /* Padding to 20 bytes */
-} idefloppy_request_sense_result_t;
-
-/*
- * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * See SFF-8070i spec.
*/
#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b
#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05
-/*
- * Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
- u16 mode_data_length; /* Length of the following data transfer */
- u8 medium_type; /* Medium Type */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved3 :7;
- unsigned wp :1; /* Write protect */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- unsigned wp :1; /* Write protect */
- unsigned reserved3 :7;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
- u8 reserved[4];
-} idefloppy_mode_parameter_header_t;
-
static DEFINE_MUTEX(idefloppy_ref_mutex);
#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
@@ -458,39 +246,35 @@
return floppy;
}
-static void ide_floppy_release(struct kref *);
+static void idefloppy_cleanup_obj(struct kref *);
static void ide_floppy_put(struct ide_floppy_obj *floppy)
{
mutex_lock(&idefloppy_ref_mutex);
- kref_put(&floppy->kref, ide_floppy_release);
+ kref_put(&floppy->kref, idefloppy_cleanup_obj);
mutex_unlock(&idefloppy_ref_mutex);
}
/*
- * Too bad. The drive wants to send us data which we are not ready to accept.
- * Just throw it away.
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
*/
-static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
+static void idefloppy_discard_data(ide_drive_t *drive, unsigned int bcount)
{
while (bcount--)
(void) HWIF(drive)->INB(IDE_DATA_REG);
}
-#if IDEFLOPPY_DEBUG_BUGS
-static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
+static void idefloppy_write_zeros(ide_drive_t *drive, unsigned int bcount)
{
while (bcount--)
HWIF(drive)->OUTB(0, IDE_DATA_REG);
}
-#endif /* IDEFLOPPY_DEBUG_BUGS */
/*
- * idefloppy_do_end_request is used to finish servicing a request.
- *
- * For read/write requests, we will call ide_end_request to pass to the
- * next buffer.
+ * Used to finish servicing a request. For read/write requests, we will call
+ * ide_end_request to pass to the next buffer.
*/
static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
{
@@ -498,12 +282,12 @@
struct request *rq = HWGROUP(drive)->rq;
int error;
- debug_log(KERN_INFO "Reached idefloppy_end_request\n");
+ debug_log("Reached %s\n", __func__);
switch (uptodate) {
- case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
- case 1: error = 0; break;
- default: error = uptodate;
+ case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
+ case 1: error = 0; break;
+ default: error = uptodate;
}
if (error)
floppy->failed_pc = NULL;
@@ -521,39 +305,8 @@
return 0;
}
-static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
-{
- struct request *rq = pc->rq;
- struct bio_vec *bvec;
- struct req_iterator iter;
- unsigned long flags;
- char *data;
- int count, done = 0;
-
- rq_for_each_segment(bvec, rq, iter) {
- if (!bcount)
- break;
-
- count = min(bvec->bv_len, bcount);
-
- data = bvec_kmap_irq(bvec, &flags);
- drive->hwif->atapi_input_bytes(drive, data, count);
- bvec_kunmap_irq(data, &flags);
-
- bcount -= count;
- pc->b_count += count;
- done += count;
- }
-
- idefloppy_do_end_request(drive, 1, done >> 9);
-
- if (bcount) {
- printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
- idefloppy_discard_data(drive, bcount);
- }
-}
-
-static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+static void ide_floppy_io_buffers(ide_drive_t *drive, idefloppy_pc_t *pc,
+ unsigned int bcount, int direction)
{
struct request *rq = pc->rq;
struct req_iterator iter;
@@ -569,7 +322,10 @@
count = min(bvec->bv_len, bcount);
data = bvec_kmap_irq(bvec, &flags);
- drive->hwif->atapi_output_bytes(drive, data, count);
+ if (direction)
+ drive->hwif->atapi_output_bytes(drive, data, count);
+ else
+ drive->hwif->atapi_input_bytes(drive, data, count);
bvec_kunmap_irq(data, &flags);
bcount -= count;
@@ -579,15 +335,18 @@
idefloppy_do_end_request(drive, 1, done >> 9);
-#if IDEFLOPPY_DEBUG_BUGS
if (bcount) {
- printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
- idefloppy_write_zeros(drive, bcount);
+ printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
+ drive->name, __func__, bcount);
+ if (direction)
+ idefloppy_write_zeros(drive, bcount);
+ else
+ idefloppy_discard_data(drive, bcount);
+
}
-#endif
}
-static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
+static void idefloppy_update_buffers(ide_drive_t *drive, idefloppy_pc_t *pc)
{
struct request *rq = pc->rq;
struct bio *bio = rq->bio;
@@ -597,11 +356,12 @@
}
/*
- * idefloppy_queue_pc_head generates a new packet command request in front
- * of the request queue, before the current request, so that it will be
- * processed immediately, on the next pass through the driver.
+ * Generate a new packet command request in front of the request queue, before
+ * the current request so that it will be processed immediately, on the next
+ * pass through the driver.
*/
-static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
+static void idefloppy_queue_pc_head(ide_drive_t *drive, idefloppy_pc_t *pc,
+ struct request *rq)
{
struct ide_floppy_obj *floppy = drive->driver_data;
@@ -612,16 +372,16 @@
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
-static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
+static idefloppy_pc_t *idefloppy_next_pc_storage(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
- floppy->pc_stack_index=0;
+ floppy->pc_stack_index = 0;
return (&floppy->pc_stack[floppy->pc_stack_index++]);
}
-static struct request *idefloppy_next_rq_storage (ide_drive_t *drive)
+static struct request *idefloppy_next_rq_storage(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
@@ -630,60 +390,53 @@
return (&floppy->rq_stack[floppy->rq_stack_index++]);
}
-/*
- * idefloppy_analyze_error is called on each failed packet command retry
- * to analyze the request sense.
- */
-static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_result_t *result)
+static void idefloppy_request_sense_callback(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
+ u8 *buf = floppy->pc->buffer;
- floppy->sense_key = result->sense_key;
- floppy->asc = result->asc;
- floppy->ascq = result->ascq;
- floppy->progress_indication = result->sksv[0] & 0x80 ?
- (u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
- if (floppy->failed_pc)
- debug_log(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
- "asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
- result->sense_key, result->asc, result->ascq);
- else
- debug_log(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
- "ascq = %x\n", result->sense_key,
- result->asc, result->ascq);
-}
+ debug_log("Reached %s\n", __func__);
-static void idefloppy_request_sense_callback (ide_drive_t *drive)
-{
- idefloppy_floppy_t *floppy = drive->driver_data;
-
- debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
-
if (!floppy->pc->error) {
- idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+ floppy->sense_key = buf[2] & 0x0F;
+ floppy->asc = buf[12];
+ floppy->ascq = buf[13];
+ floppy->progress_indication = buf[15] & 0x80 ?
+ (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
+
+ if (floppy->failed_pc)
+ debug_log("pc = %x, sense key = %x, asc = %x,"
+ " ascq = %x\n",
+ floppy->failed_pc->c[0],
+ floppy->sense_key,
+ floppy->asc,
+ floppy->ascq);
+ else
+ debug_log("sense key = %x, asc = %x, ascq = %x\n",
+ floppy->sense_key,
+ floppy->asc,
+ floppy->ascq);
+
+
idefloppy_do_end_request(drive, 1, 0);
} else {
- printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+ printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting"
+ " request!\n");
idefloppy_do_end_request(drive, 0, 0);
}
}
-/*
- * General packet command callback function.
- */
-static void idefloppy_pc_callback (ide_drive_t *drive)
+/* General packet command callback function. */
+static void idefloppy_pc_callback(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
-
- debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
+
+ debug_log("Reached %s\n", __func__);
idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0);
}
-/*
- * idefloppy_init_pc initializes a packet command.
- */
-static void idefloppy_init_pc (idefloppy_pc_t *pc)
+static void idefloppy_init_pc(idefloppy_pc_t *pc)
{
memset(pc->c, 0, 12);
pc->retries = 0;
@@ -694,75 +447,75 @@
pc->callback = &idefloppy_pc_callback;
}
-static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
+static void idefloppy_create_request_sense_cmd(idefloppy_pc_t *pc)
{
- idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
+ idefloppy_init_pc(pc);
+ pc->c[0] = GPCMD_REQUEST_SENSE;
pc->c[4] = 255;
pc->request_transfer = 18;
pc->callback = &idefloppy_request_sense_callback;
}
/*
- * idefloppy_retry_pc is called when an error was detected during the
- * last packet command. We queue a request sense packet command in
- * the head of the request list.
+ * Called when an error was detected during the last packet command. We queue a
+ * request sense packet command in the head of the request list.
*/
-static void idefloppy_retry_pc (ide_drive_t *drive)
+static void idefloppy_retry_pc(ide_drive_t *drive)
{
idefloppy_pc_t *pc;
struct request *rq;
- (void)drive->hwif->INB(IDE_ERROR_REG);
+ (void)ide_read_error(drive);
pc = idefloppy_next_pc_storage(drive);
rq = idefloppy_next_rq_storage(drive);
idefloppy_create_request_sense_cmd(pc);
idefloppy_queue_pc_head(drive, pc, rq);
}
-/*
- * idefloppy_pc_intr is the usual interrupt handler which will be called
- * during a packet command.
- */
+/* The usual interrupt handler called during a packet command. */
static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
ide_hwif_t *hwif = drive->hwif;
idefloppy_pc_t *pc = floppy->pc;
struct request *rq = pc->rq;
+ xfer_func_t *xferfunc;
unsigned int temp;
+ int dma_error = 0;
u16 bcount;
u8 stat, ireason;
- debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
- __FUNCTION__);
+ debug_log("Reached %s interrupt handler\n", __func__);
- if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->ide_dma_end(drive)) {
- set_bit(PC_DMA_ERROR, &pc->flags);
+ if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
+ dma_error = hwif->ide_dma_end(drive);
+ if (dma_error) {
+ printk(KERN_ERR "%s: DMA %s error\n", drive->name,
+ rq_data_dir(rq) ? "write" : "read");
+ pc->flags |= PC_FLAG_DMA_ERROR;
} else {
pc->actually_transferred = pc->request_transfer;
idefloppy_update_buffers(drive, pc);
}
- debug_log(KERN_INFO "ide-floppy: DMA finished\n");
+ debug_log("DMA finished\n");
}
/* Clear the interrupt */
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
- if ((stat & DRQ_STAT) == 0) { /* No more interrupts */
- debug_log(KERN_INFO "Packet command completed, %d bytes "
- "transferred\n", pc->actually_transferred);
- clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ /* No more interrupts */
+ if ((stat & DRQ_STAT) == 0) {
+ debug_log("Packet command completed, %d bytes transferred\n",
+ pc->actually_transferred);
+ pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
local_irq_enable_in_hardirq();
- if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
+ if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
/* Error detected */
- debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
- drive->name);
+ debug_log("%s: I/O error\n", drive->name);
rq->errors++;
- if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+ if (pc->c[0] == GPCMD_REQUEST_SENSE) {
printk(KERN_ERR "ide-floppy: I/O error in "
"request sense command\n");
return ide_do_reset(drive);
@@ -780,7 +533,8 @@
return ide_stopped;
}
- if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
+ pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
printk(KERN_ERR "ide-floppy: The floppy wants to issue "
"more interrupts in DMA mode\n");
ide_dma_off(drive);
@@ -794,10 +548,10 @@
ireason = hwif->INB(IDE_IREASON_REG);
if (ireason & CD) {
- printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+ printk(KERN_ERR "ide-floppy: CoD != 0 in %s\n", __func__);
return ide_do_reset(drive);
}
- if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
+ if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
/* Hopefully, we will never get here */
printk(KERN_ERR "ide-floppy: We wanted to %s, ",
(ireason & IO) ? "Write" : "Read");
@@ -805,7 +559,7 @@
(ireason & IO) ? "Read" : "Write");
return ide_do_reset(drive);
}
- if (!test_bit(PC_WRITING, &pc->flags)) {
+ if (!(pc->flags & PC_FLAG_WRITING)) {
/* Reading - Check that we have enough space */
temp = pc->actually_transferred + bcount;
if (temp > pc->request_transfer) {
@@ -814,39 +568,34 @@
"to send us more data than expected "
"- discarding data\n");
idefloppy_discard_data(drive, bcount);
- BUG_ON(HWGROUP(drive)->handler != NULL);
+
ide_set_handler(drive,
&idefloppy_pc_intr,
IDEFLOPPY_WAIT_CMD,
NULL);
return ide_started;
}
- debug_log(KERN_NOTICE "ide-floppy: The floppy wants to "
- "send us more data than expected - "
- "allowing transfer\n");
+ debug_log("The floppy wants to send us more data than"
+ " expected - allowing transfer\n");
}
}
- if (test_bit(PC_WRITING, &pc->flags)) {
- if (pc->buffer != NULL)
- /* Write the current buffer */
- hwif->atapi_output_bytes(drive, pc->current_position,
- bcount);
- else
- idefloppy_output_buffers(drive, pc, bcount);
- } else {
- if (pc->buffer != NULL)
- /* Read the current buffer */
- hwif->atapi_input_bytes(drive, pc->current_position,
- bcount);
- else
- idefloppy_input_buffers(drive, pc, bcount);
- }
+ if (pc->flags & PC_FLAG_WRITING)
+ xferfunc = hwif->atapi_output_bytes;
+ else
+ xferfunc = hwif->atapi_input_bytes;
+
+ if (pc->buffer)
+ xferfunc(drive, pc->current_position, bcount);
+ else
+ ide_floppy_io_buffers(drive, pc, bcount,
+ !!(pc->flags & PC_FLAG_WRITING));
+
/* Update the current position */
pc->actually_transferred += bcount;
pc->current_position += bcount;
- BUG_ON(HWGROUP(drive)->handler != NULL);
- ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
+ /* And set the interrupt handler again */
+ ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
return ide_started;
}
@@ -855,7 +604,7 @@
* It fails at high speeds on the Iomega ZIP drive, so there's a slower version
* for that drive below. The algorithm is chosen based on drive type
*/
-static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive)
{
ide_startstop_t startstop;
idefloppy_floppy_t *floppy = drive->driver_data;
@@ -872,7 +621,7 @@
"issuing a packet command\n");
return ide_do_reset(drive);
}
- BUG_ON(HWGROUP(drive)->handler != NULL);
+
/* Set the interrupt routine */
ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
/* Send the actual packet */
@@ -882,18 +631,16 @@
/*
- * What we have here is a classic case of a top half / bottom half
- * interrupt service routine. In interrupt mode, the device sends
- * an interrupt to signal it's ready to receive a packet. However,
- * we need to delay about 2-3 ticks before issuing the packet or we
- * gets in trouble.
+ * What we have here is a classic case of a top half / bottom half interrupt
+ * service routine. In interrupt mode, the device sends an interrupt to signal
+ * that it is ready to receive a packet. However, we need to delay about 2-3
+ * ticks before issuing the packet or we gets in trouble.
*
- * So, follow carefully. transfer_pc1 is called as an interrupt (or
- * directly). In either case, when the device says it's ready for a
- * packet, we schedule the packet transfer to occur about 2-3 ticks
- * later in transfer_pc2.
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or directly).
+ * In either case, when the device says it's ready for a packet, we schedule
+ * the packet transfer to occur about 2-3 ticks later in transfer_pc2.
*/
-static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+static int idefloppy_transfer_pc2(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
@@ -903,7 +650,7 @@
return IDEFLOPPY_WAIT_CMD;
}
-static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc1(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
ide_startstop_t startstop;
@@ -920,7 +667,7 @@
"while issuing a packet command\n");
return ide_do_reset(drive);
}
- /*
+ /*
* The following delay solves a problem with ATAPI Zip 100 drives
* where the Busy flag was apparently being deasserted before the
* unit was ready to receive data. This was happening on a
@@ -928,32 +675,30 @@
* 40 and 50msec work well. idefloppy_pc_intr will not be actually
* used until after the packet is moved in about 50 msec.
*/
- BUG_ON(HWGROUP(drive)->handler != NULL);
- ide_set_handler(drive,
- &idefloppy_pc_intr, /* service routine for packet command */
- floppy->ticks, /* wait this long before "failing" */
- &idefloppy_transfer_pc2); /* fail == transfer_pc2 */
+
+ ide_set_handler(drive, &idefloppy_pc_intr, floppy->ticks,
+ &idefloppy_transfer_pc2);
return ide_started;
}
-/**
- * idefloppy_should_report_error()
- *
- * Supresses error messages resulting from Medium not present
- */
-static inline int idefloppy_should_report_error(idefloppy_floppy_t *floppy)
+static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
+ idefloppy_pc_t *pc)
{
+ /* supress error messages resulting from Medium not present */
if (floppy->sense_key == 0x02 &&
floppy->asc == 0x3a &&
floppy->ascq == 0x00)
- return 0;
- return 1;
+ return;
+
+ printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, "
+ "asc = %2x, ascq = %2x\n",
+ floppy->drive->name, pc->c[0], floppy->sense_key,
+ floppy->asc, floppy->ascq);
+
}
-/*
- * Issue a packet command
- */
-static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
+static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
+ idefloppy_pc_t *pc)
{
idefloppy_floppy_t *floppy = drive->driver_data;
ide_hwif_t *hwif = drive->hwif;
@@ -962,36 +707,23 @@
u8 dma;
if (floppy->failed_pc == NULL &&
- pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+ pc->c[0] != GPCMD_REQUEST_SENSE)
floppy->failed_pc = pc;
/* Set the current packet command */
floppy->pc = pc;
- if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
- test_bit(PC_ABORT, &pc->flags)) {
- /*
- * We will "abort" retrying a packet command in case
- * a legitimate error code was received.
- */
- if (!test_bit(PC_ABORT, &pc->flags)) {
- if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
- if (idefloppy_should_report_error(floppy))
- printk(KERN_ERR "ide-floppy: %s: I/O error, "
- "pc = %2x, key = %2x, "
- "asc = %2x, ascq = %2x\n",
- drive->name, pc->c[0],
- floppy->sense_key,
- floppy->asc, floppy->ascq);
- }
- /* Giving up */
- pc->error = IDEFLOPPY_ERROR_GENERAL;
- }
+ if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
+ if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
+ ide_floppy_report_error(floppy, pc);
+ /* Giving up */
+ pc->error = IDEFLOPPY_ERROR_GENERAL;
+
floppy->failed_pc = NULL;
pc->callback(drive);
return ide_stopped;
}
- debug_log(KERN_INFO "Retry number - %d\n",pc->retries);
+ debug_log("Retry number - %d\n", pc->retries);
pc->retries++;
/* We haven't transferred any data yet */
@@ -999,24 +731,26 @@
pc->current_position = pc->buffer;
bcount = min(pc->request_transfer, 63 * 1024);
- if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
+ if (pc->flags & PC_FLAG_DMA_ERROR) {
+ pc->flags &= ~PC_FLAG_DMA_ERROR;
ide_dma_off(drive);
-
+ }
dma = 0;
- if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ if ((pc->flags & PC_FLAG_DMA_RECOMMENDED) && drive->using_dma)
dma = !hwif->dma_setup(drive);
ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
IDE_TFLAG_OUT_DEVICE, bcount, dma);
- if (dma) { /* Begin DMA, if necessary */
- set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ if (dma) {
+ /* Begin DMA, if necessary */
+ pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
hwif->dma_start(drive);
}
/* Can we transfer the packet when we get the interrupt or wait? */
- if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+ if (floppy->flags & IDEFLOPPY_FLAG_ZIP_DRIVE) {
/* wait */
pkt_xfer_routine = &idefloppy_transfer_pc1;
} else {
@@ -1024,7 +758,7 @@
pkt_xfer_routine = &idefloppy_transfer_pc;
}
- if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+ if (floppy->flags & IDEFLOPPY_FLAG_DRQ_INTERRUPT) {
/* Issue the packet command */
ide_execute_command(drive, WIN_PACKETCMD,
pkt_xfer_routine,
@@ -1038,38 +772,37 @@
}
}
-static void idefloppy_rw_callback (ide_drive_t *drive)
+static void idefloppy_rw_callback(ide_drive_t *drive)
{
- debug_log(KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
+ debug_log("Reached %s\n", __func__);
idefloppy_do_end_request(drive, 1, 0);
return;
}
-static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
+static void idefloppy_create_prevent_cmd(idefloppy_pc_t *pc, int prevent)
{
- debug_log(KERN_INFO "ide-floppy: creating prevent removal command, "
- "prevent = %d\n", prevent);
+ debug_log("creating prevent removal command, prevent = %d\n", prevent);
idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
+ pc->c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
pc->c[4] = prevent;
}
-static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
+static void idefloppy_create_read_capacity_cmd(idefloppy_pc_t *pc)
{
idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
+ pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
pc->c[7] = 255;
pc->c[8] = 255;
pc->request_transfer = 255;
}
-static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
+static void idefloppy_create_format_unit_cmd(idefloppy_pc_t *pc, int b, int l,
int flags)
{
idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
+ pc->c[0] = GPCMD_FORMAT_UNIT;
pc->c[1] = 0x17;
memset(pc->buffer, 0, 12);
@@ -1080,83 +813,79 @@
pc->buffer[1] ^= 0x20; /* ... turn off DCRT bit */
pc->buffer[3] = 8;
- put_unaligned(htonl(b), (unsigned int *)(&pc->buffer[4]));
- put_unaligned(htonl(l), (unsigned int *)(&pc->buffer[8]));
- pc->buffer_size=12;
- set_bit(PC_WRITING, &pc->flags);
+ put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buffer[4]));
+ put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buffer[8]));
+ pc->buffer_size = 12;
+ pc->flags |= PC_FLAG_WRITING;
}
-/*
- * A mode sense command is used to "sense" floppy parameters.
- */
-static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
+/* A mode sense command is used to "sense" floppy parameters. */
+static void idefloppy_create_mode_sense_cmd(idefloppy_pc_t *pc, u8 page_code,
+ u8 type)
{
- u16 length = sizeof(idefloppy_mode_parameter_header_t);
-
+ u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
+
idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
+ pc->c[0] = GPCMD_MODE_SENSE_10;
pc->c[1] = 0;
pc->c[2] = page_code + (type << 6);
switch (page_code) {
- case IDEFLOPPY_CAPABILITIES_PAGE:
- length += 12;
- break;
- case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
- length += 32;
- break;
- default:
- printk(KERN_ERR "ide-floppy: unsupported page code "
+ case IDEFLOPPY_CAPABILITIES_PAGE:
+ length += 12;
+ break;
+ case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
+ length += 32;
+ break;
+ default:
+ printk(KERN_ERR "ide-floppy: unsupported page code "
"in create_mode_sense_cmd\n");
}
- put_unaligned(htons(length), (u16 *) &pc->c[7]);
+ put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
pc->request_transfer = length;
}
-static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
+static void idefloppy_create_start_stop_cmd(idefloppy_pc_t *pc, int start)
{
idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_START_STOP_CMD;
+ pc->c[0] = GPCMD_START_STOP_UNIT;
pc->c[4] = start;
}
static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
{
idefloppy_init_pc(pc);
- pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
+ pc->c[0] = GPCMD_TEST_UNIT_READY;
}
-static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
+static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
+ idefloppy_pc_t *pc, struct request *rq,
+ unsigned long sector)
{
int block = sector / floppy->bs_factor;
int blocks = rq->nr_sectors / floppy->bs_factor;
int cmd = rq_data_dir(rq);
- debug_log("create_rw1%d_cmd: block == %d, blocks == %d\n",
- 2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags),
+ debug_log("create_rw10_cmd: block == %d, blocks == %d\n",
block, blocks);
idefloppy_init_pc(pc);
- if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
- pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
- put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
- } else {
- pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
- put_unaligned(htons(blocks), (unsigned short *) &pc->c[7]);
- }
- put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
+ pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
+ put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
+ put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
+
pc->callback = &idefloppy_rw_callback;
pc->rq = rq;
pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
if (rq->cmd_flags & REQ_RW)
- set_bit(PC_WRITING, &pc->flags);
+ pc->flags |= PC_FLAG_WRITING;
pc->buffer = NULL;
pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
- set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+ pc->flags |= PC_FLAG_DMA_RECOMMENDED;
}
-static void
-idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq)
+static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
+ idefloppy_pc_t *pc, struct request *rq)
{
idefloppy_init_pc(pc);
pc->callback = &idefloppy_rw_callback;
@@ -1164,11 +893,10 @@
pc->rq = rq;
pc->b_count = rq->data_len;
if (rq->data_len && rq_data_dir(rq) == WRITE)
- set_bit(PC_WRITING, &pc->flags);
+ pc->flags |= PC_FLAG_WRITING;
pc->buffer = rq->data;
if (rq->bio)
- set_bit(PC_DMA_RECOMMENDED, &pc->flags);
-
+ pc->flags |= PC_FLAG_DMA_RECOMMENDED;
/*
* possibly problematic, doesn't look like ide-floppy correctly
* handled scattered requests if dma fails...
@@ -1176,30 +904,23 @@
pc->request_transfer = pc->buffer_size = rq->data_len;
}
-/*
- * idefloppy_do_request is our request handling function.
- */
-static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, sector_t block_s)
+static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t block_s)
{
idefloppy_floppy_t *floppy = drive->driver_data;
idefloppy_pc_t *pc;
unsigned long block = (unsigned long)block_s;
- debug_log(KERN_INFO "dev: %s, flags: %lx, errors: %d\n",
+ debug_log("dev: %s, cmd_type: %x, errors: %d\n",
rq->rq_disk ? rq->rq_disk->disk_name : "?",
- rq->flags, rq->errors);
- debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+ rq->cmd_type, rq->errors);
+ debug_log("sector: %ld, nr_sectors: %ld, "
"current_nr_sectors: %d\n", (long)rq->sector,
rq->nr_sectors, rq->current_nr_sectors);
if (rq->errors >= ERROR_MAX) {
- if (floppy->failed_pc != NULL) {
- if (idefloppy_should_report_error(floppy))
- printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
- " key = %2x, asc = %2x, ascq = %2x\n",
- drive->name, floppy->failed_pc->c[0],
- floppy->sense_key, floppy->asc, floppy->ascq);
- }
+ if (floppy->failed_pc)
+ ide_floppy_report_error(floppy, floppy->failed_pc);
else
printk(KERN_ERR "ide-floppy: %s: I/O error\n",
drive->name);
@@ -1209,8 +930,8 @@
if (blk_fs_request(rq)) {
if (((long)rq->sector % floppy->bs_factor) ||
(rq->nr_sectors % floppy->bs_factor)) {
- printk("%s: unsupported r/w request size\n",
- drive->name);
+ printk(KERN_ERR "%s: unsupported r/w request size\n",
+ drive->name);
idefloppy_do_end_request(drive, 0, 0);
return ide_stopped;
}
@@ -1233,15 +954,15 @@
}
/*
- * idefloppy_queue_pc_tail adds a special packet command request to the
- * tail of the request queue, and waits for it to be serviced.
+ * Add a special packet command request to the tail of the request queue,
+ * and wait for it to be serviced.
*/
-static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
+static int idefloppy_queue_pc_tail(ide_drive_t *drive, idefloppy_pc_t *pc)
{
struct ide_floppy_obj *floppy = drive->driver_data;
struct request rq;
- ide_init_drive_cmd (&rq);
+ ide_init_drive_cmd(&rq);
rq.buffer = (char *) pc;
rq.cmd_type = REQ_TYPE_SPECIAL;
rq.rq_disk = floppy->disk;
@@ -1250,88 +971,90 @@
}
/*
- * Look at the flexible disk page parameters. We will ignore the CHS
- * capacity parameters and use the LBA parameters instead.
+ * Look at the flexible disk page parameters. We ignore the CHS capacity
+ * parameters and use the LBA parameters instead.
*/
-static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
+static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
idefloppy_pc_t pc;
- idefloppy_mode_parameter_header_t *header;
- idefloppy_flexible_disk_page_t *page;
+ u8 *page;
int capacity, lba_capacity;
+ u16 transfer_rate, sector_size, cyls, rpm;
+ u8 heads, sectors;
- idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
- if (idefloppy_queue_pc_tail(drive,&pc)) {
- printk(KERN_ERR "ide-floppy: Can't get flexible disk "
- "page parameters\n");
+ idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE,
+ MODE_SENSE_CURRENT);
+
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-floppy: Can't get flexible disk page"
+ " parameters\n");
return 1;
}
- header = (idefloppy_mode_parameter_header_t *) pc.buffer;
- floppy->wp = header->wp;
+ floppy->wp = !!(pc.buffer[3] & 0x80);
set_disk_ro(floppy->disk, floppy->wp);
- page = (idefloppy_flexible_disk_page_t *) (header + 1);
+ page = &pc.buffer[8];
- page->transfer_rate = ntohs(page->transfer_rate);
- page->sector_size = ntohs(page->sector_size);
- page->cyls = ntohs(page->cyls);
- page->rpm = ntohs(page->rpm);
- capacity = page->cyls * page->heads * page->sectors * page->sector_size;
- if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
+ transfer_rate = be16_to_cpu(*(u16 *)&pc.buffer[8 + 2]);
+ sector_size = be16_to_cpu(*(u16 *)&pc.buffer[8 + 6]);
+ cyls = be16_to_cpu(*(u16 *)&pc.buffer[8 + 8]);
+ rpm = be16_to_cpu(*(u16 *)&pc.buffer[8 + 28]);
+ heads = pc.buffer[8 + 4];
+ sectors = pc.buffer[8 + 5];
+
+ capacity = cyls * heads * sectors * sector_size;
+
+ if (memcmp(page, &floppy->flexible_disk_page, 32))
printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
"%d sector size, %d rpm\n",
- drive->name, capacity / 1024, page->cyls,
- page->heads, page->sectors,
- page->transfer_rate / 8, page->sector_size, page->rpm);
+ drive->name, capacity / 1024, cyls, heads,
+ sectors, transfer_rate / 8, sector_size, rpm);
- floppy->flexible_disk_page = *page;
- drive->bios_cyl = page->cyls;
- drive->bios_head = page->heads;
- drive->bios_sect = page->sectors;
+ memcpy(&floppy->flexible_disk_page, page, 32);
+ drive->bios_cyl = cyls;
+ drive->bios_head = heads;
+ drive->bios_sect = sectors;
lba_capacity = floppy->blocks * floppy->block_size;
+
if (capacity < lba_capacity) {
printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
"bytes, but the drive only handles %d\n",
drive->name, lba_capacity, capacity);
- floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
+ floppy->blocks = floppy->block_size ?
+ capacity / floppy->block_size : 0;
}
return 0;
}
-static int idefloppy_get_capability_page(ide_drive_t *drive)
+static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
idefloppy_pc_t pc;
- idefloppy_mode_parameter_header_t *header;
- idefloppy_capabilities_page_t *page;
floppy->srfp = 0;
idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
MODE_SENSE_CURRENT);
- set_bit(PC_SUPPRESS_ERROR, &pc.flags);
- if (idefloppy_queue_pc_tail(drive,&pc)) {
+ pc.flags |= PC_FLAG_SUPPRESS_ERROR;
+ if (idefloppy_queue_pc_tail(drive, &pc))
return 1;
- }
- header = (idefloppy_mode_parameter_header_t *) pc.buffer;
- page= (idefloppy_capabilities_page_t *)(header+1);
- floppy->srfp = page->srfp;
+ floppy->srfp = pc.buffer[8 + 2] & 0x40;
return (0);
}
/*
- * Determine if a media is present in the floppy drive, and if so,
- * its LBA capacity.
+ * Determine if a media is present in the floppy drive, and if so, its LBA
+ * capacity.
*/
-static int idefloppy_get_capacity (ide_drive_t *drive)
+static int ide_floppy_get_capacity(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
idefloppy_pc_t pc;
- idefloppy_capacity_header_t *header;
- idefloppy_capacity_descriptor_t *descriptor;
- int i, descriptors, rc = 1, blocks, length;
-
+ u8 *cap_desc;
+ u8 header_len, desc_cnt;
+ int i, rc = 1, blocks, length;
+
drive->bios_cyl = 0;
drive->bios_head = drive->bios_sect = 0;
floppy->blocks = 0;
@@ -1343,44 +1066,55 @@
printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
return 1;
}
- header = (idefloppy_capacity_header_t *) pc.buffer;
- descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
- descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
+ header_len = pc.buffer[3];
+ cap_desc = &pc.buffer[4];
+ desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
- for (i = 0; i < descriptors; i++, descriptor++) {
- blocks = descriptor->blocks = ntohl(descriptor->blocks);
- length = descriptor->length = ntohs(descriptor->length);
+ for (i = 0; i < desc_cnt; i++) {
+ unsigned int desc_start = 4 + i*8;
- if (!i)
- {
- switch (descriptor->dc) {
+ blocks = be32_to_cpu(*(u32 *)&pc.buffer[desc_start]);
+ length = be16_to_cpu(*(u16 *)&pc.buffer[desc_start + 6]);
+
+ debug_log("Descriptor %d: %dkB, %d blocks, %d sector size\n",
+ i, blocks * length / 1024, blocks, length);
+
+ if (i)
+ continue;
+ /*
+ * the code below is valid only for the 1st descriptor, ie i=0
+ */
+
+ switch (pc.buffer[desc_start + 4] & 0x03) {
/* Clik! drive returns this instead of CAPACITY_CURRENT */
case CAPACITY_UNFORMATTED:
- if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
- /*
+ if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE))
+ /*
* If it is not a clik drive, break out
* (maintains previous driver behaviour)
*/
break;
case CAPACITY_CURRENT:
/* Normal Zip/LS-120 disks */
- if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+ if (memcmp(cap_desc, &floppy->cap_desc, 8))
printk(KERN_INFO "%s: %dkB, %d blocks, %d "
"sector size\n", drive->name,
blocks * length / 1024, blocks, length);
- floppy->capacity = *descriptor;
+ memcpy(&floppy->cap_desc, cap_desc, 8);
+
if (!length || length % 512) {
printk(KERN_NOTICE "%s: %d bytes block size "
"not supported\n", drive->name, length);
} else {
- floppy->blocks = blocks;
- floppy->block_size = length;
- if ((floppy->bs_factor = length / 512) != 1)
- printk(KERN_NOTICE "%s: warning: non "
+ floppy->blocks = blocks;
+ floppy->block_size = length;
+ floppy->bs_factor = length / 512;
+ if (floppy->bs_factor != 1)
+ printk(KERN_NOTICE "%s: warning: non "
"512 bytes block size not "
"fully supported\n",
drive->name);
- rc = 0;
+ rc = 0;
}
break;
case CAPACITY_NO_CARTRIDGE:
@@ -1395,54 +1129,42 @@
"in drive\n", drive->name);
break;
}
- }
- if (!i) {
- debug_log( "Descriptor 0 Code: %d\n",
- descriptor->dc);
- }
- debug_log( "Descriptor %d: %dkB, %d blocks, %d "
- "sector size\n", i, blocks * length / 1024, blocks,
- length);
+ debug_log("Descriptor 0 Code: %d\n",
+ pc.buffer[desc_start + 4] & 0x03);
}
/* Clik! disk does not support get_flexible_disk_page */
- if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
- (void) idefloppy_get_flexible_disk_page(drive);
- }
+ if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE))
+ (void) ide_floppy_get_flexible_disk_page(drive);
set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
return rc;
}
/*
-** Obtain the list of formattable capacities.
-** Very similar to idefloppy_get_capacity, except that we push the capacity
-** descriptors to userland, instead of our own structures.
-**
-** Userland gives us the following structure:
-**
-** struct idefloppy_format_capacities {
-** int nformats;
-** struct {
-** int nblocks;
-** int blocksize;
-** } formats[];
-** } ;
-**
-** userland initializes nformats to the number of allocated formats[]
-** records. On exit we set nformats to the number of records we've
-** actually initialized.
-**
-*/
+ * Obtain the list of formattable capacities.
+ * Very similar to ide_floppy_get_capacity, except that we push the capacity
+ * descriptors to userland, instead of our own structures.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_capacities {
+ * int nformats;
+ * struct {
+ * int nblocks;
+ * int blocksize;
+ * } formats[];
+ * };
+ *
+ * userland initializes nformats to the number of allocated formats[] records.
+ * On exit we set nformats to the number of records we've actually initialized.
+ */
-static int idefloppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
+static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
{
- idefloppy_pc_t pc;
- idefloppy_capacity_header_t *header;
- idefloppy_capacity_descriptor_t *descriptor;
- int i, descriptors, blocks, length;
- int u_array_size;
- int u_index;
+ idefloppy_pc_t pc;
+ u8 header_len, desc_cnt;
+ int i, blocks, length, u_array_size, u_index;
int __user *argp;
if (get_user(u_array_size, arg))
@@ -1454,30 +1176,27 @@
idefloppy_create_read_capacity_cmd(&pc);
if (idefloppy_queue_pc_tail(drive, &pc)) {
printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
- return (-EIO);
- }
- header = (idefloppy_capacity_header_t *) pc.buffer;
- descriptors = header->length /
- sizeof(idefloppy_capacity_descriptor_t);
- descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
+ return (-EIO);
+ }
+ header_len = pc.buffer[3];
+ desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
u_index = 0;
argp = arg + 1;
/*
- ** We always skip the first capacity descriptor. That's the
- ** current capacity. We are interested in the remaining descriptors,
- ** the formattable capacities.
- */
+ * We always skip the first capacity descriptor. That's the current
+ * capacity. We are interested in the remaining descriptors, the
+ * formattable capacities.
+ */
+ for (i = 1; i < desc_cnt; i++) {
+ unsigned int desc_start = 4 + i*8;
- for (i=0; i<descriptors; i++, descriptor++) {
if (u_index >= u_array_size)
break; /* User-supplied buffer too small */
- if (i == 0)
- continue; /* Skip the first descriptor */
- blocks = ntohl(descriptor->blocks);
- length = ntohs(descriptor->length);
+ blocks = be32_to_cpu(*(u32 *)&pc.buffer[desc_start]);
+ length = be16_to_cpu(*(u16 *)&pc.buffer[desc_start + 6]);
if (put_user(blocks, argp))
return(-EFAULT);
@@ -1496,53 +1215,14 @@
}
/*
-** Send ATAPI_FORMAT_UNIT to the drive.
-**
-** Userland gives us the following structure:
-**
-** struct idefloppy_format_command {
-** int nblocks;
-** int blocksize;
-** int flags;
-** } ;
-**
-** flags is a bitmask, currently, the only defined flag is:
-**
-** 0x01 - verify media after format.
-*/
-
-static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg)
-{
- int blocks;
- int length;
- int flags;
- idefloppy_pc_t pc;
-
- if (get_user(blocks, arg) ||
- get_user(length, arg+1) ||
- get_user(flags, arg+2)) {
- return (-EFAULT);
- }
-
- /* Get the SFRP bit */
- (void) idefloppy_get_capability_page(drive);
- idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
- if (idefloppy_queue_pc_tail(drive, &pc)) {
- return (-EIO);
- }
-
- return (0);
-}
-
-/*
-** Get ATAPI_FORMAT_UNIT progress indication.
-**
-** Userland gives a pointer to an int. The int is set to a progress
-** indicator 0-65536, with 65536=100%.
-**
-** If the drive does not support format progress indication, we just check
-** the dsc bit, and return either 0 or 65536.
-*/
+ * Get ATAPI_FORMAT_UNIT progress indication.
+ *
+ * Userland gives a pointer to an int. The int is set to a progress
+ * indicator 0-65536, with 65536=100%.
+ *
+ * If the drive does not support format progress indication, we just check
+ * the dsc bit, and return either 0 or 65536.
+ */
static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
{
@@ -1552,23 +1232,21 @@
if (floppy->srfp) {
idefloppy_create_request_sense_cmd(&pc);
- if (idefloppy_queue_pc_tail(drive, &pc)) {
+ if (idefloppy_queue_pc_tail(drive, &pc))
return (-EIO);
- }
if (floppy->sense_key == 2 &&
floppy->asc == 4 &&
- floppy->ascq == 4) {
+ floppy->ascq == 4)
progress_indication = floppy->progress_indication;
- }
- /* Else assume format_unit has finished, and we're
- ** at 0x10000 */
+
+ /* Else assume format_unit has finished, and we're at 0x10000 */
} else {
unsigned long flags;
u8 stat;
local_irq_save(flags);
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
local_irq_restore(flags);
progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
@@ -1579,10 +1257,7 @@
return (0);
}
-/*
- * Return the current floppy capacity.
- */
-static sector_t idefloppy_capacity (ide_drive_t *drive)
+static sector_t idefloppy_capacity(ide_drive_t *drive)
{
idefloppy_floppy_t *floppy = drive->driver_data;
unsigned long capacity = floppy->blocks * floppy->bs_factor;
@@ -1591,15 +1266,12 @@
}
/*
- * idefloppy_identify_device checks if we can support a drive,
- * based on the ATAPI IDENTIFY command results.
+ * Check whether we can support a drive, based on the ATAPI IDENTIFY command
+ * results.
*/
-static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
+static int idefloppy_identify_device(ide_drive_t *drive, struct hd_driveid *id)
{
struct idefloppy_id_gcw gcw;
-#if IDEFLOPPY_DEBUG_INFO
- char buffer[80];
-#endif /* IDEFLOPPY_DEBUG_INFO */
*((u16 *) &gcw) = id->config;
@@ -1608,54 +1280,23 @@
if ((gcw.device_type == 5) &&
!strstr(id->model, "CD-ROM") &&
strstr(id->model, "ZIP"))
- gcw.device_type = 0;
+ gcw.device_type = 0;
#endif
-#if IDEFLOPPY_DEBUG_INFO
- printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
- switch (gcw.protocol) {
- case 0: case 1: sprintf(buffer, "ATA");break;
- case 2: sprintf(buffer, "ATAPI");break;
- case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
- }
- printk(KERN_INFO "Protocol Type: %s\n", buffer);
- switch (gcw.device_type) {
- case 0: sprintf(buffer, "Direct-access Device");break;
- case 1: sprintf(buffer, "Streaming Tape Device");break;
- case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
- case 5: sprintf(buffer, "CD-ROM Device");break;
- case 6: sprintf(buffer, "Reserved");
- case 7: sprintf(buffer, "Optical memory Device");break;
- case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
- default: sprintf(buffer, "Reserved");
- }
- printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
- printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");
- switch (gcw.drq_type) {
- case 0: sprintf(buffer, "Microprocessor DRQ");break;
- case 1: sprintf(buffer, "Interrupt DRQ");break;
- case 2: sprintf(buffer, "Accelerated DRQ");break;
- case 3: sprintf(buffer, "Reserved");break;
- }
- printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
- switch (gcw.packet_size) {
- case 0: sprintf(buffer, "12 bytes");break;
- case 1: sprintf(buffer, "16 bytes");break;
- default: sprintf(buffer, "Reserved");break;
- }
- printk(KERN_INFO "Command Packet Size: %s\n", buffer);
-#endif /* IDEFLOPPY_DEBUG_INFO */
-
if (gcw.protocol != 2)
- printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+ printk(KERN_ERR "ide-floppy: Protocol (0x%02x) is not ATAPI\n",
+ gcw.protocol);
else if (gcw.device_type != 0)
- printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+ printk(KERN_ERR "ide-floppy: Device type (0x%02x) is not set "
+ "to floppy\n", gcw.device_type);
else if (!gcw.removable)
printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
else if (gcw.drq_type == 3) {
- printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+ printk(KERN_ERR "ide-floppy: Sorry, DRQ type (0x%02x) not "
+ "supported\n", gcw.drq_type);
} else if (gcw.packet_size != 0) {
- printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+ printk(KERN_ERR "ide-floppy: Packet size (0x%02x) is not 12 "
+ "bytes long\n", gcw.packet_size);
} else
return 1;
return 0;
@@ -1666,59 +1307,53 @@
{
idefloppy_floppy_t *floppy = drive->driver_data;
-/*
- * drive setting name read/write data type min max mul_factor div_factor data pointer set function
- */
- ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
- ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
- ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
- ide_add_setting(drive, "ticks", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &floppy->ticks, NULL);
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1,
+ &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
+ &drive->bios_head, NULL);
+ ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1,
+ &drive->bios_sect, NULL);
+ ide_add_setting(drive, "ticks", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
+ &floppy->ticks, NULL);
}
#else
static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }
#endif
-/*
- * Driver initialization.
- */
-static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
+static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
{
struct idefloppy_id_gcw gcw;
*((u16 *) &gcw) = drive->id->config;
floppy->pc = floppy->pc_stack;
if (gcw.drq_type == 1)
- set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+ floppy->flags |= IDEFLOPPY_FLAG_DRQ_INTERRUPT;
/*
- * We used to check revisions here. At this point however
- * I'm giving up. Just assume they are all broken, its easier.
+ * We used to check revisions here. At this point however I'm giving up.
+ * Just assume they are all broken, its easier.
*
- * The actual reason for the workarounds was likely
- * a driver bug after all rather than a firmware bug,
- * and the workaround below used to hide it. It should
- * be fixed as of version 1.9, but to be on the safe side
- * we'll leave the limitation below for the 2.2.x tree.
+ * The actual reason for the workarounds was likely a driver bug after
+ * all rather than a firmware bug, and the workaround below used to hide
+ * it. It should be fixed as of version 1.9, but to be on the safe side
+ * we'll leave the limitation below for the 2.2.x tree.
*/
-
if (!strncmp(drive->id->model, "IOMEGA ZIP 100 ATAPI", 20)) {
- set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
+ floppy->flags |= IDEFLOPPY_FLAG_ZIP_DRIVE;
/* This value will be visible in the /proc/ide/hdx/settings */
floppy->ticks = IDEFLOPPY_TICKS_DELAY;
blk_queue_max_sectors(drive->queue, 64);
}
/*
- * Guess what? The IOMEGA Clik! drive also needs the
- * above fix. It makes nasty clicking noises without
- * it, so please don't remove this.
- */
+ * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
+ * nasty clicking noises without it, so please don't remove this.
+ */
if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
blk_queue_max_sectors(drive->queue, 64);
- set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
+ floppy->flags |= IDEFLOPPY_FLAG_CLIK_DRIVE;
}
-
- (void) idefloppy_get_capacity(drive);
+ (void) ide_floppy_get_capacity(drive);
idefloppy_add_settings(drive);
}
@@ -1734,7 +1369,7 @@
ide_floppy_put(floppy);
}
-static void ide_floppy_release(struct kref *kref)
+static void idefloppy_cleanup_obj(struct kref *kref)
{
struct ide_floppy_obj *floppy = to_ide_floppy(kref);
ide_drive_t *drive = floppy->drive;
@@ -1747,19 +1382,19 @@
}
#ifdef CONFIG_IDE_PROC_FS
-static int proc_idefloppy_read_capacity
- (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
ide_drive_t*drive = (ide_drive_t *)data;
int len;
- len = sprintf(page,"%llu\n", (long long)idefloppy_capacity(drive));
- PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+ len = sprintf(page, "%llu\n", (long long)idefloppy_capacity(drive));
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
}
static ide_proc_entry_t idefloppy_proc[] = {
- { "capacity", S_IFREG|S_IRUGO, proc_idefloppy_read_capacity, NULL },
- { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
+ { "capacity", S_IFREG|S_IRUGO, proc_idefloppy_read_capacity, NULL },
+ { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
{ NULL, 0, NULL, NULL }
};
#endif /* CONFIG_IDE_PROC_FS */
@@ -1794,9 +1429,10 @@
idefloppy_pc_t pc;
int ret = 0;
- debug_log(KERN_INFO "Reached idefloppy_open\n");
+ debug_log("Reached %s\n", __func__);
- if (!(floppy = ide_floppy_get(disk)))
+ floppy = ide_floppy_get(disk);
+ if (!floppy)
return -ENXIO;
drive = floppy->drive;
@@ -1804,7 +1440,7 @@
floppy->openers++;
if (floppy->openers == 1) {
- clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+ floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
/* Just in case */
idefloppy_create_test_unit_ready_cmd(&pc);
@@ -1813,13 +1449,13 @@
(void) idefloppy_queue_pc_tail(drive, &pc);
}
- if (idefloppy_get_capacity (drive)
+ if (ide_floppy_get_capacity(drive)
&& (filp->f_flags & O_NDELAY) == 0
/*
- ** Allow O_NDELAY to open a drive without a disk, or with
- ** an unreadable disk, so that we can get the format
- ** capacity of the drive or begin the format - Sam
- */
+ * Allow O_NDELAY to open a drive without a disk, or with an
+ * unreadable disk, so that we can get the format capacity
+ * of the drive or begin the format - Sam
+ */
) {
ret = -EIO;
goto out_put_floppy;
@@ -1829,14 +1465,14 @@
ret = -EROFS;
goto out_put_floppy;
}
- set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+ floppy->flags |= IDEFLOPPY_FLAG_MEDIA_CHANGED;
/* IOMEGA Clik! drives do not support lock/unlock commands */
- if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+ if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE)) {
idefloppy_create_prevent_cmd(&pc, 1);
(void) idefloppy_queue_pc_tail(drive, &pc);
}
check_disk_change(inode->i_bdev);
- } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
+ } else if (floppy->flags & IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS) {
ret = -EBUSY;
goto out_put_floppy;
}
@@ -1854,17 +1490,17 @@
struct ide_floppy_obj *floppy = ide_floppy_g(disk);
ide_drive_t *drive = floppy->drive;
idefloppy_pc_t pc;
-
- debug_log(KERN_INFO "Reached idefloppy_release\n");
+
+ debug_log("Reached %s\n", __func__);
if (floppy->openers == 1) {
/* IOMEGA Clik! drives do not support lock/unlock commands */
- if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+ if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE)) {
idefloppy_create_prevent_cmd(&pc, 0);
(void) idefloppy_queue_pc_tail(drive, &pc);
}
- clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+ floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
}
floppy->openers--;
@@ -1885,64 +1521,105 @@
return 0;
}
+static int ide_floppy_lockdoor(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc,
+ unsigned long arg, unsigned int cmd)
+{
+ if (floppy->openers > 1)
+ return -EBUSY;
+
+ /* The IOMEGA Clik! Drive doesn't support this command -
+ * no room for an eject mechanism */
+ if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE)) {
+ int prevent = arg ? 1 : 0;
+
+ if (cmd == CDROMEJECT)
+ prevent = 0;
+
+ idefloppy_create_prevent_cmd(pc, prevent);
+ (void) idefloppy_queue_pc_tail(floppy->drive, pc);
+ }
+
+ if (cmd == CDROMEJECT) {
+ idefloppy_create_start_stop_cmd(pc, 2);
+ (void) idefloppy_queue_pc_tail(floppy->drive, pc);
+ }
+
+ return 0;
+}
+
+static int ide_floppy_format_unit(idefloppy_floppy_t *floppy,
+ int __user *arg)
+{
+ int blocks, length, flags, err = 0;
+ idefloppy_pc_t pc;
+
+ if (floppy->openers > 1) {
+ /* Don't format if someone is using the disk */
+ floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
+ return -EBUSY;
+ }
+
+ floppy->flags |= IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
+
+ /*
+ * Send ATAPI_FORMAT_UNIT to the drive.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_command {
+ * int nblocks;
+ * int blocksize;
+ * int flags;
+ * } ;
+ *
+ * flags is a bitmask, currently, the only defined flag is:
+ *
+ * 0x01 - verify media after format.
+ */
+ if (get_user(blocks, arg) ||
+ get_user(length, arg+1) ||
+ get_user(flags, arg+2)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ (void) idefloppy_get_sfrp_bit(floppy->drive);
+ idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
+
+ if (idefloppy_queue_pc_tail(floppy->drive, &pc))
+ err = -EIO;
+
+out:
+ if (err)
+ floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
+ return err;
+}
+
+
static int idefloppy_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
ide_drive_t *drive = floppy->drive;
+ idefloppy_pc_t pc;
void __user *argp = (void __user *)arg;
int err;
- int prevent = (arg) ? 1 : 0;
- idefloppy_pc_t pc;
switch (cmd) {
case CDROMEJECT:
- prevent = 0;
/* fall through */
case CDROM_LOCKDOOR:
- if (floppy->openers > 1)
- return -EBUSY;
-
- /* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
- if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
- idefloppy_create_prevent_cmd(&pc, prevent);
- (void) idefloppy_queue_pc_tail(drive, &pc);
- }
- if (cmd == CDROMEJECT) {
- idefloppy_create_start_stop_cmd(&pc, 2);
- (void) idefloppy_queue_pc_tail(drive, &pc);
- }
- return 0;
+ return ide_floppy_lockdoor(floppy, &pc, arg, cmd);
case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
return 0;
case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
- return idefloppy_get_format_capacities(drive, argp);
+ return ide_floppy_get_format_capacities(drive, argp);
case IDEFLOPPY_IOCTL_FORMAT_START:
-
if (!(file->f_mode & 2))
return -EPERM;
- if (floppy->openers > 1) {
- /* Don't format if someone is using the disk */
-
- clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
- &floppy->flags);
- return -EBUSY;
- }
-
- set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
-
- err = idefloppy_begin_format(drive, argp);
- if (err)
- clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
- return err;
- /*
- ** Note, the bit will be cleared when the device is
- ** closed. This is the cleanest way to handle the
- ** situation where the drive does not support
- ** format progress reporting.
- */
+ return ide_floppy_format_unit(floppy, (int __user *)arg);
case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
return idefloppy_get_format_progress(drive, argp);
}
@@ -1967,13 +1644,16 @@
{
struct ide_floppy_obj *floppy = ide_floppy_g(disk);
ide_drive_t *drive = floppy->drive;
+ int ret;
/* do not scan partitions twice if this is a removable device */
if (drive->attach) {
drive->attach = 0;
return 0;
}
- return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+ ret = !!(floppy->flags & IDEFLOPPY_FLAG_MEDIA_CHANGED);
+ floppy->flags &= ~IDEFLOPPY_FLAG_MEDIA_CHANGED;
+ return ret;
}
static int idefloppy_revalidate_disk(struct gendisk *disk)
@@ -2004,16 +1684,20 @@
goto failed;
if (drive->media != ide_floppy)
goto failed;
- if (!idefloppy_identify_device (drive, drive->id)) {
- printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+ if (!idefloppy_identify_device(drive, drive->id)) {
+ printk(KERN_ERR "ide-floppy: %s: not supported by this version"
+ " of ide-floppy\n", drive->name);
goto failed;
}
if (drive->scsi) {
- printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+ printk(KERN_INFO "ide-floppy: passing drive %s to ide-scsi"
+ " emulation.\n", drive->name);
goto failed;
}
- if ((floppy = kzalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
- printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+ floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
+ if (!floppy) {
+ printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy"
+ " structure\n", drive->name);
goto failed;
}
@@ -2035,7 +1719,7 @@
drive->driver_data = floppy;
- idefloppy_setup (drive, floppy);
+ idefloppy_setup(drive, floppy);
g->minors = 1 << PARTN_BITS;
g->driverfs_dev = &drive->gendev;
@@ -2051,9 +1735,7 @@
return -ENODEV;
}
-MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
-
-static void __exit idefloppy_exit (void)
+static void __exit idefloppy_exit(void)
{
driver_unregister(&idefloppy_driver.gen_driver);
}
@@ -2068,3 +1750,5 @@
module_init(idefloppy_init);
module_exit(idefloppy_exit);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
+
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index bb30c29..709b9e4 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -20,10 +20,16 @@
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
ide_get_lock(NULL, NULL); /* for atari only */
- for (i = 0; i < MAX_HWIFS; i++)
- idx[i] = ide_hwifs[i].present ? 0xff : i;
+ for (i = 0; i < MAX_HWIFS; i++) {
+ ide_hwif_t *hwif = &ide_hwifs[i];
- ide_device_add_all(idx);
+ if (hwif->io_ports[IDE_DATA_OFFSET] && !hwif->present)
+ idx[i] = i;
+ else
+ idx[i] = 0xff;
+ }
+
+ ide_device_add_all(idx, NULL);
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
ide_release_lock(); /* for atari only */
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 4bddef0..3addbe4 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -466,7 +466,7 @@
return ide_stopped;
}
- if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
rq->errors |= ERROR_RESET;
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
@@ -493,7 +493,7 @@
/* add decoding error stuff */
}
- if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
/* force an abort */
hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
@@ -821,9 +821,8 @@
#ifdef DEBUG
printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
- ide_end_drive_cmd(drive,
- hwif->INB(IDE_STATUS_REG),
- hwif->INB(IDE_ERROR_REG));
+ ide_end_drive_cmd(drive, ide_read_status(drive), ide_read_error(drive));
+
return ide_stopped;
}
@@ -1231,7 +1230,7 @@
printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
(void)HWIF(drive)->ide_dma_end(drive);
ret = ide_error(drive, "dma timeout error",
- hwif->INB(IDE_STATUS_REG));
+ ide_read_status(drive));
} else {
printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
hwif->dma_timeout(drive);
@@ -1355,7 +1354,8 @@
startstop = ide_dma_timeout_retry(drive, wait);
} else
startstop =
- ide_error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
+ ide_error(drive, "irq timeout",
+ ide_read_status(drive));
}
drive->service_time = jiffies - drive->service_start;
spin_lock_irq(&ide_lock);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 16b1f6e..c32e759 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -163,8 +163,6 @@
HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
}
-EXPORT_SYMBOL(SELECT_DRIVE);
-
void SELECT_MASK (ide_drive_t *drive, int mask)
{
if (HWIF(drive)->maskproc)
@@ -432,10 +430,10 @@
* about possible isa-pnp and pci-pnp issues yet.
*/
if (IDE_CONTROL_REG)
- stat = hwif->INB(IDE_ALTSTATUS_REG);
+ stat = ide_read_altstatus(drive);
else
/* Note: this may clear a pending IRQ!! */
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (stat & BUSY_STAT)
/* drive busy: definitely not interrupting */
@@ -460,23 +458,24 @@
*/
static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
{
- ide_hwif_t *hwif = drive->hwif;
unsigned long flags;
int i;
u8 stat;
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ stat = ide_read_status(drive);
+
+ if (stat & BUSY_STAT) {
local_irq_set(flags);
timeout += jiffies;
- while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ while ((stat = ide_read_status(drive)) & BUSY_STAT) {
if (time_after(jiffies, timeout)) {
/*
* One last read after the timeout in case
* heavy interrupt load made us not make any
* progress during the timeout..
*/
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (!(stat & BUSY_STAT))
break;
@@ -496,7 +495,9 @@
*/
for (i = 0; i < 10; i++) {
udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+ stat = ide_read_status(drive);
+
+ if (OK_STAT(stat, good, bad)) {
*rstat = stat;
return 0;
}
@@ -614,71 +615,12 @@
return 0;
}
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
-{
- if (args->tf.command == WIN_SETFEATURES &&
- args->tf.nsect > XFER_UDMA_2 &&
- args->tf.feature == SETFEATURES_XFER) {
- if (eighty_ninty_three(drive) == 0) {
- printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
- "be set\n", drive->name);
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
- * 1 : Safe to update drive->id DMA registers.
- * 0 : OOPs not allowed.
- */
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
-{
- if (args->tf.command == WIN_SETFEATURES &&
- args->tf.nsect >= XFER_SW_DMA_0 &&
- args->tf.feature == SETFEATURES_XFER &&
- (drive->id->dma_ultra ||
- drive->id->dma_mword ||
- drive->id->dma_1word))
- return 1;
-
- return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static u8 ide_auto_reduce_xfer (ide_drive_t *drive)
-{
- if (!drive->crc_count)
- return drive->current_speed;
- drive->crc_count = 0;
-
- switch(drive->current_speed) {
- case XFER_UDMA_7: return XFER_UDMA_6;
- case XFER_UDMA_6: return XFER_UDMA_5;
- case XFER_UDMA_5: return XFER_UDMA_4;
- case XFER_UDMA_4: return XFER_UDMA_3;
- case XFER_UDMA_3: return XFER_UDMA_2;
- case XFER_UDMA_2: return XFER_UDMA_1;
- case XFER_UDMA_1: return XFER_UDMA_0;
- /*
- * OOPS we do not goto non Ultra DMA modes
- * without iCRC's available we force
- * the system to PIO and make the user
- * invoke the ATA-1 ATA-2 DMA modes.
- */
- case XFER_UDMA_0:
- default: return XFER_PIO_4;
- }
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
int ide_driveid_update(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id;
unsigned long timeout, flags;
+ u8 stat;
/*
* Re-read drive->id for possible DMA mode
@@ -695,10 +637,15 @@
SELECT_MASK(drive, 0);
return 0; /* drive timed-out */
}
+
msleep(50); /* give drive a breather */
- } while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+ stat = ide_read_altstatus(drive);
+ } while (stat & BUSY_STAT);
+
msleep(50); /* wait for IRQ and DRQ_STAT */
- if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+ stat = ide_read_status(drive);
+
+ if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
SELECT_MASK(drive, 0);
printk("%s: CHECK for good STATUS\n", drive->name);
return 0;
@@ -711,7 +658,7 @@
return 0;
}
ata_input_data(drive, id, SECTOR_WORDS);
- (void) hwif->INB(IDE_STATUS_REG); /* clear drive IRQ */
+ (void)ide_read_status(drive); /* clear drive IRQ */
local_irq_enable();
local_irq_restore(flags);
ide_fix_driveid(id);
@@ -882,22 +829,17 @@
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
-
+
spin_lock_irqsave(&ide_lock, flags);
-
BUG_ON(hwgroup->handler);
- hwgroup->handler = handler;
- hwgroup->expiry = expiry;
- hwgroup->timer.expires = jiffies + timeout;
- hwgroup->req_gen_timer = hwgroup->req_gen;
- add_timer(&hwgroup->timer);
+ __ide_set_handler(drive, handler, timeout, expiry);
hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG);
- /* Drive takes 400nS to respond, we must avoid the IRQ being
- serviced before that.
-
- FIXME: we could skip this delay with care on non shared
- devices
- */
+ /*
+ * Drive takes 400nS to respond, we must avoid the IRQ being
+ * serviced before that.
+ *
+ * FIXME: we could skip this delay with care on non shared devices
+ */
ndelay(400);
spin_unlock_irqrestore(&ide_lock, flags);
}
@@ -917,17 +859,16 @@
static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- ide_hwif_t *hwif = HWIF(drive);
u8 stat;
SELECT_DRIVE(drive);
udelay (10);
+ stat = ide_read_status(drive);
- if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+ if (OK_STAT(stat, 0, BUSY_STAT))
printk("%s: ATAPI reset complete\n", drive->name);
- } else {
+ else {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
@@ -965,9 +906,10 @@
}
}
- if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+ tmp = ide_read_status(drive);
+
+ if (!OK_STAT(tmp, 0, BUSY_STAT)) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
- BUG_ON(HWGROUP(drive)->handler != NULL);
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
@@ -976,7 +918,9 @@
drive->failures++;
} else {
printk("%s: reset: ", hwif->name);
- if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+ tmp = ide_read_error(drive);
+
+ if (tmp == 1) {
printk("success\n");
drive->failures = 0;
} else {
@@ -1005,19 +949,6 @@
return ide_stopped;
}
-static void check_dma_crc(ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (drive->crc_count) {
- ide_dma_off_quietly(drive);
- ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
- if (drive->current_speed >= XFER_SW_DMA_0)
- ide_dma_on(drive);
- } else
- ide_dma_off(drive);
-#endif
-}
-
static void ide_disk_pre_reset(ide_drive_t *drive)
{
int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
@@ -1039,17 +970,20 @@
else
drive->post_reset = 1;
+ if (drive->using_dma) {
+ if (drive->crc_count)
+ ide_check_dma_crc(drive);
+ else
+ ide_dma_off(drive);
+ }
+
if (!drive->keep_settings) {
- if (drive->using_dma) {
- check_dma_crc(drive);
- } else {
+ if (!drive->using_dma) {
drive->unmask = 0;
drive->io_32bit = 0;
}
return;
}
- if (drive->using_dma)
- check_dma_crc(drive);
if (HWIF(drive)->pre_reset != NULL)
HWIF(drive)->pre_reset(drive);
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index b42940d..1ff676cc 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -578,7 +578,7 @@
}
printk("}\n");
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
- err = drive->hwif->INB(IDE_ERROR_REG);
+ err = ide_read_error(drive);
printk("%s: %s: error=0x%02x ", drive->name, msg, err);
if (drive->media == ide_disk)
ide_dump_ata_error(drive, err);
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 4bda5cf..b163b2e 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -49,7 +49,7 @@
printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
pnp_set_drvdata(dev,hwif);
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
return 0;
}
@@ -60,9 +60,10 @@
static void idepnp_remove(struct pnp_dev * dev)
{
ide_hwif_t *hwif = pnp_get_drvdata(dev);
- if (hwif) {
- ide_unregister(hwif->index);
- } else
+
+ if (hwif)
+ ide_unregister(hwif->index, 0, 0);
+ else
printk(KERN_ERR "idepnp: Unable to remove device, please report.\n");
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 98a8af4..6daea89 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -264,8 +264,7 @@
static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
{
ide_hwif_t *hwif = HWIF(drive);
- int rc;
- unsigned long hd_status;
+ int use_altstatus = 0, rc;
unsigned long timeout;
u8 s = 0, a = 0;
@@ -273,19 +272,17 @@
msleep(50);
if (IDE_CONTROL_REG) {
- a = hwif->INB(IDE_ALTSTATUS_REG);
- s = hwif->INB(IDE_STATUS_REG);
- if ((a ^ s) & ~INDEX_STAT) {
- printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of "
- "ALTSTATUS(0x%02x)\n", drive->name, s, a);
+ a = ide_read_altstatus(drive);
+ s = ide_read_status(drive);
+ if ((a ^ s) & ~INDEX_STAT)
/* ancient Seagate drives, broken interfaces */
- hd_status = IDE_STATUS_REG;
- } else {
+ printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
+ "instead of ALTSTATUS(0x%02x)\n",
+ drive->name, s, a);
+ else
/* use non-intrusive polling */
- hd_status = IDE_ALTSTATUS_REG;
- }
- } else
- hd_status = IDE_STATUS_REG;
+ use_altstatus = 1;
+ }
/* set features register for atapi
* identify command to be sure of reply
@@ -306,11 +303,15 @@
}
/* give drive a breather */
msleep(50);
- } while ((hwif->INB(hd_status)) & BUSY_STAT);
+ s = use_altstatus ? ide_read_altstatus(drive)
+ : ide_read_status(drive);
+ } while (s & BUSY_STAT);
/* wait for IRQ and DRQ_STAT */
msleep(50);
- if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
+ s = ide_read_status(drive);
+
+ if (OK_STAT(s, DRQ_STAT, BAD_R_STAT)) {
unsigned long flags;
/* local CPU only; some systems need this */
@@ -320,7 +321,7 @@
/* drive responded with ID */
rc = 0;
/* clear drive IRQ */
- (void) hwif->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
local_irq_restore(flags);
} else {
/* drive refused ID */
@@ -367,7 +368,7 @@
ide_set_irq(drive, 0);
/* clear drive IRQ */
- (void) hwif->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
udelay(5);
irq = probe_irq_off(cookie);
if (!hwif->irq) {
@@ -423,8 +424,9 @@
static int do_probe (ide_drive_t *drive, u8 cmd)
{
- int rc;
ide_hwif_t *hwif = HWIF(drive);
+ int rc;
+ u8 stat;
if (drive->present) {
/* avoid waiting for inappropriate probes */
@@ -454,22 +456,26 @@
return 3;
}
- if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+ stat = ide_read_status(drive);
+
+ if (OK_STAT(stat, READY_STAT, BUSY_STAT) ||
drive->present || cmd == WIN_PIDENTIFY) {
/* send cmd and wait */
if ((rc = try_to_identify(drive, cmd))) {
/* failed: try again */
rc = try_to_identify(drive,cmd);
}
- if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+
+ stat = ide_read_status(drive);
+
+ if (stat == (BUSY_STAT | READY_STAT))
return 4;
if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
((drive->autotune == IDE_TUNE_DEFAULT) ||
(drive->autotune == IDE_TUNE_AUTO))) {
- printk("%s: no response (status = 0x%02x), "
- "resetting drive\n", drive->name,
- hwif->INB(IDE_STATUS_REG));
+ printk(KERN_ERR "%s: no response (status = 0x%02x), "
+ "resetting drive\n", drive->name, stat);
msleep(50);
hwif->OUTB(drive->select.all, IDE_SELECT_REG);
msleep(50);
@@ -477,11 +483,13 @@
(void)ide_busy_sleep(hwif);
rc = try_to_identify(drive, cmd);
}
+
+ /* ensure drive IRQ is clear */
+ stat = ide_read_status(drive);
+
if (rc == 1)
- printk("%s: no response (status = 0x%02x)\n",
- drive->name, hwif->INB(IDE_STATUS_REG));
- /* ensure drive irq is clear */
- (void) hwif->INB(IDE_STATUS_REG);
+ printk(KERN_ERR "%s: no response (status = 0x%02x)\n",
+ drive->name, stat);
} else {
/* not present or maybe ATAPI */
rc = 3;
@@ -491,7 +499,7 @@
SELECT_DRIVE(&hwif->drives[0]);
msleep(50);
/* ensure drive irq is clear */
- (void) hwif->INB(IDE_STATUS_REG);
+ (void)ide_read_status(drive);
}
return rc;
}
@@ -502,6 +510,7 @@
static void enable_nest (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
+ u8 stat;
printk("%s: enabling %s -- ", hwif->name, drive->id->model);
SELECT_DRIVE(drive);
@@ -515,11 +524,12 @@
msleep(50);
- if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
- printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
- } else {
- printk("success\n");
- }
+ stat = ide_read_status(drive);
+
+ if (!OK_STAT(stat, 0, BAD_STAT))
+ printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
+ else
+ printk(KERN_CONT "success\n");
/* if !(success||timed-out) */
if (do_probe(drive, WIN_IDENTIFY) >= 2) {
@@ -822,7 +832,7 @@
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
- if (hwif->no_io_32bit)
+ if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
drive->no_io_32bit = 1;
else
drive->no_io_32bit = drive->id->dword_io ? 1 : 0;
@@ -881,13 +891,6 @@
q->queuedata = drive;
blk_queue_segment_boundary(q, 0xffff);
- if (!hwif->rqsize) {
- if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
- (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
- hwif->rqsize = 256;
- else
- hwif->rqsize = 65536;
- }
if (hwif->rqsize < max_sectors)
max_sectors = hwif->rqsize;
blk_queue_max_sectors(q, max_sectors);
@@ -918,6 +921,48 @@
return 0;
}
+static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
+{
+ ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+
+ spin_lock_irq(&ide_lock);
+ if (!hwgroup->drive) {
+ /* first drive for hwgroup. */
+ drive->next = drive;
+ hwgroup->drive = drive;
+ hwgroup->hwif = HWIF(hwgroup->drive);
+ } else {
+ drive->next = hwgroup->drive->next;
+ hwgroup->drive->next = drive;
+ }
+ spin_unlock_irq(&ide_lock);
+}
+
+/*
+ * For any present drive:
+ * - allocate the block device queue
+ * - link drive into the hwgroup
+ */
+static void ide_port_setup_devices(ide_hwif_t *hwif)
+{
+ int i;
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+
+ if (!drive->present)
+ continue;
+
+ if (ide_init_queue(drive)) {
+ printk(KERN_ERR "ide: failed to init %s\n",
+ drive->name);
+ continue;
+ }
+
+ ide_add_drive_to_hwgroup(drive);
+ }
+}
+
/*
* This routine sets up the irq for an ide interface, and creates a new
* hwgroup for the irq/hwif if none was previously assigned.
@@ -1004,7 +1049,7 @@
*/
if (!match || match->irq != hwif->irq) {
int sa = 0;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
sa = IRQF_SHARED;
#endif /* __mc68000__ || CONFIG_APUS */
@@ -1019,33 +1064,15 @@
goto out_unlink;
}
- /*
- * For any present drive:
- * - allocate the block device queue
- * - link drive into the hwgroup
- */
- for (index = 0; index < MAX_DRIVES; ++index) {
- ide_drive_t *drive = &hwif->drives[index];
- if (!drive->present)
- continue;
- if (ide_init_queue(drive)) {
- printk(KERN_ERR "ide: failed to init %s\n",drive->name);
- continue;
- }
- spin_lock_irq(&ide_lock);
- if (!hwgroup->drive) {
- /* first drive for hwgroup. */
- drive->next = drive;
- hwgroup->drive = drive;
- hwgroup->hwif = HWIF(hwgroup->drive);
- } else {
- drive->next = hwgroup->drive->next;
- hwgroup->drive->next = drive;
- }
- spin_unlock_irq(&ide_lock);
+ if (!hwif->rqsize) {
+ if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+ (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
+ hwif->rqsize = 256;
+ else
+ hwif->rqsize = 65536;
}
-#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+#if !defined(__mc68000__)
printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
hwif->io_ports[IDE_DATA_OFFSET],
hwif->io_ports[IDE_DATA_OFFSET]+7,
@@ -1053,11 +1080,14 @@
#else
printk("%s at 0x%08lx on irq %d", hwif->name,
hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
-#endif /* __mc68000__ && CONFIG_APUS */
+#endif /* __mc68000__ */
if (match)
printk(" (%sed with %s)",
hwif->sharing_irq ? "shar" : "serializ", match->name);
printk("\n");
+
+ ide_port_setup_devices(hwif);
+
mutex_unlock(&ide_cfg_mtx);
return 0;
out_unlink:
@@ -1182,30 +1212,6 @@
complete(&drive->gendev_rel_comp);
}
-/*
- * init_gendisk() (as opposed to ide_geninit) is called for each major device,
- * after probing for drives, to allocate partition tables and other data
- * structures needed for the routines in genhd.c. ide_geninit() gets called
- * somewhat later, during the partition check.
- */
-static void init_gendisk (ide_hwif_t *hwif)
-{
- unsigned int unit;
-
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t * drive = &hwif->drives[unit];
- ide_add_generic_settings(drive);
- snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u",
- hwif->index,unit);
- drive->gendev.parent = &hwif->gendev;
- drive->gendev.bus = &ide_bus_type;
- drive->gendev.driver_data = drive;
- drive->gendev.release = drive_release_dev;
- }
- blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
- THIS_MODULE, ata_probe, ata_lock, hwif);
-}
-
static int hwif_init(ide_hwif_t *hwif)
{
int old_irq;
@@ -1262,8 +1268,8 @@
hwif->name, hwif->irq);
done:
- init_gendisk(hwif);
- ide_acpi_init(hwif);
+ blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
+ THIS_MODULE, ata_probe, ata_lock, hwif);
return 1;
out:
@@ -1277,24 +1283,119 @@
for (i = 0; i < MAX_DRIVES; i++) {
ide_drive_t *drive = &hwif->drives[i];
+ struct device *dev = &drive->gendev;
+ int ret;
- if (drive->present) {
- int ret = device_register(&drive->gendev);
+ if (!drive->present)
+ continue;
- if (ret < 0)
- printk(KERN_WARNING "IDE: %s: "
- "device_register error: %d\n",
- __FUNCTION__, ret);
- }
+ ide_add_generic_settings(drive);
+
+ snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
+ dev->parent = &hwif->gendev;
+ dev->bus = &ide_bus_type;
+ dev->driver_data = drive;
+ dev->release = drive_release_dev;
+
+ ret = device_register(dev);
+ if (ret < 0)
+ printk(KERN_WARNING "IDE: %s: device_register error: "
+ "%d\n", __func__, ret);
}
}
-int ide_device_add_all(u8 *idx)
+static void ide_port_init_devices(ide_hwif_t *hwif)
{
- ide_hwif_t *hwif;
+ int i;
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+
+ if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
+ drive->io_32bit = 1;
+ if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
+ drive->unmask = 1;
+ if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
+ drive->no_unmask = 1;
+ if ((hwif->host_flags & IDE_HFLAG_NO_AUTOTUNE) == 0)
+ drive->autotune = 1;
+ }
+
+ if (hwif->port_init_devs)
+ hwif->port_init_devs(hwif);
+}
+
+static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
+ const struct ide_port_info *d)
+{
+ if (d->chipset != ide_etrax100)
+ hwif->channel = port;
+
+ if (d->chipset)
+ hwif->chipset = d->chipset;
+
+ if (d->init_iops)
+ d->init_iops(hwif);
+
+ if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0)
+ ide_hwif_setup_dma(hwif, d);
+
+ if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
+ (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
+ hwif->irq = port ? 15 : 14;
+
+ hwif->host_flags = d->host_flags;
+ hwif->pio_mask = d->pio_mask;
+
+ if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
+
+ hwif->swdma_mask = d->swdma_mask;
+ hwif->mwdma_mask = d->mwdma_mask;
+ hwif->ultra_mask = d->udma_mask;
+
+ /* reset DMA masks only for SFF-style DMA controllers */
+ if ((d->host_flags && IDE_HFLAG_NO_DMA) == 0 && hwif->dma_base == 0)
+ hwif->swdma_mask = hwif->mwdma_mask = hwif->ultra_mask = 0;
+
+ if (d->host_flags & IDE_HFLAG_RQSIZE_256)
+ hwif->rqsize = 256;
+
+ /* call chipset specific routine for each enabled port */
+ if (d->init_hwif)
+ d->init_hwif(hwif);
+
+ if (hwif->cable_detect && (hwif->ultra_mask & 0x78)) {
+ if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ hwif->cbl = hwif->cable_detect(hwif);
+ }
+}
+
+int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
+{
+ ide_hwif_t *hwif, *mate = NULL;
int i, rc = 0;
for (i = 0; i < MAX_HWIFS; i++) {
+ if (d == NULL || idx[i] == 0xff) {
+ mate = NULL;
+ continue;
+ }
+
+ hwif = &ide_hwifs[idx[i]];
+
+ if (d->chipset != ide_etrax100 && (i & 1) && mate) {
+ hwif->mate = mate;
+ mate->mate = hwif;
+ }
+
+ mate = (i & 1) ? NULL : hwif;
+
+ ide_init_port(hwif, i & 1, d);
+ ide_port_init_devices(hwif);
+ }
+
+ for (i = 0; i < MAX_HWIFS; i++) {
if (idx[i] == 0xff)
continue;
@@ -1337,6 +1438,9 @@
rc = -1;
continue;
}
+
+ ide_acpi_init(hwif);
+ ide_acpi_port_init_devices(hwif);
}
for (i = 0; i < MAX_HWIFS; i++) {
@@ -1354,15 +1458,22 @@
}
for (i = 0; i < MAX_HWIFS; i++) {
- if (idx[i] != 0xff)
- ide_proc_register_port(&ide_hwifs[idx[i]]);
+ if (idx[i] == 0xff)
+ continue;
+
+ hwif = &ide_hwifs[idx[i]];
+
+ if (hwif->present) {
+ ide_proc_register_port(hwif);
+ ide_proc_port_register_devices(hwif);
+ }
}
return rc;
}
EXPORT_SYMBOL_GPL(ide_device_add_all);
-int ide_device_add(u8 idx[4])
+int ide_device_add(u8 idx[4], const struct ide_port_info *d)
{
u8 idx_all[MAX_HWIFS];
int i;
@@ -1370,6 +1481,6 @@
for (i = 0; i < MAX_HWIFS; i++)
idx_all[i] = (i < 4) ? idx[i] : 0xff;
- return ide_device_add_all(idx_all);
+ return ide_device_add_all(idx_all, d);
}
EXPORT_SYMBOL_GPL(ide_device_add);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 00c249c..bab88ca 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -65,6 +65,7 @@
case ide_4drives: name = "4drives"; break;
case ide_pmac: name = "mac-io"; break;
case ide_au1xxx: name = "au1xxx"; break;
+ case ide_palm3710: name = "palm3710"; break;
case ide_etrax100: name = "etrax100"; break;
case ide_acorn: name = "acorn"; break;
default: name = "(unknown)"; break;
@@ -739,7 +740,7 @@
EXPORT_SYMBOL(ide_proc_unregister_driver);
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+void ide_proc_port_register_devices(ide_hwif_t *hwif)
{
int d;
struct proc_dir_entry *ent;
@@ -793,9 +794,6 @@
void ide_proc_register_port(ide_hwif_t *hwif)
{
- if (!hwif->present)
- return;
-
if (!hwif->proc) {
hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
@@ -804,8 +802,6 @@
ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
}
-
- create_proc_ide_drives(hwif);
}
#ifdef CONFIG_BLK_DEV_IDEPCI
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 5aef63a..49dd2e7 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1,427 +1,21 @@
/*
+ * IDE ATAPI streaming tape driver.
+ *
* Copyright (C) 1995-1999 Gadi Oxman <gadio@netvision.net.il>
* Copyright (C) 2003-2005 Bartlomiej Zolnierkiewicz
*
- * $Header$
- *
* This driver was constructed as a student project in the software laboratory
* of the faculty of electrical engineering in the Technion - Israel's
* Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David.
*
* It is hereby placed under the terms of the GNU general public license.
* (See linux/COPYING).
- */
-
-/*
- * IDE ATAPI streaming tape driver.
*
- * This driver is a part of the Linux ide driver and works in co-operation
- * with linux/drivers/block/ide.c.
- *
- * The driver, in co-operation with ide.c, basically traverses the
- * request-list for the block device interface. The character device
- * interface, on the other hand, creates new requests, adds them
- * to the request-list of the block device, and waits for their completion.
- *
- * Pipelined operation mode is now supported on both reads and writes.
- *
- * The block device major and minor numbers are determined from the
- * tape's relative position in the ide interfaces, as explained in ide.c.
- *
- * The character device interface consists of the following devices:
- *
- * ht0 major 37, minor 0 first IDE tape, rewind on close.
- * ht1 major 37, minor 1 second IDE tape, rewind on close.
- * ...
- * nht0 major 37, minor 128 first IDE tape, no rewind on close.
- * nht1 major 37, minor 129 second IDE tape, no rewind on close.
- * ...
- *
- * Run linux/scripts/MAKEDEV.ide to create the above entries.
- *
- * The general magnetic tape commands compatible interface, as defined by
- * include/linux/mtio.h, is accessible through the character device.
- *
- * General ide driver configuration options, such as the interrupt-unmask
- * flag, can be configured by issuing an ioctl to the block device interface,
- * as any other ide device.
- *
- * Our own ide-tape ioctl's can be issued to either the block device or
- * the character device interface.
- *
- * Maximal throughput with minimal bus load will usually be achieved in the
- * following scenario:
- *
- * 1. ide-tape is operating in the pipelined operation mode.
- * 2. No buffering is performed by the user backup program.
- *
- * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
- *
- * Ver 0.1 Nov 1 95 Pre-working code :-)
- * Ver 0.2 Nov 23 95 A short backup (few megabytes) and restore procedure
- * was successful ! (Using tar cvf ... on the block
- * device interface).
- * A longer backup resulted in major swapping, bad
- * overall Linux performance and eventually failed as
- * we received non serial read-ahead requests from the
- * buffer cache.
- * Ver 0.3 Nov 28 95 Long backups are now possible, thanks to the
- * character device interface. Linux's responsiveness
- * and performance doesn't seem to be much affected
- * from the background backup procedure.
- * Some general mtio.h magnetic tape operations are
- * now supported by our character device. As a result,
- * popular tape utilities are starting to work with
- * ide tapes :-)
- * The following configurations were tested:
- * 1. An IDE ATAPI TAPE shares the same interface
- * and irq with an IDE ATAPI CDROM.
- * 2. An IDE ATAPI TAPE shares the same interface
- * and irq with a normal IDE disk.
- * Both configurations seemed to work just fine !
- * However, to be on the safe side, it is meanwhile
- * recommended to give the IDE TAPE its own interface
- * and irq.
- * The one thing which needs to be done here is to
- * add a "request postpone" feature to ide.c,
- * so that we won't have to wait for the tape to finish
- * performing a long media access (DSC) request (such
- * as a rewind) before we can access the other device
- * on the same interface. This effect doesn't disturb
- * normal operation most of the time because read/write
- * requests are relatively fast, and once we are
- * performing one tape r/w request, a lot of requests
- * from the other device can be queued and ide.c will
- * service all of them after this single tape request.
- * Ver 1.0 Dec 11 95 Integrated into Linux 1.3.46 development tree.
- * On each read / write request, we now ask the drive
- * if we can transfer a constant number of bytes
- * (a parameter of the drive) only to its buffers,
- * without causing actual media access. If we can't,
- * we just wait until we can by polling the DSC bit.
- * This ensures that while we are not transferring
- * more bytes than the constant referred to above, the
- * interrupt latency will not become too high and
- * we won't cause an interrupt timeout, as happened
- * occasionally in the previous version.
- * While polling for DSC, the current request is
- * postponed and ide.c is free to handle requests from
- * the other device. This is handled transparently to
- * ide.c. The hwgroup locking method which was used
- * in the previous version was removed.
- * Use of new general features which are provided by
- * ide.c for use with atapi devices.
- * (Programming done by Mark Lord)
- * Few potential bug fixes (Again, suggested by Mark)
- * Single character device data transfers are now
- * not limited in size, as they were before.
- * We are asking the tape about its recommended
- * transfer unit and send a larger data transfer
- * as several transfers of the above size.
- * For best results, use an integral number of this
- * basic unit (which is shown during driver
- * initialization). I will soon add an ioctl to get
- * this important parameter.
- * Our data transfer buffer is allocated on startup,
- * rather than before each data transfer. This should
- * ensure that we will indeed have a data buffer.
- * Ver 1.1 Dec 14 95 Fixed random problems which occurred when the tape
- * shared an interface with another device.
- * (poll_for_dsc was a complete mess).
- * Removed some old (non-active) code which had
- * to do with supporting buffer cache originated
- * requests.
- * The block device interface can now be opened, so
- * that general ide driver features like the unmask
- * interrupts flag can be selected with an ioctl.
- * This is the only use of the block device interface.
- * New fast pipelined operation mode (currently only on
- * writes). When using the pipelined mode, the
- * throughput can potentially reach the maximum
- * tape supported throughput, regardless of the
- * user backup program. On my tape drive, it sometimes
- * boosted performance by a factor of 2. Pipelined
- * mode is enabled by default, but since it has a few
- * downfalls as well, you may want to disable it.
- * A short explanation of the pipelined operation mode
- * is available below.
- * Ver 1.2 Jan 1 96 Eliminated pipelined mode race condition.
- * Added pipeline read mode. As a result, restores
- * are now as fast as backups.
- * Optimized shared interface behavior. The new behavior
- * typically results in better IDE bus efficiency and
- * higher tape throughput.
- * Pre-calculation of the expected read/write request
- * service time, based on the tape's parameters. In
- * the pipelined operation mode, this allows us to
- * adjust our polling frequency to a much lower value,
- * and thus to dramatically reduce our load on Linux,
- * without any decrease in performance.
- * Implemented additional mtio.h operations.
- * The recommended user block size is returned by
- * the MTIOCGET ioctl.
- * Additional minor changes.
- * Ver 1.3 Feb 9 96 Fixed pipelined read mode bug which prevented the
- * use of some block sizes during a restore procedure.
- * The character device interface will now present a
- * continuous view of the media - any mix of block sizes
- * during a backup/restore procedure is supported. The
- * driver will buffer the requests internally and
- * convert them to the tape's recommended transfer
- * unit, making performance almost independent of the
- * chosen user block size.
- * Some improvements in error recovery.
- * By cooperating with ide-dma.c, bus mastering DMA can
- * now sometimes be used with IDE tape drives as well.
- * Bus mastering DMA has the potential to dramatically
- * reduce the CPU's overhead when accessing the device,
- * and can be enabled by using hdparm -d1 on the tape's
- * block device interface. For more info, read the
- * comments in ide-dma.c.
- * Ver 1.4 Mar 13 96 Fixed serialize support.
- * Ver 1.5 Apr 12 96 Fixed shared interface operation, broken in 1.3.85.
- * Fixed pipelined read mode inefficiency.
- * Fixed nasty null dereferencing bug.
- * Ver 1.6 Aug 16 96 Fixed FPU usage in the driver.
- * Fixed end of media bug.
- * Ver 1.7 Sep 10 96 Minor changes for the CONNER CTT8000-A model.
- * Ver 1.8 Sep 26 96 Attempt to find a better balance between good
- * interactive response and high system throughput.
- * Ver 1.9 Nov 5 96 Automatically cross encountered filemarks rather
- * than requiring an explicit FSF command.
- * Abort pending requests at end of media.
- * MTTELL was sometimes returning incorrect results.
- * Return the real block size in the MTIOCGET ioctl.
- * Some error recovery bug fixes.
- * Ver 1.10 Nov 5 96 Major reorganization.
- * Reduced CPU overhead a bit by eliminating internal
- * bounce buffers.
- * Added module support.
- * Added multiple tape drives support.
- * Added partition support.
- * Rewrote DSC handling.
- * Some portability fixes.
- * Removed ide-tape.h.
- * Additional minor changes.
- * Ver 1.11 Dec 2 96 Bug fix in previous DSC timeout handling.
- * Use ide_stall_queue() for DSC overlap.
- * Use the maximum speed rather than the current speed
- * to compute the request service time.
- * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data
- * corruption, which could occur if the total number
- * of bytes written to the tape was not an integral
- * number of tape blocks.
- * Add support for INTERRUPT DRQ devices.
- * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB
- * Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives.
- * Replace cli()/sti() with hwgroup spinlocks.
- * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup
- * spinlock with private per-tape spinlock.
- * Ver 1.16 Sep 1 99 Add OnStream tape support.
- * Abort read pipeline on EOD.
- * Wait for the tape to become ready in case it returns
- * "in the process of becoming ready" on open().
- * Fix zero padding of the last written block in
- * case the tape block size is larger than PAGE_SIZE.
- * Decrease the default disconnection time to tn.
- * Ver 1.16e Oct 3 99 Minor fixes.
- * Ver 1.16e1 Oct 13 99 Patches by Arnold Niessen,
- * niessen@iae.nl / arnold.niessen@philips.com
- * GO-1) Undefined code in idetape_read_position
- * according to Gadi's email
- * AJN-1) Minor fix asc == 11 should be asc == 0x11
- * in idetape_issue_packet_command (did effect
- * debugging output only)
- * AJN-2) Added more debugging output, and
- * added ide-tape: where missing. I would also
- * like to add tape->name where possible
- * AJN-3) Added different debug_level's
- * via /proc/ide/hdc/settings
- * "debug_level" determines amount of debugging output;
- * can be changed using /proc/ide/hdx/settings
- * 0 : almost no debugging output
- * 1 : 0+output errors only
- * 2 : 1+output all sensekey/asc
- * 3 : 2+follow all chrdev related procedures
- * 4 : 3+follow all procedures
- * 5 : 4+include pc_stack rq_stack info
- * 6 : 5+USE_COUNT updates
- * AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
- * from 5 to 10 minutes
- * AJN-5) Changed maximum number of blocks to skip when
- * reading tapes with multiple consecutive write
- * errors from 100 to 1000 in idetape_get_logical_blk
- * Proposed changes to code:
- * 1) output "logical_blk_num" via /proc
- * 2) output "current_operation" via /proc
- * 3) Either solve or document the fact that `mt rewind' is
- * required after reading from /dev/nhtx to be
- * able to rmmod the idetape module;
- * Also, sometimes an application finishes but the
- * device remains `busy' for some time. Same cause ?
- * Proposed changes to release-notes:
- * 4) write a simple `quickstart' section in the
- * release notes; I volunteer if you don't want to
- * 5) include a pointer to video4linux in the doc
- * to stimulate video applications
- * 6) release notes lines 331 and 362: explain what happens
- * if the application data rate is higher than 1100 KB/s;
- * similar approach to lower-than-500 kB/s ?
- * 7) 6.6 Comparison; wouldn't it be better to allow different
- * strategies for read and write ?
- * Wouldn't it be better to control the tape buffer
- * contents instead of the bandwidth ?
- * 8) line 536: replace will by would (if I understand
- * this section correctly, a hypothetical and unwanted situation
- * is being described)
- * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames.
- * Ver 1.17 Nov 2000 / Jan 2001 Marcel Mol, marcel@mesa.nl
- * - Add idetape_onstream_mode_sense_tape_parameter_page
- * function to get tape capacity in frames: tape->capacity.
- * - Add support for DI-50 drives( or any DI- drive).
- * - 'workaround' for read error/blank block around block 3000.
- * - Implement Early warning for end of media for Onstream.
- * - Cosmetic code changes for readability.
- * - Idetape_position_tape should not use SKIP bit during
- * Onstream read recovery.
- * - Add capacity, logical_blk_num and first/last_frame_position
- * to /proc/ide/hd?/settings.
- * - Module use count was gone in the Linux 2.4 driver.
- * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
- * - Get drive's actual block size from mode sense block descriptor
- * - Limit size of pipeline
- * Ver 1.17b Oct 2002 Alan Stern <stern@rowland.harvard.edu>
- * Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
- * it in the code!
- * Actually removed aborted stages in idetape_abort_pipeline
- * instead of just changing the command code.
- * Made the transfer byte count for Request Sense equal to the
- * actual length of the data transfer.
- * Changed handling of partial data transfers: they do not
- * cause DMA errors.
- * Moved initiation of DMA transfers to the correct place.
- * Removed reference to unallocated memory.
- * Made __idetape_discard_read_pipeline return the number of
- * sectors skipped, not the number of stages.
- * Replaced errant kfree() calls with __idetape_kfree_stage().
- * Fixed off-by-one error in testing the pipeline length.
- * Fixed handling of filemarks in the read pipeline.
- * Small code optimization for MTBSF and MTBSFM ioctls.
- * Don't try to unlock the door during device close if is
- * already unlocked!
- * Cosmetic fixes to miscellaneous debugging output messages.
- * Set the minimum /proc/ide/hd?/settings values for "pipeline",
- * "pipeline_min", and "pipeline_max" to 1.
- *
- * Here are some words from the first releases of hd.c, which are quoted
- * in ide.c and apply here as well:
- *
- * | Special care is recommended. Have Fun!
- *
+ * For a historical changelog see
+ * Documentation/ide/ChangeLog.ide-tape.1995-2002
*/
-/*
- * An overview of the pipelined operation mode.
- *
- * In the pipelined write mode, we will usually just add requests to our
- * pipeline and return immediately, before we even start to service them. The
- * user program will then have enough time to prepare the next request while
- * we are still busy servicing previous requests. In the pipelined read mode,
- * the situation is similar - we add read-ahead requests into the pipeline,
- * before the user even requested them.
- *
- * The pipeline can be viewed as a "safety net" which will be activated when
- * the system load is high and prevents the user backup program from keeping up
- * with the current tape speed. At this point, the pipeline will get
- * shorter and shorter but the tape will still be streaming at the same speed.
- * Assuming we have enough pipeline stages, the system load will hopefully
- * decrease before the pipeline is completely empty, and the backup program
- * will be able to "catch up" and refill the pipeline again.
- *
- * When using the pipelined mode, it would be best to disable any type of
- * buffering done by the user program, as ide-tape already provides all the
- * benefits in the kernel, where it can be done in a more efficient way.
- * As we will usually not block the user program on a request, the most
- * efficient user code will then be a simple read-write-read-... cycle.
- * Any additional logic will usually just slow down the backup process.
- *
- * Using the pipelined mode, I get a constant over 400 KBps throughput,
- * which seems to be the maximum throughput supported by my tape.
- *
- * However, there are some downfalls:
- *
- * 1. We use memory (for data buffers) in proportional to the number
- * of pipeline stages (each stage is about 26 KB with my tape).
- * 2. In the pipelined write mode, we cheat and postpone error codes
- * to the user task. In read mode, the actual tape position
- * will be a bit further than the last requested block.
- *
- * Concerning (1):
- *
- * 1. We allocate stages dynamically only when we need them. When
- * we don't need them, we don't consume additional memory. In
- * case we can't allocate stages, we just manage without them
- * (at the expense of decreased throughput) so when Linux is
- * tight in memory, we will not pose additional difficulties.
- *
- * 2. The maximum number of stages (which is, in fact, the maximum
- * amount of memory) which we allocate is limited by the compile
- * time parameter IDETAPE_MAX_PIPELINE_STAGES.
- *
- * 3. The maximum number of stages is a controlled parameter - We
- * don't start from the user defined maximum number of stages
- * but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
- * will not even allocate this amount of stages if the user
- * program can't handle the speed). We then implement a feedback
- * loop which checks if the pipeline is empty, and if it is, we
- * increase the maximum number of stages as necessary until we
- * reach the optimum value which just manages to keep the tape
- * busy with minimum allocated memory or until we reach
- * IDETAPE_MAX_PIPELINE_STAGES.
- *
- * Concerning (2):
- *
- * In pipelined write mode, ide-tape can not return accurate error codes
- * to the user program since we usually just add the request to the
- * pipeline without waiting for it to be serviced. In case an error
- * occurs, I will report it on the next user request.
- *
- * In the pipelined read mode, subsequent read requests or forward
- * filemark spacing will perform correctly, as we preserve all blocks
- * and filemarks which we encountered during our excess read-ahead.
- *
- * For accurate tape positioning and error reporting, disabling
- * pipelined mode might be the best option.
- *
- * You can enable/disable/tune the pipelined operation mode by adjusting
- * the compile time parameters below.
- */
-
-/*
- * Possible improvements.
- *
- * 1. Support for the ATAPI overlap protocol.
- *
- * In order to maximize bus throughput, we currently use the DSC
- * overlap method which enables ide.c to service requests from the
- * other device while the tape is busy executing a command. The
- * DSC overlap method involves polling the tape's status register
- * for the DSC bit, and servicing the other device while the tape
- * isn't ready.
- *
- * In the current QIC development standard (December 1995),
- * it is recommended that new tape drives will *in addition*
- * implement the ATAPI overlap protocol, which is used for the
- * same purpose - efficient use of the IDE bus, but is interrupt
- * driven and thus has much less CPU overhead.
- *
- * ATAPI overlap is likely to be supported in most new ATAPI
- * devices, including new ATAPI cdroms, and thus provides us
- * a method by which we can achieve higher throughput when
- * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
- */
-
-#define IDETAPE_VERSION "1.19"
+#define IDETAPE_VERSION "1.20"
#include <linux/module.h>
#include <linux/types.h>
@@ -442,107 +36,73 @@
#include <linux/completion.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <scsi/scsi.h>
#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/unaligned.h>
-
-/*
- * partition
- */
-typedef struct os_partition_s {
- __u8 partition_num;
- __u8 par_desc_ver;
- __u16 wrt_pass_cntr;
- __u32 first_frame_addr;
- __u32 last_frame_addr;
- __u32 eod_frame_addr;
-} os_partition_t;
-
-/*
- * DAT entry
- */
-typedef struct os_dat_entry_s {
- __u32 blk_sz;
- __u16 blk_cnt;
- __u8 flags;
- __u8 reserved;
-} os_dat_entry_t;
-
-/*
- * DAT
- */
-#define OS_DAT_FLAGS_DATA (0xc)
-#define OS_DAT_FLAGS_MARK (0x1)
-
-typedef struct os_dat_s {
- __u8 dat_sz;
- __u8 reserved1;
- __u8 entry_cnt;
- __u8 reserved3;
- os_dat_entry_t dat_list[16];
-} os_dat_t;
-
#include <linux/mtio.h>
+enum {
+ /* output errors only */
+ DBG_ERR = (1 << 0),
+ /* output all sense key/asc */
+ DBG_SENSE = (1 << 1),
+ /* info regarding all chrdev-related procedures */
+ DBG_CHRDEV = (1 << 2),
+ /* all remaining procedures */
+ DBG_PROCS = (1 << 3),
+ /* buffer alloc info (pc_stack & rq_stack) */
+ DBG_PCRQ_STACK = (1 << 4),
+};
+
+/* define to see debug info */
+#define IDETAPE_DEBUG_LOG 0
+
+#if IDETAPE_DEBUG_LOG
+#define debug_log(lvl, fmt, args...) \
+{ \
+ if (tape->debug_mask & lvl) \
+ printk(KERN_INFO "ide-tape: " fmt, ## args); \
+}
+#else
+#define debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
/**************************** Tunable parameters *****************************/
/*
- * Pipelined mode parameters.
+ * Pipelined mode parameters.
*
- * We try to use the minimum number of stages which is enough to
- * keep the tape constantly streaming. To accomplish that, we implement
- * a feedback loop around the maximum number of stages:
+ * We try to use the minimum number of stages which is enough to keep the tape
+ * constantly streaming. To accomplish that, we implement a feedback loop around
+ * the maximum number of stages:
*
- * We start from MIN maximum stages (we will not even use MIN stages
- * if we don't need them), increment it by RATE*(MAX-MIN)
- * whenever we sense that the pipeline is empty, until we reach
- * the optimum value or until we reach MAX.
+ * We start from MIN maximum stages (we will not even use MIN stages if we don't
+ * need them), increment it by RATE*(MAX-MIN) whenever we sense that the
+ * pipeline is empty, until we reach the optimum value or until we reach MAX.
*
- * Setting the following parameter to 0 is illegal: the pipelined mode
- * cannot be disabled (calculate_speeds() divides by tape->max_stages.)
+ * Setting the following parameter to 0 is illegal: the pipelined mode cannot be
+ * disabled (idetape_calculate_speeds() divides by tape->max_stages.)
*/
#define IDETAPE_MIN_PIPELINE_STAGES 1
#define IDETAPE_MAX_PIPELINE_STAGES 400
#define IDETAPE_INCREASE_STAGES_RATE 20
/*
- * The following are used to debug the driver:
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDETAPE_MAX_PC_RETRIES times.
*
- * Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities.
- * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
- * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in
- * some places.
- *
- * Setting them to 0 will restore normal operation mode:
- *
- * 1. Disable logging normal successful operations.
- * 2. Disable self-sanity checks.
- * 3. Errors will still be logged, of course.
- *
- * All the #if DEBUG code will be removed some day, when the driver
- * is verified to be stable enough. This will make it much more
- * esthetic.
- */
-#define IDETAPE_DEBUG_INFO 0
-#define IDETAPE_DEBUG_LOG 0
-#define IDETAPE_DEBUG_BUGS 1
-
-/*
- * After each failed packet command we issue a request sense command
- * and retry the packet command IDETAPE_MAX_PC_RETRIES times.
- *
- * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
+ * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
*/
#define IDETAPE_MAX_PC_RETRIES 3
/*
- * With each packet command, we allocate a buffer of
- * IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet
- * commands (Not for READ/WRITE commands).
+ * With each packet command, we allocate a buffer of IDETAPE_PC_BUFFER_SIZE
+ * bytes. This is used for several packet commands (Not for READ/WRITE commands)
*/
#define IDETAPE_PC_BUFFER_SIZE 256
@@ -561,48 +121,39 @@
#define IDETAPE_WAIT_CMD (900*HZ)
/*
- * The following parameter is used to select the point in the internal
- * tape fifo in which we will start to refill the buffer. Decreasing
- * the following parameter will improve the system's latency and
- * interactive response, while using a high value might improve system
- * throughput.
+ * The following parameter is used to select the point in the internal tape fifo
+ * in which we will start to refill the buffer. Decreasing the following
+ * parameter will improve the system's latency and interactive response, while
+ * using a high value might improve system throughput.
*/
-#define IDETAPE_FIFO_THRESHOLD 2
+#define IDETAPE_FIFO_THRESHOLD 2
/*
- * DSC polling parameters.
+ * DSC polling parameters.
*
- * Polling for DSC (a single bit in the status register) is a very
- * important function in ide-tape. There are two cases in which we
- * poll for DSC:
+ * Polling for DSC (a single bit in the status register) is a very important
+ * function in ide-tape. There are two cases in which we poll for DSC:
*
- * 1. Before a read/write packet command, to ensure that we
- * can transfer data from/to the tape's data buffers, without
- * causing an actual media access. In case the tape is not
- * ready yet, we take out our request from the device
- * request queue, so that ide.c will service requests from
- * the other device on the same interface meanwhile.
+ * 1. Before a read/write packet command, to ensure that we can transfer data
+ * from/to the tape's data buffers, without causing an actual media access.
+ * In case the tape is not ready yet, we take out our request from the device
+ * request queue, so that ide.c could service requests from the other device
+ * on the same interface in the meantime.
*
- * 2. After the successful initialization of a "media access
- * packet command", which is a command which can take a long
- * time to complete (it can be several seconds or even an hour).
+ * 2. After the successful initialization of a "media access packet command",
+ * which is a command that can take a long time to complete (the interval can
+ * range from several seconds to even an hour). Again, we postpone our request
+ * in the middle to free the bus for the other device. The polling frequency
+ * here should be lower than the read/write frequency since those media access
+ * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST
+ * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD
+ * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min).
*
- * Again, we postpone our request in the middle to free the bus
- * for the other device. The polling frequency here should be
- * lower than the read/write frequency since those media access
- * commands are slow. We start from a "fast" frequency -
- * IDETAPE_DSC_MA_FAST (one second), and if we don't receive DSC
- * after IDETAPE_DSC_MA_THRESHOLD (5 minutes), we switch it to a
- * lower frequency - IDETAPE_DSC_MA_SLOW (1 minute).
- *
- * We also set a timeout for the timer, in case something goes wrong.
- * The timeout should be longer then the maximum execution time of a
- * tape operation.
+ * We also set a timeout for the timer, in case something goes wrong. The
+ * timeout should be longer then the maximum execution time of a tape operation.
*/
-
-/*
- * DSC timings.
- */
+
+/* DSC timings. */
#define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */
#define IDETAPE_DSC_RW_MAX 40*HZ/100 /* 400 msec */
#define IDETAPE_DSC_RW_TIMEOUT 2*60*HZ /* 2 minutes */
@@ -613,19 +164,15 @@
/*************************** End of tunable parameters ***********************/
-/*
- * Read/Write error simulation
- */
+/* Read/Write error simulation */
#define SIMULATE_ERRORS 0
-/*
- * For general magnetic tape device compatibility.
- */
-typedef enum {
- idetape_direction_none,
- idetape_direction_read,
- idetape_direction_write
-} idetape_chrdev_direction_t;
+/* tape directions */
+enum {
+ IDETAPE_DIR_NONE = (1 << 0),
+ IDETAPE_DIR_READ = (1 << 1),
+ IDETAPE_DIR_WRITE = (1 << 2),
+};
struct idetape_bh {
u32 b_size;
@@ -634,24 +181,32 @@
char *b_data;
};
-/*
- * Our view of a packet command.
- */
typedef struct idetape_packet_command_s {
- u8 c[12]; /* Actual packet bytes */
- int retries; /* On each retry, we increment retries */
- int error; /* Error code */
- int request_transfer; /* Bytes to transfer */
- int actually_transferred; /* Bytes actually transferred */
- int buffer_size; /* Size of our data buffer */
+ /* Actual packet bytes */
+ u8 c[12];
+ /* On each retry, we increment retries */
+ int retries;
+ /* Error code */
+ int error;
+ /* Bytes to transfer */
+ int request_transfer;
+ /* Bytes actually transferred */
+ int actually_transferred;
+ /* Size of our data buffer */
+ int buffer_size;
struct idetape_bh *bh;
char *b_data;
int b_count;
- u8 *buffer; /* Data buffer */
- u8 *current_position; /* Pointer into the above buffer */
- ide_startstop_t (*callback) (ide_drive_t *); /* Called when this packet command is completed */
- u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE]; /* Temporary buffer */
- unsigned long flags; /* Status/Action bit flags: long for set_bit */
+ /* Data buffer */
+ u8 *buffer;
+ /* Pointer into the above buffer */
+ u8 *current_position;
+ /* Called when this packet command is completed */
+ ide_startstop_t (*callback) (ide_drive_t *);
+ /* Temporary buffer */
+ u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];
+ /* Status/Action bit flags: long for set_bit */
+ unsigned long flags;
} idetape_pc_t;
/*
@@ -670,68 +225,7 @@
/* Data direction */
#define PC_WRITING 5
-/*
- * Capabilities and Mechanical Status Page
- */
-typedef struct {
- unsigned page_code :6; /* Page code - Should be 0x2a */
- __u8 reserved0_6 :1;
- __u8 ps :1; /* parameters saveable */
- __u8 page_length; /* Page Length - Should be 0x12 */
- __u8 reserved2, reserved3;
- unsigned ro :1; /* Read Only Mode */
- unsigned reserved4_1234 :4;
- unsigned sprev :1; /* Supports SPACE in the reverse direction */
- unsigned reserved4_67 :2;
- unsigned reserved5_012 :3;
- unsigned efmt :1; /* Supports ERASE command initiated formatting */
- unsigned reserved5_4 :1;
- unsigned qfa :1; /* Supports the QFA two partition formats */
- unsigned reserved5_67 :2;
- unsigned lock :1; /* Supports locking the volume */
- unsigned locked :1; /* The volume is locked */
- unsigned prevent :1; /* The device defaults in the prevent state after power up */
- unsigned eject :1; /* The device can eject the volume */
- __u8 disconnect :1; /* The device can break request > ctl */
- __u8 reserved6_5 :1;
- unsigned ecc :1; /* Supports error correction */
- unsigned cmprs :1; /* Supports data compression */
- unsigned reserved7_0 :1;
- unsigned blk512 :1; /* Supports 512 bytes block size */
- unsigned blk1024 :1; /* Supports 1024 bytes block size */
- unsigned reserved7_3_6 :4;
- unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
- /* transfers for slow buffer memory ??? */
- /* Also 32768 block size in some cases */
- __u16 max_speed; /* Maximum speed supported in KBps */
- __u8 reserved10, reserved11;
- __u16 ctl; /* Continuous Transfer Limit in blocks */
- __u16 speed; /* Current Speed, in KBps */
- __u16 buffer_size; /* Buffer Size, in 512 bytes */
- __u8 reserved18, reserved19;
-} idetape_capabilities_page_t;
-
-/*
- * Block Size Page
- */
-typedef struct {
- unsigned page_code :6; /* Page code - Should be 0x30 */
- unsigned reserved1_6 :1;
- unsigned ps :1;
- __u8 page_length; /* Page Length - Should be 2 */
- __u8 reserved2;
- unsigned play32 :1;
- unsigned play32_5 :1;
- unsigned reserved2_23 :2;
- unsigned record32 :1;
- unsigned record32_5 :1;
- unsigned reserved2_6 :1;
- unsigned one :1;
-} idetape_block_size_page_t;
-
-/*
- * A pipeline stage.
- */
+/* A pipeline stage. */
typedef struct idetape_stage_s {
struct request rq; /* The corresponding request */
struct idetape_bh *bh; /* The data buffers */
@@ -739,35 +233,8 @@
} idetape_stage_t;
/*
- * REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
- unsigned error_code :7; /* Current of deferred errors */
- unsigned valid :1; /* The information field conforms to QIC-157C */
- __u8 reserved1 :8; /* Segment Number - Reserved */
- unsigned sense_key :4; /* Sense Key */
- unsigned reserved2_4 :1; /* Reserved */
- unsigned ili :1; /* Incorrect Length Indicator */
- unsigned eom :1; /* End Of Medium */
- unsigned filemark :1; /* Filemark */
- __u32 information __attribute__ ((packed));
- __u8 asl; /* Additional sense length (n-7) */
- __u32 command_specific; /* Additional command specific information */
- __u8 asc; /* Additional Sense Code */
- __u8 ascq; /* Additional Sense Code Qualifier */
- __u8 replaceable_unit_code; /* Field Replaceable Unit Code */
- unsigned sk_specific1 :7; /* Sense Key Specific */
- unsigned sksv :1; /* Sense Key Specific information is valid */
- __u8 sk_specific2; /* Sense Key Specific */
- __u8 sk_specific3; /* Sense Key Specific */
- __u8 pad[2]; /* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-
-/*
- * Most of our global data which we need to save even as we leave the
- * driver due to an interrupt or a timer event is stored in a variable
- * of type idetape_tape_t, defined below.
+ * Most of our global data which we need to save even as we leave the driver due
+ * to an interrupt or a timer event is stored in the struct defined below.
*/
typedef struct ide_tape_obj {
ide_drive_t *drive;
@@ -803,15 +270,14 @@
int rq_stack_index;
/*
- * DSC polling variables.
+ * DSC polling variables.
*
- * While polling for DSC we use postponed_rq to postpone the
- * current request so that ide.c will be able to service
- * pending requests on the other device. Note that at most
- * we will have only one DSC (usually data transfer) request
- * in the device request queue. Additional requests can be
- * queued in our internal pipeline, but they will be visible
- * to ide.c only one at a time.
+ * While polling for DSC we use postponed_rq to postpone the current
+ * request so that ide.c will be able to service pending requests on the
+ * other device. Note that at most we will have only one DSC (usually
+ * data transfer) request in the device request queue. Additional
+ * requests can be queued in our internal pipeline, but they will be
+ * visible to ide.c only one at a time.
*/
struct request *postponed_rq;
/* The time in which we started polling for DSC */
@@ -819,72 +285,57 @@
/* Timer used to poll for dsc */
struct timer_list dsc_timer;
/* Read/Write dsc polling frequency */
- unsigned long best_dsc_rw_frequency;
- /* The current polling frequency */
- unsigned long dsc_polling_frequency;
- /* Maximum waiting time */
+ unsigned long best_dsc_rw_freq;
+ unsigned long dsc_poll_freq;
unsigned long dsc_timeout;
- /*
- * Read position information
- */
+ /* Read position information */
u8 partition;
/* Current block */
- unsigned int first_frame_position;
- unsigned int last_frame_position;
- unsigned int blocks_in_buffer;
+ unsigned int first_frame;
- /*
- * Last error information
- */
+ /* Last error information */
u8 sense_key, asc, ascq;
- /*
- * Character device operation
- */
+ /* Character device operation */
unsigned int minor;
/* device name */
char name[4];
/* Current character device data transfer direction */
- idetape_chrdev_direction_t chrdev_direction;
+ u8 chrdev_dir;
- /*
- * Device information
- */
- /* Usually 512 or 1024 bytes */
- unsigned short tape_block_size;
+ /* tape block size, usually 512 or 1024 bytes */
+ unsigned short blk_size;
int user_bs_factor;
+
/* Copy of the tape's Capabilities and Mechanical Page */
- idetape_capabilities_page_t capabilities;
+ u8 caps[20];
/*
- * Active data transfer request parameters.
+ * Active data transfer request parameters.
*
- * At most, there is only one ide-tape originated data transfer
- * request in the device request queue. This allows ide.c to
- * easily service requests from the other device when we
- * postpone our active request. In the pipelined operation
- * mode, we use our internal pipeline structure to hold
- * more data requests.
- *
- * The data buffer size is chosen based on the tape's
- * recommendation.
+ * At most, there is only one ide-tape originated data transfer request
+ * in the device request queue. This allows ide.c to easily service
+ * requests from the other device when we postpone our active request.
+ * In the pipelined operation mode, we use our internal pipeline
+ * structure to hold more data requests. The data buffer size is chosen
+ * based on the tape's recommendation.
*/
- /* Pointer to the request which is waiting in the device request queue */
- struct request *active_data_request;
- /* Data buffer size (chosen based on the tape's recommendation */
+ /* ptr to the request which is waiting in the device request queue */
+ struct request *active_data_rq;
+ /* Data buffer size chosen based on the tape's recommendation */
int stage_size;
idetape_stage_t *merge_stage;
int merge_stage_size;
struct idetape_bh *bh;
char *b_data;
int b_count;
-
+
/*
- * Pipeline parameters.
+ * Pipeline parameters.
*
- * To accomplish non-pipelined mode, we simply set the following
- * variables to zero (or NULL, where appropriate).
+ * To accomplish non-pipelined mode, we simply set the following
+ * variables to zero (or NULL, where appropriate).
*/
/* Number of currently used stages */
int nr_stages;
@@ -909,23 +360,13 @@
/* Status/Action flags: long for set_bit */
unsigned long flags;
/* protects the ide-tape queue */
- spinlock_t spinlock;
+ spinlock_t lock;
- /*
- * Measures average tape speed
- */
+ /* Measures average tape speed */
unsigned long avg_time;
int avg_size;
int avg_speed;
- /* last sense information */
- idetape_request_sense_result_t sense;
-
- char vendor_id[10];
- char product_id[18];
- char firmware_revision[6];
- int firmware_revision_num;
-
/* the door is currently locked */
int door_locked;
/* the tape hardware is write protected */
@@ -934,11 +375,9 @@
char write_prot;
/*
- * Limit the number of times a request can
- * be postponed, to avoid an infinite postpone
- * deadlock.
+ * Limit the number of times a request can be postponed, to avoid an
+ * infinite postpone deadlock.
*/
- /* request postpone count limit */
int postpone_cnt;
/*
@@ -953,30 +392,19 @@
int tape_head;
int last_tape_head;
- /*
- * Speed control at the tape buffers input/output
- */
+ /* Speed control at the tape buffers input/output */
unsigned long insert_time;
int insert_size;
int insert_speed;
int max_insert_speed;
int measure_insert_time;
- /*
- * Measure tape still time, in milliseconds
- */
- unsigned long tape_still_time_begin;
- int tape_still_time;
-
- /*
- * Speed regulation negative feedback loop
- */
+ /* Speed regulation negative feedback loop */
int speed_control;
int pipeline_head_speed;
int controlled_pipeline_head_speed;
int uncontrolled_pipeline_head_speed;
int controlled_last_pipeline_head;
- int uncontrolled_last_pipeline_head;
unsigned long uncontrolled_pipeline_head_time;
unsigned long controlled_pipeline_head_time;
int controlled_previous_pipeline_head;
@@ -985,18 +413,7 @@
unsigned long uncontrolled_previous_head_time;
int restart_speed_control_req;
- /*
- * Debug_level determines amount of debugging output;
- * can be changed using /proc/ide/hdx/settings
- * 0 : almost no debugging output
- * 1 : 0+output errors only
- * 2 : 1+output all sensekey/asc
- * 3 : 2+follow all chrdev related procedures
- * 4 : 3+follow all procedures
- * 5 : 4+include pc_stack rq_stack info
- * 6 : 5+USE_COUNT updates
- */
- int debug_level;
+ u32 debug_mask;
} idetape_tape_t;
static DEFINE_MUTEX(idetape_ref_mutex);
@@ -1029,9 +446,7 @@
mutex_unlock(&idetape_ref_mutex);
}
-/*
- * Tape door status
- */
+/* Tape door status */
#define DOOR_UNLOCKED 0
#define DOOR_LOCKED 1
#define DOOR_EXPLICITLY_LOCKED 2
@@ -1051,51 +466,23 @@
/* 0 = no tape is loaded, so we don't rewind after ejecting */
#define IDETAPE_MEDIUM_PRESENT 9
-/*
- * Supported ATAPI tape drives packet commands
- */
-#define IDETAPE_TEST_UNIT_READY_CMD 0x00
-#define IDETAPE_REWIND_CMD 0x01
-#define IDETAPE_REQUEST_SENSE_CMD 0x03
-#define IDETAPE_READ_CMD 0x08
-#define IDETAPE_WRITE_CMD 0x0a
-#define IDETAPE_WRITE_FILEMARK_CMD 0x10
-#define IDETAPE_SPACE_CMD 0x11
-#define IDETAPE_INQUIRY_CMD 0x12
-#define IDETAPE_ERASE_CMD 0x19
-#define IDETAPE_MODE_SENSE_CMD 0x1a
-#define IDETAPE_MODE_SELECT_CMD 0x15
-#define IDETAPE_LOAD_UNLOAD_CMD 0x1b
-#define IDETAPE_PREVENT_CMD 0x1e
-#define IDETAPE_LOCATE_CMD 0x2b
-#define IDETAPE_READ_POSITION_CMD 0x34
-#define IDETAPE_READ_BUFFER_CMD 0x3c
-#define IDETAPE_SET_SPEED_CMD 0xbb
-
-/*
- * Some defines for the READ BUFFER command
- */
+/* A define for the READ BUFFER command */
#define IDETAPE_RETRIEVE_FAULTY_BLOCK 6
-/*
- * Some defines for the SPACE command
- */
+/* Some defines for the SPACE command */
#define IDETAPE_SPACE_OVER_FILEMARK 1
#define IDETAPE_SPACE_TO_EOD 3
-/*
- * Some defines for the LOAD UNLOAD command
- */
+/* Some defines for the LOAD UNLOAD command */
#define IDETAPE_LU_LOAD_MASK 1
#define IDETAPE_LU_RETENSION_MASK 2
#define IDETAPE_LU_EOT_MASK 4
/*
- * Special requests for our block device strategy routine.
+ * Special requests for our block device strategy routine.
*
- * In order to service a character device command, we add special
- * requests to the tail of our block device request queue and wait
- * for their completion.
+ * In order to service a character device command, we add special requests to
+ * the tail of our block device request queue and wait for their completion.
*/
enum {
@@ -1106,171 +493,20 @@
REQ_IDETAPE_READ_BUFFER = (1 << 4),
};
-/*
- * Error codes which are returned in rq->errors to the higher part
- * of the driver.
- */
+/* Error codes returned in rq->errors to the higher part of the driver. */
#define IDETAPE_ERROR_GENERAL 101
#define IDETAPE_ERROR_FILEMARK 102
#define IDETAPE_ERROR_EOD 103
-/*
- * The following is used to format the general configuration word of
- * the ATAPI IDENTIFY DEVICE command.
- */
-struct idetape_id_gcw {
- unsigned packet_size :2; /* Packet Size */
- unsigned reserved234 :3; /* Reserved */
- unsigned drq_type :2; /* Command packet DRQ type */
- unsigned removable :1; /* Removable media */
- unsigned device_type :5; /* Device type */
- unsigned reserved13 :1; /* Reserved */
- unsigned protocol :2; /* Protocol type */
-};
-
-/*
- * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
- */
-typedef struct {
- unsigned device_type :5; /* Peripheral Device Type */
- unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
- unsigned reserved1_6t0 :7; /* Reserved */
- unsigned rmb :1; /* Removable Medium Bit */
- unsigned ansi_version :3; /* ANSI Version */
- unsigned ecma_version :3; /* ECMA Version */
- unsigned iso_version :2; /* ISO Version */
- unsigned response_format :4; /* Response Data Format */
- unsigned reserved3_45 :2; /* Reserved */
- unsigned reserved3_6 :1; /* TrmIOP - Reserved */
- unsigned reserved3_7 :1; /* AENC - Reserved */
- __u8 additional_length; /* Additional Length (total_length-4) */
- __u8 rsv5, rsv6, rsv7; /* Reserved */
- __u8 vendor_id[8]; /* Vendor Identification */
- __u8 product_id[16]; /* Product Identification */
- __u8 revision_level[4]; /* Revision Level */
- __u8 vendor_specific[20]; /* Vendor Specific - Optional */
- __u8 reserved56t95[40]; /* Reserved - Optional */
- /* Additional information may be returned */
-} idetape_inquiry_result_t;
-
-/*
- * READ POSITION packet command - Data Format (From Table 6-57)
- */
-typedef struct {
- unsigned reserved0_10 :2; /* Reserved */
- unsigned bpu :1; /* Block Position Unknown */
- unsigned reserved0_543 :3; /* Reserved */
- unsigned eop :1; /* End Of Partition */
- unsigned bop :1; /* Beginning Of Partition */
- u8 partition; /* Partition Number */
- u8 reserved2, reserved3; /* Reserved */
- u32 first_block; /* First Block Location */
- u32 last_block; /* Last Block Location (Optional) */
- u8 reserved12; /* Reserved */
- u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */
- u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */
-} idetape_read_position_result_t;
-
-/*
- * Follows structures which are related to the SELECT SENSE / MODE SENSE
- * packet commands. Those packet commands are still not supported
- * by ide-tape.
- */
+/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
#define IDETAPE_BLOCK_DESCRIPTOR 0
#define IDETAPE_CAPABILITIES_PAGE 0x2a
-#define IDETAPE_PARAMTR_PAGE 0x2b /* Onstream DI-x0 only */
-#define IDETAPE_BLOCK_SIZE_PAGE 0x30
-#define IDETAPE_BUFFER_FILLING_PAGE 0x33
/*
- * Mode Parameter Header for the MODE SENSE packet command
+ * The variables below are used for the character device interface. Additional
+ * state variables are defined in our ide_drive_t structure.
*/
-typedef struct {
- __u8 mode_data_length; /* Length of the following data transfer */
- __u8 medium_type; /* Medium Type */
- __u8 dsp; /* Device Specific Parameter */
- __u8 bdl; /* Block Descriptor Length */
-#if 0
- /* data transfer page */
- __u8 page_code :6;
- __u8 reserved0_6 :1;
- __u8 ps :1; /* parameters saveable */
- __u8 page_length; /* page Length == 0x02 */
- __u8 reserved2;
- __u8 read32k :1; /* 32k blk size (data only) */
- __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */
- __u8 reserved3_23 :2;
- __u8 write32k :1; /* 32k blk size (data only) */
- __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */
- __u8 reserved3_6 :1;
- __u8 streaming :1; /* streaming mode enable */
-#endif
-} idetape_mode_parameter_header_t;
-
-/*
- * Mode Parameter Block Descriptor the MODE SENSE packet command
- *
- * Support for block descriptors is optional.
- */
-typedef struct {
- __u8 density_code; /* Medium density code */
- __u8 blocks[3]; /* Number of blocks */
- __u8 reserved4; /* Reserved */
- __u8 length[3]; /* Block Length */
-} idetape_parameter_block_descriptor_t;
-
-/*
- * The Data Compression Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
- unsigned page_code :6; /* Page Code - Should be 0xf */
- unsigned reserved0 :1; /* Reserved */
- unsigned ps :1;
- __u8 page_length; /* Page Length - Should be 14 */
- unsigned reserved2 :6; /* Reserved */
- unsigned dcc :1; /* Data Compression Capable */
- unsigned dce :1; /* Data Compression Enable */
- unsigned reserved3 :5; /* Reserved */
- unsigned red :2; /* Report Exception on Decompression */
- unsigned dde :1; /* Data Decompression Enable */
- __u32 ca; /* Compression Algorithm */
- __u32 da; /* Decompression Algorithm */
- __u8 reserved[4]; /* Reserved */
-} idetape_data_compression_page_t;
-
-/*
- * The Medium Partition Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
- unsigned page_code :6; /* Page Code - Should be 0x11 */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned ps :1;
- __u8 page_length; /* Page Length - Should be 6 */
- __u8 map; /* Maximum Additional Partitions - Should be 0 */
- __u8 apd; /* Additional Partitions Defined - Should be 0 */
- unsigned reserved4_012 :3; /* Reserved */
- unsigned psum :2; /* Should be 0 */
- unsigned idp :1; /* Should be 0 */
- unsigned sdp :1; /* Should be 0 */
- unsigned fdp :1; /* Fixed Data Partitions */
- __u8 mfr; /* Medium Format Recognition */
- __u8 reserved[2]; /* Reserved */
-} idetape_medium_partition_page_t;
-
-/*
- * Run time configurable parameters.
- */
-typedef struct {
- int dsc_rw_frequency;
- int dsc_media_access_frequency;
- int nr_stages;
-} idetape_config_t;
-
-/*
- * The variables below are used for the character device interface.
- * Additional state variables are defined in our ide_drive_t structure.
- */
-static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
#define ide_tape_f(file) ((file)->private_data)
@@ -1287,38 +523,33 @@
}
/*
- * Function declarations
- *
- */
-static int idetape_chrdev_release (struct inode *inode, struct file *filp);
-static void idetape_write_release (ide_drive_t *drive, unsigned int minor);
-
-/*
* Too bad. The drive wants to send us data which we are not ready to accept.
* Just throw it away.
*/
-static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
+static void idetape_discard_data(ide_drive_t *drive, unsigned int bcount)
{
while (bcount--)
(void) HWIF(drive)->INB(IDE_DATA_REG);
}
-static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+static void idetape_input_buffers(ide_drive_t *drive, idetape_pc_t *pc,
+ unsigned int bcount)
{
struct idetape_bh *bh = pc->bh;
int count;
while (bcount) {
-#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
printk(KERN_ERR "ide-tape: bh == NULL in "
"idetape_input_buffers\n");
idetape_discard_data(drive, bcount);
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
- count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount);
- HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
+ count = min(
+ (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
+ bcount);
+ HWIF(drive)->atapi_input_bytes(drive, bh->b_data +
+ atomic_read(&bh->b_count), count);
bcount -= count;
atomic_add(count, &bh->b_count);
if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -1330,26 +561,26 @@
pc->bh = bh;
}
-static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+static void idetape_output_buffers(ide_drive_t *drive, idetape_pc_t *pc,
+ unsigned int bcount)
{
struct idetape_bh *bh = pc->bh;
int count;
while (bcount) {
-#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_output_buffers\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
count = min((unsigned int)pc->b_count, (unsigned int)bcount);
HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
bcount -= count;
pc->b_data += count;
pc->b_count -= count;
if (!pc->b_count) {
- pc->bh = bh = bh->b_reqnext;
+ bh = bh->b_reqnext;
+ pc->bh = bh;
if (bh) {
pc->b_data = bh->b_data;
pc->b_count = atomic_read(&bh->b_count);
@@ -1358,7 +589,7 @@
}
}
-static void idetape_update_buffers (idetape_pc_t *pc)
+static void idetape_update_buffers(idetape_pc_t *pc)
{
struct idetape_bh *bh = pc->bh;
int count;
@@ -1367,13 +598,11 @@
if (test_bit(PC_WRITING, &pc->flags))
return;
while (bcount) {
-#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_update_buffers\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
count = min((unsigned int)bh->b_size, (unsigned int)bcount);
atomic_set(&bh->b_count, count);
if (atomic_read(&bh->b_count) == bh->b_size)
@@ -1389,17 +618,14 @@
* driver. A storage space for a maximum of IDETAPE_PC_STACK packet
* commands is allocated at initialization time.
*/
-static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
+static idetape_pc_t *idetape_next_pc_storage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 5)
- printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
- tape->pc_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PCRQ_STACK, "pc_stack_index=%d\n", tape->pc_stack_index);
+
if (tape->pc_stack_index == IDETAPE_PC_STACK)
- tape->pc_stack_index=0;
+ tape->pc_stack_index = 0;
return (&tape->pc_stack[tape->pc_stack_index++]);
}
@@ -1408,32 +634,26 @@
* Since we queue packet commands in the request queue, we need to
* allocate a request, along with the allocation of a packet command.
*/
-
+
/**************************************************************
* *
* This should get fixed to use kmalloc(.., GFP_ATOMIC) *
* followed later on by kfree(). -ml *
* *
**************************************************************/
-
-static struct request *idetape_next_rq_storage (ide_drive_t *drive)
+
+static struct request *idetape_next_rq_storage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 5)
- printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
- tape->rq_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PCRQ_STACK, "rq_stack_index=%d\n", tape->rq_stack_index);
+
if (tape->rq_stack_index == IDETAPE_PC_STACK)
- tape->rq_stack_index=0;
+ tape->rq_stack_index = 0;
return (&tape->rq_stack[tape->rq_stack_index++]);
}
-/*
- * idetape_init_pc initializes a packet command.
- */
-static void idetape_init_pc (idetape_pc_t *pc)
+static void idetape_init_pc(idetape_pc_t *pc)
{
memset(pc->c, 0, 12);
pc->retries = 0;
@@ -1446,36 +666,26 @@
}
/*
- * idetape_analyze_error is called on each failed packet command retry
- * to analyze the request sense. We currently do not utilize this
- * information.
+ * called on each failed packet command retry to analyze the request sense. We
+ * currently do not utilize this information.
*/
-static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result)
+static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc = tape->failed_pc;
- tape->sense = *result;
- tape->sense_key = result->sense_key;
- tape->asc = result->asc;
- tape->ascq = result->ascq;
-#if IDETAPE_DEBUG_LOG
- /*
- * Without debugging, we only log an error if we decided to
- * give up retrying.
- */
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
- "asc = %x, ascq = %x\n",
- pc->c[0], result->sense_key,
- result->asc, result->ascq);
-#endif /* IDETAPE_DEBUG_LOG */
+ tape->sense_key = sense[2] & 0xF;
+ tape->asc = sense[12];
+ tape->ascq = sense[13];
- /*
- * Correct pc->actually_transferred by asking the tape.
- */
+ debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n",
+ pc->c[0], tape->sense_key, tape->asc, tape->ascq);
+
+ /* Correct pc->actually_transferred by asking the tape. */
if (test_bit(PC_DMA_ERROR, &pc->flags)) {
- pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information));
+ pc->actually_transferred = pc->request_transfer -
+ tape->blk_size *
+ be32_to_cpu(get_unaligned((u32 *)&sense[3]));
idetape_update_buffers(pc);
}
@@ -1484,29 +694,29 @@
* with sense key=5, asc=0x22, ascq=0, let it slide. Some drives
* (i.e. Seagate STT3401A Travan) don't support 0-length read/writes.
*/
- if ((pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD)
- && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { /* length==0 */
- if (result->sense_key == 5) {
+ if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6)
+ /* length == 0 */
+ && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) {
+ if (tape->sense_key == 5) {
/* don't report an error, everything's ok */
pc->error = 0;
/* don't retry read/write */
set_bit(PC_ABORT, &pc->flags);
}
}
- if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
+ if (pc->c[0] == READ_6 && (sense[2] & 0x80)) {
pc->error = IDETAPE_ERROR_FILEMARK;
set_bit(PC_ABORT, &pc->flags);
}
- if (pc->c[0] == IDETAPE_WRITE_CMD) {
- if (result->eom ||
- (result->sense_key == 0xd && result->asc == 0x0 &&
- result->ascq == 0x2)) {
+ if (pc->c[0] == WRITE_6) {
+ if ((sense[2] & 0x40) || (tape->sense_key == 0xd
+ && tape->asc == 0x0 && tape->ascq == 0x2)) {
pc->error = IDETAPE_ERROR_EOD;
set_bit(PC_ABORT, &pc->flags);
}
}
- if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
- if (result->sense_key == 8) {
+ if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
+ if (tape->sense_key == 8) {
pc->error = IDETAPE_ERROR_EOD;
set_bit(PC_ABORT, &pc->flags);
}
@@ -1516,61 +726,30 @@
}
}
-/*
- * idetape_active_next_stage will declare the next stage as "active".
- */
-static void idetape_active_next_stage (ide_drive_t *drive)
+static void idetape_activate_next_stage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage = tape->next_stage;
struct request *rq = &stage->rq;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
if (stage == NULL) {
- printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+ printk(KERN_ERR "ide-tape: bug: Trying to activate a non"
+ " existing stage\n");
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
rq->rq_disk = tape->disk;
rq->buffer = NULL;
rq->special = (void *)stage->bh;
- tape->active_data_request = rq;
+ tape->active_data_rq = rq;
tape->active_stage = stage;
tape->next_stage = stage->next;
}
-/*
- * idetape_increase_max_pipeline_stages is a part of the feedback
- * loop which tries to find the optimum number of stages. In the
- * feedback loop, we are starting from a minimum maximum number of
- * stages, and if we sense that the pipeline is empty, we try to
- * increase it, until we reach the user compile time memory limit.
- */
-static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- int increase = (tape->max_pipeline - tape->min_pipeline) / 10;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
- tape->max_stages += max(increase, 1);
- tape->max_stages = max(tape->max_stages, tape->min_pipeline);
- tape->max_stages = min(tape->max_stages, tape->max_pipeline);
-}
-
-/*
- * idetape_kfree_stage calls kfree to completely free a stage, along with
- * its related buffers.
- */
-static void __idetape_kfree_stage (idetape_stage_t *stage)
+/* Free a stage along with its related buffers completely. */
+static void __idetape_kfree_stage(idetape_stage_t *stage)
{
struct idetape_bh *prev_bh, *bh = stage->bh;
int size;
@@ -1591,46 +770,43 @@
kfree(stage);
}
-static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
+static void idetape_kfree_stage(idetape_tape_t *tape, idetape_stage_t *stage)
{
__idetape_kfree_stage(stage);
}
/*
- * idetape_remove_stage_head removes tape->first_stage from the pipeline.
- * The caller should avoid race conditions.
+ * Remove tape->first_stage from the pipeline. The caller should avoid race
+ * conditions.
*/
-static void idetape_remove_stage_head (ide_drive_t *drive)
+static void idetape_remove_stage_head(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
if (tape->first_stage == NULL) {
printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
- return;
- }
- if (tape->active_stage == tape->first_stage) {
- printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
+ if (tape->active_stage == tape->first_stage) {
+ printk(KERN_ERR "ide-tape: bug: Trying to free our active "
+ "pipeline stage\n");
+ return;
+ }
stage = tape->first_stage;
tape->first_stage = stage->next;
idetape_kfree_stage(tape, stage);
tape->nr_stages--;
if (tape->first_stage == NULL) {
tape->last_stage = NULL;
-#if IDETAPE_DEBUG_BUGS
if (tape->next_stage != NULL)
- printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+ printk(KERN_ERR "ide-tape: bug: tape->next_stage !="
+ " NULL\n");
if (tape->nr_stages)
- printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
-#endif /* IDETAPE_DEBUG_BUGS */
+ printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 "
+ "now\n");
}
}
@@ -1645,10 +821,8 @@
idetape_stage_t *stage = new_last_stage->next;
idetape_stage_t *nstage;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
-#endif
+ debug_log(DBG_PROCS, "%s: Enter %s\n", tape->name, __func__);
+
while (stage) {
nstage = stage->next;
idetape_kfree_stage(tape, stage);
@@ -1663,8 +837,8 @@
}
/*
- * idetape_end_request is used to finish servicing a request, and to
- * insert a pending pipeline request into the main device queue.
+ * Finish servicing a request and insert a pending pipeline request into the
+ * main device queue.
*/
static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
{
@@ -1675,15 +849,12 @@
int remove_stage = 0;
idetape_stage_t *active_stage;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_end_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
switch (uptodate) {
- case 0: error = IDETAPE_ERROR_GENERAL; break;
- case 1: error = 0; break;
- default: error = uptodate;
+ case 0: error = IDETAPE_ERROR_GENERAL; break;
+ case 1: error = 0; break;
+ default: error = uptodate;
}
rq->errors = error;
if (error)
@@ -1694,20 +865,21 @@
return 0;
}
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
/* The request was a pipelined data transfer request */
- if (tape->active_data_request == rq) {
+ if (tape->active_data_rq == rq) {
active_stage = tape->active_stage;
tape->active_stage = NULL;
- tape->active_data_request = NULL;
+ tape->active_data_rq = NULL;
tape->nr_pending_stages--;
if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
remove_stage = 1;
if (error) {
set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
if (error == IDETAPE_ERROR_EOD)
- idetape_abort_pipeline(drive, active_stage);
+ idetape_abort_pipeline(drive,
+ active_stage);
}
} else if (rq->cmd[0] & REQ_IDETAPE_READ) {
if (error == IDETAPE_ERROR_EOD) {
@@ -1716,51 +888,60 @@
}
}
if (tape->next_stage != NULL) {
- idetape_active_next_stage(drive);
+ idetape_activate_next_stage(drive);
- /*
- * Insert the next request into the request queue.
- */
- (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+ /* Insert the next request into the request queue. */
+ (void)ide_do_drive_cmd(drive, tape->active_data_rq,
+ ide_end);
} else if (!error) {
- idetape_increase_max_pipeline_stages(drive);
+ /*
+ * This is a part of the feedback loop which tries to
+ * find the optimum number of stages. We are starting
+ * from a minimum maximum number of stages, and if we
+ * sense that the pipeline is empty, we try to increase
+ * it, until we reach the user compile time memory
+ * limit.
+ */
+ int i = (tape->max_pipeline - tape->min_pipeline) / 10;
+
+ tape->max_stages += max(i, 1);
+ tape->max_stages = max(tape->max_stages,
+ tape->min_pipeline);
+ tape->max_stages = min(tape->max_stages,
+ tape->max_pipeline);
}
}
ide_end_drive_cmd(drive, 0, 0);
-// blkdev_dequeue_request(rq);
-// drive->rq = NULL;
-// end_that_request_last(rq);
if (remove_stage)
idetape_remove_stage_head(drive);
- if (tape->active_data_request == NULL)
+ if (tape->active_data_rq == NULL)
clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
return 0;
}
-static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_request_sense_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
if (!tape->pc->error) {
- idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+ idetape_analyze_error(drive, tape->pc->buffer);
idetape_end_request(drive, 1, 0);
} else {
- printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
+ printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - "
+ "Aborting request!\n");
idetape_end_request(drive, 0, 0);
}
return ide_stopped;
}
-static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
+static void idetape_create_request_sense_cmd(idetape_pc_t *pc)
{
- idetape_init_pc(pc);
- pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
+ idetape_init_pc(pc);
+ pc->c[0] = REQUEST_SENSE;
pc->c[4] = 20;
pc->request_transfer = 20;
pc->callback = &idetape_request_sense_callback;
@@ -1774,25 +955,22 @@
}
/*
- * idetape_queue_pc_head generates a new packet command request in front
- * of the request queue, before the current request, so that it will be
- * processed immediately, on the next pass through the driver.
+ * Generate a new packet command request in front of the request queue, before
+ * the current request, so that it will be processed immediately, on the next
+ * pass through the driver. The function below is called from the request
+ * handling part of the driver (the "bottom" part). Safe storage for the request
+ * should be allocated with ide_tape_next_{pc,rq}_storage() prior to that.
*
- * idetape_queue_pc_head is called from the request handling part of
- * the driver (the "bottom" part). Safe storage for the request should
- * be allocated with idetape_next_pc_storage and idetape_next_rq_storage
- * before calling idetape_queue_pc_head.
+ * Memory for those requests is pre-allocated at initialization time, and is
+ * limited to IDETAPE_PC_STACK requests. We assume that we have enough space for
+ * the maximum possible number of inter-dependent packet commands.
*
- * Memory for those requests is pre-allocated at initialization time, and
- * is limited to IDETAPE_PC_STACK requests. We assume that we have enough
- * space for the maximum possible number of inter-dependent packet commands.
- *
- * The higher level of the driver - The ioctl handler and the character
- * device handling functions should queue request to the lower level part
- * and wait for their completion using idetape_queue_pc_tail or
- * idetape_queue_rw_tail.
+ * The higher level of the driver - The ioctl handler and the character device
+ * handling functions should queue request to the lower level part and wait for
+ * their completion using idetape_queue_pc_tail or idetape_queue_rw_tail.
*/
-static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
+static void idetape_queue_pc_head(ide_drive_t *drive, idetape_pc_t *pc,
+ struct request *rq)
{
struct ide_tape_obj *tape = drive->driver_data;
@@ -1813,7 +991,7 @@
idetape_pc_t *pc;
struct request *rq;
- (void)drive->hwif->INB(IDE_ERROR_REG);
+ (void)ide_read_error(drive);
pc = idetape_next_pc_storage(drive);
rq = idetape_next_rq_storage(drive);
idetape_create_request_sense_cmd(pc);
@@ -1823,50 +1001,46 @@
}
/*
- * idetape_postpone_request postpones the current request so that
- * ide.c will be able to service requests from another device on
- * the same hwgroup while we are polling for DSC.
+ * Postpone the current request so that ide.c will be able to service requests
+ * from another device on the same hwgroup while we are polling for DSC.
*/
-static void idetape_postpone_request (ide_drive_t *drive)
+static void idetape_postpone_request(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
-#endif
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
tape->postponed_rq = HWGROUP(drive)->rq;
- ide_stall_queue(drive, tape->dsc_polling_frequency);
+ ide_stall_queue(drive, tape->dsc_poll_freq);
}
+typedef void idetape_io_buf(ide_drive_t *, idetape_pc_t *, unsigned int);
+
/*
- * idetape_pc_intr is the usual interrupt handler which will be called
- * during a packet command. We will transfer some of the data (as
- * requested by the drive) and will re-point interrupt handler to us.
- * When data transfer is finished, we will act according to the
- * algorithm described before idetape_issue_packet_command.
- *
+ * This is the usual interrupt handler which will be called during a packet
+ * command. We will transfer some of the data (as requested by the drive) and
+ * will re-point interrupt handler to us. When data transfer is finished, we
+ * will act according to the algorithm described before
+ * idetape_issue_pc.
*/
-static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc = tape->pc;
+ xfer_func_t *xferfunc;
+ idetape_io_buf *iobuf;
unsigned int temp;
#if SIMULATE_ERRORS
- static int error_sim_count = 0;
+ static int error_sim_count;
#endif
u16 bcount;
u8 stat, ireason;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
- "interrupt handler\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s - interrupt handler\n", __func__);
/* Clear the interrupt */
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
@@ -1896,48 +1070,40 @@
pc->actually_transferred = pc->request_transfer;
idetape_update_buffers(pc);
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: DMA finished\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "DMA finished\n");
+
}
/* No more interrupts */
if ((stat & DRQ_STAT) == 0) {
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDETAPE_DEBUG_LOG */
- clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ debug_log(DBG_SENSE, "Packet command completed, %d bytes"
+ " transferred\n", pc->actually_transferred);
+ clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
local_irq_enable();
#if SIMULATE_ERRORS
- if ((pc->c[0] == IDETAPE_WRITE_CMD ||
- pc->c[0] == IDETAPE_READ_CMD) &&
+ if ((pc->c[0] == WRITE_6 || pc->c[0] == READ_6) &&
(++error_sim_count % 100) == 0) {
printk(KERN_INFO "ide-tape: %s: simulating error\n",
tape->name);
stat |= ERR_STAT;
}
#endif
- if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+ if ((stat & ERR_STAT) && pc->c[0] == REQUEST_SENSE)
stat &= ~ERR_STAT;
if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
/* Error detected */
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: %s: I/O error\n",
- tape->name);
-#endif /* IDETAPE_DEBUG_LOG */
- if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
- printk(KERN_ERR "ide-tape: I/O error in request sense command\n");
+ debug_log(DBG_ERR, "%s: I/O error\n", tape->name);
+
+ if (pc->c[0] == REQUEST_SENSE) {
+ printk(KERN_ERR "ide-tape: I/O error in request"
+ " sense command\n");
return ide_do_reset(drive);
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
-#endif
+ debug_log(DBG_ERR, "[cmd %x]: check condition\n",
+ pc->c[0]);
+
/* Retry operation */
return idetape_retry_pc(drive);
}
@@ -1946,7 +1112,7 @@
(stat & SEEK_STAT) == 0) {
/* Media access command */
tape->dsc_polling_start = jiffies;
- tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
/* Allow ide.c to handle other requests */
idetape_postpone_request(drive);
@@ -1971,7 +1137,7 @@
ireason = hwif->INB(IDE_IREASON_REG);
if (ireason & CD) {
- printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+ printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__);
return ide_do_reset(drive);
}
if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
@@ -1987,86 +1153,76 @@
temp = pc->actually_transferred + bcount;
if (temp > pc->request_transfer) {
if (temp > pc->buffer_size) {
- printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+ printk(KERN_ERR "ide-tape: The tape wants to "
+ "send us more data than expected "
+ "- discarding data\n");
idetape_discard_data(drive, bcount);
- ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ ide_set_handler(drive, &idetape_pc_intr,
+ IDETAPE_WAIT_CMD, NULL);
return ide_started;
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_SENSE, "The tape wants to send us more "
+ "data than expected - allowing transfer\n");
}
- }
- if (test_bit(PC_WRITING, &pc->flags)) {
- if (pc->bh != NULL)
- idetape_output_buffers(drive, pc, bcount);
- else
- /* Write the current buffer */
- hwif->atapi_output_bytes(drive, pc->current_position,
- bcount);
+ iobuf = &idetape_input_buffers;
+ xferfunc = hwif->atapi_input_bytes;
} else {
- if (pc->bh != NULL)
- idetape_input_buffers(drive, pc, bcount);
- else
- /* Read the current buffer */
- hwif->atapi_input_bytes(drive, pc->current_position,
- bcount);
+ iobuf = &idetape_output_buffers;
+ xferfunc = hwif->atapi_output_bytes;
}
+
+ if (pc->bh)
+ iobuf(drive, pc, bcount);
+ else
+ xferfunc(drive, pc->current_position, bcount);
+
/* Update the current position */
pc->actually_transferred += bcount;
pc->current_position += bcount;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
- "on that interrupt\n", pc->c[0], bcount);
-#endif
+
+ debug_log(DBG_SENSE, "[cmd %x] transferred %d bytes on that intr.\n",
+ pc->c[0], bcount);
+
/* And set the interrupt handler again */
ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
return ide_started;
}
/*
- * Packet Command Interface
+ * Packet Command Interface
*
- * The current Packet Command is available in tape->pc, and will not
- * change until we finish handling it. Each packet command is associated
- * with a callback function that will be called when the command is
- * finished.
+ * The current Packet Command is available in tape->pc, and will not change
+ * until we finish handling it. Each packet command is associated with a
+ * callback function that will be called when the command is finished.
*
- * The handling will be done in three stages:
+ * The handling will be done in three stages:
*
- * 1. idetape_issue_packet_command will send the packet command to the
- * drive, and will set the interrupt handler to idetape_pc_intr.
+ * 1. idetape_issue_pc will send the packet command to the drive, and will set
+ * the interrupt handler to idetape_pc_intr.
*
- * 2. On each interrupt, idetape_pc_intr will be called. This step
- * will be repeated until the device signals us that no more
- * interrupts will be issued.
+ * 2. On each interrupt, idetape_pc_intr will be called. This step will be
+ * repeated until the device signals us that no more interrupts will be issued.
*
- * 3. ATAPI Tape media access commands have immediate status with a
- * delayed process. In case of a successful initiation of a
- * media access packet command, the DSC bit will be set when the
- * actual execution of the command is finished.
- * Since the tape drive will not issue an interrupt, we have to
- * poll for this event. In this case, we define the request as
- * "low priority request" by setting rq_status to
- * IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and exit
- * the driver.
+ * 3. ATAPI Tape media access commands have immediate status with a delayed
+ * process. In case of a successful initiation of a media access packet command,
+ * the DSC bit will be set when the actual execution of the command is finished.
+ * Since the tape drive will not issue an interrupt, we have to poll for this
+ * event. In this case, we define the request as "low priority request" by
+ * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and
+ * exit the driver.
*
- * ide.c will then give higher priority to requests which
- * originate from the other device, until will change rq_status
- * to RQ_ACTIVE.
+ * ide.c will then give higher priority to requests which originate from the
+ * other device, until will change rq_status to RQ_ACTIVE.
*
- * 4. When the packet command is finished, it will be checked for errors.
+ * 4. When the packet command is finished, it will be checked for errors.
*
- * 5. In case an error was found, we queue a request sense packet
- * command in front of the request queue and retry the operation
- * up to IDETAPE_MAX_PC_RETRIES times.
+ * 5. In case an error was found, we queue a request sense packet command in
+ * front of the request queue and retry the operation up to
+ * IDETAPE_MAX_PC_RETRIES times.
*
- * 6. In case no error was found, or we decided to give up and not
- * to retry again, the callback function will be called and then
- * we will handle the next request.
- *
+ * 6. In case no error was found, or we decided to give up and not to retry
+ * again, the callback function will be called and then we will handle the next
+ * request.
*/
static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
{
@@ -2077,8 +1233,9 @@
ide_startstop_t startstop;
u8 ireason;
- if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
- printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+ if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk(KERN_ERR "ide-tape: Strange, packet command initiated "
+ "yet DRQ isn't asserted\n");
return startstop;
}
ireason = hwif->INB(IDE_IREASON_REG);
@@ -2111,22 +1268,20 @@
return ide_started;
}
-static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, idetape_pc_t *pc)
{
ide_hwif_t *hwif = drive->hwif;
idetape_tape_t *tape = drive->driver_data;
int dma_ok = 0;
u16 bcount;
-#if IDETAPE_DEBUG_BUGS
- if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
- pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+ if (tape->pc->c[0] == REQUEST_SENSE &&
+ pc->c[0] == REQUEST_SENSE) {
printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
"Two request sense in serial were issued\n");
}
-#endif /* IDETAPE_DEBUG_BUGS */
- if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
+ if (tape->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
tape->failed_pc = pc;
/* Set the current packet command */
tape->pc = pc;
@@ -2134,12 +1289,12 @@
if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
test_bit(PC_ABORT, &pc->flags)) {
/*
- * We will "abort" retrying a packet command in case
- * a legitimate error code was received (crossing a
- * filemark, or end of the media, for example).
+ * We will "abort" retrying a packet command in case legitimate
+ * error code was received (crossing a filemark, or end of the
+ * media, for example).
*/
if (!test_bit(PC_ABORT, &pc->flags)) {
- if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+ if (!(pc->c[0] == TEST_UNIT_READY &&
tape->sense_key == 2 && tape->asc == 4 &&
(tape->ascq == 1 || tape->ascq == 8))) {
printk(KERN_ERR "ide-tape: %s: I/O error, "
@@ -2155,10 +1310,7 @@
tape->failed_pc = NULL;
return pc->callback(drive);
}
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
pc->retries++;
/* We haven't transferred any data yet */
@@ -2181,8 +1333,8 @@
if (dma_ok) /* Will begin DMA later */
set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
- ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
- hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+ ide_execute_command(drive, WIN_PACKETCMD, &idetape_transfer_pc,
+ IDETAPE_WAIT_CMD, NULL);
return ide_started;
} else {
hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -2190,31 +1342,24 @@
}
}
-/*
- * General packet command callback function.
- */
-static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
idetape_end_request(drive, tape->pc->error ? 0 : 1, 0);
return ide_stopped;
}
-/*
- * A mode sense command is used to "sense" tape parameters.
- */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
+/* A mode sense command is used to "sense" tape parameters. */
+static void idetape_create_mode_sense_cmd(idetape_pc_t *pc, u8 page_code)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_MODE_SENSE_CMD;
+ pc->c[0] = MODE_SENSE;
if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
- pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */
+ /* DBD = 1 - Don't return block descriptors */
+ pc->c[1] = 8;
pc->c[2] = page_code;
/*
* Changed pc->c[3] to 0 (255 will at best return unused info).
@@ -2224,7 +1369,8 @@
* and return an error when 255 is used.
*/
pc->c[3] = 0;
- pc->c[4] = 255; /* (We will just discard data in that case) */
+ /* We will just discard data in that case */
+ pc->c[4] = 255;
if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
pc->request_transfer = 12;
else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -2234,66 +1380,81 @@
pc->callback = &idetape_pc_callback;
}
-static void calculate_speeds(ide_drive_t *drive)
+static void idetape_calculate_speeds(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
- int full = 125, empty = 75;
- if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
- tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
- tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
+ if (time_after(jiffies,
+ tape->controlled_pipeline_head_time + 120 * HZ)) {
+ tape->controlled_previous_pipeline_head =
+ tape->controlled_last_pipeline_head;
+ tape->controlled_previous_head_time =
+ tape->controlled_pipeline_head_time;
tape->controlled_last_pipeline_head = tape->pipeline_head;
tape->controlled_pipeline_head_time = jiffies;
}
if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
- tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
+ tape->controlled_pipeline_head_speed = (tape->pipeline_head -
+ tape->controlled_last_pipeline_head) * 32 * HZ /
+ (jiffies - tape->controlled_pipeline_head_time);
else if (time_after(jiffies, tape->controlled_previous_head_time))
- tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
+ tape->controlled_pipeline_head_speed = (tape->pipeline_head -
+ tape->controlled_previous_pipeline_head) * 32 *
+ HZ / (jiffies - tape->controlled_previous_head_time);
- if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+ if (tape->nr_pending_stages < tape->max_stages/*- 1 */) {
/* -1 for read mode error recovery */
- if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
+ if (time_after(jiffies, tape->uncontrolled_previous_head_time +
+ 10 * HZ)) {
tape->uncontrolled_pipeline_head_time = jiffies;
- tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
+ tape->uncontrolled_pipeline_head_speed =
+ (tape->pipeline_head -
+ tape->uncontrolled_previous_pipeline_head) *
+ 32 * HZ / (jiffies -
+ tape->uncontrolled_previous_head_time);
}
} else {
tape->uncontrolled_previous_head_time = jiffies;
tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
- if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
+ if (time_after(jiffies, tape->uncontrolled_pipeline_head_time +
+ 30 * HZ))
tape->uncontrolled_pipeline_head_time = jiffies;
- }
+
}
- tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed);
- if (tape->speed_control == 0) {
- tape->max_insert_speed = 5000;
- } else if (tape->speed_control == 1) {
+ tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed,
+ tape->controlled_pipeline_head_speed);
+
+ if (tape->speed_control == 1) {
if (tape->nr_pending_stages >= tape->max_stages / 2)
tape->max_insert_speed = tape->pipeline_head_speed +
- (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages;
+ (1100 - tape->pipeline_head_speed) * 2 *
+ (tape->nr_pending_stages - tape->max_stages / 2)
+ / tape->max_stages;
else
tape->max_insert_speed = 500 +
- (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages;
+ (tape->pipeline_head_speed - 500) * 2 *
+ tape->nr_pending_stages / tape->max_stages;
+
if (tape->nr_pending_stages >= tape->max_stages * 99 / 100)
tape->max_insert_speed = 5000;
- } else if (tape->speed_control == 2) {
- tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 +
- (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages;
} else
tape->max_insert_speed = tape->speed_control;
+
tape->max_insert_speed = max(tape->max_insert_speed, 500);
}
-static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
+static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc = tape->pc;
u8 stat;
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
+
if (stat & SEEK_STAT) {
if (stat & ERR_STAT) {
/* Error detected */
- if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
+ if (pc->c[0] != TEST_UNIT_READY)
printk(KERN_ERR "ide-tape: %s: I/O error, ",
tape->name);
/* Retry operation */
@@ -2309,14 +1470,14 @@
return pc->callback(drive);
}
-static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_rw_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq;
- int blocks = tape->pc->actually_transferred / tape->tape_block_size;
+ int blocks = tape->pc->actually_transferred / tape->blk_size;
- tape->avg_size += blocks * tape->tape_block_size;
- tape->insert_size += blocks * tape->tape_block_size;
+ tape->avg_size += blocks * tape->blk_size;
+ tape->insert_size += blocks * tape->blk_size;
if (tape->insert_size > 1024 * 1024)
tape->measure_insert_time = 1;
if (tape->measure_insert_time) {
@@ -2325,19 +1486,17 @@
tape->insert_size = 0;
}
if (time_after(jiffies, tape->insert_time))
- tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+ tape->insert_speed = tape->insert_size / 1024 * HZ /
+ (jiffies - tape->insert_time);
if (time_after_eq(jiffies, tape->avg_time + HZ)) {
- tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
+ tape->avg_speed = tape->avg_size * HZ /
+ (jiffies - tape->avg_time) / 1024;
tape->avg_size = 0;
tape->avg_time = jiffies;
}
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
- tape->first_frame_position += blocks;
+ tape->first_frame += blocks;
rq->current_nr_sectors -= blocks;
if (!tape->pc->error)
@@ -2347,28 +1506,31 @@
return ide_stopped;
}
-static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc,
+ unsigned int length, struct idetape_bh *bh)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_READ_CMD;
- put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
+ pc->c[0] = READ_6;
+ put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
pc->c[1] = 1;
pc->callback = &idetape_rw_callback;
pc->bh = bh;
atomic_set(&bh->b_count, 0);
pc->buffer = NULL;
- pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+ pc->buffer_size = length * tape->blk_size;
+ pc->request_transfer = pc->buffer_size;
if (pc->request_transfer == tape->stage_size)
set_bit(PC_DMA_RECOMMENDED, &pc->flags);
}
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape,
+ idetape_pc_t *pc, struct idetape_bh *bh)
{
int size = 32768;
struct idetape_bh *p = bh;
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_READ_BUFFER_CMD;
+ pc->c[0] = READ_BUFFER;
pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
pc->c[7] = size >> 8;
pc->c[8] = size & 0xff;
@@ -2380,14 +1542,16 @@
atomic_set(&p->b_count, 0);
p = p->b_reqnext;
}
- pc->request_transfer = pc->buffer_size = size;
+ pc->request_transfer = size;
+ pc->buffer_size = size;
}
-static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc,
+ unsigned int length, struct idetape_bh *bh)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_WRITE_CMD;
- put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
+ pc->c[0] = WRITE_6;
+ put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
pc->c[1] = 1;
pc->callback = &idetape_rw_callback;
set_bit(PC_WRITING, &pc->flags);
@@ -2395,14 +1559,12 @@
pc->b_data = bh->b_data;
pc->b_count = atomic_read(&bh->b_count);
pc->buffer = NULL;
- pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+ pc->buffer_size = length * tape->blk_size;
+ pc->request_transfer = pc->buffer_size;
if (pc->request_transfer == tape->stage_size)
set_bit(PC_DMA_RECOMMENDED, &pc->flags);
}
-/*
- * idetape_do_request is our request handling function.
- */
static ide_startstop_t idetape_do_request(ide_drive_t *drive,
struct request *rq, sector_t block)
{
@@ -2411,37 +1573,22 @@
struct request *postponed_rq = tape->postponed_rq;
u8 stat;
-#if IDETAPE_DEBUG_LOG
-#if 0
- if (tape->debug_level >= 5)
- printk(KERN_INFO "ide-tape: %d, "
- "dev: %s, cmd: %ld, errors: %d\n",
- rq->rq_disk->disk_name, rq->cmd[0], rq->errors);
-#endif
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: sector: %ld, "
- "nr_sectors: %ld, current_nr_sectors: %d\n",
+ debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld,"
+ " current_nr_sectors: %d\n",
rq->sector, rq->nr_sectors, rq->current_nr_sectors);
-#endif /* IDETAPE_DEBUG_LOG */
if (!blk_special_request(rq)) {
- /*
- * We do not support buffer cache originated requests.
- */
+ /* We do not support buffer cache originated requests. */
printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
"request queue (%d)\n", drive->name, rq->cmd_type);
ide_end_request(drive, 0, 0);
return ide_stopped;
}
- /*
- * Retry a failed packet command
- */
- if (tape->failed_pc != NULL &&
- tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
- return idetape_issue_packet_command(drive, tape->failed_pc);
- }
-#if IDETAPE_DEBUG_BUGS
+ /* Retry a failed packet command */
+ if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE)
+ return idetape_issue_pc(drive, tape->failed_pc);
+
if (postponed_rq != NULL)
if (rq != postponed_rq) {
printk(KERN_ERR "ide-tape: ide-tape.c bug - "
@@ -2449,7 +1596,6 @@
idetape_end_request(drive, 0, 0);
return ide_stopped;
}
-#endif /* IDETAPE_DEBUG_BUGS */
tape->postponed_rq = NULL;
@@ -2457,7 +1603,7 @@
* If the tape is still busy, postpone our request and service
* the other device meanwhile.
*/
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
@@ -2467,16 +1613,15 @@
drive->post_reset = 0;
}
- if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
- tape->measure_insert_time = 1;
if (time_after(jiffies, tape->insert_time))
- tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
- calculate_speeds(drive);
+ tape->insert_speed = tape->insert_size / 1024 * HZ /
+ (jiffies - tape->insert_time);
+ idetape_calculate_speeds(drive);
if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
(stat & SEEK_STAT) == 0) {
if (postponed_rq == NULL) {
tape->dsc_polling_start = jiffies;
- tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
+ tape->dsc_poll_freq = tape->best_dsc_rw_freq;
tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
} else if (time_after(jiffies, tape->dsc_timeout)) {
printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
@@ -2487,8 +1632,10 @@
} else {
return ide_do_reset(drive);
}
- } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
- tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
+ } else if (time_after(jiffies,
+ tape->dsc_polling_start +
+ IDETAPE_DSC_MA_THRESHOLD))
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
idetape_postpone_request(drive);
return ide_stopped;
}
@@ -2496,20 +1643,23 @@
tape->buffer_head++;
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
- idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ idetape_create_read_cmd(tape, pc, rq->current_nr_sectors,
+ (struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
tape->buffer_head++;
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
- idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ idetape_create_write_cmd(tape, pc, rq->current_nr_sectors,
+ (struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) {
tape->postpone_cnt = 0;
pc = idetape_next_pc_storage(drive);
- idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ idetape_create_read_buffer_cmd(tape, pc,
+ (struct idetape_bh *)rq->special);
goto out;
}
if (rq->cmd[0] & REQ_IDETAPE_PC1) {
@@ -2524,49 +1674,51 @@
}
BUG();
out:
- return idetape_issue_packet_command(drive, pc);
+ return idetape_issue_pc(drive, pc);
}
-/*
- * Pipeline related functions
- */
-static inline int idetape_pipeline_active (idetape_tape_t *tape)
+/* Pipeline related functions */
+static inline int idetape_pipeline_active(idetape_tape_t *tape)
{
int rc1, rc2;
rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
- rc2 = (tape->active_data_request != NULL);
+ rc2 = (tape->active_data_rq != NULL);
return rc1;
}
/*
- * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline
- * stage, along with all the necessary small buffers which together make
- * a buffer of size tape->stage_size (or a bit more). We attempt to
- * combine sequential pages as much as possible.
+ * The function below uses __get_free_page to allocate a pipeline stage, along
+ * with all the necessary small buffers which together make a buffer of size
+ * tape->stage_size (or a bit more). We attempt to combine sequential pages as
+ * much as possible.
*
- * Returns a pointer to the new allocated stage, or NULL if we
- * can't (or don't want to) allocate a stage.
+ * It returns a pointer to the new allocated stage, or NULL if we can't (or
+ * don't want to) allocate a stage.
*
- * Pipeline stages are optional and are used to increase performance.
- * If we can't allocate them, we'll manage without them.
+ * Pipeline stages are optional and are used to increase performance. If we
+ * can't allocate them, we'll manage without them.
*/
-static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
+static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full,
+ int clear)
{
idetape_stage_t *stage;
struct idetape_bh *prev_bh, *bh;
int pages = tape->pages_per_stage;
char *b_data = NULL;
- if ((stage = kmalloc(sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+ stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL);
+ if (!stage)
return NULL;
stage->next = NULL;
- bh = stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ bh = stage->bh;
if (bh == NULL)
goto abort;
bh->b_reqnext = NULL;
- if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ bh->b_data = (char *) __get_free_page(GFP_KERNEL);
+ if (!bh->b_data)
goto abort;
if (clear)
memset(bh->b_data, 0, PAGE_SIZE);
@@ -2574,7 +1726,8 @@
atomic_set(&bh->b_count, full ? bh->b_size : 0);
while (--pages) {
- if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ b_data = (char *) __get_free_page(GFP_KERNEL);
+ if (!b_data)
goto abort;
if (clear)
memset(b_data, 0, PAGE_SIZE);
@@ -2592,7 +1745,8 @@
continue;
}
prev_bh = bh;
- if ((bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
+ bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ if (!bh) {
free_page((unsigned long) b_data);
goto abort;
}
@@ -2611,14 +1765,11 @@
return NULL;
}
-static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
+static idetape_stage_t *idetape_kmalloc_stage(idetape_tape_t *tape)
{
idetape_stage_t *cache_stage = tape->cache_stage;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
if (tape->nr_stages >= tape->max_stages)
return NULL;
@@ -2629,22 +1780,24 @@
return __idetape_kmalloc_stage(tape, 0, 0);
}
-static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user(idetape_tape_t *tape,
+ idetape_stage_t *stage, const char __user *buf, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
int ret = 0;
while (n) {
-#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_copy_stage_from_user\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return 1;
}
-#endif /* IDETAPE_DEBUG_BUGS */
- count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
- if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+ count = min((unsigned int)
+ (bh->b_size - atomic_read(&bh->b_count)),
+ (unsigned int)n);
+ if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf,
+ count))
ret = 1;
n -= count;
atomic_add(count, &bh->b_count);
@@ -2659,20 +1812,19 @@
return ret;
}
-static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
+ idetape_stage_t *stage, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
int ret = 0;
while (n) {
-#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
- printk(KERN_ERR "ide-tape: bh == NULL in "
- "idetape_copy_stage_to_user\n");
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
return 1;
}
-#endif /* IDETAPE_DEBUG_BUGS */
count = min(tape->b_count, n);
if (copy_to_user(buf, tape->b_data, count))
ret = 1;
@@ -2681,7 +1833,8 @@
tape->b_count -= count;
buf += count;
if (!tape->b_count) {
- tape->bh = bh = bh->b_reqnext;
+ bh = bh->b_reqnext;
+ tape->bh = bh;
if (bh) {
tape->b_data = bh->b_data;
tape->b_count = atomic_read(&bh->b_count);
@@ -2691,12 +1844,12 @@
return ret;
}
-static void idetape_init_merge_stage (idetape_tape_t *tape)
+static void idetape_init_merge_stage(idetape_tape_t *tape)
{
struct idetape_bh *bh = tape->merge_stage->bh;
-
+
tape->bh = bh;
- if (tape->chrdev_direction == idetape_direction_write)
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
atomic_set(&bh->b_count, 0);
else {
tape->b_data = bh->b_data;
@@ -2704,7 +1857,7 @@
}
}
-static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
+static void idetape_switch_buffers(idetape_tape_t *tape, idetape_stage_t *stage)
{
struct idetape_bh *tmp;
@@ -2714,89 +1867,76 @@
idetape_init_merge_stage(tape);
}
-/*
- * idetape_add_stage_tail adds a new stage at the end of the pipeline.
- */
-static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
+/* Add a new stage at the end of the pipeline. */
+static void idetape_add_stage_tail(ide_drive_t *drive, idetape_stage_t *stage)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
-#endif /* IDETAPE_DEBUG_LOG */
- spin_lock_irqsave(&tape->spinlock, flags);
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ spin_lock_irqsave(&tape->lock, flags);
stage->next = NULL;
if (tape->last_stage != NULL)
- tape->last_stage->next=stage;
+ tape->last_stage->next = stage;
else
- tape->first_stage = tape->next_stage=stage;
+ tape->first_stage = stage;
+ tape->next_stage = stage;
tape->last_stage = stage;
if (tape->next_stage == NULL)
tape->next_stage = tape->last_stage;
tape->nr_stages++;
tape->nr_pending_stages++;
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
}
-/*
- * idetape_wait_for_request installs a completion in a pending request
- * and sleeps until it is serviced.
- *
- * The caller should ensure that the request will not be serviced
- * before we install the completion (usually by disabling interrupts).
+/* Install a completion in a pending request and sleep until it is serviced. The
+ * caller should ensure that the request will not be serviced before we install
+ * the completion (usually by disabling interrupts).
*/
-static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
+static void idetape_wait_for_request(ide_drive_t *drive, struct request *rq)
{
DECLARE_COMPLETION_ONSTACK(wait);
idetape_tape_t *tape = drive->driver_data;
-#if IDETAPE_DEBUG_BUGS
if (rq == NULL || !blk_special_request(rq)) {
- printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+ printk(KERN_ERR "ide-tape: bug: Trying to sleep on non-valid"
+ " request\n");
return;
}
-#endif /* IDETAPE_DEBUG_BUGS */
rq->end_io_data = &wait;
rq->end_io = blk_end_sync_rq;
- spin_unlock_irq(&tape->spinlock);
+ spin_unlock_irq(&tape->lock);
wait_for_completion(&wait);
/* The stage and its struct request have been deallocated */
- spin_lock_irq(&tape->spinlock);
+ spin_lock_irq(&tape->lock);
}
-static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
- idetape_read_position_result_t *result;
-
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ u8 *readpos = tape->pc->buffer;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
if (!tape->pc->error) {
- result = (idetape_read_position_result_t *) tape->pc->buffer;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
-#endif /* IDETAPE_DEBUG_LOG */
- if (result->bpu) {
- printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+ debug_log(DBG_SENSE, "BOP - %s\n",
+ (readpos[0] & 0x80) ? "Yes" : "No");
+ debug_log(DBG_SENSE, "EOP - %s\n",
+ (readpos[0] & 0x40) ? "Yes" : "No");
+
+ if (readpos[0] & 0x4) {
+ printk(KERN_INFO "ide-tape: Block location is unknown"
+ "to the tape\n");
clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
idetape_end_request(drive, 0, 0);
} else {
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block));
-#endif /* IDETAPE_DEBUG_LOG */
- tape->partition = result->partition;
- tape->first_frame_position = ntohl(result->first_block);
- tape->last_frame_position = ntohl(result->last_block);
- tape->blocks_in_buffer = result->blocks_in_buffer[2];
+ debug_log(DBG_SENSE, "Block Location - %u\n",
+ be32_to_cpu(*(u32 *)&readpos[4]));
+
+ tape->partition = readpos[1];
+ tape->first_frame =
+ be32_to_cpu(*(u32 *)&readpos[4]);
set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
idetape_end_request(drive, 1, 0);
}
@@ -2807,17 +1947,14 @@
}
/*
- * idetape_create_write_filemark_cmd will:
- *
- * 1. Write a filemark if write_filemark=1.
- * 2. Flush the device buffers without writing a filemark
- * if write_filemark=0.
- *
+ * Write a filemark if write_filemark=1. Flush the device buffers without
+ * writing a filemark otherwise.
*/
-static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark)
+static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
+ idetape_pc_t *pc, int write_filemark)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
+ pc->c[0] = WRITE_FILEMARKS;
pc->c[4] = write_filemark;
set_bit(PC_WAIT_FOR_DSC, &pc->flags);
pc->callback = &idetape_pc_callback;
@@ -2826,31 +1963,24 @@
static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD;
+ pc->c[0] = TEST_UNIT_READY;
pc->callback = &idetape_pc_callback;
}
/*
- * idetape_queue_pc_tail is based on the following functions:
+ * We add a special packet command request to the tail of the request queue, and
+ * wait for it to be serviced. This is not to be called from within the request
+ * handling part of the driver! We allocate here data on the stack and it is
+ * valid until the request is finished. This is not the case for the bottom part
+ * of the driver, where we are always leaving the functions to wait for an
+ * interrupt or a timer event.
*
- * ide_do_drive_cmd from ide.c
- * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
- *
- * We add a special packet command request to the tail of the request
- * queue, and wait for it to be serviced.
- *
- * This is not to be called from within the request handling part
- * of the driver ! We allocate here data in the stack, and it is valid
- * until the request is finished. This is not the case for the bottom
- * part of the driver, where we are always leaving the functions to wait
- * for an interrupt or a timer event.
- *
- * From the bottom part of the driver, we should allocate safe memory
- * using idetape_next_pc_storage and idetape_next_rq_storage, and add
- * the request to the request list without waiting for it to be serviced !
- * In that case, we usually use idetape_queue_pc_head.
+ * From the bottom part of the driver, we should allocate safe memory using
+ * idetape_next_pc_storage() and ide_tape_next_rq_storage(), and add the request
+ * to the request list without waiting for it to be serviced! In that case, we
+ * usually use idetape_queue_pc_head().
*/
-static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
+static int __idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc)
{
struct ide_tape_obj *tape = drive->driver_data;
struct request rq;
@@ -2861,10 +1991,11 @@
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
-static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
+static void idetape_create_load_unload_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+ int cmd)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
+ pc->c[0] = START_STOP;
pc->c[4] = cmd;
set_bit(PC_WAIT_FOR_DSC, &pc->flags);
pc->callback = &idetape_pc_callback;
@@ -2876,9 +2007,7 @@
idetape_pc_t pc;
int load_attempted = 0;
- /*
- * Wait for the tape to become ready
- */
+ /* Wait for the tape to become ready */
set_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
timeout += jiffies;
while (time_before(jiffies, timeout)) {
@@ -2886,10 +2015,12 @@
if (!__idetape_queue_pc_tail(drive, &pc))
return 0;
if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
- || (tape->asc == 0x3A)) { /* no media */
+ || (tape->asc == 0x3A)) {
+ /* no media */
if (load_attempted)
return -ENOMEDIUM;
- idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+ idetape_create_load_unload_cmd(drive, &pc,
+ IDETAPE_LU_LOAD_MASK);
__idetape_queue_pc_tail(drive, &pc);
load_attempted = 1;
/* not about to be ready */
@@ -2901,85 +2032,86 @@
return -EIO;
}
-static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
+static int idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc)
{
return __idetape_queue_pc_tail(drive, pc);
}
-static int idetape_flush_tape_buffers (ide_drive_t *drive)
+static int idetape_flush_tape_buffers(ide_drive_t *drive)
{
idetape_pc_t pc;
int rc;
idetape_create_write_filemark_cmd(drive, &pc, 0);
- if ((rc = idetape_queue_pc_tail(drive, &pc)))
+ rc = idetape_queue_pc_tail(drive, &pc);
+ if (rc)
return rc;
idetape_wait_ready(drive, 60 * 5 * HZ);
return 0;
}
-static void idetape_create_read_position_cmd (idetape_pc_t *pc)
+static void idetape_create_read_position_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_READ_POSITION_CMD;
+ pc->c[0] = READ_POSITION;
pc->request_transfer = 20;
pc->callback = &idetape_read_position_callback;
}
-static int idetape_read_position (ide_drive_t *drive)
+static int idetape_read_position(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
int position;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_read_position\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
idetape_create_read_position_cmd(&pc);
if (idetape_queue_pc_tail(drive, &pc))
return -1;
- position = tape->first_frame_position;
+ position = tape->first_frame;
return position;
}
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
+static void idetape_create_locate_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+ unsigned int block, u8 partition, int skip)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_LOCATE_CMD;
+ pc->c[0] = POSITION_TO_ELEMENT;
pc->c[1] = 2;
- put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
+ put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
pc->c[8] = partition;
set_bit(PC_WAIT_FOR_DSC, &pc->flags);
pc->callback = &idetape_pc_callback;
}
-static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
+static int idetape_create_prevent_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+ int prevent)
{
idetape_tape_t *tape = drive->driver_data;
- if (!tape->capabilities.lock)
+ /* device supports locking according to capabilities page */
+ if (!(tape->caps[6] & 0x01))
return 0;
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_PREVENT_CMD;
+ pc->c[0] = ALLOW_MEDIUM_REMOVAL;
pc->c[4] = prevent;
pc->callback = &idetape_pc_callback;
return 1;
}
-static int __idetape_discard_read_pipeline (ide_drive_t *drive)
+static int __idetape_discard_read_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
int cnt;
- if (tape->chrdev_direction != idetape_direction_read)
+ if (tape->chrdev_dir != IDETAPE_DIR_READ)
return 0;
/* Remove merge stage. */
- cnt = tape->merge_stage_size / tape->tape_block_size;
+ cnt = tape->merge_stage_size / tape->blk_size;
if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
++cnt; /* Filemarks count as 1 sector */
tape->merge_stage_size = 0;
@@ -2990,22 +2122,22 @@
/* Clear pipeline flags. */
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
/* Remove pipeline stages. */
if (tape->first_stage == NULL)
return 0;
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
tape->next_stage = NULL;
if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
while (tape->first_stage != NULL) {
struct request *rq_ptr = &tape->first_stage->rq;
- cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
+ cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
++cnt;
idetape_remove_stage_head(drive);
@@ -3016,21 +2148,19 @@
}
/*
- * idetape_position_tape positions the tape to the requested block
- * using the LOCATE packet command. A READ POSITION command is then
- * issued to check where we are positioned.
- *
- * Like all higher level operations, we queue the commands at the tail
- * of the request queue and wait for their completion.
- *
+ * Position the tape to the requested block using the LOCATE packet command.
+ * A READ POSITION command is then issued to check where we are positioned. Like
+ * all higher level operations, we queue the commands at the tail of the request
+ * queue and wait for their completion.
*/
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
+static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
+ u8 partition, int skip)
{
idetape_tape_t *tape = drive->driver_data;
int retval;
idetape_pc_t pc;
- if (tape->chrdev_direction == idetape_direction_read)
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
__idetape_discard_read_pipeline(drive);
idetape_wait_ready(drive, 60 * 5 * HZ);
idetape_create_locate_cmd(drive, &pc, block, partition, skip);
@@ -3042,7 +2172,8 @@
return (idetape_queue_pc_tail(drive, &pc));
}
-static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
+static void idetape_discard_read_pipeline(ide_drive_t *drive,
+ int restore_position)
{
idetape_tape_t *tape = drive->driver_data;
int cnt;
@@ -3053,37 +2184,37 @@
position = idetape_read_position(drive);
seek = position > cnt ? position - cnt : 0;
if (idetape_position_tape(drive, seek, 0, 0)) {
- printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+ printk(KERN_INFO "ide-tape: %s: position_tape failed in"
+ " discard_pipeline()\n", tape->name);
return;
}
}
}
/*
- * idetape_queue_rw_tail generates a read/write request for the block
- * device interface and wait for it to be serviced.
+ * Generate a read/write request for the block device interface and wait for it
+ * to be serviced.
*/
-static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_bh *bh)
+static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
+ struct idetape_bh *bh)
{
idetape_tape_t *tape = drive->driver_data;
struct request rq;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
+ debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+
if (idetape_pipeline_active(tape)) {
- printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+ printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+ __func__);
return (0);
}
-#endif /* IDETAPE_DEBUG_BUGS */
idetape_init_rq(&rq, cmd);
rq.rq_disk = tape->disk;
rq.special = (void *)bh;
- rq.sector = tape->first_frame_position;
- rq.nr_sectors = rq.current_nr_sectors = blocks;
+ rq.sector = tape->first_frame;
+ rq.nr_sectors = blocks;
+ rq.current_nr_sectors = blocks;
(void) ide_do_drive_cmd(drive, &rq, ide_wait);
if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
@@ -3093,14 +2224,11 @@
idetape_init_merge_stage(tape);
if (rq.errors == IDETAPE_ERROR_GENERAL)
return -EIO;
- return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
+ return (tape->blk_size * (blocks-rq.current_nr_sectors));
}
-/*
- * idetape_insert_pipeline_into_queue is used to start servicing the
- * pipeline stages, starting from tape->next_stage.
- */
-static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+/* start servicing the pipeline stages, starting from tape->next_stage. */
+static void idetape_plug_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
@@ -3108,142 +2236,128 @@
return;
if (!idetape_pipeline_active(tape)) {
set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
- idetape_active_next_stage(drive);
- (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+ idetape_activate_next_stage(drive);
+ (void) ide_do_drive_cmd(drive, tape->active_data_rq, ide_end);
}
}
-static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
+static void idetape_create_inquiry_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_INQUIRY_CMD;
- pc->c[4] = pc->request_transfer = 254;
+ pc->c[0] = INQUIRY;
+ pc->c[4] = 254;
+ pc->request_transfer = 254;
pc->callback = &idetape_pc_callback;
}
-static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
+static void idetape_create_rewind_cmd(ide_drive_t *drive, idetape_pc_t *pc)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_REWIND_CMD;
+ pc->c[0] = REZERO_UNIT;
set_bit(PC_WAIT_FOR_DSC, &pc->flags);
pc->callback = &idetape_pc_callback;
}
-#if 0
-static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
+static void idetape_create_erase_cmd(idetape_pc_t *pc)
{
idetape_init_pc(pc);
- set_bit(PC_WRITING, &pc->flags);
- pc->c[0] = IDETAPE_MODE_SELECT_CMD;
- pc->c[1] = 0x10;
- put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
- pc->request_transfer = 255;
- pc->callback = &idetape_pc_callback;
-}
-#endif
-
-static void idetape_create_erase_cmd (idetape_pc_t *pc)
-{
- idetape_init_pc(pc);
- pc->c[0] = IDETAPE_ERASE_CMD;
+ pc->c[0] = ERASE;
pc->c[1] = 1;
set_bit(PC_WAIT_FOR_DSC, &pc->flags);
pc->callback = &idetape_pc_callback;
}
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd)
+static void idetape_create_space_cmd(idetape_pc_t *pc, int count, u8 cmd)
{
idetape_init_pc(pc);
- pc->c[0] = IDETAPE_SPACE_CMD;
- put_unaligned(htonl(count), (unsigned int *) &pc->c[1]);
+ pc->c[0] = SPACE;
+ put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
pc->c[1] = cmd;
set_bit(PC_WAIT_FOR_DSC, &pc->flags);
pc->callback = &idetape_pc_callback;
}
-static void idetape_wait_first_stage (ide_drive_t *drive)
+static void idetape_wait_first_stage(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
if (tape->first_stage == NULL)
return;
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
if (tape->active_stage == tape->first_stage)
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
}
/*
- * idetape_add_chrdev_write_request tries to add a character device
- * originated write request to our pipeline. In case we don't succeed,
- * we revert to non-pipelined operation mode for this request.
+ * Try to add a character device originated write request to our pipeline. In
+ * case we don't succeed, we revert to non-pipelined operation mode for this
+ * request. In order to accomplish that, we
*
- * 1. Try to allocate a new pipeline stage.
- * 2. If we can't, wait for more and more requests to be serviced
- * and try again each time.
- * 3. If we still can't allocate a stage, fallback to
- * non-pipelined operation mode for this request.
+ * 1. Try to allocate a new pipeline stage.
+ * 2. If we can't, wait for more and more requests to be serviced and try again
+ * each time.
+ * 3. If we still can't allocate a stage, fallback to non-pipelined operation
+ * mode for this request.
*/
-static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
+static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *new_stage;
unsigned long flags;
struct request *rq;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
- /*
- * Attempt to allocate a new stage.
- * Pay special attention to possible race conditions.
- */
+ /* Attempt to allocate a new stage. Beware possible race conditions. */
while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) {
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
if (idetape_pipeline_active(tape)) {
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
} else {
- spin_unlock_irqrestore(&tape->spinlock, flags);
- idetape_insert_pipeline_into_queue(drive);
+ spin_unlock_irqrestore(&tape->lock, flags);
+ idetape_plug_pipeline(drive);
if (idetape_pipeline_active(tape))
continue;
/*
- * Linux is short on memory. Fallback to
- * non-pipelined operation mode for this request.
+ * The machine is short on memory. Fallback to non-
+ * pipelined operation mode for this request.
*/
- return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
+ blocks, tape->merge_stage->bh);
}
}
rq = &new_stage->rq;
idetape_init_rq(rq, REQ_IDETAPE_WRITE);
/* Doesn't actually matter - We always assume sequential access */
- rq->sector = tape->first_frame_position;
- rq->nr_sectors = rq->current_nr_sectors = blocks;
+ rq->sector = tape->first_frame;
+ rq->current_nr_sectors = blocks;
+ rq->nr_sectors = blocks;
idetape_switch_buffers(tape, new_stage);
idetape_add_stage_tail(drive, new_stage);
tape->pipeline_head++;
- calculate_speeds(drive);
+ idetape_calculate_speeds(drive);
/*
- * Estimate whether the tape has stopped writing by checking
- * if our write pipeline is currently empty. If we are not
- * writing anymore, wait for the pipeline to be full enough
- * (90%) before starting to service requests, so that we will
- * be able to keep up with the higher speeds of the tape.
+ * Estimate whether the tape has stopped writing by checking if our
+ * write pipeline is currently empty. If we are not writing anymore,
+ * wait for the pipeline to be almost completely full (90%) before
+ * starting to service requests, so that we will be able to keep up with
+ * the higher speeds of the tape.
*/
if (!idetape_pipeline_active(tape)) {
if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
- tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) {
+ tape->nr_stages >= tape->max_stages -
+ tape->uncontrolled_pipeline_head_speed * 3 * 1024 /
+ tape->blk_size) {
tape->measure_insert_time = 1;
tape->insert_time = jiffies;
tape->insert_size = 0;
tape->insert_speed = 0;
- idetape_insert_pipeline_into_queue(drive);
+ idetape_plug_pipeline(drive);
}
}
if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
@@ -3253,46 +2367,46 @@
}
/*
- * idetape_wait_for_pipeline will wait until all pending pipeline
- * requests are serviced. Typically called on device close.
+ * Wait until all pending pipeline requests are serviced. Typically called on
+ * device close.
*/
-static void idetape_wait_for_pipeline (ide_drive_t *drive)
+static void idetape_wait_for_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
while (tape->next_stage || idetape_pipeline_active(tape)) {
- idetape_insert_pipeline_into_queue(drive);
- spin_lock_irqsave(&tape->spinlock, flags);
+ idetape_plug_pipeline(drive);
+ spin_lock_irqsave(&tape->lock, flags);
if (idetape_pipeline_active(tape))
- idetape_wait_for_request(drive, tape->active_data_request);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_for_request(drive, tape->active_data_rq);
+ spin_unlock_irqrestore(&tape->lock, flags);
}
}
-static void idetape_empty_write_pipeline (ide_drive_t *drive)
+static void idetape_empty_write_pipeline(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
int blocks, min;
struct idetape_bh *bh;
-
-#if IDETAPE_DEBUG_BUGS
- if (tape->chrdev_direction != idetape_direction_write) {
- printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+
+ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+ printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline,"
+ " but we are not writing.\n");
return;
}
if (tape->merge_stage_size > tape->stage_size) {
printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
tape->merge_stage_size = tape->stage_size;
}
-#endif /* IDETAPE_DEBUG_BUGS */
if (tape->merge_stage_size) {
- blocks = tape->merge_stage_size / tape->tape_block_size;
- if (tape->merge_stage_size % tape->tape_block_size) {
+ blocks = tape->merge_stage_size / tape->blk_size;
+ if (tape->merge_stage_size % tape->blk_size) {
unsigned int i;
blocks++;
- i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
+ i = tape->blk_size - tape->merge_stage_size %
+ tape->blk_size;
bh = tape->bh->b_reqnext;
while (bh) {
atomic_set(&bh->b_count, 0);
@@ -3301,12 +2415,14 @@
bh = tape->bh;
while (i) {
if (bh == NULL) {
-
- printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+ printk(KERN_INFO "ide-tape: bug,"
+ " bh NULL\n");
break;
}
- min = min(i, (unsigned int)(bh->b_size - atomic_read(&bh->b_count)));
- memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
+ min = min(i, (unsigned int)(bh->b_size -
+ atomic_read(&bh->b_count)));
+ memset(bh->b_data + atomic_read(&bh->b_count),
+ 0, min);
atomic_add(min, &bh->b_count);
i -= min;
bh = bh->b_reqnext;
@@ -3321,16 +2437,15 @@
tape->merge_stage = NULL;
}
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
/*
- * On the next backup, perform the feedback loop again.
- * (I don't want to keep sense information between backups,
- * as some systems are constantly on, and the system load
- * can be totally different on the next backup).
+ * On the next backup, perform the feedback loop again. (I don't want to
+ * keep sense information between backups, as some systems are
+ * constantly on, and the system load can be totally different on the
+ * next backup).
*/
tape->max_stages = tape->min_pipeline;
-#if IDETAPE_DEBUG_BUGS
if (tape->first_stage != NULL ||
tape->next_stage != NULL ||
tape->last_stage != NULL ||
@@ -3341,60 +2456,64 @@
tape->first_stage, tape->next_stage,
tape->last_stage, tape->nr_stages);
}
-#endif /* IDETAPE_DEBUG_BUGS */
}
-static void idetape_restart_speed_control (ide_drive_t *drive)
+static void idetape_restart_speed_control(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
tape->restart_speed_control_req = 0;
tape->pipeline_head = 0;
- tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0;
- tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0;
- tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000;
+ tape->controlled_last_pipeline_head = 0;
+ tape->controlled_previous_pipeline_head = 0;
+ tape->uncontrolled_previous_pipeline_head = 0;
+ tape->controlled_pipeline_head_speed = 5000;
+ tape->pipeline_head_speed = 5000;
tape->uncontrolled_pipeline_head_speed = 0;
- tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies;
- tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies;
+ tape->controlled_pipeline_head_time =
+ tape->uncontrolled_pipeline_head_time = jiffies;
+ tape->controlled_previous_head_time =
+ tape->uncontrolled_previous_head_time = jiffies;
}
-static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
+static int idetape_init_read(ide_drive_t *drive, int max_stages)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *new_stage;
struct request rq;
int bytes_read;
- int blocks = tape->capabilities.ctl;
+ u16 blocks = *(u16 *)&tape->caps[12];
/* Initialize read operation */
- if (tape->chrdev_direction != idetape_direction_read) {
- if (tape->chrdev_direction == idetape_direction_write) {
+ if (tape->chrdev_dir != IDETAPE_DIR_READ) {
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
idetape_empty_write_pipeline(drive);
idetape_flush_tape_buffers(drive);
}
-#if IDETAPE_DEBUG_BUGS
if (tape->merge_stage || tape->merge_stage_size) {
- printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+ printk(KERN_ERR "ide-tape: merge_stage_size should be"
+ " 0 now\n");
tape->merge_stage_size = 0;
}
-#endif /* IDETAPE_DEBUG_BUGS */
- if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+ tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
+ if (!tape->merge_stage)
return -ENOMEM;
- tape->chrdev_direction = idetape_direction_read;
+ tape->chrdev_dir = IDETAPE_DIR_READ;
/*
- * Issue a read 0 command to ensure that DSC handshake
- * is switched from completion mode to buffer available
- * mode.
- * No point in issuing this if DSC overlap isn't supported,
- * some drives (Seagate STT3401A) will return an error.
+ * Issue a read 0 command to ensure that DSC handshake is
+ * switched from completion mode to buffer available mode.
+ * No point in issuing this if DSC overlap isn't supported, some
+ * drives (Seagate STT3401A) will return an error.
*/
if (drive->dsc_overlap) {
- bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh);
+ bytes_read = idetape_queue_rw_tail(drive,
+ REQ_IDETAPE_READ, 0,
+ tape->merge_stage->bh);
if (bytes_read < 0) {
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
return bytes_read;
}
}
@@ -3402,8 +2521,9 @@
if (tape->restart_speed_control_req)
idetape_restart_speed_control(drive);
idetape_init_rq(&rq, REQ_IDETAPE_READ);
- rq.sector = tape->first_frame_position;
- rq.nr_sectors = rq.current_nr_sectors = blocks;
+ rq.sector = tape->first_frame;
+ rq.nr_sectors = blocks;
+ rq.current_nr_sectors = blocks;
if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
tape->nr_stages < max_stages) {
new_stage = idetape_kmalloc_stage(tape);
@@ -3421,50 +2541,43 @@
tape->insert_time = jiffies;
tape->insert_size = 0;
tape->insert_speed = 0;
- idetape_insert_pipeline_into_queue(drive);
+ idetape_plug_pipeline(drive);
}
}
return 0;
}
/*
- * idetape_add_chrdev_read_request is called from idetape_chrdev_read
- * to service a character device read request and add read-ahead
- * requests to our pipeline.
+ * Called from idetape_chrdev_read() to service a character device read request
+ * and add read-ahead requests to our pipeline.
*/
-static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
+static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
{
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
struct request *rq_ptr;
int bytes_read;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
- /*
- * If we are at a filemark, return a read length of 0
- */
+ /* If we are at a filemark, return a read length of 0 */
if (test_bit(IDETAPE_FILEMARK, &tape->flags))
return 0;
- /*
- * Wait for the next block to be available at the head
- * of the pipeline
- */
- idetape_initiate_read(drive, tape->max_stages);
+ /* Wait for the next block to reach the head of the pipeline. */
+ idetape_init_read(drive, tape->max_stages);
if (tape->first_stage == NULL) {
if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
return 0;
- return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh);
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
+ tape->merge_stage->bh);
}
idetape_wait_first_stage(drive);
rq_ptr = &tape->first_stage->rq;
- bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
- rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
-
+ bytes_read = tape->blk_size * (rq_ptr->nr_sectors -
+ rq_ptr->current_nr_sectors);
+ rq_ptr->nr_sectors = 0;
+ rq_ptr->current_nr_sectors = 0;
if (rq_ptr->errors == IDETAPE_ERROR_EOD)
return 0;
@@ -3472,45 +2585,46 @@
idetape_switch_buffers(tape, tape->first_stage);
if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
set_bit(IDETAPE_FILEMARK, &tape->flags);
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
idetape_remove_stage_head(drive);
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
tape->pipeline_head++;
- calculate_speeds(drive);
+ idetape_calculate_speeds(drive);
}
-#if IDETAPE_DEBUG_BUGS
- if (bytes_read > blocks * tape->tape_block_size) {
- printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
- bytes_read = blocks * tape->tape_block_size;
+ if (bytes_read > blocks * tape->blk_size) {
+ printk(KERN_ERR "ide-tape: bug: trying to return more bytes"
+ " than requested\n");
+ bytes_read = blocks * tape->blk_size;
}
-#endif /* IDETAPE_DEBUG_BUGS */
return (bytes_read);
}
-static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
+static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
{
idetape_tape_t *tape = drive->driver_data;
struct idetape_bh *bh;
int blocks;
-
+
while (bcount) {
unsigned int count;
bh = tape->merge_stage->bh;
count = min(tape->stage_size, bcount);
bcount -= count;
- blocks = count / tape->tape_block_size;
+ blocks = count / tape->blk_size;
while (count) {
- atomic_set(&bh->b_count, min(count, (unsigned int)bh->b_size));
+ atomic_set(&bh->b_count,
+ min(count, (unsigned int)bh->b_size));
memset(bh->b_data, 0, atomic_read(&bh->b_count));
count -= atomic_read(&bh->b_count);
bh = bh->b_reqnext;
}
- idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+ idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks,
+ tape->merge_stage->bh);
}
}
-static int idetape_pipeline_size (ide_drive_t *drive)
+static int idetape_pipeline_size(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_stage_t *stage;
@@ -3521,9 +2635,10 @@
stage = tape->first_stage;
while (stage != NULL) {
rq = &stage->rq;
- size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors);
+ size += tape->blk_size * (rq->nr_sectors -
+ rq->current_nr_sectors);
if (rq->errors == IDETAPE_ERROR_FILEMARK)
- size += tape->tape_block_size;
+ size += tape->blk_size;
stage = stage->next;
}
size += tape->merge_stage_size;
@@ -3531,20 +2646,18 @@
}
/*
- * Rewinds the tape to the Beginning Of the current Partition (BOP).
- *
- * We currently support only one partition.
- */
-static int idetape_rewind_tape (ide_drive_t *drive)
+ * Rewinds the tape to the Beginning Of the current Partition (BOP). We
+ * currently support only one partition.
+ */
+static int idetape_rewind_tape(ide_drive_t *drive)
{
int retval;
idetape_pc_t pc;
-#if IDETAPE_DEBUG_LOG
- idetape_tape_t *tape = drive->driver_data;
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
+ idetape_tape_t *tape;
+ tape = drive->driver_data;
+
+ debug_log(DBG_SENSE, "Enter %s\n", __func__);
+
idetape_create_rewind_cmd(drive, &pc);
retval = idetape_queue_pc_tail(drive, &pc);
if (retval)
@@ -3557,71 +2670,66 @@
return 0;
}
-/*
- * Our special ide-tape ioctl's.
- *
- * Currently there aren't any ioctl's.
- * mtio.h compatible commands should be issued to the character device
- * interface.
- */
-static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+/* mtio.h compatible commands should be issued to the chrdev interface. */
+static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
+ unsigned long arg)
{
idetape_tape_t *tape = drive->driver_data;
- idetape_config_t config;
void __user *argp = (void __user *)arg;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 4)
- printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
-#endif /* IDETAPE_DEBUG_LOG */
+ struct idetape_config {
+ int dsc_rw_frequency;
+ int dsc_media_access_frequency;
+ int nr_stages;
+ } config;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
switch (cmd) {
- case 0x0340:
- if (copy_from_user(&config, argp, sizeof (idetape_config_t)))
- return -EFAULT;
- tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
- tape->max_stages = config.nr_stages;
- break;
- case 0x0350:
- config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
- config.nr_stages = tape->max_stages;
- if (copy_to_user(argp, &config, sizeof (idetape_config_t)))
- return -EFAULT;
- break;
- default:
- return -EIO;
+ case 0x0340:
+ if (copy_from_user(&config, argp, sizeof(config)))
+ return -EFAULT;
+ tape->best_dsc_rw_freq = config.dsc_rw_frequency;
+ tape->max_stages = config.nr_stages;
+ break;
+ case 0x0350:
+ config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
+ config.nr_stages = tape->max_stages;
+ if (copy_to_user(argp, &config, sizeof(config)))
+ return -EFAULT;
+ break;
+ default:
+ return -EIO;
}
return 0;
}
/*
- * idetape_space_over_filemarks is now a bit more complicated than just
- * passing the command to the tape since we may have crossed some
- * filemarks during our pipelined read-ahead mode.
- *
- * As a minor side effect, the pipeline enables us to support MTFSFM when
- * the filemark is in our internal pipeline even if the tape doesn't
- * support spacing over filemarks in the reverse direction.
+ * The function below is now a bit more complicated than just passing the
+ * command to the tape since we may have crossed some filemarks during our
+ * pipelined read-ahead mode. As a minor side effect, the pipeline enables us to
+ * support MTFSFM when the filemark is in our internal pipeline even if the tape
+ * doesn't support spacing over filemarks in the reverse direction.
*/
-static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
+ int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
unsigned long flags;
- int retval,count=0;
+ int retval, count = 0;
+ int sprev = !!(tape->caps[4] & 0x20);
if (mt_count == 0)
return 0;
if (MTBSF == mt_op || MTBSFM == mt_op) {
- if (!tape->capabilities.sprev)
+ if (!sprev)
return -EIO;
- mt_count = - mt_count;
+ mt_count = -mt_count;
}
- if (tape->chrdev_direction == idetape_direction_read) {
- /*
- * We have a read-ahead buffer. Scan it for crossed
- * filemarks.
- */
+ if (tape->chrdev_dir == IDETAPE_DIR_READ) {
+ /* its a read-ahead buffer, scan it for crossed filemarks. */
tape->merge_stage_size = 0;
if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
++count;
@@ -3631,24 +2739,27 @@
set_bit(IDETAPE_FILEMARK, &tape->flags);
return 0;
}
- spin_lock_irqsave(&tape->spinlock, flags);
+ spin_lock_irqsave(&tape->lock, flags);
if (tape->first_stage == tape->active_stage) {
/*
- * We have reached the active stage in the read pipeline.
- * There is no point in allowing the drive to continue
- * reading any farther, so we stop the pipeline.
+ * We have reached the active stage in the read
+ * pipeline. There is no point in allowing the
+ * drive to continue reading any farther, so we
+ * stop the pipeline.
*
- * This section should be moved to a separate subroutine,
- * because a similar function is performed in
- * __idetape_discard_read_pipeline(), for example.
+ * This section should be moved to a separate
+ * subroutine because similar operations are
+ * done in __idetape_discard_read_pipeline(),
+ * for example.
*/
tape->next_stage = NULL;
- spin_unlock_irqrestore(&tape->spinlock, flags);
+ spin_unlock_irqrestore(&tape->lock, flags);
idetape_wait_first_stage(drive);
tape->next_stage = tape->first_stage->next;
} else
- spin_unlock_irqrestore(&tape->spinlock, flags);
- if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+ spin_unlock_irqrestore(&tape->lock, flags);
+ if (tape->first_stage->rq.errors ==
+ IDETAPE_ERROR_FILEMARK)
++count;
idetape_remove_stage_head(drive);
}
@@ -3656,157 +2767,156 @@
}
/*
- * The filemark was not found in our internal pipeline.
- * Now we can issue the space command.
+ * The filemark was not found in our internal pipeline; now we can issue
+ * the space command.
*/
switch (mt_op) {
- case MTFSF:
- case MTBSF:
- idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTFSFM:
- case MTBSFM:
- if (!tape->capabilities.sprev)
- return (-EIO);
- retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
- if (retval) return (retval);
- count = (MTBSFM == mt_op ? 1 : -1);
- return (idetape_space_over_filemarks(drive, MTFSF, count));
- default:
- printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
- return (-EIO);
+ case MTFSF:
+ case MTBSF:
+ idetape_create_space_cmd(&pc, mt_count - count,
+ IDETAPE_SPACE_OVER_FILEMARK);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTFSFM:
+ case MTBSFM:
+ if (!sprev)
+ return -EIO;
+ retval = idetape_space_over_filemarks(drive, MTFSF,
+ mt_count - count);
+ if (retval)
+ return retval;
+ count = (MTBSFM == mt_op ? 1 : -1);
+ return idetape_space_over_filemarks(drive, MTFSF, count);
+ default:
+ printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+ mt_op);
+ return -EIO;
}
}
-
/*
- * Our character device read / write functions.
+ * Our character device read / write functions.
*
- * The tape is optimized to maximize throughput when it is transferring
- * an integral number of the "continuous transfer limit", which is
- * a parameter of the specific tape (26 KB on my particular tape).
- * (32 kB for Onstream)
+ * The tape is optimized to maximize throughput when it is transferring an
+ * integral number of the "continuous transfer limit", which is a parameter of
+ * the specific tape (26kB on my particular tape, 32kB for Onstream).
*
- * As of version 1.3 of the driver, the character device provides an
- * abstract continuous view of the media - any mix of block sizes (even 1
- * byte) on the same backup/restore procedure is supported. The driver
- * will internally convert the requests to the recommended transfer unit,
- * so that an unmatch between the user's block size to the recommended
- * size will only result in a (slightly) increased driver overhead, but
- * will no longer hit performance.
- * This is not applicable to Onstream.
+ * As of version 1.3 of the driver, the character device provides an abstract
+ * continuous view of the media - any mix of block sizes (even 1 byte) on the
+ * same backup/restore procedure is supported. The driver will internally
+ * convert the requests to the recommended transfer unit, so that an unmatch
+ * between the user's block size to the recommended size will only result in a
+ * (slightly) increased driver overhead, but will no longer hit performance.
+ * This is not applicable to Onstream.
*/
-static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
- ssize_t bytes_read,temp, actually_read = 0, rc;
+ ssize_t bytes_read, temp, actually_read = 0, rc;
ssize_t ret = 0;
+ u16 ctl = *(u16 *)&tape->caps[12];
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
- if (tape->chrdev_direction != idetape_direction_read) {
+ if (tape->chrdev_dir != IDETAPE_DIR_READ) {
if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
- if (count > tape->tape_block_size &&
- (count % tape->tape_block_size) == 0)
- tape->user_bs_factor = count / tape->tape_block_size;
+ if (count > tape->blk_size &&
+ (count % tape->blk_size) == 0)
+ tape->user_bs_factor = count / tape->blk_size;
}
- if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
+ rc = idetape_init_read(drive, tape->max_stages);
+ if (rc < 0)
return rc;
if (count == 0)
return (0);
if (tape->merge_stage_size) {
- actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+ actually_read = min((unsigned int)(tape->merge_stage_size),
+ (unsigned int)count);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+ actually_read))
ret = -EFAULT;
buf += actually_read;
tape->merge_stage_size -= actually_read;
count -= actually_read;
}
while (count >= tape->stage_size) {
- bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
+ bytes_read = idetape_add_chrdev_read_request(drive, ctl);
if (bytes_read <= 0)
goto finish;
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+ bytes_read))
ret = -EFAULT;
buf += bytes_read;
count -= bytes_read;
actually_read += bytes_read;
}
if (count) {
- bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
+ bytes_read = idetape_add_chrdev_read_request(drive, ctl);
if (bytes_read <= 0)
goto finish;
temp = min((unsigned long)count, (unsigned long)bytes_read);
- if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+ temp))
ret = -EFAULT;
actually_read += temp;
tape->merge_stage_size = bytes_read-temp;
}
finish:
if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 2)
- printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
-#endif
+ debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
+
idetape_space_over_filemarks(drive, MTFSF, 1);
return 0;
}
- return (ret) ? ret : actually_read;
+ return ret ? ret : actually_read;
}
-static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
+static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
ssize_t actually_written = 0;
ssize_t ret = 0;
+ u16 ctl = *(u16 *)&tape->caps[12];
/* The drive is write protected. */
if (tape->write_prot)
return -EACCES;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
- "count %Zd\n", count);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
/* Initialize write operation */
- if (tape->chrdev_direction != idetape_direction_write) {
- if (tape->chrdev_direction == idetape_direction_read)
+ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
idetape_discard_read_pipeline(drive, 1);
-#if IDETAPE_DEBUG_BUGS
if (tape->merge_stage || tape->merge_stage_size) {
printk(KERN_ERR "ide-tape: merge_stage_size "
"should be 0 now\n");
tape->merge_stage_size = 0;
}
-#endif /* IDETAPE_DEBUG_BUGS */
- if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+ tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
+ if (!tape->merge_stage)
return -ENOMEM;
- tape->chrdev_direction = idetape_direction_write;
+ tape->chrdev_dir = IDETAPE_DIR_WRITE;
idetape_init_merge_stage(tape);
/*
- * Issue a write 0 command to ensure that DSC handshake
- * is switched from completion mode to buffer available
- * mode.
- * No point in issuing this if DSC overlap isn't supported,
- * some drives (Seagate STT3401A) will return an error.
+ * Issue a write 0 command to ensure that DSC handshake is
+ * switched from completion mode to buffer available mode. No
+ * point in issuing this if DSC overlap isn't supported, some
+ * drives (Seagate STT3401A) will return an error.
*/
if (drive->dsc_overlap) {
- ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+ ssize_t retval = idetape_queue_rw_tail(drive,
+ REQ_IDETAPE_WRITE, 0,
+ tape->merge_stage->bh);
if (retval < 0) {
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
return retval;
}
}
@@ -3816,14 +2926,15 @@
if (tape->restart_speed_control_req)
idetape_restart_speed_control(drive);
if (tape->merge_stage_size) {
-#if IDETAPE_DEBUG_BUGS
if (tape->merge_stage_size >= tape->stage_size) {
- printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
+ printk(KERN_ERR "ide-tape: bug: merge buf too big\n");
tape->merge_stage_size = 0;
}
-#endif /* IDETAPE_DEBUG_BUGS */
- actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+ actually_written = min((unsigned int)
+ (tape->stage_size - tape->merge_stage_size),
+ (unsigned int)count);
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+ actually_written))
ret = -EFAULT;
buf += actually_written;
tape->merge_stage_size += actually_written;
@@ -3832,32 +2943,34 @@
if (tape->merge_stage_size == tape->stage_size) {
ssize_t retval;
tape->merge_stage_size = 0;
- retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
+ retval = idetape_add_chrdev_write_request(drive, ctl);
if (retval <= 0)
return (retval);
}
}
while (count >= tape->stage_size) {
ssize_t retval;
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+ tape->stage_size))
ret = -EFAULT;
buf += tape->stage_size;
count -= tape->stage_size;
- retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
+ retval = idetape_add_chrdev_write_request(drive, ctl);
actually_written += tape->stage_size;
if (retval <= 0)
return (retval);
}
if (count) {
actually_written += count;
- if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+ count))
ret = -EFAULT;
tape->merge_stage_size += count;
}
- return (ret) ? ret : actually_written;
+ return ret ? ret : actually_written;
}
-static int idetape_write_filemark (ide_drive_t *drive)
+static int idetape_write_filemark(ide_drive_t *drive)
{
idetape_pc_t pc;
@@ -3871,265 +2984,224 @@
}
/*
- * idetape_mtioctop is called from idetape_chrdev_ioctl when
- * the general mtio MTIOCTOP ioctl is requested.
+ * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is
+ * requested.
*
- * We currently support the following mtio.h operations:
+ * Note: MTBSF and MTBSFM are not supported when the tape doesn't support
+ * spacing over filemarks in the reverse direction. In this case, MTFSFM is also
+ * usually not supported (it is supported in the rare case in which we crossed
+ * the filemark during our read-ahead pipelined operation mode).
*
- * MTFSF - Space over mt_count filemarks in the positive direction.
- * The tape is positioned after the last spaced filemark.
+ * The following commands are currently not supported:
*
- * MTFSFM - Same as MTFSF, but the tape is positioned before the
- * last filemark.
- *
- * MTBSF - Steps background over mt_count filemarks, tape is
- * positioned before the last filemark.
- *
- * MTBSFM - Like MTBSF, only tape is positioned after the last filemark.
- *
- * Note:
- *
- * MTBSF and MTBSFM are not supported when the tape doesn't
- * support spacing over filemarks in the reverse direction.
- * In this case, MTFSFM is also usually not supported (it is
- * supported in the rare case in which we crossed the filemark
- * during our read-ahead pipelined operation mode).
- *
- * MTWEOF - Writes mt_count filemarks. Tape is positioned after
- * the last written filemark.
- *
- * MTREW - Rewinds tape.
- *
- * MTLOAD - Loads the tape.
- *
- * MTOFFL - Puts the tape drive "Offline": Rewinds the tape and
- * MTUNLOAD prevents further access until the media is replaced.
- *
- * MTNOP - Flushes tape buffers.
- *
- * MTRETEN - Retension media. This typically consists of one end
- * to end pass on the media.
- *
- * MTEOM - Moves to the end of recorded data.
- *
- * MTERASE - Erases tape.
- *
- * MTSETBLK - Sets the user block size to mt_count bytes. If
- * mt_count is 0, we will attempt to autodetect
- * the block size.
- *
- * MTSEEK - Positions the tape in a specific block number, where
- * each block is assumed to contain which user_block_size
- * bytes.
- *
- * MTSETPART - Switches to another tape partition.
- *
- * MTLOCK - Locks the tape door.
- *
- * MTUNLOCK - Unlocks the tape door.
- *
- * The following commands are currently not supported:
- *
- * MTFSS, MTBSS, MTWSM, MTSETDENSITY,
- * MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD.
+ * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS,
+ * MT_ST_WRITE_THRESHOLD.
*/
-static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
- int i,retval;
+ int i, retval;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: "
- "mt_op=%d, mt_count=%d\n", mt_op, mt_count);
-#endif /* IDETAPE_DEBUG_LOG */
- /*
- * Commands which need our pipelined read-ahead stages.
- */
+ debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",
+ mt_op, mt_count);
+
+ /* Commands which need our pipelined read-ahead stages. */
switch (mt_op) {
- case MTFSF:
- case MTFSFM:
- case MTBSF:
- case MTBSFM:
- if (!mt_count)
- return (0);
- return (idetape_space_over_filemarks(drive,mt_op,mt_count));
- default:
- break;
+ case MTFSF:
+ case MTFSFM:
+ case MTBSF:
+ case MTBSFM:
+ if (!mt_count)
+ return 0;
+ return idetape_space_over_filemarks(drive, mt_op, mt_count);
+ default:
+ break;
}
+
switch (mt_op) {
- case MTWEOF:
- if (tape->write_prot)
- return -EACCES;
- idetape_discard_read_pipeline(drive, 1);
- for (i = 0; i < mt_count; i++) {
- retval = idetape_write_filemark(drive);
- if (retval)
- return retval;
- }
- return (0);
- case MTREW:
- idetape_discard_read_pipeline(drive, 0);
- if (idetape_rewind_tape(drive))
+ case MTWEOF:
+ if (tape->write_prot)
+ return -EACCES;
+ idetape_discard_read_pipeline(drive, 1);
+ for (i = 0; i < mt_count; i++) {
+ retval = idetape_write_filemark(drive);
+ if (retval)
+ return retval;
+ }
+ return 0;
+ case MTREW:
+ idetape_discard_read_pipeline(drive, 0);
+ if (idetape_rewind_tape(drive))
+ return -EIO;
+ return 0;
+ case MTLOAD:
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,
+ IDETAPE_LU_LOAD_MASK);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTUNLOAD:
+ case MTOFFL:
+ /*
+ * If door is locked, attempt to unlock before
+ * attempting to eject.
+ */
+ if (tape->door_locked) {
+ if (idetape_create_prevent_cmd(drive, &pc, 0))
+ if (!idetape_queue_pc_tail(drive, &pc))
+ tape->door_locked = DOOR_UNLOCKED;
+ }
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,
+ !IDETAPE_LU_LOAD_MASK);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (!retval)
+ clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+ return retval;
+ case MTNOP:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_flush_tape_buffers(drive);
+ case MTRETEN:
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,
+ IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTEOM:
+ idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTERASE:
+ (void)idetape_rewind_tape(drive);
+ idetape_create_erase_cmd(&pc);
+ return idetape_queue_pc_tail(drive, &pc);
+ case MTSETBLK:
+ if (mt_count) {
+ if (mt_count < tape->blk_size ||
+ mt_count % tape->blk_size)
return -EIO;
+ tape->user_bs_factor = mt_count / tape->blk_size;
+ clear_bit(IDETAPE_DETECT_BS, &tape->flags);
+ } else
+ set_bit(IDETAPE_DETECT_BS, &tape->flags);
+ return 0;
+ case MTSEEK:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_position_tape(drive,
+ mt_count * tape->user_bs_factor, tape->partition, 0);
+ case MTSETPART:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_position_tape(drive, 0, mt_count, 0);
+ case MTFSR:
+ case MTBSR:
+ case MTLOCK:
+ if (!idetape_create_prevent_cmd(drive, &pc, 1))
return 0;
- case MTLOAD:
- idetape_discard_read_pipeline(drive, 0);
- idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTUNLOAD:
- case MTOFFL:
- /*
- * If door is locked, attempt to unlock before
- * attempting to eject.
- */
- if (tape->door_locked) {
- if (idetape_create_prevent_cmd(drive, &pc, 0))
- if (!idetape_queue_pc_tail(drive, &pc))
- tape->door_locked = DOOR_UNLOCKED;
- }
- idetape_discard_read_pipeline(drive, 0);
- idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
- retval = idetape_queue_pc_tail(drive, &pc);
- if (!retval)
- clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
return retval;
- case MTNOP:
- idetape_discard_read_pipeline(drive, 0);
- return (idetape_flush_tape_buffers(drive));
- case MTRETEN:
- idetape_discard_read_pipeline(drive, 0);
- idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTEOM:
- idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTERASE:
- (void) idetape_rewind_tape(drive);
- idetape_create_erase_cmd(&pc);
- return (idetape_queue_pc_tail(drive, &pc));
- case MTSETBLK:
- if (mt_count) {
- if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
- return -EIO;
- tape->user_bs_factor = mt_count / tape->tape_block_size;
- clear_bit(IDETAPE_DETECT_BS, &tape->flags);
- } else
- set_bit(IDETAPE_DETECT_BS, &tape->flags);
+ tape->door_locked = DOOR_EXPLICITLY_LOCKED;
+ return 0;
+ case MTUNLOCK:
+ if (!idetape_create_prevent_cmd(drive, &pc, 0))
return 0;
- case MTSEEK:
- idetape_discard_read_pipeline(drive, 0);
- return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
- case MTSETPART:
- idetape_discard_read_pipeline(drive, 0);
- return (idetape_position_tape(drive, 0, mt_count, 0));
- case MTFSR:
- case MTBSR:
- case MTLOCK:
- if (!idetape_create_prevent_cmd(drive, &pc, 1))
- return 0;
- retval = idetape_queue_pc_tail(drive, &pc);
- if (retval) return retval;
- tape->door_locked = DOOR_EXPLICITLY_LOCKED;
- return 0;
- case MTUNLOCK:
- if (!idetape_create_prevent_cmd(drive, &pc, 0))
- return 0;
- retval = idetape_queue_pc_tail(drive, &pc);
- if (retval) return retval;
- tape->door_locked = DOOR_UNLOCKED;
- return 0;
- default:
- printk(KERN_ERR "ide-tape: MTIO operation %d not "
- "supported\n", mt_op);
- return (-EIO);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
+ return retval;
+ tape->door_locked = DOOR_UNLOCKED;
+ return 0;
+ default:
+ printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+ mt_op);
+ return -EIO;
}
}
/*
- * Our character device ioctls.
- *
- * General mtio.h magnetic io commands are supported here, and not in
- * the corresponding block interface.
- *
- * The following ioctls are supported:
- *
- * MTIOCTOP - Refer to idetape_mtioctop for detailed description.
- *
- * MTIOCGET - The mt_dsreg field in the returned mtget structure
- * will be set to (user block size in bytes <<
- * MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK.
- *
- * The mt_blkno is set to the current user block number.
- * The other mtget fields are not supported.
- *
- * MTIOCPOS - The current tape "block position" is returned. We
- * assume that each block contains user_block_size
- * bytes.
- *
- * Our own ide-tape ioctls are supported on both interfaces.
+ * Our character device ioctls. General mtio.h magnetic io commands are
+ * supported here, and not in the corresponding block interface. Our own
+ * ide-tape ioctls are supported on both interfaces.
*/
-static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
struct mtop mtop;
struct mtget mtget;
struct mtpos mtpos;
- int block_offset = 0, position = tape->first_frame_position;
+ int block_offset = 0, position = tape->first_frame;
void __user *argp = (void __user *)arg;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, "
- "cmd=%u\n", cmd);
-#endif /* IDETAPE_DEBUG_LOG */
+ debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd);
tape->restart_speed_control_req = 1;
- if (tape->chrdev_direction == idetape_direction_write) {
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
idetape_empty_write_pipeline(drive);
idetape_flush_tape_buffers(drive);
}
if (cmd == MTIOCGET || cmd == MTIOCPOS) {
- block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
- if ((position = idetape_read_position(drive)) < 0)
+ block_offset = idetape_pipeline_size(drive) /
+ (tape->blk_size * tape->user_bs_factor);
+ position = idetape_read_position(drive);
+ if (position < 0)
return -EIO;
}
switch (cmd) {
- case MTIOCTOP:
- if (copy_from_user(&mtop, argp, sizeof (struct mtop)))
- return -EFAULT;
- return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
- case MTIOCGET:
- memset(&mtget, 0, sizeof (struct mtget));
- mtget.mt_type = MT_ISSCSI2;
- mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
- mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
- if (tape->drv_write_prot) {
- mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
- }
- if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
- return -EFAULT;
- return 0;
- case MTIOCPOS:
- mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
- if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
- return -EFAULT;
- return 0;
- default:
- if (tape->chrdev_direction == idetape_direction_read)
- idetape_discard_read_pipeline(drive, 1);
- return idetape_blkdev_ioctl(drive, cmd, arg);
+ case MTIOCTOP:
+ if (copy_from_user(&mtop, argp, sizeof(struct mtop)))
+ return -EFAULT;
+ return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count);
+ case MTIOCGET:
+ memset(&mtget, 0, sizeof(struct mtget));
+ mtget.mt_type = MT_ISSCSI2;
+ mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
+ mtget.mt_dsreg =
+ ((tape->blk_size * tape->user_bs_factor)
+ << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
+
+ if (tape->drv_write_prot)
+ mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
+
+ if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
+ return -EFAULT;
+ return 0;
+ case MTIOCPOS:
+ mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
+ if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
+ return -EFAULT;
+ return 0;
+ default:
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
+ idetape_discard_read_pipeline(drive, 1);
+ return idetape_blkdev_ioctl(drive, cmd, arg);
}
}
-static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive);
-
/*
- * Our character device open function.
+ * Do a mode sense page 0 with block descriptor and if it succeeds set the tape
+ * block size with the reported value.
*/
-static int idetape_chrdev_open (struct inode *inode, struct file *filp)
+static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t pc;
+
+ idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+ if (idetape_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
+ if (tape->blk_size == 0) {
+ printk(KERN_WARNING "ide-tape: Cannot deal with zero "
+ "block size, assuming 32k\n");
+ tape->blk_size = 32768;
+ }
+ return;
+ }
+ tape->blk_size = (pc.buffer[4 + 5] << 16) +
+ (pc.buffer[4 + 6] << 8) +
+ pc.buffer[4 + 7];
+ tape->drv_write_prot = (pc.buffer[2] & 0x80) >> 7;
+}
+
+static int idetape_chrdev_open(struct inode *inode, struct file *filp)
{
unsigned int minor = iminor(inode), i = minor & ~0xc0;
ide_drive_t *drive;
@@ -4137,6 +3209,15 @@
idetape_pc_t pc;
int retval;
+ if (i >= MAX_HWIFS * MAX_DRIVES)
+ return -ENXIO;
+
+ tape = ide_tape_chrdev_get(i);
+ if (!tape)
+ return -ENXIO;
+
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
/*
* We really want to do nonseekable_open(inode, filp); here, but some
* versions of tar incorrectly call lseek on tapes and bail out if that
@@ -4144,16 +3225,6 @@
*/
filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-#if IDETAPE_DEBUG_LOG
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
- if (i >= MAX_HWIFS * MAX_DRIVES)
- return -ENXIO;
-
- if (!(tape = ide_tape_chrdev_get(i)))
- return -ENXIO;
-
drive = tape->drive;
filp->private_data = tape;
@@ -4174,11 +3245,11 @@
if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
(void)idetape_rewind_tape(drive);
- if (tape->chrdev_direction != idetape_direction_read)
+ if (tape->chrdev_dir != IDETAPE_DIR_READ)
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
/* Read block size and write protect status from drive. */
- idetape_get_blocksize_from_block_descriptor(drive);
+ ide_tape_get_bsize_from_bdesc(drive);
/* Set write protect flag if device is opened as read-only. */
if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
@@ -4196,10 +3267,8 @@
}
}
- /*
- * Lock the tape drive door so user can't eject.
- */
- if (tape->chrdev_direction == idetape_direction_none) {
+ /* Lock the tape drive door so user can't eject. */
+ if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
if (idetape_create_prevent_cmd(drive, &pc, 1)) {
if (!idetape_queue_pc_tail(drive, &pc)) {
if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
@@ -4216,14 +3285,15 @@
return retval;
}
-static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
+static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
{
idetape_tape_t *tape = drive->driver_data;
idetape_empty_write_pipeline(drive);
tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
if (tape->merge_stage != NULL) {
- idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+ idetape_pad_zeros(drive, tape->blk_size *
+ (tape->user_bs_factor - 1));
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
}
@@ -4232,10 +3302,7 @@
idetape_flush_tape_buffers(drive);
}
-/*
- * Our character device release function.
- */
-static int idetape_chrdev_release (struct inode *inode, struct file *filp)
+static int idetape_chrdev_release(struct inode *inode, struct file *filp)
{
struct ide_tape_obj *tape = ide_tape_f(filp);
ide_drive_t *drive = tape->drive;
@@ -4244,14 +3311,12 @@
lock_kernel();
tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
- if (tape->debug_level >= 3)
- printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
-#endif /* IDETAPE_DEBUG_LOG */
- if (tape->chrdev_direction == idetape_direction_write)
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
idetape_write_release(drive, minor);
- if (tape->chrdev_direction == idetape_direction_read) {
+ if (tape->chrdev_dir == IDETAPE_DIR_READ) {
if (minor < 128)
idetape_discard_read_pipeline(drive, 1);
else
@@ -4263,7 +3328,7 @@
}
if (minor < 128 && test_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags))
(void) idetape_rewind_tape(drive);
- if (tape->chrdev_direction == idetape_direction_none) {
+ if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
if (tape->door_locked == DOOR_LOCKED) {
if (idetape_create_prevent_cmd(drive, &pc, 0)) {
if (!idetape_queue_pc_tail(drive, &pc))
@@ -4278,258 +3343,182 @@
}
/*
- * idetape_identify_device is called to check the contents of the
- * ATAPI IDENTIFY command results. We return:
+ * check the contents of the ATAPI IDENTIFY command results. We return:
*
- * 1 If the tape can be supported by us, based on the information
- * we have so far.
+ * 1 - If the tape can be supported by us, based on the information we have so
+ * far.
*
- * 0 If this tape driver is not currently supported by us.
+ * 0 - If this tape driver is not currently supported by us.
*/
-static int idetape_identify_device (ide_drive_t *drive)
+static int idetape_identify_device(ide_drive_t *drive)
{
- struct idetape_id_gcw gcw;
- struct hd_driveid *id = drive->id;
+ u8 gcw[2], protocol, device_type, removable, packet_size;
if (drive->id_read == 0)
return 1;
- *((unsigned short *) &gcw) = id->config;
+ *((unsigned short *) &gcw) = drive->id->config;
-#if IDETAPE_DEBUG_INFO
- printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
- printk(KERN_INFO "ide-tape: Protocol Type: ");
- switch (gcw.protocol) {
- case 0: case 1: printk("ATA\n");break;
- case 2: printk("ATAPI\n");break;
- case 3: printk("Reserved (Unknown to ide-tape)\n");break;
- }
- printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);
- switch (gcw.device_type) {
- case 0: printk("Direct-access Device\n");break;
- case 1: printk("Streaming Tape Device\n");break;
- case 2: case 3: case 4: printk("Reserved\n");break;
- case 5: printk("CD-ROM Device\n");break;
- case 6: printk("Reserved\n");
- case 7: printk("Optical memory Device\n");break;
- case 0x1f: printk("Unknown or no Device type\n");break;
- default: printk("Reserved\n");
- }
- printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");
- printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
- switch (gcw.drq_type) {
- case 0: printk("Microprocessor DRQ\n");break;
- case 1: printk("Interrupt DRQ\n");break;
- case 2: printk("Accelerated DRQ\n");break;
- case 3: printk("Reserved\n");break;
- }
- printk(KERN_INFO "ide-tape: Command Packet Size: ");
- switch (gcw.packet_size) {
- case 0: printk("12 bytes\n");break;
- case 1: printk("16 bytes\n");break;
- default: printk("Reserved\n");break;
- }
-#endif /* IDETAPE_DEBUG_INFO */
+ protocol = (gcw[1] & 0xC0) >> 6;
+ device_type = gcw[1] & 0x1F;
+ removable = !!(gcw[0] & 0x80);
+ packet_size = gcw[0] & 0x3;
/* Check that we can support this device */
-
- if (gcw.protocol !=2 )
- printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
- else if (gcw.device_type != 1)
- printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
- else if (!gcw.removable)
+ if (protocol != 2)
+ printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n",
+ protocol);
+ else if (device_type != 1)
+ printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set "
+ "to tape\n", device_type);
+ else if (!removable)
printk(KERN_ERR "ide-tape: The removable flag is not set\n");
- else if (gcw.packet_size != 0) {
- printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
- if (gcw.packet_size == 1)
- printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+ else if (packet_size != 0) {
+ printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12"
+ " bytes\n", packet_size);
} else
return 1;
return 0;
}
-/*
- * Use INQUIRY to get the firmware revision
- */
-static void idetape_get_inquiry_results (ide_drive_t *drive)
+static void idetape_get_inquiry_results(ide_drive_t *drive)
{
- char *r;
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
- idetape_inquiry_result_t *inquiry;
-
+ char fw_rev[6], vendor_id[10], product_id[18];
+
idetape_create_inquiry_cmd(&pc);
if (idetape_queue_pc_tail(drive, &pc)) {
- printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+ printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
+ tape->name);
return;
}
- inquiry = (idetape_inquiry_result_t *) pc.buffer;
- memcpy(tape->vendor_id, inquiry->vendor_id, 8);
- memcpy(tape->product_id, inquiry->product_id, 16);
- memcpy(tape->firmware_revision, inquiry->revision_level, 4);
- ide_fixstring(tape->vendor_id, 10, 0);
- ide_fixstring(tape->product_id, 18, 0);
- ide_fixstring(tape->firmware_revision, 6, 0);
- r = tape->firmware_revision;
- if (*(r + 1) == '.')
- tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0';
- printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision);
+ memcpy(vendor_id, &pc.buffer[8], 8);
+ memcpy(product_id, &pc.buffer[16], 16);
+ memcpy(fw_rev, &pc.buffer[32], 4);
+
+ ide_fixstring(vendor_id, 10, 0);
+ ide_fixstring(product_id, 18, 0);
+ ide_fixstring(fw_rev, 6, 0);
+
+ printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n",
+ drive->name, tape->name, vendor_id, product_id, fw_rev);
}
/*
- * idetape_get_mode_sense_results asks the tape about its various
- * parameters. In particular, we will adjust our data transfer buffer
- * size to the recommended value as returned by the tape.
+ * Ask the tape about its various parameters. In particular, we will adjust our
+ * data transfer buffer size to the recommended value as returned by the tape.
*/
-static void idetape_get_mode_sense_results (ide_drive_t *drive)
+static void idetape_get_mode_sense_results(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- idetape_capabilities_page_t *capabilities;
-
+ u8 *caps;
+ u8 speed, max_speed;
+
idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
if (idetape_queue_pc_tail(drive, &pc)) {
- printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
- tape->tape_block_size = 512;
- tape->capabilities.ctl = 52;
- tape->capabilities.speed = 450;
- tape->capabilities.buffer_size = 6 * 52;
+ printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
+ " some default values\n");
+ tape->blk_size = 512;
+ put_unaligned(52, (u16 *)&tape->caps[12]);
+ put_unaligned(540, (u16 *)&tape->caps[14]);
+ put_unaligned(6*52, (u16 *)&tape->caps[16]);
return;
}
- header = (idetape_mode_parameter_header_t *) pc.buffer;
- capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
+ caps = pc.buffer + 4 + pc.buffer[3];
- capabilities->max_speed = ntohs(capabilities->max_speed);
- capabilities->ctl = ntohs(capabilities->ctl);
- capabilities->speed = ntohs(capabilities->speed);
- capabilities->buffer_size = ntohs(capabilities->buffer_size);
+ /* convert to host order and save for later use */
+ speed = be16_to_cpu(*(u16 *)&caps[14]);
+ max_speed = be16_to_cpu(*(u16 *)&caps[8]);
- if (!capabilities->speed) {
- printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
- capabilities->speed = 650;
+ put_unaligned(max_speed, (u16 *)&caps[8]);
+ put_unaligned(be16_to_cpu(*(u16 *)&caps[12]), (u16 *)&caps[12]);
+ put_unaligned(speed, (u16 *)&caps[14]);
+ put_unaligned(be16_to_cpu(*(u16 *)&caps[16]), (u16 *)&caps[16]);
+
+ if (!speed) {
+ printk(KERN_INFO "ide-tape: %s: invalid tape speed "
+ "(assuming 650KB/sec)\n", drive->name);
+ put_unaligned(650, (u16 *)&caps[14]);
}
- if (!capabilities->max_speed) {
- printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name);
- capabilities->max_speed = 650;
+ if (!max_speed) {
+ printk(KERN_INFO "ide-tape: %s: invalid max_speed "
+ "(assuming 650KB/sec)\n", drive->name);
+ put_unaligned(650, (u16 *)&caps[8]);
}
- tape->capabilities = *capabilities; /* Save us a copy */
- if (capabilities->blk512)
- tape->tape_block_size = 512;
- else if (capabilities->blk1024)
- tape->tape_block_size = 1024;
-
-#if IDETAPE_DEBUG_INFO
- printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
- printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
- printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
- printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
- printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
- printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
-
- printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
- printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
- printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
- printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
- printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
- printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
- printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
- printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
- printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);
- printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
-#endif /* IDETAPE_DEBUG_INFO */
-}
-
-/*
- * ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor
- * and if it succeeds sets the tape block size with the reported value
- */
-static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
-{
-
- idetape_tape_t *tape = drive->driver_data;
- idetape_pc_t pc;
- idetape_mode_parameter_header_t *header;
- idetape_parameter_block_descriptor_t *block_descrp;
-
- idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
- if (idetape_queue_pc_tail(drive, &pc)) {
- printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
- if (tape->tape_block_size == 0) {
- printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
- tape->tape_block_size = 32768;
- }
- return;
- }
- header = (idetape_mode_parameter_header_t *) pc.buffer;
- block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
- tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
- tape->drv_write_prot = (header->dsp & 0x80) >> 7;
-
-#if IDETAPE_DEBUG_INFO
- printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
-#endif /* IDETAPE_DEBUG_INFO */
+ memcpy(&tape->caps, caps, 20);
+ if (caps[7] & 0x02)
+ tape->blk_size = 512;
+ else if (caps[7] & 0x04)
+ tape->blk_size = 1024;
}
#ifdef CONFIG_IDE_PROC_FS
-static void idetape_add_settings (ide_drive_t *drive)
+static void idetape_add_settings(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
-/*
- * drive setting name read/write data type min max mul_factor div_factor data pointer set function
- */
- ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL);
- ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
- ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL);
- ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
- ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL);
- ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL);
- ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL);
- ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL);
- ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL);
- ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
- ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL);
- ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed,NULL);
- ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL);
- ide_add_setting(drive, "debug_level", SETTING_RW, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL);
+ ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
+ 1, 2, (u16 *)&tape->caps[16], NULL);
+ ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff,
+ tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
+ ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff,
+ tape->stage_size / 1024, 1, &tape->max_stages, NULL);
+ ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff,
+ tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
+ ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0,
+ 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages,
+ NULL);
+ ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0,
+ 0xffff, tape->stage_size / 1024, 1,
+ &tape->nr_pending_stages, NULL);
+ ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
+ 1, 1, (u16 *)&tape->caps[14], NULL);
+ ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1,
+ 1024, &tape->stage_size, NULL);
+ ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN,
+ IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq,
+ NULL);
+ ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
+ 1, &drive->dsc_overlap, NULL);
+ ide_add_setting(drive, "pipeline_head_speed_c", SETTING_READ, TYPE_INT,
+ 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed,
+ NULL);
+ ide_add_setting(drive, "pipeline_head_speed_u", SETTING_READ, TYPE_INT,
+ 0, 0xffff, 1, 1,
+ &tape->uncontrolled_pipeline_head_speed, NULL);
+ ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
+ 1, 1, &tape->avg_speed, NULL);
+ ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
+ 1, &tape->debug_mask, NULL);
}
#else
static inline void idetape_add_settings(ide_drive_t *drive) { ; }
#endif
/*
- * ide_setup is called to:
+ * The function below is called to:
*
- * 1. Initialize our various state variables.
- * 2. Ask the tape for its capabilities.
- * 3. Allocate a buffer which will be used for data
- * transfer. The buffer size is chosen based on
- * the recommendation which we received in step (2).
+ * 1. Initialize our various state variables.
+ * 2. Ask the tape for its capabilities.
+ * 3. Allocate a buffer which will be used for data transfer. The buffer size
+ * is chosen based on the recommendation which we received in step 2.
*
- * Note that at this point ide.c already assigned us an irq, so that
- * we can queue requests here and wait for their completion.
+ * Note that at this point ide.c already assigned us an irq, so that we can
+ * queue requests here and wait for their completion.
*/
-static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
+static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
{
unsigned long t1, tmid, tn, t;
int speed;
- struct idetape_id_gcw gcw;
int stage_size;
+ u8 gcw[2];
struct sysinfo si;
+ u16 *ctl = (u16 *)&tape->caps[12];
- spin_lock_init(&tape->spinlock);
+ spin_lock_init(&tape->lock);
drive->dsc_overlap = 1;
if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
@@ -4543,25 +3532,29 @@
tape->name[0] = 'h';
tape->name[1] = 't';
tape->name[2] = '0' + minor;
- tape->chrdev_direction = idetape_direction_none;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
tape->pc = tape->pc_stack;
tape->max_insert_speed = 10000;
tape->speed_control = 1;
*((unsigned short *) &gcw) = drive->id->config;
- if (gcw.drq_type == 1)
+
+ /* Command packet DRQ type */
+ if (((gcw[0] & 0x60) >> 5) == 1)
set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
- tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10;
-
+ tape->min_pipeline = 10;
+ tape->max_pipeline = 10;
+ tape->max_stages = 10;
+
idetape_get_inquiry_results(drive);
idetape_get_mode_sense_results(drive);
- idetape_get_blocksize_from_block_descriptor(drive);
+ ide_tape_get_bsize_from_bdesc(drive);
tape->user_bs_factor = 1;
- tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+ tape->stage_size = *ctl * tape->blk_size;
while (tape->stage_size > 0xffff) {
printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
- tape->capabilities.ctl /= 2;
- tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+ *ctl /= 2;
+ tape->stage_size = *ctl * tape->blk_size;
}
stage_size = tape->stage_size;
tape->pages_per_stage = stage_size / PAGE_SIZE;
@@ -4570,28 +3563,30 @@
tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE;
}
- /*
- * Select the "best" DSC read/write polling frequency
- * and pipeline size.
- */
- speed = max(tape->capabilities.speed, tape->capabilities.max_speed);
+ /* Select the "best" DSC read/write polling freq and pipeline size. */
+ speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
tape->max_stages = speed * 1000 * 10 / tape->stage_size;
- /*
- * Limit memory use for pipeline to 10% of physical memory
- */
+ /* Limit memory use for pipeline to 10% of physical memory */
si_meminfo(&si);
- if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
- tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
+ if (tape->max_stages * tape->stage_size >
+ si.totalram * si.mem_unit / 10)
+ tape->max_stages =
+ si.totalram * si.mem_unit / (10 * tape->stage_size);
+
tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
- tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
- if (tape->max_stages == 0)
- tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
+ tape->max_pipeline =
+ min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+ if (tape->max_stages == 0) {
+ tape->max_stages = 1;
+ tape->min_pipeline = 1;
+ tape->max_pipeline = 1;
+ }
t1 = (tape->stage_size * HZ) / (speed * 1000);
- tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
+ tmid = (*(u16 *)&tape->caps[16] * 32 * HZ) / (speed * 125);
tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000);
if (tape->max_stages)
@@ -4600,17 +3595,19 @@
t = t1;
/*
- * Ensure that the number we got makes sense; limit
- * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
+ * Ensure that the number we got makes sense; limit it within
+ * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
*/
- tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+ tape->best_dsc_rw_freq = max_t(unsigned long,
+ min_t(unsigned long, t, IDETAPE_DSC_RW_MAX),
+ IDETAPE_DSC_RW_MIN);
printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
"%dkB pipeline, %lums tDSC%s\n",
- drive->name, tape->name, tape->capabilities.speed,
- (tape->capabilities.buffer_size * 512) / tape->stage_size,
+ drive->name, tape->name, *(u16 *)&tape->caps[14],
+ (*(u16 *)&tape->caps[16] * 512) / tape->stage_size,
tape->stage_size / 1024,
tape->max_stages * tape->stage_size / 1024,
- tape->best_dsc_rw_frequency * 1000 / HZ,
+ tape->best_dsc_rw_freq * 1000 / HZ,
drive->using_dma ? ", DMA":"");
idetape_add_settings(drive);
@@ -4638,7 +3635,8 @@
drive->dsc_overlap = 0;
drive->driver_data = NULL;
device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
- device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+ device_destroy(idetape_sysfs_class,
+ MKDEV(IDETAPE_MAJOR, tape->minor + 128));
idetape_devs[tape->minor] = NULL;
g->private_data = NULL;
put_disk(g);
@@ -4687,9 +3685,7 @@
#endif
};
-/*
- * Our character device supporting functions, passed to register_chrdev.
- */
+/* Our character device supporting functions, passed to register_chrdev. */
static const struct file_operations idetape_fops = {
.owner = THIS_MODULE,
.read = idetape_chrdev_read,
@@ -4704,7 +3700,8 @@
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_tape_obj *tape;
- if (!(tape = ide_tape_get(disk)))
+ tape = ide_tape_get(disk);
+ if (!tape)
return -ENXIO;
return 0;
@@ -4751,21 +3748,20 @@
goto failed;
if (drive->media != ide_tape)
goto failed;
- if (!idetape_identify_device (drive)) {
- printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+ if (!idetape_identify_device(drive)) {
+ printk(KERN_ERR "ide-tape: %s: not supported by this version of"
+ " the driver\n", drive->name);
goto failed;
}
if (drive->scsi) {
- printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+ printk(KERN_INFO "ide-tape: passing drive %s to ide-scsi"
+ " emulation.\n", drive->name);
goto failed;
}
- if (strstr(drive->id->model, "OnStream DI-")) {
- printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
- printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
- }
- tape = kzalloc(sizeof (idetape_tape_t), GFP_KERNEL);
+ tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
if (tape == NULL) {
- printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+ printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
+ drive->name);
goto failed;
}
@@ -4811,10 +3807,7 @@
return -ENODEV;
}
-MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
-MODULE_LICENSE("GPL");
-
-static void __exit idetape_exit (void)
+static void __exit idetape_exit(void)
{
driver_unregister(&idetape_driver.gen_driver);
class_destroy(idetape_sysfs_class);
@@ -4833,7 +3826,8 @@
}
if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
- printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
+ printk(KERN_ERR "ide-tape: Failed to register chrdev"
+ " interface\n");
error = -EBUSY;
goto out_free_class;
}
@@ -4856,3 +3850,5 @@
module_init(idetape_init);
module_exit(idetape_exit);
MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
+MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 16a9a58..0518a2e 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -189,12 +189,11 @@
*/
static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
+ u8 stat = ide_read_status(drive);
- if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+ if (OK_STAT(stat, READY_STAT, BAD_STAT))
drive->mult_count = drive->mult_req;
- } else {
+ else {
drive->mult_req = drive->mult_count = 0;
drive->special.b.recalibrate = 1;
(void) ide_dump_status(drive, "set_multmode", stat);
@@ -207,11 +206,10 @@
*/
static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
int retries = 5;
u8 stat;
- while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+ while (((stat = ide_read_status(drive)) & BUSY_STAT) && retries--)
udelay(10);
if (OK_STAT(stat, READY_STAT, BAD_STAT))
@@ -230,10 +228,9 @@
*/
static ide_startstop_t recal_intr(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
+ u8 stat = ide_read_status(drive);
- if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
return ide_error(drive, "recal_intr", stat);
return ide_stopped;
}
@@ -244,23 +241,23 @@
static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
{
ide_task_t *args = HWGROUP(drive)->rq->special;
- ide_hwif_t *hwif = HWIF(drive);
u8 stat;
local_irq_enable_in_hardirq();
- if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+ stat = ide_read_status(drive);
+
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
return ide_error(drive, "task_no_data_intr", stat);
/* calls ide_end_drive_cmd */
- }
+
if (args)
- ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+ ide_end_drive_cmd(drive, stat, ide_read_error(drive));
return ide_stopped;
}
static u8 wait_drive_not_busy(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
int retries;
u8 stat;
@@ -269,7 +266,9 @@
* This can take up to 10 usec, but we will wait max 1 ms.
*/
for (retries = 0; retries < 100; retries++) {
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
+ stat = ide_read_status(drive);
+
+ if (stat & BUSY_STAT)
udelay(10);
else
break;
@@ -408,7 +407,7 @@
void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
{
if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
- u8 err = drive->hwif->INB(IDE_ERROR_REG);
+ u8 err = ide_read_error(drive);
ide_end_drive_cmd(drive, stat, err);
return;
@@ -430,7 +429,7 @@
{
ide_hwif_t *hwif = drive->hwif;
struct request *rq = HWGROUP(drive)->rq;
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat = ide_read_status(drive);
/* new way for dealing with premature shared PCI interrupts */
if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
@@ -465,7 +464,7 @@
{
ide_hwif_t *hwif = drive->hwif;
struct request *rq = HWGROUP(drive)->rq;
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat = ide_read_status(drive);
if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
return task_error(drive, rq, __FUNCTION__, stat);
@@ -755,6 +754,7 @@
u8 args[4], xfer_rate = 0;
ide_task_t tfargs;
struct ide_taskfile *tf = &tfargs.tf;
+ struct hd_driveid *id = drive->id;
if (NULL == (void *) arg) {
struct request rq;
@@ -792,10 +792,16 @@
return -ENOMEM;
}
- if (set_transfer(drive, &tfargs)) {
+ if (tf->command == WIN_SETFEATURES &&
+ tf->feature == SETFEATURES_XFER &&
+ tf->nsect >= XFER_SW_DMA_0 &&
+ (id->dma_ultra || id->dma_mword || id->dma_1word)) {
xfer_rate = args[1];
- if (ide_ata66_check(drive, &tfargs))
+ if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
+ printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+ "be set\n", drive->name);
goto abort;
+ }
}
err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
index adeda76..3b12ffe 100644
--- a/drivers/ide/ide-timing.h
+++ b/drivers/ide/ide-timing.h
@@ -199,7 +199,7 @@
}
/*
- * Lenghten active & recovery time so that cycle time is correct.
+ * Lengthen active & recovery time so that cycle time is correct.
*/
if (t->act8b + t->rec8b < t->cyc8b) {
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index ab9ca2b..ad0e995 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -499,6 +499,8 @@
/**
* ide_unregister - free an IDE interface
* @index: index of interface (will change soon to a pointer)
+ * @init_default: init default hwif flag
+ * @restore: restore hwif flag
*
* Perform the final unregister of an IDE interface. At the moment
* we don't refcount interfaces so this will also get split up.
@@ -518,7 +520,7 @@
* This is raving bonkers.
*/
-void ide_unregister(unsigned int index)
+void ide_unregister(unsigned int index, int init_default, int restore)
{
ide_drive_t *drive;
ide_hwif_t *hwif, *g;
@@ -602,9 +604,12 @@
/* restore hwif data to pristine status */
ide_init_port_data(hwif, index);
- init_hwif_default(hwif, index);
- ide_hwif_restore(hwif, &tmp_hwif);
+ if (init_default)
+ init_hwif_default(hwif, index);
+
+ if (restore)
+ ide_hwif_restore(hwif, &tmp_hwif);
abort:
spin_unlock_irq(&ide_lock);
@@ -613,60 +618,6 @@
EXPORT_SYMBOL(ide_unregister);
-
-/**
- * ide_setup_ports - set up IDE interface ports
- * @hw: register descriptions
- * @base: base register
- * @offsets: table of register offsets
- * @ctrl: control register
- * @ack_irq: IRQ ack
- * @irq: interrupt lie
- *
- * Setup hw_regs_t structure described by parameters. You
- * may set up the hw structure yourself OR use this routine to
- * do it for you. This is basically a helper
- *
- */
-
-void ide_setup_ports ( hw_regs_t *hw,
- unsigned long base, int *offsets,
- unsigned long ctrl, unsigned long intr,
- ide_ack_intr_t *ack_intr,
-/*
- * ide_io_ops_t *iops,
- */
- int irq)
-{
- int i;
-
- memset(hw, 0, sizeof(hw_regs_t));
- for (i = 0; i < IDE_NR_PORTS; i++) {
- if (offsets[i] == -1) {
- switch(i) {
- case IDE_CONTROL_OFFSET:
- hw->io_ports[i] = ctrl;
- break;
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
- case IDE_IRQ_OFFSET:
- hw->io_ports[i] = intr;
- break;
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
- default:
- hw->io_ports[i] = 0;
- break;
- }
- } else {
- hw->io_ports[i] = base + offsets[i];
- }
- }
- hw->irq = irq;
- hw->ack_intr = ack_intr;
-/*
- * hw->iops = iops;
- */
-}
-
void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
{
memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
@@ -678,6 +629,31 @@
}
EXPORT_SYMBOL_GPL(ide_init_port_hw);
+ide_hwif_t *ide_deprecated_find_port(unsigned long base)
+{
+ ide_hwif_t *hwif;
+ int i;
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == base)
+ goto found;
+ }
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->hold)
+ continue;
+ if (!hwif->present && hwif->mate == NULL)
+ goto found;
+ }
+
+ hwif = NULL;
+found:
+ return hwif;
+}
+EXPORT_SYMBOL_GPL(ide_deprecated_find_port);
+
/**
* ide_register_hw - register IDE interface
* @hw: hardware registers
@@ -697,38 +673,26 @@
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
do {
- for (index = 0; index < MAX_HWIFS; ++index) {
- hwif = &ide_hwifs[index];
- if (hwif->io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
- goto found;
- }
- for (index = 0; index < MAX_HWIFS; ++index) {
- hwif = &ide_hwifs[index];
- if (hwif->hold)
- continue;
- if (!hwif->present && hwif->mate == NULL)
- goto found;
- }
+ hwif = ide_deprecated_find_port(hw->io_ports[IDE_DATA_OFFSET]);
+ index = hwif->index;
+ if (hwif)
+ goto found;
for (index = 0; index < MAX_HWIFS; index++)
- ide_unregister(index);
+ ide_unregister(index, 1, 1);
} while (retry--);
return -1;
found:
if (hwif->present)
- ide_unregister(index);
- else if (!hwif->hold) {
+ ide_unregister(index, 0, 1);
+ else if (!hwif->hold)
ide_init_port_data(hwif, index);
- init_hwif_default(hwif, index);
- }
- if (hwif->present)
- return -1;
ide_init_port_hw(hwif, hw);
hwif->quirkproc = quirkproc;
idx[0] = index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
if (hwifp)
*hwifp = hwif;
@@ -791,10 +755,6 @@
return -EBUSY;
drive->io_32bit = arg;
-#ifdef CONFIG_BLK_DEV_DTC2278
- if (HWIF(drive)->chipset == ide_dtc2278)
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
-#endif /* CONFIG_BLK_DEV_DTC2278 */
spin_unlock_irq(&ide_lock);
@@ -1021,11 +981,8 @@
case HDIO_GET_NICE:
return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP |
- drive->nice0 << IDE_NICE_0 |
- drive->nice1 << IDE_NICE_1 |
- drive->nice2 << IDE_NICE_2,
+ drive->nice1 << IDE_NICE_1,
(long __user *) arg);
-
#ifdef CONFIG_IDE_TASK_IOCTL
case HDIO_DRIVE_TASKFILE:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -1066,7 +1023,7 @@
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_RAWIO)) return -EACCES;
/* (arg > MAX_HWIFS) checked in function */
- ide_unregister(arg);
+ ide_unregister(arg, 1, 1);
return 0;
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
@@ -1711,7 +1668,7 @@
int index;
for (index = 0; index < MAX_HWIFS; ++index)
- ide_unregister(index);
+ ide_unregister(index, 0, 0);
proc_ide_destroy();
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index e3ea209..d4d1a6b 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -191,9 +191,14 @@
return t;
}
+static const struct ide_port_info ali14xx_port_info = {
+ .chipset = ide_ali14xx,
+ .host_flags = IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE,
+ .pio_mask = ATA_PIO4,
+};
+
static int __init ali14xx_probe(void)
{
- ide_hwif_t *hwif, *mate;
static u8 idx[4] = { 0, 1, 0xff, 0xff };
printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
@@ -205,21 +210,10 @@
return 1;
}
- hwif = &ide_hwifs[0];
- mate = &ide_hwifs[1];
+ ide_hwifs[0].set_pio_mode = &ali14xx_set_pio_mode;
+ ide_hwifs[1].set_pio_mode = &ali14xx_set_pio_mode;
- hwif->chipset = ide_ali14xx;
- hwif->pio_mask = ATA_PIO4;
- hwif->set_pio_mode = &ali14xx_set_pio_mode;
- hwif->mate = mate;
-
- mate->chipset = ide_ali14xx;
- mate->pio_mask = ATA_PIO4;
- mate->set_pio_mode = &ali14xx_set_pio_mode;
- mate->mate = hwif;
- mate->channel = 1;
-
- ide_device_add(idx);
+ ide_device_add(idx, &ali14xx_port_info);
return 0;
}
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index dd3d198..50ffa87 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -56,31 +56,11 @@
XSURF_BASE1, XSURF_BASE2
};
-
/*
* Offsets from one of the above bases
*/
-#define BUDDHA_DATA 0x00
-#define BUDDHA_ERROR 0x06 /* see err-bits */
-#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */
-#define BUDDHA_SECTOR 0x0e /* starting sector */
-#define BUDDHA_LCYL 0x12 /* starting cylinder */
-#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */
-#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS 0x1e /* see status-bits */
#define BUDDHA_CONTROL 0x11a
-#define XSURF_CONTROL -1 /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
- BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
- BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
- BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
- BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
/*
* Other registers
@@ -140,6 +120,26 @@
return 1;
}
+static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
+ unsigned long ctl, unsigned long irq_port,
+ ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports[IDE_DATA_OFFSET] = base;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports[i] = base + 2 + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+ hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+
+ hw->irq = IRQ_AMIGA_PORTS;
+ hw->ack_intr = ack_intr;
+}
+
/*
* Probe for a Buddha or Catweasel IDE interface
*/
@@ -202,22 +202,24 @@
printk(KERN_INFO "ide: %s IDE controller\n",
buddha_board_name[type]);
- for(i=0;i<buddha_num_hwifs;i++) {
- if(type != BOARD_XSURF) {
- ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
- buddha_offsets, 0,
- (buddha_board+buddha_irqports[i]),
- buddha_ack_intr,
-// budda_iops,
- IRQ_AMIGA_PORTS);
+ for (i = 0; i < buddha_num_hwifs; i++) {
+ unsigned long base, ctl, irq_port;
+ ide_ack_intr_t *ack_intr;
+
+ if (type != BOARD_XSURF) {
+ base = buddha_board + buddha_bases[i];
+ ctl = base + BUDDHA_CONTROL;
+ irq_port = buddha_board + buddha_irqports[i];
+ ack_intr = buddha_ack_intr;
} else {
- ide_setup_ports(&hw, (buddha_board+xsurf_bases[i]),
- xsurf_offsets, 0,
- (buddha_board+xsurf_irqports[i]),
- xsurf_ack_intr,
-// xsurf_iops,
- IRQ_AMIGA_PORTS);
- }
+ base = buddha_board + xsurf_bases[i];
+ /* X-Surf has no CS1* (Control/AltStat) */
+ ctl = 0;
+ irq_port = buddha_board + xsurf_irqports[i];
+ ack_intr = xsurf_ack_intr;
+ }
+
+ buddha_setup_ports(&hw, base, ctl, irq_port, ack_intr);
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif) {
@@ -232,7 +234,7 @@
}
}
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
}
return 0;
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 611c970..73396f7 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -84,14 +84,20 @@
/* Actually we do - there is a data sheet available for the
Winbond but does anyone actually care */
}
-
- /*
- * 32bit I/O has to be enabled for *both* drives at the same time.
- */
- drive->io_32bit = 1;
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
}
+static const struct ide_port_info dtc2278_port_info __initdata = {
+ .chipset = ide_dtc2278,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_UNMASK_IRQS |
+ IDE_HFLAG_IO_32BIT |
+ /* disallow ->io_32bit changes */
+ IDE_HFLAG_NO_IO_32BIT |
+ IDE_HFLAG_NO_DMA |
+ IDE_HFLAG_NO_AUTOTUNE,
+ .pio_mask = ATA_PIO4,
+};
+
static int __init dtc2278_probe(void)
{
unsigned long flags;
@@ -122,23 +128,9 @@
#endif
local_irq_restore(flags);
- hwif->serialized = 1;
- hwif->chipset = ide_dtc2278;
- hwif->pio_mask = ATA_PIO4;
hwif->set_pio_mode = &dtc2278_set_pio_mode;
- hwif->drives[0].no_unmask = 1;
- hwif->drives[1].no_unmask = 1;
- hwif->mate = mate;
- mate->serialized = 1;
- mate->chipset = ide_dtc2278;
- mate->pio_mask = ATA_PIO4;
- mate->drives[0].no_unmask = 1;
- mate->drives[1].no_unmask = 1;
- mate->mate = hwif;
- mate->channel = 1;
-
- ide_device_add(idx);
+ ide_device_add(idx, &dtc2278_port_info);
return 0;
}
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index c9bd6bf..f044048 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -33,22 +33,8 @@
* Offsets from the above base
*/
-#define ATA_HD_DATA 0x00
-#define ATA_HD_ERROR 0x05 /* see err-bits */
-#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */
-#define ATA_HD_SECTOR 0x0d /* starting sector */
-#define ATA_HD_LCYL 0x11 /* starting cylinder */
-#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */
-#define ATA_HD_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS 0x1d /* see status-bits */
#define ATA_HD_CONTROL 0x39
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
- ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
- ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
/*
* falconide_intr_lock is used to obtain access to the IDE interrupt,
* which is shared between several drivers.
@@ -57,6 +43,22 @@
int falconide_intr_lock;
EXPORT_SYMBOL(falconide_intr_lock);
+static void __init falconide_setup_ports(hw_regs_t *hw)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports[IDE_DATA_OFFSET] = ATA_HD_BASE;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_CONTROL;
+
+ hw->irq = IRQ_MFP_IDE;
+ hw->ack_intr = NULL;
+}
/*
* Probe for a Falcon IDE interface
@@ -64,16 +66,15 @@
static int __init falconide_init(void)
{
- if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
hw_regs_t hw;
ide_hwif_t *hwif;
+ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
+ return 0;
+
printk(KERN_INFO "ide: Falcon IDE controller\n");
- ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
- 0, 0, NULL,
-// falconide_iops,
- IRQ_MFP_IDE);
+ falconide_setup_ports(&hw);
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif) {
@@ -83,11 +84,10 @@
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
}
- }
- return 0;
+ return 0;
}
module_init(falconide_init);
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index f67c51a..9d3851d 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -34,22 +34,8 @@
* Offsets from one of the above bases
*/
-#define GAYLE_DATA 0x00
-#define GAYLE_ERROR 0x06 /* see err-bits */
-#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */
-#define GAYLE_SECTOR 0x0e /* starting sector */
-#define GAYLE_LCYL 0x12 /* starting cylinder */
-#define GAYLE_HCYL 0x16 /* high byte of starting cyl */
-#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS 0x1e /* see status-bits */
#define GAYLE_CONTROL 0x101a
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
- GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
- GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
/*
* These are at different offsets from the base
*/
@@ -106,6 +92,26 @@
return 1;
}
+static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
+ unsigned long ctl, unsigned long irq_port,
+ ide_ack_intr_t *ack_intr);
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports[IDE_DATA_OFFSET] = base;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports[i] = base + 2 + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+ hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+
+ hw->irq = IRQ_AMIGA_PORTS;
+ hw->ack_intr = ack_intr;
+}
+
/*
* Probe for a Gayle IDE interface (and optionally for an IDE doubler)
*/
@@ -167,10 +173,7 @@
base = (unsigned long)ZTWO_VADDR(phys_base);
ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
- ide_setup_ports(&hw, base, gayle_offsets,
- ctrlport, irqport, ack_intr,
-// &gayle_iops,
- IRQ_AMIGA_PORTS);
+ gayle_setup_ports(&hw, base, ctrlport, irqport, ack_intr);
hwif = ide_find_port(base);
if (hwif) {
@@ -186,7 +189,7 @@
release_mem_region(res_start, res_n);
}
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
return 0;
}
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 8e05d88..0b0d867 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -421,11 +421,14 @@
static inline int wait_DRQ(void)
{
- int retries = 100000, stat;
+ int retries;
+ int stat;
- while (--retries > 0)
- if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+ for (retries = 0; retries < 100000; retries++) {
+ stat = inb_p(HD_STATUS);
+ if (stat & DRQ_STAT)
return 0;
+ }
dump_status("wait_DRQ", stat);
return -1;
}
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index 57bc15c..02d12c7 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -300,16 +300,36 @@
#endif
}
+static void __init ht6560b_port_init_devs(ide_hwif_t *hwif)
+{
+ /* Setting default configurations for drives. */
+ int t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT;
+
+ if (hwif->channel)
+ t |= (HT_SECONDARY_IF << 8);
+
+ hwif->drives[0].drive_data = t;
+ hwif->drives[1].drive_data = t;
+}
+
int probe_ht6560b = 0;
module_param_named(probe, probe_ht6560b, bool, 0);
MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
+static const struct ide_port_info ht6560b_port_info __initdata = {
+ .chipset = ide_ht6560b,
+ .host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */
+ IDE_HFLAG_NO_DMA |
+ IDE_HFLAG_NO_AUTOTUNE |
+ IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
+};
+
static int __init ht6560b_init(void)
{
ide_hwif_t *hwif, *mate;
static u8 idx[4] = { 0, 1, 0xff, 0xff };
- int t;
if (probe_ht6560b == 0)
return -ENODEV;
@@ -328,36 +348,16 @@
goto release_region;
}
- hwif->chipset = ide_ht6560b;
hwif->selectproc = &ht6560b_selectproc;
- hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
- hwif->pio_mask = ATA_PIO5;
hwif->set_pio_mode = &ht6560b_set_pio_mode;
- hwif->serialized = 1; /* is this needed? */
- hwif->mate = mate;
- mate->chipset = ide_ht6560b;
mate->selectproc = &ht6560b_selectproc;
- mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
- mate->pio_mask = ATA_PIO5;
mate->set_pio_mode = &ht6560b_set_pio_mode;
- mate->serialized = 1; /* is this needed? */
- mate->mate = hwif;
- mate->channel = 1;
- /*
- * Setting default configurations for drives
- */
- t = (HT_CONFIG_DEFAULT << 8);
- t |= HT_TIMING_DEFAULT;
- hwif->drives[0].drive_data = t;
- hwif->drives[1].drive_data = t;
+ hwif->port_init_devs = ht6560b_port_init_devs;
+ mate->port_init_devs = ht6560b_port_init_devs;
- t |= (HT_SECONDARY_IF << 8);
- mate->drives[0].drive_data = t;
- mate->drives[1].drive_data = t;
-
- ide_device_add(idx);
+ ide_device_add(idx, &ht6560b_port_info);
return 0;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 3bd2967..15ccf69 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -145,13 +145,36 @@
static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
{
+ ide_hwif_t *hwif;
hw_regs_t hw;
+ int i;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
memset(&hw, 0, sizeof(hw));
- ide_init_hwif_ports(&hw, io, ctl, NULL);
+ ide_std_init_ports(&hw, io, ctl);
hw.irq = irq;
hw.chipset = ide_pci;
hw.dev = &handle->dev;
- return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
+
+ hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ if (hwif == NULL)
+ return -1;
+
+ i = hwif->index;
+
+ if (hwif->present)
+ ide_unregister(i, 0, 0);
+ else if (!hwif->hold)
+ ide_init_port_data(hwif, i);
+
+ ide_init_port_hw(hwif, &hw);
+ hwif->quirkproc = &ide_undecoded_slave;
+
+ idx[0] = i;
+
+ ide_device_add(idx, NULL);
+
+ return hwif->present ? i : -1;
}
/*======================================================================
@@ -337,7 +360,7 @@
if (info->ndev) {
/* FIXME: if this fails we need to queue the cleanup somehow
-- need to investigate the required PCMCIA magic */
- ide_unregister(info->hd);
+ ide_unregister(info->hd, 0, 0);
}
info->ndev = 0;
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
index 7c3231a..688fcae 100644
--- a/drivers/ide/legacy/ide_platform.c
+++ b/drivers/ide/legacy/ide_platform.c
@@ -17,7 +17,7 @@
#include <linux/ide.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -108,7 +108,7 @@
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
platform_set_drvdata(pdev, hwif);
@@ -122,7 +122,7 @@
{
ide_hwif_t *hwif = pdev->dev.driver_data;
- ide_unregister(hwif->index);
+ ide_unregister(hwif->index, 0, 0);
return 0;
}
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index c54d07f..a61e607 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -31,14 +31,6 @@
* These match MkLinux so they should be correct.
*/
-#define IDE_DATA 0x00
-#define IDE_ERROR 0x04 /* see err-bits */
-#define IDE_NSECTOR 0x08 /* nr of sectors to read/write */
-#define IDE_SECTOR 0x0c /* starting sector */
-#define IDE_LCYL 0x10 /* starting cylinder */
-#define IDE_HCYL 0x14 /* high byte of starting cyl */
-#define IDE_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS 0x1c /* see status-bits */
#define IDE_CONTROL 0x38 /* control/altstatus */
/*
@@ -63,11 +55,6 @@
volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-static int macide_offsets[IDE_NR_PORTS] = {
- IDE_DATA, IDE_ERROR, IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
- IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL
-};
-
int macide_ack_intr(ide_hwif_t* hwif)
{
if (*ide_ifr & 0x20) {
@@ -77,6 +64,22 @@
return 0;
}
+static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
+ int irq, ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ for (i = 0; i < 8; i++)
+ hw->io_ports[i] = base + i * 4;
+
+ hw->io_ports[IDE_CONTROL_OFFSET] = IDE_CONTROL;
+
+ hw->irq = irq;
+ hw->ack_intr = ack_intr;
+}
+
static const char *mac_ide_name[] =
{ "Quadra", "Powerbook", "Powerbook Baboon" };
@@ -86,27 +89,27 @@
static int __init macide_init(void)
{
- hw_regs_t hw;
ide_hwif_t *hwif;
+ ide_ack_intr_t *ack_intr;
+ unsigned long base;
+ int irq;
+ hw_regs_t hw;
switch (macintosh_config->ide_type) {
case MAC_IDE_QUADRA:
- ide_setup_ports(&hw, IDE_BASE, macide_offsets,
- 0, 0, macide_ack_intr,
-// quadra_ide_iops,
- IRQ_NUBUS_F);
+ base = IDE_BASE;
+ ack_intr = macide_ack_intr;
+ irq = IRQ_NUBUS_F;
break;
case MAC_IDE_PB:
- ide_setup_ports(&hw, IDE_BASE, macide_offsets,
- 0, 0, macide_ack_intr,
-// macide_pb_iops,
- IRQ_NUBUS_C);
+ base = IDE_BASE;
+ ack_intr = macide_ack_intr;
+ irq = IRQ_NUBUS_C;
break;
case MAC_IDE_BABOON:
- ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
- 0, 0, NULL,
-// macide_baboon_iops,
- IRQ_BABOON_1);
+ base = BABOON_BASE;
+ ack_intr = NULL;
+ irq = IRQ_BABOON_1;
break;
default:
return -ENODEV;
@@ -115,6 +118,8 @@
printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
mac_ide_name[macintosh_config->ide_type - 1]);
+ macide_setup_ports(&hw, base, irq, ack_intr);
+
hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
if (hwif) {
u8 index = hwif->index;
@@ -123,19 +128,9 @@
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
- if (macintosh_config->ide_type == MAC_IDE_BABOON &&
- macintosh_config->ident == MAC_MODEL_PB190) {
- /* Fix breakage in ide-disk.c: drive capacity */
- /* is not initialized for drives without a */
- /* hardware ID, and we can't get that without */
- /* probing the drive which freezes a 190. */
- ide_drive_t *drive = &hwif->drives[0];
- drive->capacity64 = drive->cyl*drive->head*drive->sect;
- }
-
hwif->mmio = 1;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
}
return 0;
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index a9c6b06..1381b91 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -66,16 +66,12 @@
/*
- * This is very similar to ide_setup_ports except that addresses
- * are pretranslated for q40 ISA access
+ * Addresses are pretranslated for Q40 ISA access.
*/
void q40_ide_setup_ports ( hw_regs_t *hw,
unsigned long base, int *offsets,
unsigned long ctrl, unsigned long intr,
ide_ack_intr_t *ack_intr,
-/*
- * ide_io_ops_t *iops,
- */
int irq)
{
int i;
@@ -92,9 +88,6 @@
hw->irq = irq;
hw->ack_intr = ack_intr;
-/*
- * hw->iops = iops;
- */
}
@@ -154,7 +147,7 @@
}
}
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
return 0;
}
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 37534bb..bba29df 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -305,18 +305,33 @@
* called to setup an ata channel : adjusts attributes & links for tuning
*/
-static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
- unsigned int data0, unsigned int data1)
+static void __init qd_setup(ide_hwif_t *hwif, int base, int config)
{
- hwif->chipset = ide_qd65xx;
- hwif->channel = hwif->index;
hwif->select_data = base;
hwif->config_data = config;
- hwif->drives[0].drive_data = data0;
- hwif->drives[1].drive_data = data1;
- hwif->drives[0].io_32bit =
- hwif->drives[1].io_32bit = 1;
- hwif->pio_mask = ATA_PIO4;
+}
+
+static void __init qd6500_port_init_devs(ide_hwif_t *hwif)
+{
+ u8 base = hwif->select_data, config = QD_CONFIG(hwif);
+
+ hwif->drives[0].drive_data = QD6500_DEF_DATA;
+ hwif->drives[1].drive_data = QD6500_DEF_DATA;
+}
+
+static void __init qd6580_port_init_devs(ide_hwif_t *hwif)
+{
+ u16 t1, t2;
+ u8 base = hwif->select_data, config = QD_CONFIG(hwif);
+
+ if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+ t1 = QD6580_DEF_DATA;
+ t2 = QD6580_DEF_DATA2;
+ } else
+ t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
+
+ hwif->drives[0].drive_data = t1;
+ hwif->drives[1].drive_data = t2;
}
/*
@@ -356,6 +371,14 @@
}
*/
+static const struct ide_port_info qd65xx_port_info __initdata = {
+ .chipset = ide_qd65xx,
+ .host_flags = IDE_HFLAG_IO_32BIT |
+ IDE_HFLAG_NO_DMA |
+ IDE_HFLAG_NO_AUTOTUNE,
+ .pio_mask = ATA_PIO4,
+};
+
/*
* qd_probe:
*
@@ -393,13 +416,14 @@
return 1;
}
- qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA);
+ qd_setup(hwif, base, config);
+ hwif->port_init_devs = qd6500_port_init_devs;
hwif->set_pio_mode = &qd6500_set_pio_mode;
- idx[0] = unit;
+ idx[unit] = unit;
- ide_device_add(idx);
+ ide_device_add(idx, &qd65xx_port_info);
return 1;
}
@@ -426,14 +450,15 @@
hwif = &ide_hwifs[unit];
printk(KERN_INFO "%s: qd6580: single IDE board\n",
hwif->name);
- qd_setup(hwif, base, config | (control << 8),
- QD6580_DEF_DATA, QD6580_DEF_DATA2);
+ qd_setup(hwif, base, config | (control << 8));
+
+ hwif->port_init_devs = qd6580_port_init_devs;
hwif->set_pio_mode = &qd6580_set_pio_mode;
- idx[0] = unit;
+ idx[unit] = unit;
- ide_device_add(idx);
+ ide_device_add(idx, &qd65xx_port_info);
outb(QD_DEF_CONTR, QD_CONTROL_PORT);
@@ -447,20 +472,20 @@
printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
hwif->name, mate->name);
- qd_setup(hwif, base, config | (control << 8),
- QD6580_DEF_DATA, QD6580_DEF_DATA);
+ qd_setup(hwif, base, config | (control << 8));
+ hwif->port_init_devs = qd6580_port_init_devs;
hwif->set_pio_mode = &qd6580_set_pio_mode;
- qd_setup(mate, base, config | (control << 8),
- QD6580_DEF_DATA2, QD6580_DEF_DATA2);
+ qd_setup(mate, base, config | (control << 8));
+ mate->port_init_devs = qd6580_port_init_devs;
mate->set_pio_mode = &qd6580_set_pio_mode;
idx[0] = 0;
idx[1] = 1;
- ide_device_add(idx);
+ ide_device_add(idx, &qd65xx_port_info);
outb(QD_DEF_CONTR, QD_CONTROL_PORT);
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index 26f38ce..5696ba0 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -120,9 +120,14 @@
spin_unlock_irqrestore(&ide_lock, flags);
}
+static const struct ide_port_info umc8672_port_info __initdata = {
+ .chipset = ide_umc8672,
+ .host_flags = IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE,
+ .pio_mask = ATA_PIO4,
+};
+
static int __init umc8672_probe(void)
{
- ide_hwif_t *hwif, *mate;
unsigned long flags;
static u8 idx[4] = { 0, 1, 0xff, 0xff };
@@ -143,21 +148,10 @@
umc_set_speeds (current_speeds);
local_irq_restore(flags);
- hwif = &ide_hwifs[0];
- mate = &ide_hwifs[1];
+ ide_hwifs[0].set_pio_mode = &umc_set_pio_mode;
+ ide_hwifs[1].set_pio_mode = &umc_set_pio_mode;
- hwif->chipset = ide_umc8672;
- hwif->pio_mask = ATA_PIO4;
- hwif->set_pio_mode = &umc_set_pio_mode;
- hwif->mate = mate;
-
- mate->chipset = ide_umc8672;
- mate->pio_mask = ATA_PIO4;
- mate->set_pio_mode = &umc_set_pio_mode;
- mate->mate = hwif;
- mate->channel = 1;
-
- ide_device_add(idx);
+ ide_device_add(idx, &umc8672_port_info);
return 0;
}
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index cd42b30..0f4bf5d 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -548,6 +548,17 @@
*ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET);
}
+static const struct ide_port_info au1xxx_port_info = {
+ .host_flags = IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+ IDE_HFLAG_NO_IO_32BIT |
+ IDE_HFLAG_UNMASK_IRQS,
+ .pio_mask = ATA_PIO4,
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+ .mwdma_mask = ATA_MWDMA2,
+#endif
+};
+
static int au_ide_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -606,21 +617,6 @@
hwif->dev = dev;
- hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
- hwif->mwdma_mask = 0x07; /* Multimode-2 DMA */
- hwif->swdma_mask = 0x00;
-#else
- hwif->mwdma_mask = 0x0;
- hwif->swdma_mask = 0x0;
-#endif
-
- hwif->pio_mask = ATA_PIO4;
- hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
-
- hwif->drives[0].unmask = 1;
- hwif->drives[1].unmask = 1;
-
/* hold should be on in all cases */
hwif->hold = 1;
@@ -651,16 +647,9 @@
hwif->ide_dma_test_irq = &auide_dma_test_irq;
hwif->dma_lost_irq = &auide_dma_lost_irq;
#endif
- hwif->channel = 0;
hwif->select_data = 0; /* no chipset-specific code */
hwif->config_data = 0; /* no chipset-specific code */
- hwif->drives[0].autotune = 1; /* 1=autotune, 2=noautotune, 0=default */
- hwif->drives[1].autotune = 1;
-
- hwif->drives[0].no_io_32bit = 1;
- hwif->drives[1].no_io_32bit = 1;
-
auide_hwif.hwif = hwif;
hwif->hwif_data = &auide_hwif;
@@ -671,7 +660,7 @@
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, &au1xxx_port_info);
dev_set_drvdata(dev, hwif);
@@ -688,7 +677,7 @@
ide_hwif_t *hwif = dev_get_drvdata(dev);
_auide_hwif *ahwif = &auide_hwif;
- ide_unregister(hwif->index);
+ ide_unregister(hwif->index, 0, 0);
iounmap((void *)ahwif->regbase);
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 8b3959d..956259f 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -129,7 +129,7 @@
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
dev_set_drvdata(dev, hwif);
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index 9480325..02e6ee7 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -34,7 +34,8 @@
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
# Must appear at the end of the block
-obj-$(CONFIG_BLK_DEV_GENERIC) += generic.o
+obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
+ide-pci-generic-y += generic.o
ifeq ($(CONFIG_BLK_DEV_CMD640), m)
obj-m += cmd640.o
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 824df78..cfb3265 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
@@ -166,6 +165,16 @@
return dev->irq;
}
+static u8 __devinit atp86x_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x49, &ata66);
+
+ return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -174,21 +183,10 @@
if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
hwif->set_dma_mode = &aec6210_set_mode;
- else
+ else {
hwif->set_dma_mode = &aec6260_set_mode;
- if (hwif->dma_base == 0)
- return;
-
- if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
- return;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
- u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
-
- pci_read_config_byte(dev, 0x49, &ata66);
-
- hwif->cbl = (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+ hwif->cable_detect = atp86x_cable_detect;
}
}
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 130cc6e..b3b6f51 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -31,7 +31,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
@@ -666,13 +665,12 @@
hwif->set_dma_mode = &ali_set_dma_mode;
hwif->udma_filter = &ali_udma_filter;
+ hwif->cable_detect = ata66_ali15x3;
+
if (hwif->dma_base == 0)
return;
hwif->dma_setup = &ali15x3_dma_setup;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_ali15x3(hwif);
}
/**
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 8c52bc9..2ef890c 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -17,12 +17,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
-#include <asm/io.h>
#include "ide-timing.h"
@@ -199,6 +196,14 @@
return dev->irq;
}
+static u8 __devinit amd_cable_detect(ide_hwif_t *hwif)
+{
+ if ((amd_80w >> hwif->channel) & 1)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -209,15 +214,7 @@
hwif->set_pio_mode = &amd_set_pio_mode;
hwif->set_dma_mode = &amd_set_drive;
- if (!hwif->dma_base)
- return;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
- if ((amd_80w >> hwif->channel) & 1)
- hwif->cbl = ATA_CBL_PATA80;
- else
- hwif->cbl = ATA_CBL_PATA40;
- }
+ hwif->cable_detect = amd_cable_detect;
}
#define IDE_HFLAGS_AMD \
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index b56274a..7e037c8 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -6,15 +6,11 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
-#include <linux/delay.h>
#include <linux/init.h>
-#include <asm/io.h>
-
#define ATIIXP_IDE_PIO_TIMING 0x40
#define ATIIXP_IDE_MDMA_TIMING 0x44
#define ATIIXP_IDE_PIO_CONTROL 0x48
@@ -121,6 +117,19 @@
spin_unlock_irqrestore(&atiixp_lock, flags);
}
+static u8 __devinit atiixp_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ u8 udma_mode = 0, ch = hwif->channel;
+
+ pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
+
+ if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
/**
* init_hwif_atiixp - fill in the hwif for the ATIIXP
* @hwif: IDE interface
@@ -131,21 +140,10 @@
static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- u8 udma_mode = 0, ch = hwif->channel;
-
hwif->set_pio_mode = &atiixp_set_pio_mode;
hwif->set_dma_mode = &atiixp_set_dma_mode;
- if (!hwif->dma_base)
- return;
-
- pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
-
- if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
- hwif->cbl = ATA_CBL_PATA80;
- else
- hwif->cbl = ATA_CBL_PATA40;
+ hwif->cable_detect = atiixp_cable_detect;
}
static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index 7240c20..bd24dad3 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -103,10 +103,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
@@ -703,6 +699,18 @@
return 0;
}
+static const struct ide_port_info cmd640_port_info __initdata = {
+ .chipset = ide_cmd640,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_DMA |
+ IDE_HFLAG_NO_AUTOTUNE |
+ IDE_HFLAG_ABUSE_PREFETCH |
+ IDE_HFLAG_ABUSE_FAST_DEVSEL,
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ .pio_mask = ATA_PIO5,
+#endif
+};
+
/*
* Probe for a cmd640 chipset, and initialize it if found.
*/
@@ -760,11 +768,7 @@
setup_device_ptrs ();
printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
- cmd_hwif0->chipset = ide_cmd640;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
- IDE_HFLAG_ABUSE_FAST_DEVSEL;
- cmd_hwif0->pio_mask = ATA_PIO5;
cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -815,23 +819,14 @@
* Initialize data for secondary cmd640 port, if enabled
*/
if (second_port_cmd640) {
- cmd_hwif0->serialized = 1;
- cmd_hwif1->serialized = 1;
- cmd_hwif1->chipset = ide_cmd640;
- cmd_hwif0->mate = cmd_hwif1;
- cmd_hwif1->mate = cmd_hwif0;
- cmd_hwif1->channel = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
- IDE_HFLAG_ABUSE_FAST_DEVSEL;
- cmd_hwif1->pio_mask = ATA_PIO5;
cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
idx[1] = cmd_hwif1->index;
}
printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
- cmd_hwif0->serialized ? "" : "not ", port2);
+ second_port_cmd640 ? "" : "not ", port2);
/*
* Establish initial timings/prefetch for all drives.
@@ -876,7 +871,7 @@
cmd640_dump_regs();
#endif
- ide_device_add(idx);
+ ide_device_add(idx, &cmd640_port_info);
return 1;
}
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 04aa9e596..edabe62 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
@@ -393,6 +392,8 @@
hwif->set_pio_mode = &cmd64x_set_pio_mode;
hwif->set_dma_mode = &cmd64x_set_dma_mode;
+ hwif->cable_detect = ata66_cmd64x;
+
if (!hwif->dma_base)
return;
@@ -411,9 +412,6 @@
if (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 5)
hwif->ultra_mask = 0x00;
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_cmd64x(hwif);
-
switch (dev->device) {
case PCI_DEVICE_ID_CMD_648:
case PCI_DEVICE_ID_CMD_649:
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 9e01c6d..0be1a82 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -35,22 +35,12 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
struct pio_clocks
{
int address;
@@ -156,8 +146,14 @@
ide_setup_pci_noise(dev, d);
/* We must not grab the entire device, it has 'ISA' space in its
- BARS too and we will freak out other bits of the kernel */
- if (pci_enable_device_bars(dev, 1<<2)) {
+ * BARS too and we will freak out other bits of the kernel
+ *
+ * pci_enable_device_bars() is going away. I replaced it with
+ * IO only enable for now but I'll need confirmation this is
+ * allright for that device. If not, it will need some kind of
+ * quirk. --BenH.
+ */
+ if (pci_enable_device_io(dev)) {
printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
return -ENODEV;
}
@@ -174,7 +170,7 @@
ide_pci_setup_ports(dev, d, 14, &idx[0]);
- ide_device_add(idx);
+ ide_device_add(idx, d);
return 0;
}
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 765aac3..941a134 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -15,18 +15,12 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
-#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
+
#include <asm/io.h>
-#include <asm/irq.h>
/*
* Here are the standard PIO mode 0-4 timings for each "format".
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 66433aa..d7b5ea9 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -155,8 +155,9 @@
cs5535_set_speed(drive, XFER_PIO_0 + pio);
}
-static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
+static u8 __devinit cs5535_cable_detect(ide_hwif_t *hwif)
{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
u8 bit;
/* if a 80 wire cable was detected */
@@ -175,15 +176,10 @@
*/
static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
hwif->set_pio_mode = &cs5535_set_pio_mode;
hwif->set_dma_mode = &cs5535_set_dma_mode;
- if (hwif->dma_base == 0)
- return;
-
- hwif->cbl = cs5535_cable_detect(dev);
+ hwif->cable_detect = cs5535_cable_detect;
}
static const struct ide_port_info cs5535_chipset __devinitdata = {
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 50100ac..724cbac 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -45,7 +45,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index 27e47fc..3f9cd64 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -16,15 +16,14 @@
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
-#include <linux/autoconf.h>
+
#include <linux/types.h>
#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/pci.h>
+
#include <asm/io.h>
/*
@@ -52,6 +51,7 @@
ide_hwif_t *hwif = NULL;
ide_drive_t *drive;
int i, rc;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
rc = pci_enable_device(dev);
if (rc) {
@@ -78,12 +78,27 @@
hw.irq = dev->irq;
hw.chipset = ide_pci; /* this enables IRQ sharing */
- rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
- if (rc < 0) {
- printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
- pci_disable_device(dev);
- return -ENODEV;
- }
+ hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+ if (hwif == NULL)
+ goto out_disable;
+
+ i = hwif->index;
+
+ if (hwif->present)
+ ide_unregister(i, 0, 0);
+ else if (!hwif->hold)
+ ide_init_port_data(hwif, i);
+
+ ide_init_port_hw(hwif, &hw);
+ hwif->quirkproc = &ide_undecoded_slave;
+
+ idx[0] = i;
+
+ ide_device_add(idx, NULL);
+
+ if (!hwif->present)
+ goto out_disable;
+
pci_set_drvdata(dev, hwif);
hwif->dev = &dev->dev;
drive = &hwif->drives[0];
@@ -92,6 +107,11 @@
drive->unmask = 1;
}
return 0;
+
+out_disable:
+ printk(KERN_ERR "delkin_cb: no IDE devices found\n");
+ pci_disable_device(dev);
+ return -ENODEV;
}
static void
@@ -100,7 +120,8 @@
ide_hwif_t *hwif = pci_get_drvdata(dev);
if (hwif)
- ide_unregister(hwif->index);
+ ide_unregister(hwif->index, 0, 0);
+
pci_disable_device(dev);
}
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 59ebe84..7fd83a9 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -22,33 +22,13 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <asm/io.h>
-
static int ide_generic_all; /* Set to claim all devices */
-/*
- * the module_param_named() was added for the modular case
- * the __setup() is left as compatibility for existing setups
- */
-#ifndef MODULE
-static int __init ide_generic_all_on(char *unused)
-{
- ide_generic_all = 1;
- printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
- return 1;
-}
-const __setup("all-generic-ide", ide_generic_all_on);
-#endif
module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 25dbb81..9f01da4 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -26,20 +26,13 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
#define HPT343_DEBUG_DRIVE_INFO 0
static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 5623cad..d0f7bb8 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -121,12 +121,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
-
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -134,7 +130,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/irq.h>
/* various tuning parameters */
#define HPT_RESET_STATE_ENGINE
@@ -1279,12 +1274,55 @@
return dev->irq;
}
+static u8 __devinit hpt3xx_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 chip_type = info->chip_type;
+ u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
+
+ /*
+ * The HPT37x uses the CBLID pins as outputs for MA15/MA16
+ * address lines to access an external EEPROM. To read valid
+ * cable detect state the pins must be enabled as inputs.
+ */
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+ /*
+ * HPT374 PCI function 1
+ * - set bit 15 of reg 0x52 to enable TCBLID as input
+ * - set bit 15 of reg 0x56 to enable FCBLID as input
+ */
+ u8 mcr_addr = hwif->select_data + 2;
+ u16 mcr;
+
+ pci_read_config_word(dev, mcr_addr, &mcr);
+ pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
+ /* now read cable id register */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ } else if (chip_type >= HPT370) {
+ /*
+ * HPT370/372 and 374 pcifn 0
+ * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
+ */
+ u8 scr2 = 0;
+
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+ /* now read cable id register */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ pci_write_config_byte(dev, 0x5b, scr2);
+ } else
+ pci_read_config_byte(dev, 0x5a, &scr1);
+
+ return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct hpt_info *info = pci_get_drvdata(dev);
int serialize = HPT_SERIALIZE_IO;
- u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
u8 chip_type = info->chip_type;
u8 new_mcr, old_mcr = 0;
@@ -1301,6 +1339,8 @@
hwif->udma_filter = &hpt3xx_udma_filter;
hwif->mdma_filter = &hpt3xx_mdma_filter;
+ hwif->cable_detect = hpt3xx_cable_detect;
+
/*
* HPT3xxN chips have some complications:
*
@@ -1346,43 +1386,6 @@
if (hwif->dma_base == 0)
return;
- /*
- * The HPT37x uses the CBLID pins as outputs for MA15/MA16
- * address lines to access an external EEPROM. To read valid
- * cable detect state the pins must be enabled as inputs.
- */
- if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
- /*
- * HPT374 PCI function 1
- * - set bit 15 of reg 0x52 to enable TCBLID as input
- * - set bit 15 of reg 0x56 to enable FCBLID as input
- */
- u8 mcr_addr = hwif->select_data + 2;
- u16 mcr;
-
- pci_read_config_word (dev, mcr_addr, &mcr);
- pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
- /* now read cable id register */
- pci_read_config_byte (dev, 0x5a, &scr1);
- pci_write_config_word(dev, mcr_addr, mcr);
- } else if (chip_type >= HPT370) {
- /*
- * HPT370/372 and 374 pcifn 0
- * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
- */
- u8 scr2 = 0;
-
- pci_read_config_byte (dev, 0x5b, &scr2);
- pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
- /* now read cable id register */
- pci_read_config_byte (dev, 0x5a, &scr1);
- pci_write_config_byte(dev, 0x5b, scr2);
- } else
- pci_read_config_byte (dev, 0x5a, &scr1);
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-
if (chip_type >= HPT374) {
hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
hwif->ide_dma_end = &hpt374_ide_dma_end;
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index df74e58..e3427ea 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -10,13 +10,10 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <asm/io.h>
-
/**
* it8213_set_pio_mode - set host controller for PIO mode
* @drive: drive
@@ -143,6 +140,16 @@
}
}
+static u8 __devinit it8213_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 reg42h = 0;
+
+ pci_read_config_byte(dev, 0x42, ®42h);
+
+ return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
/**
* init_hwif_it8213 - set up hwif structs
* @hwif: interface to set up
@@ -152,19 +159,10 @@
static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 reg42h = 0;
-
hwif->set_dma_mode = &it8213_set_dma_mode;
hwif->set_pio_mode = &it8213_set_pio_mode;
- if (!hwif->dma_base)
- return;
-
- pci_read_config_byte(dev, 0x42, ®42h);
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+ hwif->cable_detect = it8213_cable_detect;
}
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 938d35f..1597f0c 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -63,13 +63,10 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <asm/io.h>
-
struct it821x_dev
{
unsigned int smart:1, /* Are we in smart raid mode */
@@ -579,14 +576,13 @@
} else
hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
+ hwif->cable_detect = ata66_it821x;
+
if (hwif->dma_base == 0)
return;
hwif->ultra_mask = ATA_UDMA6;
hwif->mwdma_mask = ATA_MWDMA2;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_it821x(hwif);
}
static void __devinit it8212_disable_raid(struct pci_dev *dev)
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index 8b40f64..a56bcb4 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -8,13 +8,10 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <asm/io.h>
-
typedef enum {
PORT_PATA0 = 0,
PORT_PATA1 = 1,
@@ -111,11 +108,7 @@
hwif->set_pio_mode = &jmicron_set_pio_mode;
hwif->set_dma_mode = &jmicron_set_dma_mode;
- if (hwif->dma_base == 0)
- return;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_jmicron(hwif);
+ hwif->cable_detect = ata66_jmicron;
}
static const struct ide_port_info jmicron_chipset __devinitdata = {
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index fc9eee9..bf0d3b2 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -10,11 +10,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/delay.h>
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 0ce92d3..46e8748 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -87,11 +87,6 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
@@ -320,14 +315,18 @@
spin_unlock_irqrestore(&opti621_lock, flags);
}
+static void __devinit opti621_port_init_devs(ide_hwif_t *hwif)
+{
+ hwif->drives[0].drive_data = PIO_DONT_KNOW;
+ hwif->drives[1].drive_data = PIO_DONT_KNOW;
+}
+
/*
* init_hwif_opti621() is called once for each hwif found at boot.
*/
static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
{
- hwif->drives[0].drive_data = PIO_DONT_KNOW;
- hwif->drives[1].drive_data = PIO_DONT_KNOW;
-
+ hwif->port_init_devs = opti621_port_init_devs;
hwif->set_pio_mode = &opti621_set_pio_mode;
}
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index bb29db0..1c8cb77 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -19,18 +19,12 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
-#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <asm/io.h>
-#include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/prom.h>
@@ -197,7 +191,7 @@
}
}
-static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+static u8 __devinit pdcnew_cable_detect(ide_hwif_t *hwif)
{
if (get_indexed_reg(hwif, 0x0b) & 0x04)
return ATA_CBL_PATA40;
@@ -456,11 +450,7 @@
hwif->quirkproc = &pdcnew_quirkproc;
hwif->resetproc = &pdcnew_reset;
- if (hwif->dma_base == 0)
- return;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = pdcnew_cable_detect(hwif);
+ hwif->cable_detect = pdcnew_cable_detect;
}
static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 31a13084..da43297 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -32,18 +32,13 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
-#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <asm/io.h>
-#include <asm/irq.h>
#define PDC202XX_DEBUG_DRIVE_INFO 0
@@ -140,10 +135,10 @@
pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
}
-static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+static u8 __devinit pdc2026x_old_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+ u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
pci_read_config_word(dev, 0x50, &CIS);
@@ -311,9 +306,12 @@
hwif->quirkproc = &pdc202xx_quirkproc;
- if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
+ if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
hwif->resetproc = &pdc202xx_reset;
+ hwif->cable_detect = pdc2026x_old_cable_detect;
+ }
+
if (hwif->dma_base == 0)
return;
@@ -321,9 +319,6 @@
hwif->dma_timeout = &pdc202xx_dma_timeout;
if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = pdc202xx_old_cable_detect(hwif);
-
hwif->dma_start = &pdc202xx_old_ide_dma_start;
hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index c1a6b683..decef0f 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -47,11 +47,9 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -290,14 +288,11 @@
hwif->set_pio_mode = &piix_set_pio_mode;
hwif->set_dma_mode = &piix_set_dma_mode;
+ hwif->cable_detect = piix_cable_detect;
+
if (!hwif->dma_base)
return;
- if (hwif->ultra_mask & 0x78) {
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = piix_cable_detect(hwif);
- }
-
if (no_piix_dma)
hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
}
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 7ed6625..5167661 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -16,18 +16,11 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <asm/io.h>
-
static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -40,8 +33,7 @@
} else {
if (hwif->mate)
hwif->mate->serialized = hwif->serialized = 1;
- hwif->drives[0].no_unmask = 1;
- hwif->drives[1].no_unmask = 1;
+ hwif->host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
printk(KERN_INFO "%s: serialized, disabled unmasking "
"(buggy RZ1000/RZ1001)\n", hwif->name);
}
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index af499a6..561aa47 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -14,19 +14,13 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
-#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/pm.h>
+
#include <asm/io.h>
-#include <asm/irq.h>
#define SC1200_REV_A 0x00
#define SC1200_REV_B1 0x01
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index 7694969..238e3e1 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -644,6 +644,11 @@
init_mmio_iops_scc(hwif);
}
+static u8 __devinit scc_cable_detect(ide_hwif_t *hwif)
+{
+ return ATA_CBL_PATA80;
+}
+
/**
* init_hwif_scc - set up hwif
* @hwif: interface to set up
@@ -678,8 +683,7 @@
else
hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
- /* we support 80c cable only. */
- hwif->cbl = ATA_CBL_PATA80;
+ hwif->cable_detect = scc_cable_detect;
}
#define DECLARE_SCC_DEV(name_str) \
@@ -732,7 +736,7 @@
hwif->dmatable_cpu = NULL;
}
- ide_unregister(hwif->index);
+ ide_unregister(hwif->index, 0, 0);
hwif->chipset = ide_unknown;
iounmap((void*)ports->dma);
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index f495253..c11880b 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -31,12 +31,10 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <asm/io.h>
@@ -346,13 +344,8 @@
hwif->set_dma_mode = &svwks_set_dma_mode;
hwif->udma_filter = &svwks_udma_filter;
- if (!hwif->dma_base)
- return;
-
- if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_svwks(hwif);
- }
+ if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+ hwif->cable_detect = ata66_svwks;
}
#define IDE_HFLAGS_SVWKS \
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 8590207..0546264 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -25,8 +25,6 @@
#include <linux/hdreg.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
@@ -555,7 +553,6 @@
ide_init_sgiioc4(ide_hwif_t * hwif)
{
hwif->mmio = 1;
- hwif->pio_mask = 0x00;
hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
hwif->set_dma_mode = &sgiioc4_set_dma_mode;
hwif->selectproc = NULL;/* Use the default routine to select drive */
@@ -572,8 +569,6 @@
if (hwif->dma_base == 0)
return;
- hwif->mwdma_mask = ATA_MWDMA2_ONLY;
-
hwif->dma_host_set = &sgiioc4_dma_host_set;
hwif->dma_setup = &sgiioc4_ide_dma_setup;
hwif->dma_start = &sgiioc4_ide_dma_start;
@@ -583,6 +578,13 @@
hwif->dma_timeout = &ide_dma_timeout;
}
+static const struct ide_port_info sgiioc4_port_info __devinitdata = {
+ .chipset = ide_pci,
+ .host_flags = IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+ IDE_HFLAG_NO_AUTOTUNE,
+ .mwdma_mask = ATA_MWDMA2_ONLY,
+};
+
static int __devinit
sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
{
@@ -593,6 +595,7 @@
int h;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
hw_regs_t hw;
+ struct ide_port_info d = sgiioc4_port_info;
/*
* Find an empty HWIF; if none available, return -ENOMEM.
@@ -641,7 +644,6 @@
ide_init_port_hw(hwif, &hw);
hwif->dev = &dev->dev;
- hwif->channel = 0; /* Single Channel chip */
/* The IOC4 uses MMIO rather than Port IO. */
default_hwif_mmiops(hwif);
@@ -649,15 +651,17 @@
/* Initializing chipset IRQ Registers */
writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
- if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base))
+ if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base)) {
printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
hwif->name, DRV_NAME);
+ d.mwdma_mask = 0;
+ }
ide_init_sgiioc4(hwif);
idx[0] = hwif->index;
- if (ide_device_add(idx))
+ if (ide_device_add(idx, &d))
return -EIO;
return 0;
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 4877bc8..cc4be96 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -39,7 +39,6 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
@@ -332,15 +331,18 @@
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long addr = siimage_selreg(hwif, 0x1);
+ void __iomem *sata_error_addr
+ = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET];
- if (SATA_ERROR_REG) {
+ if (sata_error_addr) {
unsigned long base = (unsigned long)hwif->hwif_data;
-
u32 ext_stat = readl((void __iomem *)(base + 0x10));
u8 watchdog = 0;
+
if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
- u32 sata_error = readl((void __iomem *)SATA_ERROR_REG);
- writel(sata_error, (void __iomem *)SATA_ERROR_REG);
+ u32 sata_error = readl(sata_error_addr);
+
+ writel(sata_error, sata_error_addr);
watchdog = (sata_error & 0x00680000) ? 1 : 0;
printk(KERN_WARNING "%s: sata_error = 0x%08x, "
"watchdog = %d, %s\n",
@@ -419,13 +421,17 @@
static int sil_sata_reset_poll(ide_drive_t *drive)
{
- if (SATA_STATUS_REG) {
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
+ void __iomem *sata_status_addr
+ = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET];
- /* SATA_STATUS_REG is valid only when in MMIO mode */
- if ((readl((void __iomem *)SATA_STATUS_REG) & 0x03) != 0x03) {
+ if (sata_status_addr) {
+ /* SATA Status is available only when in MMIO mode */
+ u32 sata_stat = readl(sata_status_addr);
+
+ if ((sata_stat & 0x03) != 0x03) {
printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
- hwif->name, readl((void __iomem *)SATA_STATUS_REG));
+ hwif->name, sata_stat);
HWGROUP(drive)->polling = 0;
return ide_started;
}
@@ -698,9 +704,6 @@
hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104;
hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108;
hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100;
- hwif->sata_misc[SATA_MISC_OFFSET] = base + 0x140;
- hwif->sata_misc[SATA_PHY_OFFSET] = base + 0x144;
- hwif->sata_misc[SATA_IEN_OFFSET] = base + 0x148;
}
memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
@@ -827,15 +830,14 @@
} else
hwif->udma_filter = &sil_pata_udma_filter;
+ hwif->cable_detect = ata66_siimage;
+
if (hwif->dma_base == 0)
return;
if (sata)
hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_siimage(hwif);
-
if (hwif->mmio) {
hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
} else {
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 2a461de..512bb4c 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -47,20 +47,11 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
-#include <asm/irq.h>
-
#include "ide-timing.h"
/* registers layout and init values are chipset family dependant */
@@ -565,13 +556,12 @@
if (chipset_family >= ATA_133)
hwif->udma_filter = sis5513_ata133_udma_filter;
+ hwif->cable_detect = ata66_sis5513;
+
if (hwif->dma_base == 0)
return;
hwif->ultra_mask = udma_rates[chipset_family];
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_sis5513(hwif);
}
static const struct ide_port_info sis5513_chipset __devinitdata = {
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index da13a12..ee261ae 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -17,17 +17,11 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <asm/io.h>
-#include <asm/dma.h>
#undef DEBUG
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index a6cf810..65f4c2f 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -10,15 +10,11 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
-#include <linux/delay.h>
#include <linux/init.h>
-#include <asm/io.h>
-
static DEFINE_SPINLOCK(slc90e66_lock);
static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
@@ -118,23 +114,23 @@
}
}
-static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
+static u8 __devinit slc90e66_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 reg47 = 0;
- u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */
-
- hwif->set_pio_mode = &slc90e66_set_pio_mode;
- hwif->set_dma_mode = &slc90e66_set_dma_mode;
+ u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02;
pci_read_config_byte(dev, 0x47, ®47);
- if (hwif->dma_base == 0)
- return;
+ /* bit[0(1)]: 0:80, 1:40 */
+ return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- /* bit[0(1)]: 0:80, 1:40 */
- hwif->cbl = (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+static void __devinit init_hwif_slc90e66(ide_hwif_t *hwif)
+{
+ hwif->set_pio_mode = &slc90e66_set_pio_mode;
+ hwif->set_dma_mode = &slc90e66_set_dma_mode;
+
+ hwif->cable_detect = slc90e66_cable_detect;
}
static const struct ide_port_info slc90e66_chipset __devinitdata = {
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 9fbbb4f..2ef2ed2 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -160,6 +160,19 @@
return 0;
}
+static u8 __devinit tc86c001_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long sc_base = pci_resource_start(dev, 5);
+ u16 scr1 = inw(sc_base + 0x00);
+
+ /*
+ * System Control 1 Register bit 13 (PDIAGN):
+ * 0=80-pin cable, 1=40-pin cable
+ */
+ return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -183,6 +196,8 @@
hwif->busproc = &tc86c001_busproc;
+ hwif->cable_detect = tc86c001_cable_detect;
+
if (!hwif->dma_base)
return;
@@ -196,15 +211,6 @@
hwif->rqsize = 0xffff;
hwif->dma_start = &tc86c001_dma_start;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
- /*
- * System Control 1 Register bit 13 (PDIAGN):
- * 0=80-pin cable, 1=40-pin cable
- */
- scr1 = inw(sc_base + 0x00);
- hwif->cbl = (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
- }
}
static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 852b726..a67d02a3 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -28,11 +28,6 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/ide.h>
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index d9ebb69..de750f7 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -131,14 +131,12 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/ide.h>
#include <asm/io.h>
@@ -179,10 +177,7 @@
static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
{
- BUG_ON(HWGROUP(drive)->handler != NULL); /* paranoia check */
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
- /* issue cmd to drive */
- outb(command, IDE_COMMAND_REG);
+ ide_execute_command(drive, command, &ide_dma_intr, WAIT_CMD, NULL);
}
static int trm290_dma_setup(ide_drive_t *drive)
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 24cb904..f3f79f8 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -26,15 +26,11 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/dmi.h>
-#include <asm/io.h>
-
#ifdef CONFIG_PPC_CHRP
#include <asm/processor.h>
#endif
@@ -424,11 +420,7 @@
hwif->set_pio_mode = &via_set_pio_mode;
hwif->set_dma_mode = &via_set_drive;
- if (!hwif->dma_base)
- return;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = via82cxxx_cable_detect(hwif);
+ hwif->cable_detect = via82cxxx_cable_detect;
}
static const struct ide_port_info via82cxxx_chipset __devinitdata = {
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 45c1d55..06190b1 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -848,7 +848,7 @@
#endif
#endif
- ide_device_add(idx);
+ ide_device_add(idx, NULL);
return 0;
}
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 23112ef..12ac3bf 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -412,7 +412,7 @@
*/
#define IDE_WAKEUP_DELAY (1*HZ)
-static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
+static int pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
static void pmac_ide_selectproc(ide_drive_t *drive);
static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
@@ -1003,6 +1003,17 @@
return 0;
}
+static const struct ide_port_info pmac_port_info = {
+ .chipset = ide_pmac,
+ .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
+ IDE_HFLAG_PIO_NO_DOWNGRADE |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+ IDE_HFLAG_UNMASK_IRQS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
/*
* Setup, register & probe an IDE channel driven by this driver, this is
* called by one of the 2 probe functions (macio or PCI). Note that a channel
@@ -1016,23 +1027,28 @@
struct device_node *np = pmif->node;
const int *bidp;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ struct ide_port_info d = pmac_port_info;
pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
- if (of_device_is_compatible(np, "shasta-ata"))
+ if (of_device_is_compatible(np, "shasta-ata")) {
pmif->kind = controller_sh_ata6;
- else if (of_device_is_compatible(np, "kauai-ata"))
+ d.udma_mask = ATA_UDMA6;
+ } else if (of_device_is_compatible(np, "kauai-ata")) {
pmif->kind = controller_un_ata6;
- else if (of_device_is_compatible(np, "K2-UATA"))
+ d.udma_mask = ATA_UDMA5;
+ } else if (of_device_is_compatible(np, "K2-UATA")) {
pmif->kind = controller_k2_ata6;
- else if (of_device_is_compatible(np, "keylargo-ata")) {
- if (strcmp(np->name, "ata-4") == 0)
+ d.udma_mask = ATA_UDMA5;
+ } else if (of_device_is_compatible(np, "keylargo-ata")) {
+ if (strcmp(np->name, "ata-4") == 0) {
pmif->kind = controller_kl_ata4;
- else
+ d.udma_mask = ATA_UDMA4;
+ } else
pmif->kind = controller_kl_ata3;
- } else if (of_device_is_compatible(np, "heathrow-ata"))
+ } else if (of_device_is_compatible(np, "heathrow-ata")) {
pmif->kind = controller_heathrow;
- else {
+ } else {
pmif->kind = controller_ohare;
pmif->broken_dma = 1;
}
@@ -1101,19 +1117,10 @@
/* Tell common code _not_ to mess with resources */
hwif->mmio = 1;
hwif->hwif_data = pmif;
- hw->chipset = ide_pmac;
ide_init_port_hw(hwif, hw);
hwif->noprobe = pmif->mediabay;
hwif->hold = pmif->mediabay;
hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
- hwif->drives[0].unmask = 1;
- hwif->drives[1].unmask = 1;
- hwif->drives[0].autotune = IDE_TUNE_AUTO;
- hwif->drives[1].autotune = IDE_TUNE_AUTO;
- hwif->host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
- IDE_HFLAG_PIO_NO_DOWNGRADE |
- IDE_HFLAG_POST_SET_MODE;
- hwif->pio_mask = ATA_PIO4;
hwif->set_pio_mode = pmac_ide_set_pio_mode;
if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6
@@ -1133,14 +1140,16 @@
#endif /* CONFIG_PMAC_MEDIABAY */
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ if (pmif->cable_80 == 0)
+ d.udma_mask &= ATA_UDMA2;
/* has a DBDMA controller channel */
- if (pmif->dma_regs)
- pmac_ide_setup_dma(pmif, hwif);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+ if (pmif->dma_regs == 0 || pmac_ide_setup_dma(pmif, hwif) < 0)
+#endif
+ d.udma_mask = d.mwdma_mask = 0;
idx[0] = hwif->index;
- ide_device_add(idx);
+ ide_device_add(idx, &d);
return 0;
}
@@ -1721,8 +1730,7 @@
* Allocate the data structures needed for using DMA with an interface
* and fill the proper list of functions pointers
*/
-static void __devinit
-pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+static int __devinit pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -1730,7 +1738,7 @@
* DMA routines ...
*/
if (dev == NULL)
- return;
+ return -ENODEV;
/*
* Allocate space for the DBDMA commands.
* The +2 is +1 for the stop command and +1 to allow for
@@ -1743,7 +1751,7 @@
if (pmif->dma_table_cpu == NULL) {
printk(KERN_ERR "%s: unable to allocate DMA command list\n",
hwif->name);
- return;
+ return -ENOMEM;
}
hwif->sg_max_nents = MAX_DCMDS;
@@ -1757,29 +1765,7 @@
hwif->dma_timeout = &ide_dma_timeout;
hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
- switch(pmif->kind) {
- case controller_sh_ata6:
- hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x00;
- break;
- case controller_un_ata6:
- case controller_k2_ata6:
- hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x00;
- break;
- case controller_kl_ata4:
- hwif->ultra_mask = pmif->cable_80 ? 0x1f : 0x07;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x00;
- break;
- default:
- hwif->ultra_mask = 0x00;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x00;
- break;
- }
+ return 0;
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 8ff5a0e..634e3f6 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -228,7 +228,9 @@
* @d: IDE port info
*
* Enable the IDE PCI device. We attempt to enable the device in full
- * but if that fails then we only need BAR4 so we will enable that.
+ * but if that fails then we only need IO space. The PCI code should
+ * have setup the proper resources for us already for controllers in
+ * legacy mode.
*
* Returns zero on success or an error code
*/
@@ -238,7 +240,7 @@
int ret;
if (pci_enable_device(dev)) {
- ret = pci_enable_device_bars(dev, 1 << 4);
+ ret = pci_enable_device_io(dev);
if (ret < 0) {
printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
"Could not enable device.\n", d->name);
@@ -337,7 +339,8 @@
* ide_hwif_configure - configure an IDE interface
* @dev: PCI device holding interface
* @d: IDE port info
- * @mate: Paired interface if any
+ * @port: port number
+ * @irq: PCI IRQ
*
* Perform the initial set up for the hardware interface structure. This
* is done per interface port rather than per PCI device. There may be
@@ -346,7 +349,9 @@
* Returns the new hardware interface structure, or NULL on a failure
*/
-static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port_info *d, ide_hwif_t *mate, int port, int irq)
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev,
+ const struct ide_port_info *d,
+ unsigned int port, int irq)
{
unsigned long ctl = 0, base = 0;
ide_hwif_t *hwif;
@@ -392,29 +397,24 @@
hwif->dev = &dev->dev;
hwif->cds = d;
- hwif->channel = port;
- if (mate) {
- hwif->mate = mate;
- mate->mate = hwif;
- }
return hwif;
}
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
/**
* ide_hwif_setup_dma - configure DMA interface
- * @dev: PCI device
- * @d: IDE port info
* @hwif: IDE interface
+ * @d: IDE port info
*
* Set up the DMA base for the interface. Enable the master bits as
* necessary and attempt to bring the device DMA into a ready to use
* state
*/
-static void ide_hwif_setup_dma(struct pci_dev *dev, const struct ide_port_info *d, ide_hwif_t *hwif)
+void ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
{
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
u16 pcicmd;
pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
@@ -446,8 +446,8 @@
"(BIOS)\n", hwif->name, d->name);
}
}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI*/
}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
/**
* ide_setup_pci_controller - set up IDE PCI
@@ -509,7 +509,7 @@
void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int pciirq, u8 *idx)
{
int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
- ide_hwif_t *hwif, *mate = NULL;
+ ide_hwif_t *hwif;
u8 tmp;
/*
@@ -525,56 +525,11 @@
continue; /* port not enabled */
}
- if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+ hwif = ide_hwif_configure(dev, d, port, pciirq);
+ if (hwif == NULL)
continue;
*(idx + port) = hwif->index;
-
- if (d->init_iops)
- d->init_iops(hwif);
-
- if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0)
- ide_hwif_setup_dma(dev, d, hwif);
-
- if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
- (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
- hwif->irq = port ? 15 : 14;
-
- hwif->host_flags = d->host_flags;
- hwif->pio_mask = d->pio_mask;
-
- if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate)
- hwif->mate->serialized = hwif->serialized = 1;
-
- if (d->host_flags & IDE_HFLAG_IO_32BIT) {
- hwif->drives[0].io_32bit = 1;
- hwif->drives[1].io_32bit = 1;
- }
-
- if (d->host_flags & IDE_HFLAG_UNMASK_IRQS) {
- hwif->drives[0].unmask = 1;
- hwif->drives[1].unmask = 1;
- }
-
- if (hwif->dma_base) {
- hwif->swdma_mask = d->swdma_mask;
- hwif->mwdma_mask = d->mwdma_mask;
- hwif->ultra_mask = d->udma_mask;
- }
-
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
-
- if (d->host_flags & IDE_HFLAG_RQSIZE_256)
- hwif->rqsize = 256;
-
- if (d->init_hwif)
- /* Call chipset-specific routine
- * for each enabled hwif
- */
- d->init_hwif(hwif);
-
- mate = hwif;
}
}
@@ -656,7 +611,7 @@
ret = do_ide_setup_pci_device(dev, d, &idx[0], 1);
if (ret >= 0)
- ide_device_add(idx);
+ ide_device_add(idx, d);
return ret;
}
@@ -680,7 +635,7 @@
goto out;
}
- ide_device_add(idx);
+ ide_device_add(idx, d);
out:
return ret;
}
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 2b889d9..28e155a 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1465,10 +1465,9 @@
orb->misc |= ORB_SET_DIRECTION(orb_direction);
/* special case if only one element (and less than 64KB in size) */
- if ((scsi_use_sg == 1) &&
- (sg_dma_len(sg) <= SBP2_MAX_SG_ELEMENT_LENGTH)) {
+ if (scsi_use_sg == 1 && sg->length <= SBP2_MAX_SG_ELEMENT_LENGTH) {
- cmd->dma_size = sg_dma_len(sg);
+ cmd->dma_size = sg->length;
cmd->dma_type = CMD_DMA_PAGE;
cmd->cmd_dma = dma_map_page(hi->host->device.parent,
sg_page(sg), sg->offset,
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index a193dfb..a5dc78a 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -44,8 +44,8 @@
source "drivers/infiniband/hw/ehca/Kconfig"
source "drivers/infiniband/hw/amso1100/Kconfig"
source "drivers/infiniband/hw/cxgb3/Kconfig"
-
source "drivers/infiniband/hw/mlx4/Kconfig"
+source "drivers/infiniband/hw/nes/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index 75f325e4..ed35e44 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/
obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/
+obj-$(CONFIG_INFINIBAND_NES) += hw/nes/
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index c015014..638b727 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -974,6 +974,9 @@
struct cm_id_private *cm_id_priv,
struct ib_cm_req_param *param)
{
+ struct ib_sa_path_rec *pri_path = param->primary_path;
+ struct ib_sa_path_rec *alt_path = param->alternate_path;
+
cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID,
cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));
@@ -997,35 +1000,46 @@
cm_req_set_max_cm_retries(req_msg, param->max_cm_retries);
cm_req_set_srq(req_msg, param->srq);
- req_msg->primary_local_lid = param->primary_path->slid;
- req_msg->primary_remote_lid = param->primary_path->dlid;
- req_msg->primary_local_gid = param->primary_path->sgid;
- req_msg->primary_remote_gid = param->primary_path->dgid;
- cm_req_set_primary_flow_label(req_msg, param->primary_path->flow_label);
- cm_req_set_primary_packet_rate(req_msg, param->primary_path->rate);
- req_msg->primary_traffic_class = param->primary_path->traffic_class;
- req_msg->primary_hop_limit = param->primary_path->hop_limit;
- cm_req_set_primary_sl(req_msg, param->primary_path->sl);
- cm_req_set_primary_subnet_local(req_msg, 1); /* local only... */
+ if (pri_path->hop_limit <= 1) {
+ req_msg->primary_local_lid = pri_path->slid;
+ req_msg->primary_remote_lid = pri_path->dlid;
+ } else {
+ /* Work-around until there's a way to obtain remote LID info */
+ req_msg->primary_local_lid = IB_LID_PERMISSIVE;
+ req_msg->primary_remote_lid = IB_LID_PERMISSIVE;
+ }
+ req_msg->primary_local_gid = pri_path->sgid;
+ req_msg->primary_remote_gid = pri_path->dgid;
+ cm_req_set_primary_flow_label(req_msg, pri_path->flow_label);
+ cm_req_set_primary_packet_rate(req_msg, pri_path->rate);
+ req_msg->primary_traffic_class = pri_path->traffic_class;
+ req_msg->primary_hop_limit = pri_path->hop_limit;
+ cm_req_set_primary_sl(req_msg, pri_path->sl);
+ cm_req_set_primary_subnet_local(req_msg, (pri_path->hop_limit <= 1));
cm_req_set_primary_local_ack_timeout(req_msg,
cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
- param->primary_path->packet_life_time));
+ pri_path->packet_life_time));
- if (param->alternate_path) {
- req_msg->alt_local_lid = param->alternate_path->slid;
- req_msg->alt_remote_lid = param->alternate_path->dlid;
- req_msg->alt_local_gid = param->alternate_path->sgid;
- req_msg->alt_remote_gid = param->alternate_path->dgid;
+ if (alt_path) {
+ if (alt_path->hop_limit <= 1) {
+ req_msg->alt_local_lid = alt_path->slid;
+ req_msg->alt_remote_lid = alt_path->dlid;
+ } else {
+ req_msg->alt_local_lid = IB_LID_PERMISSIVE;
+ req_msg->alt_remote_lid = IB_LID_PERMISSIVE;
+ }
+ req_msg->alt_local_gid = alt_path->sgid;
+ req_msg->alt_remote_gid = alt_path->dgid;
cm_req_set_alt_flow_label(req_msg,
- param->alternate_path->flow_label);
- cm_req_set_alt_packet_rate(req_msg, param->alternate_path->rate);
- req_msg->alt_traffic_class = param->alternate_path->traffic_class;
- req_msg->alt_hop_limit = param->alternate_path->hop_limit;
- cm_req_set_alt_sl(req_msg, param->alternate_path->sl);
- cm_req_set_alt_subnet_local(req_msg, 1); /* local only... */
+ alt_path->flow_label);
+ cm_req_set_alt_packet_rate(req_msg, alt_path->rate);
+ req_msg->alt_traffic_class = alt_path->traffic_class;
+ req_msg->alt_hop_limit = alt_path->hop_limit;
+ cm_req_set_alt_sl(req_msg, alt_path->sl);
+ cm_req_set_alt_subnet_local(req_msg, (alt_path->hop_limit <= 1));
cm_req_set_alt_local_ack_timeout(req_msg,
cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
- param->alternate_path->packet_life_time));
+ alt_path->packet_life_time));
}
if (param->private_data && param->private_data_len)
@@ -1441,6 +1455,34 @@
return listen_cm_id_priv;
}
+/*
+ * Work-around for inter-subnet connections. If the LIDs are permissive,
+ * we need to override the LID/SL data in the REQ with the LID information
+ * in the work completion.
+ */
+static void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc)
+{
+ if (!cm_req_get_primary_subnet_local(req_msg)) {
+ if (req_msg->primary_local_lid == IB_LID_PERMISSIVE) {
+ req_msg->primary_local_lid = cpu_to_be16(wc->slid);
+ cm_req_set_primary_sl(req_msg, wc->sl);
+ }
+
+ if (req_msg->primary_remote_lid == IB_LID_PERMISSIVE)
+ req_msg->primary_remote_lid = cpu_to_be16(wc->dlid_path_bits);
+ }
+
+ if (!cm_req_get_alt_subnet_local(req_msg)) {
+ if (req_msg->alt_local_lid == IB_LID_PERMISSIVE) {
+ req_msg->alt_local_lid = cpu_to_be16(wc->slid);
+ cm_req_set_alt_sl(req_msg, wc->sl);
+ }
+
+ if (req_msg->alt_remote_lid == IB_LID_PERMISSIVE)
+ req_msg->alt_remote_lid = cpu_to_be16(wc->dlid_path_bits);
+ }
+}
+
static int cm_req_handler(struct cm_work *work)
{
struct ib_cm_id *cm_id;
@@ -1481,6 +1523,7 @@
cm_id_priv->id.service_id = req_msg->service_id;
cm_id_priv->id.service_mask = __constant_cpu_to_be64(~0ULL);
+ cm_process_routed_req(req_msg, work->mad_recv_wc->wc);
cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
if (ret) {
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 6c7aa59..7f00347 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -320,10 +320,13 @@
.max_maps = pool->max_remaps,
.page_shift = params->page_shift
};
+ int bytes_per_fmr = sizeof *fmr;
+
+ if (pool->cache_bucket)
+ bytes_per_fmr += params->max_pages_per_fmr * sizeof (u64);
for (i = 0; i < params->pool_size; ++i) {
- fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64),
- GFP_KERNEL);
+ fmr = kmalloc(bytes_per_fmr, GFP_KERNEL);
if (!fmr) {
printk(KERN_WARNING PFX "failed to allocate fmr "
"struct for FMR %d\n", i);
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index f281d16..92cce8a 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -101,6 +101,7 @@
spinlock_t mod_sqp_lock;
enum ib_port_state port_state;
struct ehca_sma_attr saved_attr;
+ u32 pma_qp_nr;
};
#define HCA_CAP_MR_PGSIZE_4K 0x80000000
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 863b34f..b5ca94c 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -403,6 +403,8 @@
sport->port_state = IB_PORT_ACTIVE;
dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
"is active");
+ ehca_query_sma_attr(shca, port,
+ &sport->saved_attr);
} else
notify_port_conf_change(shca, port);
break;
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index c469bfd..a8a2ea5 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -187,6 +187,11 @@
int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+ struct ib_wc *in_wc, struct ib_grh *in_grh,
+ struct ib_mad *in_mad,
+ struct ib_mad *out_mad);
+
void ehca_poll_eqs(unsigned long data);
int ehca_calc_ipd(struct ehca_shca *shca, int port,
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 84c9b7b..a86ebcc 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -472,7 +472,7 @@
shca->ib_device.dealloc_fmr = ehca_dealloc_fmr;
shca->ib_device.attach_mcast = ehca_attach_mcast;
shca->ib_device.detach_mcast = ehca_detach_mcast;
- /* shca->ib_device.process_mad = ehca_process_mad; */
+ shca->ib_device.process_mad = ehca_process_mad;
shca->ib_device.mmap = ehca_mmap;
if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 3aacc8c..2ce8cff 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -209,6 +209,10 @@
ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
return -EINVAL;
}
+ if (unlikely(send_wr->wr.ud.remote_qpn == 0)) {
+ ehca_gen_err("dest QP# is 0. qp=%x", qp->real_qp_num);
+ return -EINVAL;
+ }
my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah);
wqe_p->u.ud_av.ud_av = my_av->av;
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index 79e72b2..706d97a 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -39,12 +39,18 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <rdma/ib_mad.h>
#include "ehca_classes.h"
#include "ehca_tools.h"
#include "ehca_iverbs.h"
#include "hcp_if.h"
+#define IB_MAD_STATUS_REDIRECT __constant_htons(0x0002)
+#define IB_MAD_STATUS_UNSUP_VERSION __constant_htons(0x0004)
+#define IB_MAD_STATUS_UNSUP_METHOD __constant_htons(0x0008)
+
+#define IB_PMA_CLASS_PORT_INFO __constant_htons(0x0001)
/**
* ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue
@@ -83,6 +89,9 @@
port, ret);
return ret;
}
+ shca->sport[port - 1].pma_qp_nr = pma_qp_nr;
+ ehca_dbg(&shca->ib_device, "port=%x pma_qp_nr=%x",
+ port, pma_qp_nr);
break;
default:
ehca_err(&shca->ib_device, "invalid qp_type=%x",
@@ -109,3 +118,85 @@
return H_SUCCESS;
}
+
+struct ib_perf {
+ struct ib_mad_hdr mad_hdr;
+ u8 reserved[40];
+ u8 data[192];
+} __attribute__ ((packed));
+
+
+static int ehca_process_perf(struct ib_device *ibdev, u8 port_num,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ struct ib_perf *in_perf = (struct ib_perf *)in_mad;
+ struct ib_perf *out_perf = (struct ib_perf *)out_mad;
+ struct ib_class_port_info *poi =
+ (struct ib_class_port_info *)out_perf->data;
+ struct ehca_shca *shca =
+ container_of(ibdev, struct ehca_shca, ib_device);
+ struct ehca_sport *sport = &shca->sport[port_num - 1];
+
+ ehca_dbg(ibdev, "method=%x", in_perf->mad_hdr.method);
+
+ *out_mad = *in_mad;
+
+ if (in_perf->mad_hdr.class_version != 1) {
+ ehca_warn(ibdev, "Unsupported class_version=%x",
+ in_perf->mad_hdr.class_version);
+ out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_VERSION;
+ goto perf_reply;
+ }
+
+ switch (in_perf->mad_hdr.method) {
+ case IB_MGMT_METHOD_GET:
+ case IB_MGMT_METHOD_SET:
+ /* set class port info for redirection */
+ out_perf->mad_hdr.attr_id = IB_PMA_CLASS_PORT_INFO;
+ out_perf->mad_hdr.status = IB_MAD_STATUS_REDIRECT;
+ memset(poi, 0, sizeof(*poi));
+ poi->base_version = 1;
+ poi->class_version = 1;
+ poi->resp_time_value = 18;
+ poi->redirect_lid = sport->saved_attr.lid;
+ poi->redirect_qp = sport->pma_qp_nr;
+ poi->redirect_qkey = IB_QP1_QKEY;
+ poi->redirect_pkey = IB_DEFAULT_PKEY_FULL;
+
+ ehca_dbg(ibdev, "ehca_pma_lid=%x ehca_pma_qp=%x",
+ sport->saved_attr.lid, sport->pma_qp_nr);
+ break;
+
+ case IB_MGMT_METHOD_GET_RESP:
+ return IB_MAD_RESULT_FAILURE;
+
+ default:
+ out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_METHOD;
+ break;
+ }
+
+perf_reply:
+ out_perf->mad_hdr.method = IB_MGMT_METHOD_GET_RESP;
+
+ return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+}
+
+int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+ struct ib_wc *in_wc, struct ib_grh *in_grh,
+ struct ib_mad *in_mad,
+ struct ib_mad *out_mad)
+{
+ int ret;
+
+ if (!port_num || port_num > ibdev->phys_port_cnt)
+ return IB_MAD_RESULT_FAILURE;
+
+ /* accept only pma request */
+ if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
+ return IB_MAD_RESULT_SUCCESS;
+
+ ehca_dbg(ibdev, "port_num=%x src_qp=%x", port_num, in_wc->src_qp);
+ ret = ehca_process_perf(ibdev, port_num, in_mad, out_mad);
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index d8287d9..96a39b5 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -52,7 +52,7 @@
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
-static const char mlx4_ib_version[] __devinitdata =
+static const char mlx4_ib_version[] =
DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -468,6 +468,7 @@
if (err)
goto out;
+ dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
out:
@@ -516,9 +517,16 @@
static void *mlx4_ib_add(struct mlx4_dev *dev)
{
+ static int mlx4_ib_version_printed;
struct mlx4_ib_dev *ibdev;
int i;
+
+ if (!mlx4_ib_version_printed) {
+ printk(KERN_INFO "%s", mlx4_ib_version);
+ ++mlx4_ib_version_printed;
+ }
+
ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
if (!ibdev) {
dev_err(&dev->pdev->dev, "Device struct alloc failed\n");
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 6966f94..09a30dd 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1255,9 +1255,14 @@
if (err)
goto out;
- MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
- MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
- MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
+ if (!mthca_is_memfree(dev)) {
+ MTHCA_GET(adapter->vendor_id, outbox,
+ QUERY_ADAPTER_VENDOR_ID_OFFSET);
+ MTHCA_GET(adapter->device_id, outbox,
+ QUERY_ADAPTER_DEVICE_ID_OFFSET);
+ MTHCA_GET(adapter->revision_id, outbox,
+ QUERY_ADAPTER_REVISION_ID_OFFSET);
+ }
MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 5cf8250..cd3d8ad 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -126,7 +126,7 @@
MODULE_PARM_DESC(fmr_reserved_mtts,
"number of memory translation table segments reserved for FMR");
-static const char mthca_version[] __devinitdata =
+static char mthca_version[] __devinitdata =
DRV_NAME ": Mellanox InfiniBand HCA driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -735,7 +735,8 @@
}
mdev->eq_table.inta_pin = adapter.inta_pin;
- mdev->rev_id = adapter.revision_id;
+ if (!mthca_is_memfree(mdev))
+ mdev->rev_id = adapter.revision_id;
memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);
return 0;
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index aa6c70a..3b69855 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -613,8 +613,10 @@
sizeof *(mr->mem.tavor.mpt) * idx;
mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
- if (IS_ERR(mr->mtt))
+ if (IS_ERR(mr->mtt)) {
+ err = PTR_ERR(mr->mtt);
goto err_out_table;
+ }
mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
@@ -627,8 +629,10 @@
mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
- if (IS_ERR(mailbox))
+ if (IS_ERR(mailbox)) {
+ err = PTR_ERR(mailbox);
goto err_out_free_mtt;
+ }
mpt_entry = mailbox->buf;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 6bcde1c..9e491df 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -923,17 +923,13 @@
struct mthca_mr *mr;
u64 *page_list;
u64 total_size;
- u64 mask;
+ unsigned long mask;
int shift;
int npages;
int err;
int i, j, n;
- /* First check that we have enough alignment */
- if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK))
- return ERR_PTR(-EINVAL);
-
- mask = 0;
+ mask = buffer_list[0].addr ^ *iova_start;
total_size = 0;
for (i = 0; i < num_phys_buf; ++i) {
if (i != 0)
@@ -947,17 +943,7 @@
if (mask & ~PAGE_MASK)
return ERR_PTR(-EINVAL);
- /* Find largest page shift we can use to cover buffers */
- for (shift = PAGE_SHIFT; shift < 31; ++shift)
- if (num_phys_buf > 1) {
- if ((1ULL << shift) & mask)
- break;
- } else {
- if (1ULL << shift >=
- buffer_list[0].size +
- (buffer_list[0].addr & ((1ULL << shift) - 1)))
- break;
- }
+ shift = __ffs(mask | 1 << 31);
buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1);
buffer_list[0].addr &= ~0ull << shift;
@@ -1270,6 +1256,8 @@
goto out;
}
+ if (mthca_is_memfree(dev))
+ dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
out:
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 0e5461c..db5595b 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1175,6 +1175,7 @@
{
int ret;
int i;
+ struct mthca_next_seg *next;
qp->refcount = 1;
init_waitqueue_head(&qp->wait);
@@ -1217,7 +1218,6 @@
}
if (mthca_is_memfree(dev)) {
- struct mthca_next_seg *next;
struct mthca_data_seg *scatter;
int size = (sizeof (struct mthca_next_seg) +
qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16;
@@ -1240,6 +1240,13 @@
qp->sq.wqe_shift) +
qp->send_wqe_offset);
}
+ } else {
+ for (i = 0; i < qp->rq.max; ++i) {
+ next = get_recv_wqe(qp, i);
+ next->nda_op = htonl((((i + 1) % qp->rq.max) <<
+ qp->rq.wqe_shift) | 1);
+ }
+
}
qp->sq.last = get_send_wqe(qp, qp->sq.max - 1);
@@ -1863,7 +1870,6 @@
prev_wqe = qp->rq.last;
qp->rq.last = wqe;
- ((struct mthca_next_seg *) wqe)->nda_op = 0;
((struct mthca_next_seg *) wqe)->ee_nds =
cpu_to_be32(MTHCA_NEXT_DBD);
((struct mthca_next_seg *) wqe)->flags = 0;
@@ -1885,9 +1891,6 @@
qp->wrid[ind] = wr->wr_id;
- ((struct mthca_next_seg *) prev_wqe)->nda_op =
- cpu_to_be32((ind << qp->rq.wqe_shift) | 1);
- wmb();
((struct mthca_next_seg *) prev_wqe)->ee_nds =
cpu_to_be32(MTHCA_NEXT_DBD | size);
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 553d681..a5ffff6 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -175,9 +175,17 @@
* scatter list L_Keys to the sentry value of 0x100.
*/
for (i = 0; i < srq->max; ++i) {
- wqe = get_wqe(srq, i);
+ struct mthca_next_seg *next;
- *wqe_to_link(wqe) = i < srq->max - 1 ? i + 1 : -1;
+ next = wqe = get_wqe(srq, i);
+
+ if (i < srq->max - 1) {
+ *wqe_to_link(wqe) = i + 1;
+ next->nda_op = htonl(((i + 1) << srq->wqe_shift) | 1);
+ } else {
+ *wqe_to_link(wqe) = -1;
+ next->nda_op = 0;
+ }
for (scatter = wqe + sizeof (struct mthca_next_seg);
(void *) scatter < wqe + (1 << srq->wqe_shift);
@@ -470,16 +478,15 @@
void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr)
{
int ind;
+ struct mthca_next_seg *last_free;
ind = wqe_addr >> srq->wqe_shift;
spin_lock(&srq->lock);
- if (likely(srq->first_free >= 0))
- *wqe_to_link(get_wqe(srq, srq->last_free)) = ind;
- else
- srq->first_free = ind;
-
+ last_free = get_wqe(srq, srq->last_free);
+ *wqe_to_link(last_free) = ind;
+ last_free->nda_op = htonl((ind << srq->wqe_shift) | 1);
*wqe_to_link(get_wqe(srq, ind)) = -1;
srq->last_free = ind;
@@ -506,15 +513,7 @@
first_ind = srq->first_free;
for (nreq = 0; wr; wr = wr->next) {
- ind = srq->first_free;
-
- if (unlikely(ind < 0)) {
- mthca_err(dev, "SRQ %06x full\n", srq->srqn);
- err = -ENOMEM;
- *bad_wr = wr;
- break;
- }
-
+ ind = srq->first_free;
wqe = get_wqe(srq, ind);
next_ind = *wqe_to_link(wqe);
@@ -528,7 +527,6 @@
prev_wqe = srq->last;
srq->last = wqe;
- ((struct mthca_next_seg *) wqe)->nda_op = 0;
((struct mthca_next_seg *) wqe)->ee_nds = 0;
/* flags field will always remain 0 */
@@ -549,9 +547,6 @@
if (i < srq->max_gs)
mthca_set_data_seg_inval(wqe);
- ((struct mthca_next_seg *) prev_wqe)->nda_op =
- cpu_to_be32((ind << srq->wqe_shift) | 1);
- wmb();
((struct mthca_next_seg *) prev_wqe)->ee_nds =
cpu_to_be32(MTHCA_NEXT_DBD);
@@ -614,15 +609,7 @@
spin_lock_irqsave(&srq->lock, flags);
for (nreq = 0; wr; ++nreq, wr = wr->next) {
- ind = srq->first_free;
-
- if (unlikely(ind < 0)) {
- mthca_err(dev, "SRQ %06x full\n", srq->srqn);
- err = -ENOMEM;
- *bad_wr = wr;
- break;
- }
-
+ ind = srq->first_free;
wqe = get_wqe(srq, ind);
next_ind = *wqe_to_link(wqe);
@@ -633,8 +620,6 @@
break;
}
- ((struct mthca_next_seg *) wqe)->nda_op =
- cpu_to_be32((next_ind << srq->wqe_shift) | 1);
((struct mthca_next_seg *) wqe)->ee_nds = 0;
/* flags field will always remain 0 */
diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig
new file mode 100644
index 0000000..2aeb7ac
--- /dev/null
+++ b/drivers/infiniband/hw/nes/Kconfig
@@ -0,0 +1,16 @@
+config INFINIBAND_NES
+ tristate "NetEffect RNIC Driver"
+ depends on PCI && INET && INFINIBAND
+ select LIBCRC32C
+ ---help---
+ This is a low-level driver for NetEffect RDMA enabled
+ Network Interface Cards (RNIC).
+
+config INFINIBAND_NES_DEBUG
+ bool "Verbose debugging output"
+ depends on INFINIBAND_NES
+ default n
+ ---help---
+ This option causes the NetEffect RNIC driver to produce debug
+ messages. Select this if you are developing the driver
+ or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile
new file mode 100644
index 0000000..3514851
--- /dev/null
+++ b/drivers/infiniband/hw/nes/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
+
+iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
new file mode 100644
index 0000000..7f8853b
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/highmem.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/iw_cm.h>
+
+#include "nes.h"
+
+#include <net/netevent.h>
+#include <net/neighbour.h>
+#include <linux/route.h>
+#include <net/ip_fib.h>
+
+MODULE_AUTHOR("NetEffect");
+MODULE_DESCRIPTION("NetEffect RNIC Low-level iWARP Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+int max_mtu = 9000;
+int nics_per_function = 1;
+int interrupt_mod_interval = 0;
+
+
+/* Interoperability */
+int mpa_version = 1;
+module_param(mpa_version, int, 0);
+MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
+
+/* Interoperability */
+int disable_mpa_crc = 0;
+module_param(disable_mpa_crc, int, 0);
+MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
+
+unsigned int send_first = 0;
+module_param(send_first, int, 0);
+MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
+
+
+unsigned int nes_drv_opt = 0;
+module_param(nes_drv_opt, int, 0);
+MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
+
+unsigned int nes_debug_level = 0;
+module_param_named(debug_level, nes_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug_level, "Enable debug output level");
+
+LIST_HEAD(nes_adapter_list);
+LIST_HEAD(nes_dev_list);
+
+atomic_t qps_destroyed;
+atomic_t cqp_reqs_allocated;
+atomic_t cqp_reqs_freed;
+atomic_t cqp_reqs_dynallocated;
+atomic_t cqp_reqs_dynfreed;
+atomic_t cqp_reqs_queued;
+atomic_t cqp_reqs_redriven;
+
+static void nes_print_macaddr(struct net_device *netdev);
+static irqreturn_t nes_interrupt(int, void *);
+static int __devinit nes_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit nes_remove(struct pci_dev *);
+static int __init nes_init_module(void);
+static void __exit nes_exit_module(void);
+static unsigned int ee_flsh_adapter;
+static unsigned int sysfs_nonidx_addr;
+static unsigned int sysfs_idx_addr;
+
+static struct pci_device_id nes_pci_table[] = {
+ {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID},
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, nes_pci_table);
+
+static int nes_inetaddr_event(struct notifier_block *, unsigned long, void *);
+static int nes_net_event(struct notifier_block *, unsigned long, void *);
+static int nes_notifiers_registered;
+
+
+static struct notifier_block nes_inetaddr_notifier = {
+ .notifier_call = nes_inetaddr_event
+};
+
+static struct notifier_block nes_net_notifier = {
+ .notifier_call = nes_net_event
+};
+
+
+
+
+/**
+ * nes_inetaddr_event
+ */
+static int nes_inetaddr_event(struct notifier_block *notifier,
+ unsigned long event, void *ptr)
+{
+ struct in_ifaddr *ifa = ptr;
+ struct net_device *event_netdev = ifa->ifa_dev->dev;
+ struct nes_device *nesdev;
+ struct net_device *netdev;
+ struct nes_vnic *nesvnic;
+ unsigned int addr;
+ unsigned int mask;
+
+ addr = ntohl(ifa->ifa_address);
+ mask = ntohl(ifa->ifa_mask);
+ nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %08X, netmask %08X.\n",
+ addr, mask);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n",
+ nesdev, nesdev->netdev[0]->name);
+ netdev = nesdev->netdev[0];
+ nesvnic = netdev_priv(netdev);
+ if (netdev == event_netdev) {
+ if (nesvnic->rdma_enabled == 0) {
+ nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
+ " RDMA is not enabled.\n",
+ netdev->name);
+ return NOTIFY_OK;
+ }
+ /* we have ifa->ifa_address/mask here if we need it */
+ switch (event) {
+ case NETDEV_DOWN:
+ nes_debug(NES_DBG_NETDEV, "event:DOWN\n");
+ nes_write_indexed(nesdev,
+ NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), 0);
+
+ nes_manage_arp_cache(netdev, netdev->dev_addr,
+ ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE);
+ nesvnic->local_ipaddr = 0;
+ return NOTIFY_OK;
+ break;
+ case NETDEV_UP:
+ nes_debug(NES_DBG_NETDEV, "event:UP\n");
+
+ if (nesvnic->local_ipaddr != 0) {
+ nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n");
+ return NOTIFY_OK;
+ }
+ /* Add the address to the IP table */
+ nesvnic->local_ipaddr = ifa->ifa_address;
+
+ nes_write_indexed(nesdev,
+ NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)),
+ ntohl(ifa->ifa_address));
+ nes_manage_arp_cache(netdev, netdev->dev_addr,
+ ntohl(nesvnic->local_ipaddr), NES_ARP_ADD);
+ return NOTIFY_OK;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+
+/**
+ * nes_net_event
+ */
+static int nes_net_event(struct notifier_block *notifier,
+ unsigned long event, void *ptr)
+{
+ struct neighbour *neigh = ptr;
+ struct nes_device *nesdev;
+ struct net_device *netdev;
+ struct nes_vnic *nesvnic;
+
+ switch (event) {
+ case NETEVENT_NEIGH_UPDATE:
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ /* nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p.\n", nesdev); */
+ netdev = nesdev->netdev[0];
+ nesvnic = netdev_priv(netdev);
+ if (netdev == neigh->dev) {
+ if (nesvnic->rdma_enabled == 0) {
+ nes_debug(NES_DBG_NETDEV, "Skipping device %s since no RDMA\n",
+ netdev->name);
+ } else {
+ if (neigh->nud_state & NUD_VALID) {
+ nes_manage_arp_cache(neigh->dev, neigh->ha,
+ ntohl(*(__be32 *)neigh->primary_key), NES_ARP_ADD);
+ } else {
+ nes_manage_arp_cache(neigh->dev, neigh->ha,
+ ntohl(*(__be32 *)neigh->primary_key), NES_ARP_DELETE);
+ }
+ }
+ return NOTIFY_OK;
+ }
+ }
+ break;
+ default:
+ nes_debug(NES_DBG_NETDEV, "NETEVENT_ %lu undefined\n", event);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+
+/**
+ * nes_add_ref
+ */
+void nes_add_ref(struct ib_qp *ibqp)
+{
+ struct nes_qp *nesqp;
+
+ nesqp = to_nesqp(ibqp);
+ nes_debug(NES_DBG_QP, "Bumping refcount for QP%u. Pre-inc value = %u\n",
+ ibqp->qp_num, atomic_read(&nesqp->refcount));
+ atomic_inc(&nesqp->refcount);
+}
+
+static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
+{
+ unsigned long flags;
+ struct nes_qp *nesqp = cqp_request->cqp_callback_pointer;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 qp_id;
+
+ atomic_inc(&qps_destroyed);
+
+ /* Free the control structures */
+
+ qp_id = nesqp->hwqp.qp_id;
+ if (nesqp->pbl_vbase) {
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ nesadapter->free_256pbl++;
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
+ nesqp->pbl_vbase = NULL;
+
+ } else {
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+ }
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
+
+ kfree(nesqp->allocated_buffer);
+
+}
+
+/**
+ * nes_rem_ref
+ */
+void nes_rem_ref(struct ib_qp *ibqp)
+{
+ u64 u64temp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ u32 opcode;
+
+ nesqp = to_nesqp(ibqp);
+
+ if (atomic_read(&nesqp->refcount) == 0) {
+ printk(KERN_INFO PFX "%s: Reference count already 0 for QP%d, last aeq = 0x%04X.\n",
+ __FUNCTION__, ibqp->qp_num, nesqp->last_aeq);
+ BUG();
+ }
+
+ if (atomic_dec_and_test(&nesqp->refcount)) {
+ nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
+
+ /* Destroy the QP */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+ return;
+ }
+ cqp_request->waiting = 0;
+ cqp_request->callback = 1;
+ cqp_request->cqp_callback = nes_cqp_rem_ref_callback;
+ cqp_request->cqp_callback_pointer = nesqp;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ opcode = NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_IWARP;
+
+ if (nesqp->hte_added) {
+ opcode |= NES_CQP_QP_DEL_HTE;
+ nesqp->hte_added = 0;
+ }
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+ u64temp = (u64)nesqp->nesqp_context_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+ }
+}
+
+
+/**
+ * nes_get_qp
+ */
+struct ib_qp *nes_get_qp(struct ib_device *device, int qpn)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+ if ((qpn < NES_FIRST_QPN) || (qpn >= (NES_FIRST_QPN + nesadapter->max_qp)))
+ return NULL;
+
+ return &nesadapter->qp_table[qpn - NES_FIRST_QPN]->ibqp;
+}
+
+
+/**
+ * nes_print_macaddr
+ */
+static void nes_print_macaddr(struct net_device *netdev)
+{
+ nes_debug(NES_DBG_INIT, "%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, IRQ %u\n",
+ netdev->name,
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5],
+ netdev->irq);
+}
+
+
+/**
+ * nes_interrupt - handle interrupts
+ */
+static irqreturn_t nes_interrupt(int irq, void *dev_id)
+{
+ struct nes_device *nesdev = (struct nes_device *)dev_id;
+ int handled = 0;
+ u32 int_mask;
+ u32 int_req;
+ u32 int_stat;
+ u32 intf_int_stat;
+ u32 timer_stat;
+
+ if (nesdev->msi_enabled) {
+ /* No need to read the interrupt pending register if msi is enabled */
+ handled = 1;
+ } else {
+ if (unlikely(nesdev->nesadapter->hw_rev == NE020_REV)) {
+ /* Master interrupt enable provides synchronization for kicking off bottom half
+ when interrupt sharing is going on */
+ int_mask = nes_read32(nesdev->regs + NES_INT_MASK);
+ if (int_mask & 0x80000000) {
+ /* Check interrupt status to see if this might be ours */
+ int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+ int_req = nesdev->int_req;
+ if (int_stat&int_req) {
+ /* if interesting CEQ or AEQ is pending, claim the interrupt */
+ if ((int_stat&int_req) & (~(NES_INT_TIMER|NES_INT_INTF))) {
+ handled = 1;
+ } else {
+ if (((int_stat & int_req) & NES_INT_TIMER) == NES_INT_TIMER) {
+ /* Timer might be running but might be for another function */
+ timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+ if ((timer_stat & nesdev->timer_int_req) != 0) {
+ handled = 1;
+ }
+ }
+ if ((((int_stat & int_req) & NES_INT_INTF) == NES_INT_INTF) &&
+ (handled == 0)) {
+ intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+ if ((intf_int_stat & nesdev->intf_int_req) != 0) {
+ handled = 1;
+ }
+ }
+ }
+ if (handled) {
+ nes_write32(nesdev->regs+NES_INT_MASK, int_mask & (~0x80000000));
+ int_mask = nes_read32(nesdev->regs+NES_INT_MASK);
+ /* Save off the status to save an additional read */
+ nesdev->int_stat = int_stat;
+ nesdev->napi_isr_ran = 1;
+ }
+ }
+ }
+ } else {
+ handled = nes_read32(nesdev->regs+NES_INT_PENDING);
+ }
+ }
+
+ if (handled) {
+
+ if (nes_napi_isr(nesdev) == 0) {
+ tasklet_schedule(&nesdev->dpc_tasklet);
+
+ }
+ return IRQ_HANDLED;
+ } else {
+ return IRQ_NONE;
+ }
+}
+
+
+/**
+ * nes_probe - Device initialization
+ */
+static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+ struct net_device *netdev = NULL;
+ struct nes_device *nesdev = NULL;
+ int ret = 0;
+ struct nes_vnic *nesvnic = NULL;
+ void __iomem *mmio_regs = NULL;
+ u8 hw_rev;
+
+ assert(pcidev != NULL);
+ assert(ent != NULL);
+
+ printk(KERN_INFO PFX "NetEffect RNIC driver v%s loading. (%s)\n",
+ DRV_VERSION, pci_name(pcidev));
+
+ ret = pci_enable_device(pcidev);
+ if (ret) {
+ printk(KERN_ERR PFX "Unable to enable PCI device. (%s)\n", pci_name(pcidev));
+ goto bail0;
+ }
+
+ nes_debug(NES_DBG_INIT, "BAR0 (@0x%08lX) size = 0x%lX bytes\n",
+ (long unsigned int)pci_resource_start(pcidev, BAR_0),
+ (long unsigned int)pci_resource_len(pcidev, BAR_0));
+ nes_debug(NES_DBG_INIT, "BAR1 (@0x%08lX) size = 0x%lX bytes\n",
+ (long unsigned int)pci_resource_start(pcidev, BAR_1),
+ (long unsigned int)pci_resource_len(pcidev, BAR_1));
+
+ /* Make sure PCI base addr are MMIO */
+ if (!(pci_resource_flags(pcidev, BAR_0) & IORESOURCE_MEM) ||
+ !(pci_resource_flags(pcidev, BAR_1) & IORESOURCE_MEM)) {
+ printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
+ ret = -ENODEV;
+ goto bail1;
+ }
+
+ /* Reserve PCI I/O and memory resources */
+ ret = pci_request_regions(pcidev, DRV_NAME);
+ if (ret) {
+ printk(KERN_ERR PFX "Unable to request regions. (%s)\n", pci_name(pcidev));
+ goto bail1;
+ }
+
+ if ((sizeof(dma_addr_t) > 4)) {
+ ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "64b DMA mask configuration failed\n");
+ goto bail2;
+ }
+ ret = pci_set_consistent_dma_mask(pcidev, DMA_64BIT_MASK);
+ if (ret) {
+ printk(KERN_ERR PFX "64b DMA consistent mask configuration failed\n");
+ goto bail2;
+ }
+ } else {
+ ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "32b DMA mask configuration failed\n");
+ goto bail2;
+ }
+ ret = pci_set_consistent_dma_mask(pcidev, DMA_32BIT_MASK);
+ if (ret) {
+ printk(KERN_ERR PFX "32b DMA consistent mask configuration failed\n");
+ goto bail2;
+ }
+ }
+
+ pci_set_master(pcidev);
+
+ /* Allocate hardware structure */
+ nesdev = kzalloc(sizeof(struct nes_device), GFP_KERNEL);
+ if (!nesdev) {
+ printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", pci_name(pcidev));
+ ret = -ENOMEM;
+ goto bail2;
+ }
+
+ nes_debug(NES_DBG_INIT, "Allocated nes device at %p\n", nesdev);
+ nesdev->pcidev = pcidev;
+ pci_set_drvdata(pcidev, nesdev);
+
+ pci_read_config_byte(pcidev, 0x0008, &hw_rev);
+ nes_debug(NES_DBG_INIT, "hw_rev=%u\n", hw_rev);
+
+ spin_lock_init(&nesdev->indexed_regs_lock);
+
+ /* Remap the PCI registers in adapter BAR0 to kernel VA space */
+ mmio_regs = ioremap_nocache(pci_resource_start(pcidev, BAR_0), sizeof(mmio_regs));
+ if (mmio_regs == NULL) {
+ printk(KERN_ERR PFX "Unable to remap BAR0\n");
+ ret = -EIO;
+ goto bail3;
+ }
+ nesdev->regs = mmio_regs;
+ nesdev->index_reg = 0x50 + (PCI_FUNC(pcidev->devfn)*8) + mmio_regs;
+
+ /* Ensure interrupts are disabled */
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+
+ if (nes_drv_opt & NES_DRV_OPT_ENABLE_MSI) {
+ if (!pci_enable_msi(nesdev->pcidev)) {
+ nesdev->msi_enabled = 1;
+ nes_debug(NES_DBG_INIT, "MSI is enabled for device %s\n",
+ pci_name(pcidev));
+ } else {
+ nes_debug(NES_DBG_INIT, "MSI is disabled by linux for device %s\n",
+ pci_name(pcidev));
+ }
+ } else {
+ nes_debug(NES_DBG_INIT, "MSI not requested due to driver options for device %s\n",
+ pci_name(pcidev));
+ }
+
+ nesdev->csr_start = pci_resource_start(nesdev->pcidev, BAR_0);
+ nesdev->doorbell_region = pci_resource_start(nesdev->pcidev, BAR_1);
+
+ /* Init the adapter */
+ nesdev->nesadapter = nes_init_adapter(nesdev, hw_rev);
+ nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+ if (!nesdev->nesadapter) {
+ printk(KERN_ERR PFX "Unable to initialize adapter.\n");
+ ret = -ENOMEM;
+ goto bail5;
+ }
+
+ /* nesdev->base_doorbell_index =
+ nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
+ nesdev->base_doorbell_index = 1;
+ nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
+ nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) % nesdev->nesadapter->port_count;
+
+ tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
+
+ /* bring up the Control QP */
+ if (nes_init_cqp(nesdev)) {
+ ret = -ENODEV;
+ goto bail6;
+ }
+
+ /* Arm the CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ PCI_FUNC(nesdev->pcidev->devfn));
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+ /* Enable the interrupts */
+ nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
+ (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
+ if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
+ nesdev->int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+24));
+ }
+
+ /* TODO: This really should be the first driver to load, not function 0 */
+ if (PCI_FUNC(nesdev->pcidev->devfn) == 0) {
+ /* pick up PCI and critical errors if the first driver to load */
+ nesdev->intf_int_req = NES_INTF_INT_PCIERR | NES_INTF_INT_CRITERR;
+ nesdev->int_req |= NES_INT_INTF;
+ } else {
+ nesdev->intf_int_req = 0;
+ }
+ nesdev->intf_int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0, 0);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 0);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS2, 0x00001265);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS4, 0x18021804);
+
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS3, 0x17801790);
+
+ /* deal with both periodic and one_shot */
+ nesdev->timer_int_req = 0x101 << PCI_FUNC(nesdev->pcidev->devfn);
+ nesdev->nesadapter->timer_int_req |= nesdev->timer_int_req;
+ nes_debug(NES_DBG_INIT, "setting int_req for function %u, nesdev = 0x%04X, adapter = 0x%04X\n",
+ PCI_FUNC(nesdev->pcidev->devfn),
+ nesdev->timer_int_req, nesdev->nesadapter->timer_int_req);
+
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+
+ list_add_tail(&nesdev->list, &nes_dev_list);
+
+ /* Request an interrupt line for the driver */
+ ret = request_irq(pcidev->irq, nes_interrupt, IRQF_SHARED, DRV_NAME, nesdev);
+ if (ret) {
+ printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
+ pci_name(pcidev), pcidev->irq);
+ goto bail65;
+ }
+
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+
+ if (nes_notifiers_registered == 0) {
+ register_inetaddr_notifier(&nes_inetaddr_notifier);
+ register_netevent_notifier(&nes_net_notifier);
+ }
+ nes_notifiers_registered++;
+
+ /* Initialize network devices */
+ if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) {
+ goto bail7;
+ }
+
+ /* Register network device */
+ ret = register_netdev(netdev);
+ if (ret) {
+ printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret);
+ nes_netdev_destroy(netdev);
+ goto bail7;
+ }
+
+ nes_print_macaddr(netdev);
+ /* create a CM core for this netdev */
+ nesvnic = netdev_priv(netdev);
+
+ nesdev->netdev_count++;
+ nesdev->nesadapter->netdev_count++;
+
+
+ printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n",
+ pci_name(pcidev));
+ return 0;
+
+ bail7:
+ printk(KERN_ERR PFX "bail7\n");
+ while (nesdev->netdev_count > 0) {
+ nesdev->netdev_count--;
+ nesdev->nesadapter->netdev_count--;
+
+ unregister_netdev(nesdev->netdev[nesdev->netdev_count]);
+ nes_netdev_destroy(nesdev->netdev[nesdev->netdev_count]);
+ }
+
+ nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
+ nesdev->netdev_count, nesdev->nesadapter->netdev_count);
+
+ nes_notifiers_registered--;
+ if (nes_notifiers_registered == 0) {
+ unregister_netevent_notifier(&nes_net_notifier);
+ unregister_inetaddr_notifier(&nes_inetaddr_notifier);
+ }
+
+ list_del(&nesdev->list);
+ nes_destroy_cqp(nesdev);
+
+ bail65:
+ printk(KERN_ERR PFX "bail65\n");
+ free_irq(pcidev->irq, nesdev);
+ if (nesdev->msi_enabled) {
+ pci_disable_msi(pcidev);
+ }
+ bail6:
+ printk(KERN_ERR PFX "bail6\n");
+ tasklet_kill(&nesdev->dpc_tasklet);
+ /* Deallocate the Adapter Structure */
+ nes_destroy_adapter(nesdev->nesadapter);
+
+ bail5:
+ printk(KERN_ERR PFX "bail5\n");
+ iounmap(nesdev->regs);
+
+ bail3:
+ printk(KERN_ERR PFX "bail3\n");
+ kfree(nesdev);
+
+ bail2:
+ pci_release_regions(pcidev);
+
+ bail1:
+ pci_disable_device(pcidev);
+
+ bail0:
+ return ret;
+}
+
+
+/**
+ * nes_remove - unload from kernel
+ */
+static void __devexit nes_remove(struct pci_dev *pcidev)
+{
+ struct nes_device *nesdev = pci_get_drvdata(pcidev);
+ struct net_device *netdev;
+ int netdev_index = 0;
+
+ if (nesdev->netdev_count) {
+ netdev = nesdev->netdev[netdev_index];
+ if (netdev) {
+ netif_stop_queue(netdev);
+ unregister_netdev(netdev);
+ nes_netdev_destroy(netdev);
+
+ nesdev->netdev[netdev_index] = NULL;
+ nesdev->netdev_count--;
+ nesdev->nesadapter->netdev_count--;
+ }
+ }
+
+ nes_notifiers_registered--;
+ if (nes_notifiers_registered == 0) {
+ unregister_netevent_notifier(&nes_net_notifier);
+ unregister_inetaddr_notifier(&nes_inetaddr_notifier);
+ }
+
+ list_del(&nesdev->list);
+ nes_destroy_cqp(nesdev);
+ tasklet_kill(&nesdev->dpc_tasklet);
+
+ /* Deallocate the Adapter Structure */
+ nes_destroy_adapter(nesdev->nesadapter);
+
+ free_irq(pcidev->irq, nesdev);
+
+ if (nesdev->msi_enabled) {
+ pci_disable_msi(pcidev);
+ }
+
+ iounmap(nesdev->regs);
+ kfree(nesdev);
+
+ /* nes_debug(NES_DBG_SHUTDOWN, "calling pci_release_regions.\n"); */
+ pci_release_regions(pcidev);
+ pci_disable_device(pcidev);
+ pci_set_drvdata(pcidev, NULL);
+}
+
+
+static struct pci_driver nes_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = nes_pci_table,
+ .probe = nes_probe,
+ .remove = __devexit_p(nes_remove),
+};
+
+static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
+{
+ unsigned int devfn = 0xffffffff;
+ unsigned char bus_number = 0xff;
+ unsigned int i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ devfn = nesdev->nesadapter->devfn;
+ bus_number = nesdev->nesadapter->bus_number;
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%x:%x", bus_number, devfn);
+}
+
+static ssize_t nes_store_adapter(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ ee_flsh_adapter = simple_strtoul(p, &p, 10);
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_ee_cmd(struct device_driver *ddp, char *buf)
+{
+ u32 eeprom_cmd = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ eeprom_cmd = nes_read32(nesdev->regs + NES_EEPROM_COMMAND);
+ break;
+ }
+ i++;
+ }
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_cmd);
+}
+
+static ssize_t nes_store_ee_cmd(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ val = simple_strtoul(p, &p, 16);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nes_write32(nesdev->regs + NES_EEPROM_COMMAND, val);
+ break;
+ }
+ i++;
+ }
+ }
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_ee_data(struct device_driver *ddp, char *buf)
+{
+ u32 eeprom_data = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ eeprom_data = nes_read32(nesdev->regs + NES_EEPROM_DATA);
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_data);
+}
+
+static ssize_t nes_store_ee_data(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ val = simple_strtoul(p, &p, 16);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nes_write32(nesdev->regs + NES_EEPROM_DATA, val);
+ break;
+ }
+ i++;
+ }
+ }
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_flash_cmd(struct device_driver *ddp, char *buf)
+{
+ u32 flash_cmd = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ flash_cmd = nes_read32(nesdev->regs + NES_FLASH_COMMAND);
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", flash_cmd);
+}
+
+static ssize_t nes_store_flash_cmd(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ val = simple_strtoul(p, &p, 16);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nes_write32(nesdev->regs + NES_FLASH_COMMAND, val);
+ break;
+ }
+ i++;
+ }
+ }
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_flash_data(struct device_driver *ddp, char *buf)
+{
+ u32 flash_data = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ flash_data = nes_read32(nesdev->regs + NES_FLASH_DATA);
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", flash_data);
+}
+
+static ssize_t nes_store_flash_data(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ val = simple_strtoul(p, &p, 16);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nes_write32(nesdev->regs + NES_FLASH_DATA, val);
+ break;
+ }
+ i++;
+ }
+ }
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_nonidx_addr(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_nonidx_addr);
+}
+
+static ssize_t nes_store_nonidx_addr(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
+ sysfs_nonidx_addr = simple_strtoul(p, &p, 16);
+
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_nonidx_data(struct device_driver *ddp, char *buf)
+{
+ u32 nonidx_data = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nonidx_data = nes_read32(nesdev->regs + sysfs_nonidx_addr);
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", nonidx_data);
+}
+
+static ssize_t nes_store_nonidx_data(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ val = simple_strtoul(p, &p, 16);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nes_write32(nesdev->regs + sysfs_nonidx_addr, val);
+ break;
+ }
+ i++;
+ }
+ }
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_idx_addr(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_idx_addr);
+}
+
+static ssize_t nes_store_idx_addr(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
+ sysfs_idx_addr = simple_strtoul(p, &p, 16);
+
+ return strnlen(buf, count);
+}
+
+static ssize_t nes_show_idx_data(struct device_driver *ddp, char *buf)
+{
+ u32 idx_data = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ idx_data = nes_read_indexed(nesdev, sysfs_idx_addr);
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", idx_data);
+}
+
+static ssize_t nes_store_idx_data(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ val = simple_strtoul(p, &p, 16);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nes_write_indexed(nesdev, sysfs_idx_addr, val);
+ break;
+ }
+ i++;
+ }
+ }
+ return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
+ nes_show_adapter, nes_store_adapter);
+static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
+ nes_show_ee_cmd, nes_store_ee_cmd);
+static DRIVER_ATTR(eeprom_data, S_IRUSR | S_IWUSR,
+ nes_show_ee_data, nes_store_ee_data);
+static DRIVER_ATTR(flash_cmd, S_IRUSR | S_IWUSR,
+ nes_show_flash_cmd, nes_store_flash_cmd);
+static DRIVER_ATTR(flash_data, S_IRUSR | S_IWUSR,
+ nes_show_flash_data, nes_store_flash_data);
+static DRIVER_ATTR(nonidx_addr, S_IRUSR | S_IWUSR,
+ nes_show_nonidx_addr, nes_store_nonidx_addr);
+static DRIVER_ATTR(nonidx_data, S_IRUSR | S_IWUSR,
+ nes_show_nonidx_data, nes_store_nonidx_data);
+static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR,
+ nes_show_idx_addr, nes_store_idx_addr);
+static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
+ nes_show_idx_data, nes_store_idx_data);
+
+static int nes_create_driver_sysfs(struct pci_driver *drv)
+{
+ int error;
+ error = driver_create_file(&drv->driver, &driver_attr_adapter);
+ error |= driver_create_file(&drv->driver, &driver_attr_eeprom_cmd);
+ error |= driver_create_file(&drv->driver, &driver_attr_eeprom_data);
+ error |= driver_create_file(&drv->driver, &driver_attr_flash_cmd);
+ error |= driver_create_file(&drv->driver, &driver_attr_flash_data);
+ error |= driver_create_file(&drv->driver, &driver_attr_nonidx_addr);
+ error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data);
+ error |= driver_create_file(&drv->driver, &driver_attr_idx_addr);
+ error |= driver_create_file(&drv->driver, &driver_attr_idx_data);
+ return error;
+}
+
+static void nes_remove_driver_sysfs(struct pci_driver *drv)
+{
+ driver_remove_file(&drv->driver, &driver_attr_adapter);
+ driver_remove_file(&drv->driver, &driver_attr_eeprom_cmd);
+ driver_remove_file(&drv->driver, &driver_attr_eeprom_data);
+ driver_remove_file(&drv->driver, &driver_attr_flash_cmd);
+ driver_remove_file(&drv->driver, &driver_attr_flash_data);
+ driver_remove_file(&drv->driver, &driver_attr_nonidx_addr);
+ driver_remove_file(&drv->driver, &driver_attr_nonidx_data);
+ driver_remove_file(&drv->driver, &driver_attr_idx_addr);
+ driver_remove_file(&drv->driver, &driver_attr_idx_data);
+}
+
+/**
+ * nes_init_module - module initialization entry point
+ */
+static int __init nes_init_module(void)
+{
+ int retval;
+ int retval1;
+
+ retval = nes_cm_start();
+ if (retval) {
+ printk(KERN_ERR PFX "Unable to start NetEffect iWARP CM.\n");
+ return retval;
+ }
+ retval = pci_register_driver(&nes_pci_driver);
+ if (retval >= 0) {
+ retval1 = nes_create_driver_sysfs(&nes_pci_driver);
+ if (retval1 < 0)
+ printk(KERN_ERR PFX "Unable to create NetEffect sys files.\n");
+ }
+ return retval;
+}
+
+
+/**
+ * nes_exit_module - module unload entry point
+ */
+static void __exit nes_exit_module(void)
+{
+ nes_cm_stop();
+ nes_remove_driver_sysfs(&nes_pci_driver);
+
+ pci_unregister_driver(&nes_pci_driver);
+}
+
+
+module_init(nes_init_module);
+module_exit(nes_exit_module);
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
new file mode 100644
index 0000000..fd57e8a
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NES_H
+#define __NES_H
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/crc32c.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/rdma_cm.h>
+#include <rdma/iw_cm.h>
+
+#define NES_SEND_FIRST_WRITE
+
+#define QUEUE_DISCONNECTS
+
+#define DRV_BUILD "1"
+
+#define DRV_NAME "iw_nes"
+#define DRV_VERSION "1.0 KO Build " DRV_BUILD
+#define PFX DRV_NAME ": "
+
+/*
+ * NetEffect PCI vendor id and NE010 PCI device id.
+ */
+#ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */
+#define PCI_VENDOR_ID_NETEFFECT 0x1678
+#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
+#endif
+
+#define NE020_REV 4
+#define NE020_REV1 5
+
+#define BAR_0 0
+#define BAR_1 2
+
+#define RX_BUF_SIZE (1536 + 8)
+#define NES_REG0_SIZE (4 * 1024)
+#define NES_TX_TIMEOUT (6*HZ)
+#define NES_FIRST_QPN 64
+#define NES_SW_CONTEXT_ALIGN 1024
+
+#define NES_NIC_MAX_NICS 16
+#define NES_MAX_ARP_TABLE_SIZE 4096
+
+#define NES_NIC_CEQ_SIZE 8
+/* NICs will be on a separate CQ */
+#define NES_CCEQ_SIZE ((nesadapter->max_cq / nesadapter->port_count) - 32)
+
+#define NES_MAX_PORT_COUNT 4
+
+#define MAX_DPC_ITERATIONS 128
+
+#define NES_CQP_REQUEST_NO_DOORBELL_RING 0
+#define NES_CQP_REQUEST_RING_DOORBELL 1
+
+#define NES_DRV_OPT_ENABLE_MPA_VER_0 0x00000001
+#define NES_DRV_OPT_DISABLE_MPA_CRC 0x00000002
+#define NES_DRV_OPT_DISABLE_FIRST_WRITE 0x00000004
+#define NES_DRV_OPT_DISABLE_INTF 0x00000008
+#define NES_DRV_OPT_ENABLE_MSI 0x00000010
+#define NES_DRV_OPT_DUAL_LOGICAL_PORT 0x00000020
+#define NES_DRV_OPT_SUPRESS_OPTION_BC 0x00000040
+#define NES_DRV_OPT_NO_INLINE_DATA 0x00000080
+#define NES_DRV_OPT_DISABLE_INT_MOD 0x00000100
+#define NES_DRV_OPT_DISABLE_VIRT_WQ 0x00000200
+
+#define NES_AEQ_EVENT_TIMEOUT 2500
+#define NES_DISCONNECT_EVENT_TIMEOUT 2000
+
+/* debug levels */
+/* must match userspace */
+#define NES_DBG_HW 0x00000001
+#define NES_DBG_INIT 0x00000002
+#define NES_DBG_ISR 0x00000004
+#define NES_DBG_PHY 0x00000008
+#define NES_DBG_NETDEV 0x00000010
+#define NES_DBG_CM 0x00000020
+#define NES_DBG_CM1 0x00000040
+#define NES_DBG_NIC_RX 0x00000080
+#define NES_DBG_NIC_TX 0x00000100
+#define NES_DBG_CQP 0x00000200
+#define NES_DBG_MMAP 0x00000400
+#define NES_DBG_MR 0x00000800
+#define NES_DBG_PD 0x00001000
+#define NES_DBG_CQ 0x00002000
+#define NES_DBG_QP 0x00004000
+#define NES_DBG_MOD_QP 0x00008000
+#define NES_DBG_AEQ 0x00010000
+#define NES_DBG_IW_RX 0x00020000
+#define NES_DBG_IW_TX 0x00040000
+#define NES_DBG_SHUTDOWN 0x00080000
+#define NES_DBG_RSVD1 0x10000000
+#define NES_DBG_RSVD2 0x20000000
+#define NES_DBG_RSVD3 0x40000000
+#define NES_DBG_RSVD4 0x80000000
+#define NES_DBG_ALL 0xffffffff
+
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+#define nes_debug(level, fmt, args...) \
+ if (level & nes_debug_level) \
+ printk(KERN_ERR PFX "%s[%u]: " fmt, __FUNCTION__, __LINE__, ##args)
+
+#define assert(expr) \
+if (!(expr)) { \
+ printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \
+ #expr, __FILE__, __FUNCTION__, __LINE__); \
+}
+
+#define NES_EVENT_TIMEOUT 1200000
+#else
+#define nes_debug(level, fmt, args...)
+#define assert(expr) do {} while (0)
+
+#define NES_EVENT_TIMEOUT 100000
+#endif
+
+#include "nes_hw.h"
+#include "nes_verbs.h"
+#include "nes_context.h"
+#include "nes_user.h"
+#include "nes_cm.h"
+
+extern int max_mtu;
+extern int nics_per_function;
+#define max_frame_len (max_mtu+ETH_HLEN)
+extern int interrupt_mod_interval;
+extern int nes_if_count;
+extern int mpa_version;
+extern int disable_mpa_crc;
+extern unsigned int send_first;
+extern unsigned int nes_drv_opt;
+extern unsigned int nes_debug_level;
+
+extern struct list_head nes_adapter_list;
+extern struct list_head nes_dev_list;
+
+extern struct nes_cm_core *g_cm_core;
+
+extern atomic_t cm_connects;
+extern atomic_t cm_accepts;
+extern atomic_t cm_disconnects;
+extern atomic_t cm_closes;
+extern atomic_t cm_connecteds;
+extern atomic_t cm_connect_reqs;
+extern atomic_t cm_rejects;
+extern atomic_t mod_qp_timouts;
+extern atomic_t qps_created;
+extern atomic_t qps_destroyed;
+extern atomic_t sw_qps_destroyed;
+extern u32 mh_detected;
+extern u32 mh_pauses_sent;
+extern u32 cm_packets_sent;
+extern u32 cm_packets_bounced;
+extern u32 cm_packets_created;
+extern u32 cm_packets_received;
+extern u32 cm_packets_dropped;
+extern u32 cm_packets_retrans;
+extern u32 cm_listens_created;
+extern u32 cm_listens_destroyed;
+extern u32 cm_backlog_drops;
+extern atomic_t cm_loopbacks;
+extern atomic_t cm_nodes_created;
+extern atomic_t cm_nodes_destroyed;
+extern atomic_t cm_accel_dropped_pkts;
+extern atomic_t cm_resets_recvd;
+
+extern u32 crit_err_count;
+extern u32 int_mod_timer_init;
+extern u32 int_mod_cq_depth_256;
+extern u32 int_mod_cq_depth_128;
+extern u32 int_mod_cq_depth_32;
+extern u32 int_mod_cq_depth_24;
+extern u32 int_mod_cq_depth_16;
+extern u32 int_mod_cq_depth_4;
+extern u32 int_mod_cq_depth_1;
+
+extern atomic_t cqp_reqs_allocated;
+extern atomic_t cqp_reqs_freed;
+extern atomic_t cqp_reqs_dynallocated;
+extern atomic_t cqp_reqs_dynfreed;
+extern atomic_t cqp_reqs_queued;
+extern atomic_t cqp_reqs_redriven;
+
+
+struct nes_device {
+ struct nes_adapter *nesadapter;
+ void __iomem *regs;
+ void __iomem *index_reg;
+ struct pci_dev *pcidev;
+ struct net_device *netdev[NES_NIC_MAX_NICS];
+ u64 link_status_interrupts;
+ struct tasklet_struct dpc_tasklet;
+ spinlock_t indexed_regs_lock;
+ unsigned long csr_start;
+ unsigned long doorbell_region;
+ unsigned long doorbell_start;
+ unsigned long mac_tx_errors;
+ unsigned long mac_pause_frames_sent;
+ unsigned long mac_pause_frames_received;
+ unsigned long mac_rx_errors;
+ unsigned long mac_rx_crc_errors;
+ unsigned long mac_rx_symbol_err_frames;
+ unsigned long mac_rx_jabber_frames;
+ unsigned long mac_rx_oversized_frames;
+ unsigned long mac_rx_short_frames;
+ unsigned long port_rx_discards;
+ unsigned long port_tx_discards;
+ unsigned int mac_index;
+ unsigned int nes_stack_start;
+
+ /* Control Structures */
+ void *cqp_vbase;
+ dma_addr_t cqp_pbase;
+ u32 cqp_mem_size;
+ u8 ceq_index;
+ u8 nic_ceq_index;
+ struct nes_hw_cqp cqp;
+ struct nes_hw_cq ccq;
+ struct list_head cqp_avail_reqs;
+ struct list_head cqp_pending_reqs;
+ struct nes_cqp_request *nes_cqp_requests;
+
+ u32 int_req;
+ u32 int_stat;
+ u32 timer_int_req;
+ u32 timer_only_int_count;
+ u32 intf_int_req;
+ u32 last_mac_tx_pauses;
+ u32 last_used_chunks_tx;
+ struct list_head list;
+
+ u16 base_doorbell_index;
+ u16 currcq_count;
+ u16 deepcq_count;
+ u8 msi_enabled;
+ u8 netdev_count;
+ u8 napi_isr_ran;
+ u8 disable_rx_flow_control;
+ u8 disable_tx_flow_control;
+};
+
+
+static inline void
+set_wqe_64bit_value(__le32 *wqe_words, u32 index, u64 value)
+{
+ wqe_words[index] = cpu_to_le32((u32) ((unsigned long)value));
+ wqe_words[index + 1] = cpu_to_le32((u32)(upper_32_bits((unsigned long)value)));
+}
+
+static inline void
+set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value)
+{
+ wqe_words[index] = cpu_to_le32(value);
+}
+
+static inline void
+nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev)
+{
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_CTX_LOW_IDX,
+ (u64)((unsigned long) &nesdev->cqp));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX] = 0;
+}
+
+static inline void
+nes_fill_init_qp_wqe(struct nes_hw_qp_wqe *wqe, struct nes_qp *nesqp, u32 head)
+{
+ u32 value;
+ value = ((u32)((unsigned long) nesqp)) | head;
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX,
+ (u32)(upper_32_bits((unsigned long)(nesqp))));
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, value);
+}
+
+/* Read from memory-mapped device */
+static inline u32 nes_read_indexed(struct nes_device *nesdev, u32 reg_index)
+{
+ unsigned long flags;
+ void __iomem *addr = nesdev->index_reg;
+ u32 value;
+
+ spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
+
+ writel(reg_index, addr);
+ value = readl((void __iomem *)addr + 4);
+
+ spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
+ return value;
+}
+
+static inline u32 nes_read32(const void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static inline u16 nes_read16(const void __iomem *addr)
+{
+ return readw(addr);
+}
+
+static inline u8 nes_read8(const void __iomem *addr)
+{
+ return readb(addr);
+}
+
+/* Write to memory-mapped device */
+static inline void nes_write_indexed(struct nes_device *nesdev, u32 reg_index, u32 val)
+{
+ unsigned long flags;
+ void __iomem *addr = nesdev->index_reg;
+
+ spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
+
+ writel(reg_index, addr);
+ writel(val, (void __iomem *)addr + 4);
+
+ spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
+}
+
+static inline void nes_write32(void __iomem *addr, u32 val)
+{
+ writel(val, addr);
+}
+
+static inline void nes_write16(void __iomem *addr, u16 val)
+{
+ writew(val, addr);
+}
+
+static inline void nes_write8(void __iomem *addr, u8 val)
+{
+ writeb(val, addr);
+}
+
+
+
+static inline int nes_alloc_resource(struct nes_adapter *nesadapter,
+ unsigned long *resource_array, u32 max_resources,
+ u32 *req_resource_num, u32 *next)
+{
+ unsigned long flags;
+ u32 resource_num;
+
+ spin_lock_irqsave(&nesadapter->resource_lock, flags);
+
+ resource_num = find_next_zero_bit(resource_array, max_resources, *next);
+ if (resource_num >= max_resources) {
+ resource_num = find_first_zero_bit(resource_array, max_resources);
+ if (resource_num >= max_resources) {
+ printk(KERN_ERR PFX "%s: No available resourcess.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+ return -EMFILE;
+ }
+ }
+ set_bit(resource_num, resource_array);
+ *next = resource_num+1;
+ if (*next == max_resources) {
+ *next = 0;
+ }
+ spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+ *req_resource_num = resource_num;
+
+ return 0;
+}
+
+static inline int nes_is_resource_allocated(struct nes_adapter *nesadapter,
+ unsigned long *resource_array, u32 resource_num)
+{
+ unsigned long flags;
+ int bit_is_set;
+
+ spin_lock_irqsave(&nesadapter->resource_lock, flags);
+
+ bit_is_set = test_bit(resource_num, resource_array);
+ nes_debug(NES_DBG_HW, "resource_num %u is%s allocated.\n",
+ resource_num, (bit_is_set ? "": " not"));
+ spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+
+ return bit_is_set;
+}
+
+static inline void nes_free_resource(struct nes_adapter *nesadapter,
+ unsigned long *resource_array, u32 resource_num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&nesadapter->resource_lock, flags);
+ clear_bit(resource_num, resource_array);
+ spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+}
+
+static inline struct nes_vnic *to_nesvnic(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct nes_ib_device, ibdev)->nesvnic;
+}
+
+static inline struct nes_pd *to_nespd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct nes_pd, ibpd);
+}
+
+static inline struct nes_ucontext *to_nesucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct nes_ucontext, ibucontext);
+}
+
+static inline struct nes_mr *to_nesmr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct nes_mr, ibmr);
+}
+
+static inline struct nes_mr *to_nesmr_from_ibfmr(struct ib_fmr *ibfmr)
+{
+ return container_of(ibfmr, struct nes_mr, ibfmr);
+}
+
+static inline struct nes_mr *to_nesmw(struct ib_mw *ibmw)
+{
+ return container_of(ibmw, struct nes_mr, ibmw);
+}
+
+static inline struct nes_fmr *to_nesfmr(struct nes_mr *nesmr)
+{
+ return container_of(nesmr, struct nes_fmr, nesmr);
+}
+
+static inline struct nes_cq *to_nescq(struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct nes_cq, ibcq);
+}
+
+static inline struct nes_qp *to_nesqp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct nes_qp, ibqp);
+}
+
+
+
+/* nes.c */
+void nes_add_ref(struct ib_qp *);
+void nes_rem_ref(struct ib_qp *);
+struct ib_qp *nes_get_qp(struct ib_device *, int);
+
+
+/* nes_hw.c */
+struct nes_adapter *nes_init_adapter(struct nes_device *, u8);
+void nes_nic_init_timer_defaults(struct nes_device *, u8);
+unsigned int nes_reset_adapter_ne020(struct nes_device *, u8 *);
+int nes_init_serdes(struct nes_device *, u8, u8, u8);
+void nes_init_csr_ne020(struct nes_device *, u8, u8);
+void nes_destroy_adapter(struct nes_adapter *);
+int nes_init_cqp(struct nes_device *);
+int nes_init_phy(struct nes_device *);
+int nes_init_nic_qp(struct nes_device *, struct net_device *);
+void nes_destroy_nic_qp(struct nes_vnic *);
+int nes_napi_isr(struct nes_device *);
+void nes_dpc(unsigned long);
+void nes_process_ceq(struct nes_device *, struct nes_hw_ceq *);
+void nes_process_aeq(struct nes_device *, struct nes_hw_aeq *);
+void nes_process_mac_intr(struct nes_device *, u32);
+void nes_nic_napi_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
+void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
+void nes_cqp_ce_handler(struct nes_device *, struct nes_hw_cq *);
+void nes_process_iwarp_aeqe(struct nes_device *, struct nes_hw_aeqe *);
+void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *);
+int nes_destroy_cqp(struct nes_device *);
+int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+
+/* nes_nic.c */
+void nes_netdev_set_multicast_list(struct net_device *);
+void nes_netdev_exit(struct nes_vnic *);
+struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
+void nes_netdev_destroy(struct net_device *);
+int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+
+/* nes_cm.c */
+void *nes_cm_create(struct net_device *);
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+void nes_update_arp(unsigned char *, u32, u32, u16, u16);
+void nes_manage_arp_cache(struct net_device *, unsigned char *, u32, u32);
+void nes_sock_release(struct nes_qp *, unsigned long *);
+struct nes_cm_core *nes_cm_alloc_core(void);
+void flush_wqes(struct nes_device *nesdev, struct nes_qp *, u32, u32);
+int nes_manage_apbvt(struct nes_vnic *, u32, u32, u32);
+int nes_cm_disconn(struct nes_qp *);
+void nes_cm_disconn_worker(void *);
+
+/* nes_verbs.c */
+int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32);
+int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
+struct nes_ib_device *nes_init_ofa_device(struct net_device *);
+void nes_destroy_ofa_device(struct nes_ib_device *);
+int nes_register_ofa_device(struct nes_ib_device *);
+void nes_unregister_ofa_device(struct nes_ib_device *);
+
+/* nes_util.c */
+int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *);
+void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16);
+void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *);
+void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16);
+void nes_read_10G_phy_reg(struct nes_device *, u16, u8);
+struct nes_cqp_request *nes_get_cqp_request(struct nes_device *);
+void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int);
+int nes_arp_table(struct nes_device *, u32, u8 *, u32);
+void nes_mh_fix(unsigned long);
+void nes_clc(unsigned long);
+void nes_dump_mem(unsigned int, void *, int);
+u32 nes_crc32(u32, u32, u32, u32, u8 *, u32, u32, u32);
+
+#endif /* __NES_H */
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
new file mode 100644
index 0000000..bd5cfea
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -0,0 +1,3088 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+
+#define TCPOPT_TIMESTAMP 8
+
+#include <asm/atomic.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/notifier.h>
+#include <linux/net.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+#include "nes.h"
+
+u32 cm_packets_sent;
+u32 cm_packets_bounced;
+u32 cm_packets_dropped;
+u32 cm_packets_retrans;
+u32 cm_packets_created;
+u32 cm_packets_received;
+u32 cm_listens_created;
+u32 cm_listens_destroyed;
+u32 cm_backlog_drops;
+atomic_t cm_loopbacks;
+atomic_t cm_nodes_created;
+atomic_t cm_nodes_destroyed;
+atomic_t cm_accel_dropped_pkts;
+atomic_t cm_resets_recvd;
+
+static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *);
+static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,
+ struct nes_vnic *, struct nes_cm_info *);
+static int add_ref_cm_node(struct nes_cm_node *);
+static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
+static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
+
+
+/* External CM API Interface */
+/* instance of function pointers for client API */
+/* set address of this instance to cm_core->cm_ops at cm_core alloc */
+static struct nes_cm_ops nes_cm_api = {
+ mini_cm_accelerated,
+ mini_cm_listen,
+ mini_cm_del_listen,
+ mini_cm_connect,
+ mini_cm_close,
+ mini_cm_accept,
+ mini_cm_reject,
+ mini_cm_recv_pkt,
+ mini_cm_dealloc_core,
+ mini_cm_get,
+ mini_cm_set
+};
+
+struct nes_cm_core *g_cm_core;
+
+atomic_t cm_connects;
+atomic_t cm_accepts;
+atomic_t cm_disconnects;
+atomic_t cm_closes;
+atomic_t cm_connecteds;
+atomic_t cm_connect_reqs;
+atomic_t cm_rejects;
+
+
+/**
+ * create_event
+ */
+static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
+ enum nes_cm_event_type type)
+{
+ struct nes_cm_event *event;
+
+ if (!cm_node->cm_id)
+ return NULL;
+
+ /* allocate an empty event */
+ event = kzalloc(sizeof(*event), GFP_ATOMIC);
+
+ if (!event)
+ return NULL;
+
+ event->type = type;
+ event->cm_node = cm_node;
+ event->cm_info.rem_addr = cm_node->rem_addr;
+ event->cm_info.loc_addr = cm_node->loc_addr;
+ event->cm_info.rem_port = cm_node->rem_port;
+ event->cm_info.loc_port = cm_node->loc_port;
+ event->cm_info.cm_id = cm_node->cm_id;
+
+ nes_debug(NES_DBG_CM, "Created event=%p, type=%u, dst_addr=%08x[%x],"
+ " src_addr=%08x[%x]\n",
+ event, type,
+ event->cm_info.loc_addr, event->cm_info.loc_port,
+ event->cm_info.rem_addr, event->cm_info.rem_port);
+
+ nes_cm_post_event(event);
+ return event;
+}
+
+
+/**
+ * send_mpa_request
+ */
+int send_mpa_request(struct nes_cm_node *cm_node)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = get_free_pkt(cm_node);
+ if (!skb) {
+ nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+ return -1;
+ }
+
+ /* send an MPA Request frame */
+ form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
+ cm_node->mpa_frame_size, SET_ACK);
+
+ ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/**
+ * recv_mpa - process a received TCP pkt, we are expecting an
+ * IETF MPA frame
+ */
+static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
+{
+ struct ietf_mpa_frame *mpa_frame;
+
+ /* assume req frame is in tcp data payload */
+ if (len < sizeof(struct ietf_mpa_frame)) {
+ nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
+ return -1;
+ }
+
+ mpa_frame = (struct ietf_mpa_frame *)buffer;
+ cm_node->mpa_frame_size = ntohs(mpa_frame->priv_data_len);
+
+ if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
+ nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
+ " complete (%x + %x != %x)\n",
+ cm_node->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
+ return -1;
+ }
+
+ /* copy entire MPA frame to our cm_node's frame */
+ memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
+ cm_node->mpa_frame_size);
+
+ return 0;
+}
+
+
+/**
+ * handle_exception_pkt - process an exception packet.
+ * We have been in a TSA state, and we have now received SW
+ * TCP/IP traffic should be a FIN request or IP pkt with options
+ */
+static int handle_exception_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
+ int ret = 0;
+ struct tcphdr *tcph = tcp_hdr(skb);
+
+ /* first check to see if this a FIN pkt */
+ if (tcph->fin) {
+ /* we need to ACK the FIN request */
+ send_ack(cm_node);
+
+ /* check which side we are (client/server) and set next state accordingly */
+ if (cm_node->tcp_cntxt.client)
+ cm_node->state = NES_CM_STATE_CLOSING;
+ else {
+ /* we are the server side */
+ cm_node->state = NES_CM_STATE_CLOSE_WAIT;
+ /* since this is a self contained CM we don't wait for */
+ /* an APP to close us, just send final FIN immediately */
+ ret = send_fin(cm_node, NULL);
+ cm_node->state = NES_CM_STATE_LAST_ACK;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+
+/**
+ * form_cm_frame - get a free packet and build empty frame Use
+ * node info to build.
+ */
+struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node,
+ void *options, u32 optionsize, void *data, u32 datasize, u8 flags)
+{
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+ struct ethhdr *ethh;
+ u8 *buf;
+ u16 packetsize = sizeof(*iph);
+
+ packetsize += sizeof(*tcph);
+ packetsize += optionsize + datasize;
+
+ memset(skb->data, 0x00, ETH_HLEN + sizeof(*iph) + sizeof(*tcph));
+
+ skb->len = 0;
+ buf = skb_put(skb, packetsize + ETH_HLEN);
+
+ ethh = (struct ethhdr *) buf;
+ buf += ETH_HLEN;
+
+ iph = (struct iphdr *)buf;
+ buf += sizeof(*iph);
+ tcph = (struct tcphdr *)buf;
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, ETH_HLEN);
+ skb_set_transport_header(skb, ETH_HLEN+sizeof(*iph));
+ buf += sizeof(*tcph);
+
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->protocol = htons(0x800);
+ skb->data_len = 0;
+ skb->mac_len = ETH_HLEN;
+
+ memcpy(ethh->h_dest, cm_node->rem_mac, ETH_ALEN);
+ memcpy(ethh->h_source, cm_node->loc_mac, ETH_ALEN);
+ ethh->h_proto = htons(0x0800);
+
+ iph->version = IPVERSION;
+ iph->ihl = 5; /* 5 * 4Byte words, IP headr len */
+ iph->tos = 0;
+ iph->tot_len = htons(packetsize);
+ iph->id = htons(++cm_node->tcp_cntxt.loc_id);
+
+ iph->frag_off = htons(0x4000);
+ iph->ttl = 0x40;
+ iph->protocol = 0x06; /* IPPROTO_TCP */
+
+ iph->saddr = htonl(cm_node->loc_addr);
+ iph->daddr = htonl(cm_node->rem_addr);
+
+ tcph->source = htons(cm_node->loc_port);
+ tcph->dest = htons(cm_node->rem_port);
+ tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
+
+ if (flags & SET_ACK) {
+ cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;
+ tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);
+ tcph->ack = 1;
+ } else
+ tcph->ack_seq = 0;
+
+ if (flags & SET_SYN) {
+ cm_node->tcp_cntxt.loc_seq_num++;
+ tcph->syn = 1;
+ } else
+ cm_node->tcp_cntxt.loc_seq_num += datasize; /* data (no headers) */
+
+ if (flags & SET_FIN)
+ tcph->fin = 1;
+
+ if (flags & SET_RST)
+ tcph->rst = 1;
+
+ tcph->doff = (u16)((sizeof(*tcph) + optionsize + 3) >> 2);
+ tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
+ tcph->urg_ptr = 0;
+ if (optionsize)
+ memcpy(buf, options, optionsize);
+ buf += optionsize;
+ if (datasize)
+ memcpy(buf, data, datasize);
+
+ skb_shinfo(skb)->nr_frags = 0;
+ cm_packets_created++;
+
+ return skb;
+}
+
+
+/**
+ * print_core - dump a cm core
+ */
+static void print_core(struct nes_cm_core *core)
+{
+ nes_debug(NES_DBG_CM, "---------------------------------------------\n");
+ nes_debug(NES_DBG_CM, "CM Core -- (core = %p )\n", core);
+ if (!core)
+ return;
+ nes_debug(NES_DBG_CM, "---------------------------------------------\n");
+ nes_debug(NES_DBG_CM, "Session ID : %u \n", atomic_read(&core->session_id));
+
+ nes_debug(NES_DBG_CM, "State : %u \n", core->state);
+
+ nes_debug(NES_DBG_CM, "Tx Free cnt : %u \n", skb_queue_len(&core->tx_free_list));
+ nes_debug(NES_DBG_CM, "Listen Nodes : %u \n", atomic_read(&core->listen_node_cnt));
+ nes_debug(NES_DBG_CM, "Active Nodes : %u \n", atomic_read(&core->node_cnt));
+
+ nes_debug(NES_DBG_CM, "core : %p \n", core);
+
+ nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");
+}
+
+
+/**
+ * schedule_nes_timer
+ * note - cm_node needs to be protected before calling this. Encase in:
+ * rem_ref_cm_node(cm_core, cm_node);add_ref_cm_node(cm_node);
+ */
+int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
+ enum nes_timer_type type, int send_retrans,
+ int close_when_complete)
+{
+ unsigned long flags;
+ struct nes_cm_core *cm_core;
+ struct nes_timer_entry *new_send;
+ int ret = 0;
+ u32 was_timer_set;
+
+ new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
+ if (!new_send)
+ return -1;
+ if (!cm_node)
+ return -EINVAL;
+
+ /* new_send->timetosend = currenttime */
+ new_send->retrycount = NES_DEFAULT_RETRYS;
+ new_send->retranscount = NES_DEFAULT_RETRANS;
+ new_send->skb = skb;
+ new_send->timetosend = jiffies;
+ new_send->type = type;
+ new_send->netdev = cm_node->netdev;
+ new_send->send_retrans = send_retrans;
+ new_send->close_when_complete = close_when_complete;
+
+ if (type == NES_TIMER_TYPE_CLOSE) {
+ new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */
+ spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+ list_add_tail(&new_send->list, &cm_node->recv_list);
+ spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+ }
+
+ if (type == NES_TIMER_TYPE_SEND) {
+ new_send->seq_num = htonl(tcp_hdr(skb)->seq);
+ atomic_inc(&new_send->skb->users);
+
+ ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);
+ if (ret != NETDEV_TX_OK) {
+ nes_debug(NES_DBG_CM, "Error sending packet %p (jiffies = %lu)\n",
+ new_send, jiffies);
+ atomic_dec(&new_send->skb->users);
+ new_send->timetosend = jiffies;
+ } else {
+ cm_packets_sent++;
+ if (!send_retrans) {
+ if (close_when_complete)
+ rem_ref_cm_node(cm_node->cm_core, cm_node);
+ dev_kfree_skb_any(new_send->skb);
+ kfree(new_send);
+ return ret;
+ }
+ new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
+ }
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ list_add_tail(&new_send->list, &cm_node->retrans_list);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ }
+ if (type == NES_TIMER_TYPE_RECV) {
+ new_send->seq_num = htonl(tcp_hdr(skb)->seq);
+ new_send->timetosend = jiffies;
+ spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+ list_add_tail(&new_send->list, &cm_node->recv_list);
+ spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+ }
+ cm_core = cm_node->cm_core;
+
+ was_timer_set = timer_pending(&cm_core->tcp_timer);
+
+ if (!was_timer_set) {
+ cm_core->tcp_timer.expires = new_send->timetosend;
+ add_timer(&cm_core->tcp_timer);
+ }
+
+ return ret;
+}
+
+
+/**
+ * nes_cm_timer_tick
+ */
+void nes_cm_timer_tick(unsigned long pass)
+{
+ unsigned long flags, qplockflags;
+ unsigned long nexttimeout = jiffies + NES_LONG_TIME;
+ struct iw_cm_id *cm_id;
+ struct nes_cm_node *cm_node;
+ struct nes_timer_entry *send_entry, *recv_entry;
+ struct list_head *list_core, *list_core_temp;
+ struct list_head *list_node, *list_node_temp;
+ struct nes_cm_core *cm_core = g_cm_core;
+ struct nes_qp *nesqp;
+ struct sk_buff *skb;
+ u32 settimer = 0;
+ int ret = NETDEV_TX_OK;
+ int node_done;
+
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+ list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) {
+ cm_node = container_of(list_node, struct nes_cm_node, list);
+ add_ref_cm_node(cm_node);
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+ spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+ list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
+ recv_entry = container_of(list_core, struct nes_timer_entry, list);
+ if ((time_after(recv_entry->timetosend, jiffies)) &&
+ (recv_entry->type == NES_TIMER_TYPE_CLOSE)) {
+ if (nexttimeout > recv_entry->timetosend || !settimer) {
+ nexttimeout = recv_entry->timetosend;
+ settimer = 1;
+ }
+ continue;
+ }
+ list_del(&recv_entry->list);
+ cm_id = cm_node->cm_id;
+ spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+ if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
+ nesqp = (struct nes_qp *)recv_entry->skb;
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ if (nesqp->cm_id) {
+ nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d: "
+ "****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with something to do!!! ******\n",
+ nesqp->hwqp.qp_id, cm_id,
+ atomic_read(&nesqp->refcount));
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+ nesqp->ibqp_state = IB_QPS_ERR;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_cm_disconn(nesqp);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d:"
+ " ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with nothing to do!!! ******\n",
+ nesqp->hwqp.qp_id, cm_id,
+ atomic_read(&nesqp->refcount));
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ if (cm_id)
+ cm_id->rem_ref(cm_id);
+ }
+ kfree(recv_entry);
+ spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ node_done = 0;
+ list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
+ if (node_done) {
+ break;
+ }
+ send_entry = container_of(list_core, struct nes_timer_entry, list);
+ if (time_after(send_entry->timetosend, jiffies)) {
+ if (cm_node->state != NES_CM_STATE_TSA) {
+ if ((nexttimeout > send_entry->timetosend) || !settimer) {
+ nexttimeout = send_entry->timetosend;
+ settimer = 1;
+ }
+ node_done = 1;
+ continue;
+ } else {
+ list_del(&send_entry->list);
+ skb = send_entry->skb;
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ dev_kfree_skb_any(skb);
+ kfree(send_entry);
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ }
+ }
+ if (send_entry->type == NES_TIMER_NODE_CLEANUP) {
+ list_del(&send_entry->list);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ kfree(send_entry);
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ }
+ if ((send_entry->seq_num < cm_node->tcp_cntxt.rem_ack_num) ||
+ (cm_node->state == NES_CM_STATE_TSA) ||
+ (cm_node->state == NES_CM_STATE_CLOSED)) {
+ skb = send_entry->skb;
+ list_del(&send_entry->list);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ kfree(send_entry);
+ dev_kfree_skb_any(skb);
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ }
+
+ if (!send_entry->retranscount || !send_entry->retrycount) {
+ cm_packets_dropped++;
+ skb = send_entry->skb;
+ list_del(&send_entry->list);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ dev_kfree_skb_any(skb);
+ kfree(send_entry);
+ if (cm_node->state == NES_CM_STATE_SYN_RCVD) {
+ /* this node never even generated an indication up to the cm */
+ rem_ref_cm_node(cm_core, cm_node);
+ } else {
+ cm_node->state = NES_CM_STATE_CLOSED;
+ create_event(cm_node, NES_CM_EVENT_ABORTED);
+ }
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ }
+ /* this seems like the correct place, but leave send entry unprotected */
+ // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ atomic_inc(&send_entry->skb->users);
+ cm_packets_retrans++;
+ nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p,"
+ " jiffies = %lu, time to send = %lu, retranscount = %u, "
+ "send_entry->seq_num = 0x%08X, cm_node->tcp_cntxt.rem_ack_num = 0x%08X\n",
+ send_entry, cm_node, jiffies, send_entry->timetosend, send_entry->retranscount,
+ send_entry->seq_num, cm_node->tcp_cntxt.rem_ack_num);
+
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
+ if (ret != NETDEV_TX_OK) {
+ cm_packets_bounced++;
+ atomic_dec(&send_entry->skb->users);
+ send_entry->retrycount--;
+ nexttimeout = jiffies + NES_SHORT_TIME;
+ settimer = 1;
+ node_done = 1;
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ } else {
+ cm_packets_sent++;
+ }
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ list_del(&send_entry->list);
+ nes_debug(NES_DBG_CM, "Packet Sent: retrans count = %u, retry count = %u.\n",
+ send_entry->retranscount, send_entry->retrycount);
+ if (send_entry->send_retrans) {
+ send_entry->retranscount--;
+ send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT;
+ if (nexttimeout > send_entry->timetosend || !settimer) {
+ nexttimeout = send_entry->timetosend;
+ settimer = 1;
+ }
+ list_add(&send_entry->list, &cm_node->retrans_list);
+ continue;
+ } else {
+ int close_when_complete;
+ skb = send_entry->skb;
+ close_when_complete = send_entry->close_when_complete;
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ if (close_when_complete) {
+ BUG_ON(atomic_read(&cm_node->ref_count) == 1);
+ rem_ref_cm_node(cm_core, cm_node);
+ }
+ dev_kfree_skb_any(skb);
+ kfree(send_entry);
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ }
+ }
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+
+ rem_ref_cm_node(cm_core, cm_node);
+
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+ if (ret != NETDEV_TX_OK)
+ break;
+ }
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+ if (settimer) {
+ if (!timer_pending(&cm_core->tcp_timer)) {
+ cm_core->tcp_timer.expires = nexttimeout;
+ add_timer(&cm_core->tcp_timer);
+ }
+ }
+}
+
+
+/**
+ * send_syn
+ */
+int send_syn(struct nes_cm_node *cm_node, u32 sendack)
+{
+ int ret;
+ int flags = SET_SYN;
+ struct sk_buff *skb;
+ char optionsbuffer[sizeof(struct option_mss) +
+ sizeof(struct option_windowscale) +
+ sizeof(struct option_base) + 1];
+
+ int optionssize = 0;
+ /* Sending MSS option */
+ union all_known_options *options;
+
+ if (!cm_node)
+ return -EINVAL;
+
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_mss.optionnum = OPTION_NUMBER_MSS;
+ options->as_mss.length = sizeof(struct option_mss);
+ options->as_mss.mss = htons(cm_node->tcp_cntxt.mss);
+ optionssize += sizeof(struct option_mss);
+
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_windowscale.optionnum = OPTION_NUMBER_WINDOW_SCALE;
+ options->as_windowscale.length = sizeof(struct option_windowscale);
+ options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
+ optionssize += sizeof(struct option_windowscale);
+
+ if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)
+ ) {
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_base.optionnum = OPTION_NUMBER_WRITE0;
+ options->as_base.length = sizeof(struct option_base);
+ optionssize += sizeof(struct option_base);
+ /* we need the size to be a multiple of 4 */
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_end = 1;
+ optionssize += 1;
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_end = 1;
+ optionssize += 1;
+ }
+
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_end = OPTION_NUMBER_END;
+ optionssize += 1;
+
+ skb = get_free_pkt(cm_node);
+ if (!skb) {
+ nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+ return -1;
+ }
+
+ if (sendack)
+ flags |= SET_ACK;
+
+ form_cm_frame(skb, cm_node, optionsbuffer, optionssize, NULL, 0, flags);
+ ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+ return ret;
+}
+
+
+/**
+ * send_reset
+ */
+int send_reset(struct nes_cm_node *cm_node)
+{
+ int ret;
+ struct sk_buff *skb = get_free_pkt(cm_node);
+ int flags = SET_RST | SET_ACK;
+
+ if (!skb) {
+ nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+ return -1;
+ }
+
+ add_ref_cm_node(cm_node);
+ form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
+ ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);
+
+ return ret;
+}
+
+
+/**
+ * send_ack
+ */
+int send_ack(struct nes_cm_node *cm_node)
+{
+ int ret;
+ struct sk_buff *skb = get_free_pkt(cm_node);
+
+ if (!skb) {
+ nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+ return -1;
+ }
+
+ form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK);
+ ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 0);
+
+ return ret;
+}
+
+
+/**
+ * send_fin
+ */
+int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
+ int ret;
+
+ /* if we didn't get a frame get one */
+ if (!skb)
+ skb = get_free_pkt(cm_node);
+
+ if (!skb) {
+ nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+ return -1;
+ }
+
+ form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK | SET_FIN);
+ ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+ return ret;
+}
+
+
+/**
+ * get_free_pkt
+ */
+struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node)
+{
+ struct sk_buff *skb, *new_skb;
+
+ /* check to see if we need to repopulate the free tx pkt queue */
+ if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
+ while (skb_queue_len(&cm_node->cm_core->tx_free_list) <
+ cm_node->cm_core->free_tx_pkt_max) {
+ /* replace the frame we took, we won't get it back */
+ new_skb = dev_alloc_skb(cm_node->cm_core->mtu);
+ BUG_ON(!new_skb);
+ /* add a replacement frame to the free tx list head */
+ skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb);
+ }
+ }
+
+ skb = skb_dequeue(&cm_node->cm_core->tx_free_list);
+
+ return skb;
+}
+
+
+/**
+ * make_hashkey - generate hash key from node tuple
+ */
+static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
+ nes_addr_t rem_addr)
+{
+ u32 hashkey = 0;
+
+ hashkey = loc_addr + rem_addr + loc_port + rem_port;
+ hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
+
+ return hashkey;
+}
+
+
+/**
+ * find_node - find a cm node that matches the reference cm node
+ */
+static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
+ u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
+{
+ unsigned long flags;
+ u32 hashkey;
+ struct list_head *list_pos;
+ struct list_head *hte;
+ struct nes_cm_node *cm_node;
+
+ /* make a hash index key for this packet */
+ hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
+
+ /* get a handle on the hte */
+ hte = &cm_core->connected_nodes;
+
+ nes_debug(NES_DBG_CM, "Searching for an owner node:%x:%x from core %p->%p\n",
+ loc_addr, loc_port, cm_core, hte);
+
+ /* walk list and find cm_node associated with this session ID */
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+ list_for_each(list_pos, hte) {
+ cm_node = container_of(list_pos, struct nes_cm_node, list);
+ /* compare quad, return node handle if a match */
+ nes_debug(NES_DBG_CM, "finding node %x:%x =? %x:%x ^ %x:%x =? %x:%x\n",
+ cm_node->loc_addr, cm_node->loc_port,
+ loc_addr, loc_port,
+ cm_node->rem_addr, cm_node->rem_port,
+ rem_addr, rem_port);
+ if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) &&
+ (cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) {
+ add_ref_cm_node(cm_node);
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+ return cm_node;
+ }
+ }
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+ /* no owner node */
+ return NULL;
+}
+
+
+/**
+ * find_listener - find a cm node listening on this addr-port pair
+ */
+static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
+ nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state)
+{
+ unsigned long flags;
+ struct list_head *listen_list;
+ struct nes_cm_listener *listen_node;
+
+ /* walk list and find cm_node associated with this session ID */
+ spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+ list_for_each(listen_list, &cm_core->listen_list.list) {
+ listen_node = container_of(listen_list, struct nes_cm_listener, list);
+ /* compare node pair, return node handle if a match */
+ if (((listen_node->loc_addr == dst_addr) ||
+ listen_node->loc_addr == 0x00000000) &&
+ (listen_node->loc_port == dst_port) &&
+ (listener_state & listen_node->listener_state)) {
+ atomic_inc(&listen_node->ref_count);
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+ return listen_node;
+ }
+ }
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+ nes_debug(NES_DBG_CM, "Unable to find listener- %x:%x\n",
+ dst_addr, dst_port);
+
+ /* no listener */
+ return NULL;
+}
+
+
+/**
+ * add_hte_node - add a cm node to the hash table
+ */
+static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
+{
+ unsigned long flags;
+ u32 hashkey;
+ struct list_head *hte;
+
+ if (!cm_node || !cm_core)
+ return -EINVAL;
+
+ nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n");
+
+ /* first, make an index into our hash table */
+ hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
+ cm_node->rem_port, cm_node->rem_addr);
+ cm_node->hashkey = hashkey;
+
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+ /* get a handle on the hash table element (list head for this slot) */
+ hte = &cm_core->connected_nodes;
+ list_add_tail(&cm_node->list, hte);
+ atomic_inc(&cm_core->ht_node_cnt);
+
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+ return 0;
+}
+
+
+/**
+ * mini_cm_dec_refcnt_listen
+ */
+static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
+ struct nes_cm_listener *listener, int free_hanging_nodes)
+{
+ int ret = 1;
+ unsigned long flags;
+ spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+ if (!atomic_dec_return(&listener->ref_count)) {
+ list_del(&listener->list);
+
+ /* decrement our listen node count */
+ atomic_dec(&cm_core->listen_node_cnt);
+
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+ if (listener->nesvnic) {
+ nes_manage_apbvt(listener->nesvnic, listener->loc_port,
+ PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+ }
+
+ nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
+
+ kfree(listener);
+ ret = 0;
+ cm_listens_destroyed++;
+ } else {
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+ }
+ if (listener) {
+ if (atomic_read(&listener->pend_accepts_cnt) > 0)
+ nes_debug(NES_DBG_CM, "destroying listener (%p)"
+ " with non-zero pending accepts=%u\n",
+ listener, atomic_read(&listener->pend_accepts_cnt));
+ }
+
+ return ret;
+}
+
+
+/**
+ * mini_cm_del_listen
+ */
+static int mini_cm_del_listen(struct nes_cm_core *cm_core,
+ struct nes_cm_listener *listener)
+{
+ listener->listener_state = NES_CM_LISTENER_PASSIVE_STATE;
+ listener->cm_id = NULL; /* going to be destroyed pretty soon */
+ return mini_cm_dec_refcnt_listen(cm_core, listener, 1);
+}
+
+
+/**
+ * mini_cm_accelerated
+ */
+static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
+ struct nes_cm_node *cm_node)
+{
+ u32 was_timer_set;
+ cm_node->accelerated = 1;
+
+ if (cm_node->accept_pend) {
+ BUG_ON(!cm_node->listener);
+ atomic_dec(&cm_node->listener->pend_accepts_cnt);
+ BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
+ }
+
+ was_timer_set = timer_pending(&cm_core->tcp_timer);
+ if (!was_timer_set) {
+ cm_core->tcp_timer.expires = jiffies + NES_SHORT_TIME;
+ add_timer(&cm_core->tcp_timer);
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_addr_send_arp
+ */
+static void nes_addr_send_arp(u32 dst_ip)
+{
+ struct rtable *rt;
+ struct flowi fl;
+
+ memset(&fl, 0, sizeof fl);
+ fl.nl_u.ip4_u.daddr = htonl(dst_ip);
+ if (ip_route_output_key(&init_net, &rt, &fl)) {
+ printk("%s: ip_route_output_key failed for 0x%08X\n",
+ __FUNCTION__, dst_ip);
+ return;
+ }
+
+ neigh_event_send(rt->u.dst.neighbour, NULL);
+ ip_rt_put(rt);
+}
+
+
+/**
+ * make_cm_node - create a new instance of a cm node
+ */
+static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
+ struct nes_vnic *nesvnic, struct nes_cm_info *cm_info,
+ struct nes_cm_listener *listener)
+{
+ struct nes_cm_node *cm_node;
+ struct timespec ts;
+ int arpindex = 0;
+ struct nes_device *nesdev;
+ struct nes_adapter *nesadapter;
+
+ /* create an hte and cm_node for this instance */
+ cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
+ if (!cm_node)
+ return NULL;
+
+ /* set our node specific transport info */
+ cm_node->loc_addr = cm_info->loc_addr;
+ cm_node->rem_addr = cm_info->rem_addr;
+ cm_node->loc_port = cm_info->loc_port;
+ cm_node->rem_port = cm_info->rem_port;
+ cm_node->send_write0 = send_first;
+ nes_debug(NES_DBG_CM, "Make node addresses : loc = %x:%x, rem = %x:%x\n",
+ cm_node->loc_addr, cm_node->loc_port, cm_node->rem_addr, cm_node->rem_port);
+ cm_node->listener = listener;
+ cm_node->netdev = nesvnic->netdev;
+ cm_node->cm_id = cm_info->cm_id;
+ memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
+
+ nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n",
+ cm_node->listener, cm_node->cm_id);
+
+ INIT_LIST_HEAD(&cm_node->retrans_list);
+ spin_lock_init(&cm_node->retrans_list_lock);
+ INIT_LIST_HEAD(&cm_node->recv_list);
+ spin_lock_init(&cm_node->recv_list_lock);
+
+ cm_node->loopbackpartner = NULL;
+ atomic_set(&cm_node->ref_count, 1);
+ /* associate our parent CM core */
+ cm_node->cm_core = cm_core;
+ cm_node->tcp_cntxt.loc_id = NES_CM_DEF_LOCAL_ID;
+ cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+ cm_node->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND_SCALED >>
+ NES_CM_DEFAULT_RCV_WND_SCALE;
+ ts = current_kernel_time();
+ cm_node->tcp_cntxt.loc_seq_num = htonl(ts.tv_nsec);
+ cm_node->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) -
+ sizeof(struct tcphdr) - ETH_HLEN;
+ cm_node->tcp_cntxt.rcv_nxt = 0;
+ /* get a unique session ID , add thread_id to an upcounter to handle race */
+ atomic_inc(&cm_core->node_cnt);
+ atomic_inc(&cm_core->session_id);
+ cm_node->session_id = (u32)(atomic_read(&cm_core->session_id) + current->tgid);
+ cm_node->conn_type = cm_info->conn_type;
+ cm_node->apbvt_set = 0;
+ cm_node->accept_pend = 0;
+
+ cm_node->nesvnic = nesvnic;
+ /* get some device handles, for arp lookup */
+ nesdev = nesvnic->nesdev;
+ nesadapter = nesdev->nesadapter;
+
+ cm_node->loopbackpartner = NULL;
+ /* get the mac addr for the remote node */
+ arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
+ if (arpindex < 0) {
+ kfree(cm_node);
+ nes_addr_send_arp(cm_info->rem_addr);
+ return NULL;
+ }
+
+ /* copy the mac addr to node context */
+ memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
+ nes_debug(NES_DBG_CM, "Remote mac addr from arp table:%02x,"
+ " %02x, %02x, %02x, %02x, %02x\n",
+ cm_node->rem_mac[0], cm_node->rem_mac[1],
+ cm_node->rem_mac[2], cm_node->rem_mac[3],
+ cm_node->rem_mac[4], cm_node->rem_mac[5]);
+
+ add_hte_node(cm_core, cm_node);
+ atomic_inc(&cm_nodes_created);
+
+ return cm_node;
+}
+
+
+/**
+ * add_ref_cm_node - destroy an instance of a cm node
+ */
+static int add_ref_cm_node(struct nes_cm_node *cm_node)
+{
+ atomic_inc(&cm_node->ref_count);
+ return 0;
+}
+
+
+/**
+ * rem_ref_cm_node - destroy an instance of a cm node
+ */
+static int rem_ref_cm_node(struct nes_cm_core *cm_core,
+ struct nes_cm_node *cm_node)
+{
+ unsigned long flags, qplockflags;
+ struct nes_timer_entry *send_entry;
+ struct nes_timer_entry *recv_entry;
+ struct iw_cm_id *cm_id;
+ struct list_head *list_core, *list_node_temp;
+ struct nes_qp *nesqp;
+
+ if (!cm_node)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cm_node->cm_core->ht_lock, flags);
+ if (atomic_dec_return(&cm_node->ref_count)) {
+ spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
+ return 0;
+ }
+ list_del(&cm_node->list);
+ atomic_dec(&cm_core->ht_node_cnt);
+ spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
+
+ /* if the node is destroyed before connection was accelerated */
+ if (!cm_node->accelerated && cm_node->accept_pend) {
+ BUG_ON(!cm_node->listener);
+ atomic_dec(&cm_node->listener->pend_accepts_cnt);
+ BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
+ }
+
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
+ send_entry = container_of(list_core, struct nes_timer_entry, list);
+ list_del(&send_entry->list);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ dev_kfree_skb_any(send_entry->skb);
+ kfree(send_entry);
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ continue;
+ }
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+
+ spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+ list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
+ recv_entry = container_of(list_core, struct nes_timer_entry, list);
+ list_del(&recv_entry->list);
+ cm_id = cm_node->cm_id;
+ spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+ if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
+ nesqp = (struct nes_qp *)recv_entry->skb;
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ if (nesqp->cm_id) {
+ nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with something to do!!! ******\n",
+ nesqp->hwqp.qp_id, cm_id);
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+ nesqp->ibqp_state = IB_QPS_ERR;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_cm_disconn(nesqp);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with nothing to do!!! ******\n",
+ nesqp->hwqp.qp_id, cm_id);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ cm_id->rem_ref(cm_id);
+ } else if (recv_entry->type == NES_TIMER_TYPE_RECV) {
+ dev_kfree_skb_any(recv_entry->skb);
+ }
+ kfree(recv_entry);
+ spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+
+ if (cm_node->listener) {
+ mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
+ } else {
+ if (cm_node->apbvt_set && cm_node->nesvnic) {
+ nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
+ PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
+ NES_MANAGE_APBVT_DEL);
+ }
+ }
+
+ kfree(cm_node);
+ atomic_dec(&cm_core->node_cnt);
+ atomic_inc(&cm_nodes_destroyed);
+
+ return 0;
+}
+
+
+/**
+ * process_options
+ */
+static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet)
+{
+ u32 tmp;
+ u32 offset = 0;
+ union all_known_options *all_options;
+ char got_mss_option = 0;
+
+ while (offset < optionsize) {
+ all_options = (union all_known_options *)(optionsloc + offset);
+ switch (all_options->as_base.optionnum) {
+ case OPTION_NUMBER_END:
+ offset = optionsize;
+ break;
+ case OPTION_NUMBER_NONE:
+ offset += 1;
+ continue;
+ case OPTION_NUMBER_MSS:
+ nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d Size: %d\n",
+ __FUNCTION__,
+ all_options->as_mss.length, offset, optionsize);
+ got_mss_option = 1;
+ if (all_options->as_mss.length != 4) {
+ return 1;
+ } else {
+ tmp = ntohs(all_options->as_mss.mss);
+ if (tmp > 0 && tmp < cm_node->tcp_cntxt.mss)
+ cm_node->tcp_cntxt.mss = tmp;
+ }
+ break;
+ case OPTION_NUMBER_WINDOW_SCALE:
+ cm_node->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount;
+ break;
+ case OPTION_NUMBER_WRITE0:
+ cm_node->send_write0 = 1;
+ break;
+ default:
+ nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
+ all_options->as_base.optionnum);
+ break;
+ }
+ offset += all_options->as_base.length;
+ }
+ if ((!got_mss_option) && (syn_packet))
+ cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+ return 0;
+}
+
+
+/**
+ * process_packet
+ */
+int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
+ struct nes_cm_core *cm_core)
+{
+ int optionsize;
+ int datasize;
+ int ret = 0;
+ struct tcphdr *tcph = tcp_hdr(skb);
+ u32 inc_sequence;
+ if (cm_node->state == NES_CM_STATE_SYN_SENT && tcph->syn) {
+ inc_sequence = ntohl(tcph->seq);
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence;
+ }
+
+ if ((!tcph) || (cm_node->state == NES_CM_STATE_TSA)) {
+ BUG_ON(!tcph);
+ atomic_inc(&cm_accel_dropped_pkts);
+ return -1;
+ }
+
+ if (tcph->rst) {
+ atomic_inc(&cm_resets_recvd);
+ nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u. refcnt=%d\n",
+ cm_node, cm_node->state, atomic_read(&cm_node->ref_count));
+ switch (cm_node->state) {
+ case NES_CM_STATE_LISTENING:
+ rem_ref_cm_node(cm_core, cm_node);
+ break;
+ case NES_CM_STATE_TSA:
+ case NES_CM_STATE_CLOSED:
+ break;
+ case NES_CM_STATE_SYN_RCVD:
+ nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
+ " remote 0x%08X:%04X, node state = %u\n",
+ cm_node->loc_addr, cm_node->loc_port,
+ cm_node->rem_addr, cm_node->rem_port,
+ cm_node->state);
+ rem_ref_cm_node(cm_core, cm_node);
+ break;
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_MPAREQ_SENT:
+ default:
+ nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
+ " remote 0x%08X:%04X, node state = %u refcnt=%d\n",
+ cm_node->loc_addr, cm_node->loc_port,
+ cm_node->rem_addr, cm_node->rem_port,
+ cm_node->state, atomic_read(&cm_node->ref_count));
+ // create event
+ cm_node->state = NES_CM_STATE_CLOSED;
+
+ create_event(cm_node, NES_CM_EVENT_ABORTED);
+ break;
+
+ }
+ return -1;
+ }
+
+ optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+
+ skb_pull(skb, ip_hdr(skb)->ihl << 2);
+ skb_pull(skb, tcph->doff << 2);
+
+ datasize = skb->len;
+ inc_sequence = ntohl(tcph->seq);
+ nes_debug(NES_DBG_CM, "datasize = %u, sequence = 0x%08X, ack_seq = 0x%08X,"
+ " rcv_nxt = 0x%08X Flags: %s %s.\n",
+ datasize, inc_sequence, ntohl(tcph->ack_seq),
+ cm_node->tcp_cntxt.rcv_nxt, (tcph->syn ? "SYN":""),
+ (tcph->ack ? "ACK":""));
+
+ if (!tcph->syn && (inc_sequence != cm_node->tcp_cntxt.rcv_nxt)
+ ) {
+ nes_debug(NES_DBG_CM, "dropping packet, datasize = %u, sequence = 0x%08X,"
+ " ack_seq = 0x%08X, rcv_nxt = 0x%08X Flags: %s.\n",
+ datasize, inc_sequence, ntohl(tcph->ack_seq),
+ cm_node->tcp_cntxt.rcv_nxt, (tcph->ack ? "ACK":""));
+ if (cm_node->state == NES_CM_STATE_LISTENING) {
+ rem_ref_cm_node(cm_core, cm_node);
+ }
+ return -1;
+ }
+
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+
+
+ if (optionsize) {
+ u8 *optionsloc = (u8 *)&tcph[1];
+ if (process_options(cm_node, optionsloc, optionsize, (u32)tcph->syn)) {
+ nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __FUNCTION__, cm_node);
+ send_reset(cm_node);
+ if (cm_node->state != NES_CM_STATE_SYN_SENT)
+ rem_ref_cm_node(cm_core, cm_node);
+ return 0;
+ }
+ } else if (tcph->syn)
+ cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+
+ cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<
+ cm_node->tcp_cntxt.snd_wscale;
+
+ if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) {
+ cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
+ }
+
+ if (tcph->ack) {
+ cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+ switch (cm_node->state) {
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ /* read and stash current sequence number */
+ if (cm_node->tcp_cntxt.rem_ack_num != cm_node->tcp_cntxt.loc_seq_num) {
+ nes_debug(NES_DBG_CM, "ERROR - cm_node->tcp_cntxt.rem_ack_num !="
+ " cm_node->tcp_cntxt.loc_seq_num\n");
+ send_reset(cm_node);
+ return 0;
+ }
+ if (cm_node->state == NES_CM_STATE_SYN_SENT)
+ cm_node->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED;
+ else {
+ cm_node->state = NES_CM_STATE_ESTABLISHED;
+ }
+ break;
+ case NES_CM_STATE_LAST_ACK:
+ cm_node->state = NES_CM_STATE_CLOSED;
+ break;
+ case NES_CM_STATE_FIN_WAIT1:
+ cm_node->state = NES_CM_STATE_FIN_WAIT2;
+ break;
+ case NES_CM_STATE_CLOSING:
+ cm_node->state = NES_CM_STATE_TIME_WAIT;
+ /* need to schedule this to happen in 2MSL timeouts */
+ cm_node->state = NES_CM_STATE_CLOSED;
+ break;
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_MPAREQ_SENT:
+ case NES_CM_STATE_CLOSE_WAIT:
+ case NES_CM_STATE_TIME_WAIT:
+ case NES_CM_STATE_CLOSED:
+ break;
+ case NES_CM_STATE_LISTENING:
+ nes_debug(NES_DBG_CM, "Received an ACK on a listening port (SYN %d)\n", tcph->syn);
+ cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+ send_reset(cm_node);
+ /* send_reset bumps refcount, this should have been a new node */
+ rem_ref_cm_node(cm_core, cm_node);
+ return -1;
+ break;
+ case NES_CM_STATE_TSA:
+ nes_debug(NES_DBG_CM, "Received a packet with the ack bit set while in TSA state\n");
+ break;
+ case NES_CM_STATE_UNKNOWN:
+ case NES_CM_STATE_INITED:
+ case NES_CM_STATE_ACCEPTING:
+ case NES_CM_STATE_FIN_WAIT2:
+ default:
+ nes_debug(NES_DBG_CM, "Received ack from unknown state: %x\n",
+ cm_node->state);
+ send_reset(cm_node);
+ break;
+ }
+ }
+
+ if (tcph->syn) {
+ if (cm_node->state == NES_CM_STATE_LISTENING) {
+ /* do not exceed backlog */
+ atomic_inc(&cm_node->listener->pend_accepts_cnt);
+ if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
+ cm_node->listener->backlog) {
+ nes_debug(NES_DBG_CM, "drop syn due to backlog pressure \n");
+ cm_backlog_drops++;
+ atomic_dec(&cm_node->listener->pend_accepts_cnt);
+ rem_ref_cm_node(cm_core, cm_node);
+ return 0;
+ }
+ cm_node->accept_pend = 1;
+
+ }
+ if (datasize == 0)
+ cm_node->tcp_cntxt.rcv_nxt ++;
+
+ if (cm_node->state == NES_CM_STATE_LISTENING) {
+ cm_node->state = NES_CM_STATE_SYN_RCVD;
+ send_syn(cm_node, 1);
+ }
+ if (cm_node->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) {
+ cm_node->state = NES_CM_STATE_ESTABLISHED;
+ /* send final handshake ACK */
+ ret = send_ack(cm_node);
+ if (ret < 0)
+ return ret;
+
+ cm_node->state = NES_CM_STATE_MPAREQ_SENT;
+ ret = send_mpa_request(cm_node);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ if (tcph->fin) {
+ cm_node->tcp_cntxt.rcv_nxt++;
+ switch (cm_node->state) {
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_ACCEPTING:
+ case NES_CM_STATE_MPAREQ_SENT:
+ cm_node->state = NES_CM_STATE_CLOSE_WAIT;
+ cm_node->state = NES_CM_STATE_LAST_ACK;
+ ret = send_fin(cm_node, NULL);
+ break;
+ case NES_CM_STATE_FIN_WAIT1:
+ cm_node->state = NES_CM_STATE_CLOSING;
+ ret = send_ack(cm_node);
+ break;
+ case NES_CM_STATE_FIN_WAIT2:
+ cm_node->state = NES_CM_STATE_TIME_WAIT;
+ cm_node->tcp_cntxt.loc_seq_num ++;
+ ret = send_ack(cm_node);
+ /* need to schedule this to happen in 2MSL timeouts */
+ cm_node->state = NES_CM_STATE_CLOSED;
+ break;
+ case NES_CM_STATE_CLOSE_WAIT:
+ case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_CLOSING:
+ case NES_CM_STATE_TSA:
+ default:
+ nes_debug(NES_DBG_CM, "Received a fin while in %x state\n",
+ cm_node->state);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ if (datasize) {
+ u8 *dataloc = skb->data;
+ /* figure out what state we are in and handle transition to next state */
+ switch (cm_node->state) {
+ case NES_CM_STATE_LISTENING:
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ case NES_CM_STATE_FIN_WAIT1:
+ case NES_CM_STATE_FIN_WAIT2:
+ case NES_CM_STATE_CLOSE_WAIT:
+ case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_CLOSING:
+ break;
+ case NES_CM_STATE_MPAREQ_SENT:
+ /* recv the mpa res frame, ret=frame len (incl priv data) */
+ ret = parse_mpa(cm_node, dataloc, datasize);
+ if (ret < 0)
+ break;
+ /* set the req frame payload len in skb */
+ /* we are done handling this state, set node to a TSA state */
+ cm_node->state = NES_CM_STATE_TSA;
+ send_ack(cm_node);
+ create_event(cm_node, NES_CM_EVENT_CONNECTED);
+ break;
+
+ case NES_CM_STATE_ESTABLISHED:
+ /* we are expecting an MPA req frame */
+ ret = parse_mpa(cm_node, dataloc, datasize);
+ if (ret < 0) {
+ break;
+ }
+ cm_node->state = NES_CM_STATE_TSA;
+ send_ack(cm_node);
+ /* we got a valid MPA request, create an event */
+ create_event(cm_node, NES_CM_EVENT_MPA_REQ);
+ break;
+ case NES_CM_STATE_TSA:
+ handle_exception_pkt(cm_node, skb);
+ break;
+ case NES_CM_STATE_UNKNOWN:
+ case NES_CM_STATE_INITED:
+ default:
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * mini_cm_listen - create a listen node with params
+ */
+static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
+ struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
+{
+ struct nes_cm_listener *listener;
+ unsigned long flags;
+
+ nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
+ cm_info->loc_addr, cm_info->loc_port);
+
+ /* cannot have multiple matching listeners */
+ listener = find_listener(cm_core, htonl(cm_info->loc_addr),
+ htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE);
+ if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
+ /* find automatically incs ref count ??? */
+ atomic_dec(&listener->ref_count);
+ nes_debug(NES_DBG_CM, "Not creating listener since it already exists\n");
+ return NULL;
+ }
+
+ if (!listener) {
+ /* create a CM listen node (1/2 node to compare incoming traffic to) */
+ listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
+ if (!listener) {
+ nes_debug(NES_DBG_CM, "Not creating listener memory allocation failed\n");
+ return NULL;
+ }
+
+ memset(listener, 0, sizeof(struct nes_cm_listener));
+ listener->loc_addr = htonl(cm_info->loc_addr);
+ listener->loc_port = htons(cm_info->loc_port);
+ listener->reused_node = 0;
+
+ atomic_set(&listener->ref_count, 1);
+ }
+ /* pasive case */
+ /* find already inc'ed the ref count */
+ else {
+ listener->reused_node = 1;
+ }
+
+ listener->cm_id = cm_info->cm_id;
+ atomic_set(&listener->pend_accepts_cnt, 0);
+ listener->cm_core = cm_core;
+ listener->nesvnic = nesvnic;
+ atomic_inc(&cm_core->node_cnt);
+ atomic_inc(&cm_core->session_id);
+
+ listener->session_id = (u32)(atomic_read(&cm_core->session_id) + current->tgid);
+ listener->conn_type = cm_info->conn_type;
+ listener->backlog = cm_info->backlog;
+ listener->listener_state = NES_CM_LISTENER_ACTIVE_STATE;
+
+ if (!listener->reused_node) {
+ spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+ list_add(&listener->list, &cm_core->listen_list.list);
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+ atomic_inc(&cm_core->listen_node_cnt);
+ }
+
+ nes_debug(NES_DBG_CM, "Api - listen(): addr=0x%08X, port=0x%04x,"
+ " listener = %p, backlog = %d, cm_id = %p.\n",
+ cm_info->loc_addr, cm_info->loc_port,
+ listener, listener->backlog, listener->cm_id);
+
+ return listener;
+}
+
+
+/**
+ * mini_cm_connect - make a connection node with params
+ */
+struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
+ struct nes_vnic *nesvnic, struct ietf_mpa_frame *mpa_frame,
+ struct nes_cm_info *cm_info)
+{
+ int ret = 0;
+ struct nes_cm_node *cm_node;
+ struct nes_cm_listener *loopbackremotelistener;
+ struct nes_cm_node *loopbackremotenode;
+ struct nes_cm_info loopback_cm_info;
+
+ u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+ ntohs(mpa_frame->priv_data_len);
+
+ cm_info->loc_addr = htonl(cm_info->loc_addr);
+ cm_info->rem_addr = htonl(cm_info->rem_addr);
+ cm_info->loc_port = htons(cm_info->loc_port);
+ cm_info->rem_port = htons(cm_info->rem_port);
+
+ /* create a CM connection node */
+ cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
+ if (!cm_node)
+ return NULL;
+
+ // set our node side to client (active) side
+ cm_node->tcp_cntxt.client = 1;
+ cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+
+ if (cm_info->loc_addr == cm_info->rem_addr) {
+ loopbackremotelistener = find_listener(cm_core, cm_node->rem_addr,
+ cm_node->rem_port, NES_CM_LISTENER_ACTIVE_STATE);
+ if (loopbackremotelistener == NULL) {
+ create_event(cm_node, NES_CM_EVENT_ABORTED);
+ } else {
+ atomic_inc(&cm_loopbacks);
+ loopback_cm_info = *cm_info;
+ loopback_cm_info.loc_port = cm_info->rem_port;
+ loopback_cm_info.rem_port = cm_info->loc_port;
+ loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
+ loopbackremotenode = make_cm_node(cm_core, nesvnic, &loopback_cm_info,
+ loopbackremotelistener);
+ loopbackremotenode->loopbackpartner = cm_node;
+ loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+ cm_node->loopbackpartner = loopbackremotenode;
+ memcpy(loopbackremotenode->mpa_frame_buf, &mpa_frame->priv_data,
+ mpa_frame_size);
+ loopbackremotenode->mpa_frame_size = mpa_frame_size -
+ sizeof(struct ietf_mpa_frame);
+
+ // we are done handling this state, set node to a TSA state
+ cm_node->state = NES_CM_STATE_TSA;
+ cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num;
+ loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num;
+ cm_node->tcp_cntxt.max_snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
+ loopbackremotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
+ cm_node->tcp_cntxt.snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
+ loopbackremotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
+ cm_node->tcp_cntxt.snd_wscale = loopbackremotenode->tcp_cntxt.rcv_wscale;
+ loopbackremotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale;
+
+ create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
+ }
+ return cm_node;
+ }
+
+ /* set our node side to client (active) side */
+ cm_node->tcp_cntxt.client = 1;
+ /* init our MPA frame ptr */
+ memcpy(&cm_node->mpa_frame, mpa_frame, mpa_frame_size);
+ cm_node->mpa_frame_size = mpa_frame_size;
+
+ /* send a syn and goto syn sent state */
+ cm_node->state = NES_CM_STATE_SYN_SENT;
+ ret = send_syn(cm_node, 0);
+
+ nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X, port=0x%04x,"
+ " cm_node=%p, cm_id = %p.\n",
+ cm_node->rem_addr, cm_node->rem_port, cm_node, cm_node->cm_id);
+
+ return cm_node;
+}
+
+
+/**
+ * mini_cm_accept - accept a connection
+ * This function is never called
+ */
+int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame,
+ struct nes_cm_node *cm_node)
+{
+ return 0;
+}
+
+
+/**
+ * mini_cm_reject - reject and teardown a connection
+ */
+int mini_cm_reject(struct nes_cm_core *cm_core,
+ struct ietf_mpa_frame *mpa_frame,
+ struct nes_cm_node *cm_node)
+{
+ int ret = 0;
+ struct sk_buff *skb;
+ u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+ ntohs(mpa_frame->priv_data_len);
+
+ skb = get_free_pkt(cm_node);
+ if (!skb) {
+ nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+ return -1;
+ }
+
+ /* send an MPA Request frame */
+ form_cm_frame(skb, cm_node, NULL, 0, mpa_frame, mpa_frame_size, SET_ACK | SET_FIN);
+ ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+ cm_node->state = NES_CM_STATE_CLOSED;
+ ret = send_fin(cm_node, NULL);
+
+ if (ret < 0) {
+ printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+
+/**
+ * mini_cm_close
+ */
+int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
+{
+ int ret = 0;
+
+ if (!cm_core || !cm_node)
+ return -EINVAL;
+
+ switch (cm_node->state) {
+ /* if passed in node is null, create a reference key node for node search */
+ /* check if we found an owner node for this pkt */
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_ACCEPTING:
+ case NES_CM_STATE_MPAREQ_SENT:
+ cm_node->state = NES_CM_STATE_FIN_WAIT1;
+ send_fin(cm_node, NULL);
+ break;
+ case NES_CM_STATE_CLOSE_WAIT:
+ cm_node->state = NES_CM_STATE_LAST_ACK;
+ send_fin(cm_node, NULL);
+ break;
+ case NES_CM_STATE_FIN_WAIT1:
+ case NES_CM_STATE_FIN_WAIT2:
+ case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_TIME_WAIT:
+ case NES_CM_STATE_CLOSING:
+ ret = -1;
+ break;
+ case NES_CM_STATE_LISTENING:
+ case NES_CM_STATE_UNKNOWN:
+ case NES_CM_STATE_INITED:
+ case NES_CM_STATE_CLOSED:
+ case NES_CM_STATE_TSA:
+ ret = rem_ref_cm_node(cm_core, cm_node);
+ break;
+ }
+ cm_node->cm_id = NULL;
+ return ret;
+}
+
+
+/**
+ * recv_pkt - recv an ETHERNET packet, and process it through CM
+ * node state machine
+ */
+int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic,
+ struct sk_buff *skb)
+{
+ struct nes_cm_node *cm_node = NULL;
+ struct nes_cm_listener *listener = NULL;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ struct nes_cm_info nfo;
+ int ret = 0;
+
+ if (!skb || skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ iph = (struct iphdr *)skb->data;
+ tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
+ skb_reset_network_header(skb);
+ skb_set_transport_header(skb, sizeof(*tcph));
+ skb->len = ntohs(iph->tot_len);
+
+ nfo.loc_addr = ntohl(iph->daddr);
+ nfo.loc_port = ntohs(tcph->dest);
+ nfo.rem_addr = ntohl(iph->saddr);
+ nfo.rem_port = ntohs(tcph->source);
+
+ nes_debug(NES_DBG_CM, "Received packet: dest=0x%08X:0x%04X src=0x%08X:0x%04X\n",
+ iph->daddr, tcph->dest, iph->saddr, tcph->source);
+
+ /* note: this call is going to increment cm_node ref count */
+ cm_node = find_node(cm_core,
+ nfo.rem_port, nfo.rem_addr,
+ nfo.loc_port, nfo.loc_addr);
+
+ if (!cm_node) {
+ listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port,
+ NES_CM_LISTENER_ACTIVE_STATE);
+ if (listener) {
+ nfo.cm_id = listener->cm_id;
+ nfo.conn_type = listener->conn_type;
+ } else {
+ nfo.cm_id = NULL;
+ nfo.conn_type = 0;
+ }
+
+ cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener);
+ if (!cm_node) {
+ nes_debug(NES_DBG_CM, "Unable to allocate node\n");
+ if (listener) {
+ nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n");
+ atomic_dec(&listener->ref_count);
+ }
+ ret = -1;
+ goto out;
+ }
+ if (!listener) {
+ nes_debug(NES_DBG_CM, "Packet found for unknown port %x refcnt=%d\n",
+ nfo.loc_port, atomic_read(&cm_node->ref_count));
+ if (!tcph->rst) {
+ nes_debug(NES_DBG_CM, "Packet found for unknown port=%d"
+ " rem_port=%d refcnt=%d\n",
+ nfo.loc_port, nfo.rem_port, atomic_read(&cm_node->ref_count));
+
+ cm_node->tcp_cntxt.rcv_nxt = ntohl(tcph->seq);
+ cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+ send_reset(cm_node);
+ }
+ rem_ref_cm_node(cm_core, cm_node);
+ ret = -1;
+ goto out;
+ }
+ add_ref_cm_node(cm_node);
+ cm_node->state = NES_CM_STATE_LISTENING;
+ }
+
+ nes_debug(NES_DBG_CM, "Processing Packet for node %p, data = (%p):\n",
+ cm_node, skb->data);
+ process_packet(cm_node, skb, cm_core);
+
+ rem_ref_cm_node(cm_core, cm_node);
+ out:
+ if (skb)
+ dev_kfree_skb_any(skb);
+ return ret;
+}
+
+
+/**
+ * nes_cm_alloc_core - allocate a top level instance of a cm core
+ */
+struct nes_cm_core *nes_cm_alloc_core(void)
+{
+ int i;
+
+ struct nes_cm_core *cm_core;
+ struct sk_buff *skb = NULL;
+
+ /* setup the CM core */
+ /* alloc top level core control structure */
+ cm_core = kzalloc(sizeof(*cm_core), GFP_KERNEL);
+ if (!cm_core)
+ return NULL;
+
+ INIT_LIST_HEAD(&cm_core->connected_nodes);
+ init_timer(&cm_core->tcp_timer);
+ cm_core->tcp_timer.function = nes_cm_timer_tick;
+
+ cm_core->mtu = NES_CM_DEFAULT_MTU;
+ cm_core->state = NES_CM_STATE_INITED;
+ cm_core->free_tx_pkt_max = NES_CM_DEFAULT_FREE_PKTS;
+
+ atomic_set(&cm_core->session_id, 0);
+ atomic_set(&cm_core->events_posted, 0);
+
+ /* init the packet lists */
+ skb_queue_head_init(&cm_core->tx_free_list);
+
+ for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
+ skb = dev_alloc_skb(cm_core->mtu);
+ if (!skb) {
+ kfree(cm_core);
+ return NULL;
+ }
+ /* add 'raw' skb to free frame list */
+ skb_queue_head(&cm_core->tx_free_list, skb);
+ }
+
+ cm_core->api = &nes_cm_api;
+
+ spin_lock_init(&cm_core->ht_lock);
+ spin_lock_init(&cm_core->listen_list_lock);
+
+ INIT_LIST_HEAD(&cm_core->listen_list.list);
+
+ nes_debug(NES_DBG_CM, "Init CM Core completed -- cm_core=%p\n", cm_core);
+
+ nes_debug(NES_DBG_CM, "Enable QUEUE EVENTS\n");
+ cm_core->event_wq = create_singlethread_workqueue("nesewq");
+ cm_core->post_event = nes_cm_post_event;
+ nes_debug(NES_DBG_CM, "Enable QUEUE DISCONNECTS\n");
+ cm_core->disconn_wq = create_singlethread_workqueue("nesdwq");
+
+ print_core(cm_core);
+ return cm_core;
+}
+
+
+/**
+ * mini_cm_dealloc_core - deallocate a top level instance of a cm core
+ */
+int mini_cm_dealloc_core(struct nes_cm_core *cm_core)
+{
+ nes_debug(NES_DBG_CM, "De-Alloc CM Core (%p)\n", cm_core);
+
+ if (!cm_core)
+ return -EINVAL;
+
+ barrier();
+
+ if (timer_pending(&cm_core->tcp_timer)) {
+ del_timer(&cm_core->tcp_timer);
+ }
+
+ destroy_workqueue(cm_core->event_wq);
+ destroy_workqueue(cm_core->disconn_wq);
+ nes_debug(NES_DBG_CM, "\n");
+ kfree(cm_core);
+
+ return 0;
+}
+
+
+/**
+ * mini_cm_get
+ */
+int mini_cm_get(struct nes_cm_core *cm_core)
+{
+ return cm_core->state;
+}
+
+
+/**
+ * mini_cm_set
+ */
+int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
+{
+ int ret = 0;
+
+ switch (type) {
+ case NES_CM_SET_PKT_SIZE:
+ cm_core->mtu = value;
+ break;
+ case NES_CM_SET_FREE_PKT_Q_SIZE:
+ cm_core->free_tx_pkt_max = value;
+ break;
+ default:
+ /* unknown set option */
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+
+/**
+ * nes_cm_init_tsa_conn setup HW; MPA frames must be
+ * successfully exchanged when this is called
+ */
+static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_node)
+{
+ int ret = 0;
+
+ if (!nesqp)
+ return -EINVAL;
+
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_IPV4 |
+ NES_QPCONTEXT_MISC_NO_NAGLE | NES_QPCONTEXT_MISC_DO_NOT_FRAG |
+ NES_QPCONTEXT_MISC_DROS);
+
+ if (cm_node->tcp_cntxt.snd_wscale || cm_node->tcp_cntxt.rcv_wscale)
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WSCALE);
+
+ nesqp->nesqp_context->misc2 |= cpu_to_le32(64 << NES_QPCONTEXT_MISC2_TTL_SHIFT);
+
+ nesqp->nesqp_context->mss |= cpu_to_le32(((u32)cm_node->tcp_cntxt.mss) << 16);
+
+ nesqp->nesqp_context->tcp_state_flow_label |= cpu_to_le32(
+ (u32)NES_QPCONTEXT_TCPSTATE_EST << NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT);
+
+ nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
+ (cm_node->tcp_cntxt.snd_wscale << NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT) &
+ NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK);
+
+ nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
+ (cm_node->tcp_cntxt.rcv_wscale << NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT) &
+ NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK);
+
+ nesqp->nesqp_context->keepalive = cpu_to_le32(0x80);
+ nesqp->nesqp_context->ts_recent = 0;
+ nesqp->nesqp_context->ts_age = 0;
+ nesqp->nesqp_context->snd_nxt = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+ nesqp->nesqp_context->snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.snd_wnd);
+ nesqp->nesqp_context->rcv_nxt = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
+ nesqp->nesqp_context->rcv_wnd = cpu_to_le32(cm_node->tcp_cntxt.rcv_wnd <<
+ cm_node->tcp_cntxt.rcv_wscale);
+ nesqp->nesqp_context->snd_max = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+ nesqp->nesqp_context->snd_una = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+ nesqp->nesqp_context->srtt = 0;
+ nesqp->nesqp_context->rttvar = cpu_to_le32(0x6);
+ nesqp->nesqp_context->ssthresh = cpu_to_le32(0x3FFFC000);
+ nesqp->nesqp_context->cwnd = cpu_to_le32(2*cm_node->tcp_cntxt.mss);
+ nesqp->nesqp_context->snd_wl1 = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
+ nesqp->nesqp_context->snd_wl2 = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+ nesqp->nesqp_context->max_snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.max_snd_wnd);
+
+ nes_debug(NES_DBG_CM, "QP%u: rcv_nxt = 0x%08X, snd_nxt = 0x%08X,"
+ " Setting MSS to %u, PDWscale = 0x%08X, rcv_wnd = %u, context misc = 0x%08X.\n",
+ nesqp->hwqp.qp_id, le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
+ le32_to_cpu(nesqp->nesqp_context->snd_nxt),
+ cm_node->tcp_cntxt.mss, le32_to_cpu(nesqp->nesqp_context->pd_index_wscale),
+ le32_to_cpu(nesqp->nesqp_context->rcv_wnd),
+ le32_to_cpu(nesqp->nesqp_context->misc));
+ nes_debug(NES_DBG_CM, " snd_wnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->snd_wnd));
+ nes_debug(NES_DBG_CM, " snd_cwnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->cwnd));
+ nes_debug(NES_DBG_CM, " max_swnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->max_snd_wnd));
+
+ nes_debug(NES_DBG_CM, "Change cm_node state to TSA\n");
+ cm_node->state = NES_CM_STATE_TSA;
+
+ return ret;
+}
+
+
+/**
+ * nes_cm_disconn
+ */
+int nes_cm_disconn(struct nes_qp *nesqp)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+ if (nesqp->disconn_pending == 0) {
+ nesqp->disconn_pending++;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ /* nes_add_ref(&nesqp->ibqp); */
+ /* init our disconnect work element, to */
+ INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker);
+
+ queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_disconnect_worker
+ */
+void nes_disconnect_worker(struct work_struct *work)
+{
+ struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work);
+
+ nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",
+ nesqp->last_aeq, nesqp->hwqp.qp_id);
+ nes_cm_disconn_true(nesqp);
+}
+
+
+/**
+ * nes_cm_disconn_true
+ */
+int nes_cm_disconn_true(struct nes_qp *nesqp)
+{
+ unsigned long flags;
+ int ret = 0;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ struct nes_vnic *nesvnic;
+ u16 last_ae;
+ u8 original_hw_tcp_state;
+ u8 original_ibqp_state;
+ u8 issued_disconnect_reset = 0;
+
+ if (!nesqp) {
+ nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n");
+ return -1;
+ }
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+ cm_id = nesqp->cm_id;
+ /* make sure we havent already closed this connection */
+ if (!cm_id) {
+ nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",
+ nesqp->hwqp.qp_id);
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -1;
+ }
+
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ nes_debug(NES_DBG_CM, "Disconnecting QP%u\n", nesqp->hwqp.qp_id);
+
+ original_hw_tcp_state = nesqp->hw_tcp_state;
+ original_ibqp_state = nesqp->ibqp_state;
+ last_ae = nesqp->last_aeq;
+
+
+ nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state);
+
+ if ((nesqp->cm_id) && (cm_id->event_handler)) {
+ if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ ((original_ibqp_state == IB_QPS_RTS) &&
+ (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ atomic_inc(&cm_disconnects);
+ cm_event.event = IW_CM_EVENT_DISCONNECT;
+ if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
+ issued_disconnect_reset = 1;
+ cm_event.status = IW_CM_EVENT_STATUS_RESET;
+ nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event (status reset) for "
+ " QP%u, cm_id = %p. \n",
+ nesqp->hwqp.qp_id, cm_id);
+ } else {
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
+ }
+
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event for "
+ " QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u.\n",
+ nesqp->hwqp.qp_id,
+ nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id,
+ atomic_read(&nesqp->refcount));
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ }
+
+ nesqp->disconn_pending = 0;
+ /* There might have been another AE while the lock was released */
+ original_hw_tcp_state = nesqp->hw_tcp_state;
+ original_ibqp_state = nesqp->ibqp_state;
+ last_ae = nesqp->last_aeq;
+
+ if ((issued_disconnect_reset == 0) && (nesqp->cm_id) &&
+ ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+ (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||
+ (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
+ (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ atomic_inc(&cm_closes);
+ nesqp->cm_id = NULL;
+ nesqp->in_disconnect = 0;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_disconnect(nesqp, 1);
+
+ cm_id->provider_data = nesqp;
+ /* Send up the close complete event */
+ cm_event.event = IW_CM_EVENT_CLOSE;
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret) {
+ nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+ }
+
+ cm_id->rem_ref(cm_id);
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+ if (nesqp->flush_issued == 0) {
+ nesqp->flush_issued = 1;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ }
+
+ /* This reference is from either ModifyQP or the AE processing,
+ there is still a race here with modifyqp */
+ nes_rem_ref(&nesqp->ibqp);
+
+ } else {
+ cm_id = nesqp->cm_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ /* check to see if the inbound reset beat the outbound reset */
+ if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) {
+ nes_debug(NES_DBG_CM, "QP%u: Decing refcount due to inbound reset"
+ " beating the outbound reset.\n",
+ nesqp->hwqp.qp_id);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ }
+ } else {
+ nesqp->disconn_pending = 0;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ }
+ nes_rem_ref(&nesqp->ibqp);
+
+ return 0;
+}
+
+
+/**
+ * nes_disconnect
+ */
+int nes_disconnect(struct nes_qp *nesqp, int abrupt)
+{
+ int ret = 0;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ if (!nesvnic)
+ return -EINVAL;
+
+ nesdev = nesvnic->nesdev;
+
+ nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
+ atomic_read(&nesvnic->netdev->refcnt));
+
+ if (nesqp->active_conn) {
+
+ /* indicate this connection is NOT active */
+ nesqp->active_conn = 0;
+ } else {
+ /* Need to free the Last Streaming Mode Message */
+ if (nesqp->ietf_frame) {
+ pci_free_consistent(nesdev->pcidev,
+ nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
+ nesqp->ietf_frame, nesqp->ietf_frame_pbase);
+ }
+ }
+
+ /* close the CM node down if it is still active */
+ if (nesqp->cm_node) {
+ nes_debug(NES_DBG_CM, "Call close API\n");
+
+ g_cm_core->api->close(g_cm_core, nesqp->cm_node);
+ nesqp->cm_node = NULL;
+ }
+
+ return ret;
+}
+
+
+/**
+ * nes_accept
+ */
+int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ u64 u64temp;
+ struct ib_qp *ibqp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+ struct nes_cm_node *cm_node;
+ struct nes_adapter *adapter;
+ struct ib_qp_attr attr;
+ struct iw_cm_event cm_event;
+ struct nes_hw_qp_wqe *wqe;
+ struct nes_v4_quad nes_quad;
+ int ret;
+
+ ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+ if (!ibqp)
+ return -EINVAL;
+
+ /* get all our handles */
+ nesqp = to_nesqp(ibqp);
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ nesdev = nesvnic->nesdev;
+ adapter = nesdev->nesadapter;
+
+ nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
+ nesvnic, nesvnic->netdev, nesvnic->netdev->name);
+
+ /* since this is from a listen, we were able to put node handle into cm_id */
+ cm_node = (struct nes_cm_node *)cm_id->provider_data;
+
+ /* associate the node with the QP */
+ nesqp->cm_node = (void *)cm_node;
+
+ nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n",
+ nesqp->hwqp.qp_id, cm_node, jiffies);
+ atomic_inc(&cm_accepts);
+
+ nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
+ atomic_read(&nesvnic->netdev->refcnt));
+
+ /* allocate the ietf frame and space for private data */
+ nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
+ sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
+ &nesqp->ietf_frame_pbase);
+
+ if (!nesqp->ietf_frame) {
+ nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");
+ return -ENOMEM;
+ }
+
+
+ /* setup the MPA frame */
+ nesqp->private_data_len = conn_param->private_data_len;
+ memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
+
+ memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+ conn_param->private_data_len);
+
+ nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len);
+ nesqp->ietf_frame->rev = mpa_version;
+ nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+
+ /* setup our first outgoing iWarp send WQE (the IETF frame response) */
+ wqe = &nesqp->hwqp.sq_vbase[0];
+
+ if (cm_id->remote_addr.sin_addr.s_addr != cm_id->local_addr.sin_addr.s_addr) {
+ u64temp = (unsigned long)nesqp;
+ u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
+ u64temp);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+ cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+ cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
+ cpu_to_le32((u32)nesqp->ietf_frame_pbase);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
+ cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
+ cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
+ NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU);
+ } else {
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+ NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
+ }
+ nesqp->skip_lsmm = 1;
+
+
+ /* Cache the cm_id in the qp */
+ nesqp->cm_id = cm_id;
+ cm_node->cm_id = cm_id;
+
+ /* nesqp->cm_node = (void *)cm_id->provider_data; */
+ cm_id->provider_data = nesqp;
+ nesqp->active_conn = 0;
+
+ nes_cm_init_tsa_conn(nesqp, cm_node);
+
+ nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+ nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+ nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+
+ nesqp->nesqp_context->misc2 |= cpu_to_le32(
+ (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+
+ nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
+ nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
+ NES_ARP_RESOLVE) << 16);
+
+ nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
+ jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
+
+ nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
+
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
+ ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+
+ memset(&nes_quad, 0, sizeof(nes_quad));
+ nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+ nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+ nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
+ nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
+
+ /* Produce hash key */
+ nesqp->hte_index = cpu_to_be32(
+ crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+ nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
+ nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
+
+ nesqp->hte_index &= adapter->hte_index_mask;
+ nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
+
+ cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
+
+ nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X,"
+ " rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%zu.\n",
+ nesqp->hwqp.qp_id,
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohl(cm_id->local_addr.sin_addr.s_addr),
+ ntohs(cm_id->local_addr.sin_port),
+ le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
+ le32_to_cpu(nesqp->nesqp_context->snd_nxt),
+ conn_param->private_data_len+sizeof(struct ietf_mpa_frame));
+
+ attr.qp_state = IB_QPS_RTS;
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+
+ /* notify OF layer that accept event was successfull */
+ cm_id->add_ref(cm_id);
+
+ cm_event.event = IW_CM_EVENT_ESTABLISHED;
+ cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+ cm_event.provider_data = (void *)nesqp;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (cm_node->loopbackpartner) {
+ cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len;
+ /* copy entire MPA frame to our cm_node's frame */
+ memcpy(cm_node->loopbackpartner->mpa_frame_buf, nesqp->ietf_frame->priv_data,
+ nesqp->private_data_len);
+ create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
+ }
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return 0;
+}
+
+
+/**
+ * nes_reject
+ */
+int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+ struct nes_cm_node *cm_node;
+ struct nes_cm_core *cm_core;
+
+ atomic_inc(&cm_rejects);
+ cm_node = (struct nes_cm_node *) cm_id->provider_data;
+ cm_core = cm_node->cm_core;
+ cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
+
+ strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
+ memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+
+ cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
+ cm_node->mpa_frame.rev = mpa_version;
+ cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
+
+ cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
+
+ return 0;
+}
+
+
+/**
+ * nes_connect
+ * setup and launch cm connect node
+ */
+int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ struct ib_qp *ibqp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+ struct nes_cm_node *cm_node;
+ struct nes_cm_info cm_info;
+
+ ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+ if (!ibqp)
+ return -EINVAL;
+ nesqp = to_nesqp(ibqp);
+ if (!nesqp)
+ return -EINVAL;
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ if (!nesvnic)
+ return -EINVAL;
+ nesdev = nesvnic->nesdev;
+ if (!nesdev)
+ return -EINVAL;
+
+ atomic_inc(&cm_connects);
+
+ nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) +
+ conn_param->private_data_len, GFP_KERNEL);
+ if (!nesqp->ietf_frame)
+ return -ENOMEM;
+
+ /* set qp as having an active connection */
+ nesqp->active_conn = 1;
+
+ nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n",
+ nesqp->hwqp.qp_id,
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohl(cm_id->local_addr.sin_addr.s_addr),
+ ntohs(cm_id->local_addr.sin_port));
+
+ /* cache the cm_id in the qp */
+ nesqp->cm_id = cm_id;
+
+ cm_id->provider_data = nesqp;
+
+ /* copy the private data */
+ if (conn_param->private_data_len) {
+ memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+ conn_param->private_data_len);
+ }
+
+ nesqp->private_data_len = conn_param->private_data_len;
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+ nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
+ nes_debug(NES_DBG_CM, "mpa private data len =%u\n", conn_param->private_data_len);
+
+ strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ);
+ nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+ nesqp->ietf_frame->rev = IETF_MPA_VERSION;
+ nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len);
+
+ if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+ nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+ PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+
+ /* set up the connection params for the node */
+ cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr);
+ cm_info.loc_port = (cm_id->local_addr.sin_port);
+ cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr);
+ cm_info.rem_port = (cm_id->remote_addr.sin_port);
+ cm_info.cm_id = cm_id;
+ cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+ cm_id->add_ref(cm_id);
+ nes_add_ref(&nesqp->ibqp);
+
+ /* create a connect CM node connection */
+ cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, nesqp->ietf_frame, &cm_info);
+ if (!cm_node) {
+ if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+ nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+ PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+ nes_rem_ref(&nesqp->ibqp);
+ kfree(nesqp->ietf_frame);
+ nesqp->ietf_frame = NULL;
+ cm_id->rem_ref(cm_id);
+ return -ENOMEM;
+ }
+
+ cm_node->apbvt_set = 1;
+ nesqp->cm_node = cm_node;
+
+ return 0;
+}
+
+
+/**
+ * nes_create_listen
+ */
+int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+ struct nes_vnic *nesvnic;
+ struct nes_cm_listener *cm_node;
+ struct nes_cm_info cm_info;
+ struct nes_adapter *adapter;
+ int err;
+
+
+ nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
+ cm_id, ntohs(cm_id->local_addr.sin_port));
+
+ nesvnic = to_nesvnic(cm_id->device);
+ if (!nesvnic)
+ return -EINVAL;
+ adapter = nesvnic->nesdev->nesadapter;
+ nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
+ nesvnic, nesvnic->netdev, nesvnic->netdev->name);
+
+ nes_debug(NES_DBG_CM, "nesvnic->local_ipaddr=0x%08x, sin_addr.s_addr=0x%08x\n",
+ nesvnic->local_ipaddr, cm_id->local_addr.sin_addr.s_addr);
+
+ /* setup listen params in our api call struct */
+ cm_info.loc_addr = nesvnic->local_ipaddr;
+ cm_info.loc_port = cm_id->local_addr.sin_port;
+ cm_info.backlog = backlog;
+ cm_info.cm_id = cm_id;
+
+ cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+
+ cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
+ if (!cm_node) {
+ printk("%s[%u] Error returned from listen API call\n",
+ __FUNCTION__, __LINE__);
+ return -ENOMEM;
+ }
+
+ cm_id->provider_data = cm_node;
+
+ if (!cm_node->reused_node) {
+ err = nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+ PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+ if (err) {
+ printk("nes_manage_apbvt call returned %d.\n", err);
+ g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
+ return err;
+ }
+ cm_listens_created++;
+ }
+
+ cm_id->add_ref(cm_id);
+ cm_id->provider_data = (void *)cm_node;
+
+
+ return 0;
+}
+
+
+/**
+ * nes_destroy_listen
+ */
+int nes_destroy_listen(struct iw_cm_id *cm_id)
+{
+ if (cm_id->provider_data)
+ g_cm_core->api->stop_listener(g_cm_core, cm_id->provider_data);
+ else
+ nes_debug(NES_DBG_CM, "cm_id->provider_data was NULL\n");
+
+ cm_id->rem_ref(cm_id);
+
+ return 0;
+}
+
+
+/**
+ * nes_cm_recv
+ */
+int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
+{
+ cm_packets_received++;
+ if ((g_cm_core) && (g_cm_core->api)) {
+ g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
+ } else {
+ nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
+ " cm is not setup properly.\n");
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_cm_start
+ * Start and init a cm core module
+ */
+int nes_cm_start(void)
+{
+ nes_debug(NES_DBG_CM, "\n");
+ /* create the primary CM core, pass this handle to subsequent core inits */
+ g_cm_core = nes_cm_alloc_core();
+ if (g_cm_core) {
+ return 0;
+ } else {
+ return -ENOMEM;
+ }
+}
+
+
+/**
+ * nes_cm_stop
+ * stop and dealloc all cm core instances
+ */
+int nes_cm_stop(void)
+{
+ g_cm_core->api->destroy_cm_core(g_cm_core);
+ return 0;
+}
+
+
+/**
+ * cm_event_connected
+ * handle a connected event, setup QPs and HW
+ */
+void cm_event_connected(struct nes_cm_event *event)
+{
+ u64 u64temp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+ struct nes_cm_node *cm_node;
+ struct nes_adapter *nesadapter;
+ struct ib_qp_attr attr;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ struct nes_hw_qp_wqe *wqe;
+ struct nes_v4_quad nes_quad;
+ int ret;
+
+ /* get all our handles */
+ cm_node = event->cm_node;
+ cm_id = cm_node->cm_id;
+ nes_debug(NES_DBG_CM, "cm_event_connected - %p - cm_id = %p\n", cm_node, cm_id);
+ nesqp = (struct nes_qp *)cm_id->provider_data;
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ nesdev = nesvnic->nesdev;
+ nesadapter = nesdev->nesadapter;
+
+ if (nesqp->destroyed) {
+ return;
+ }
+ atomic_inc(&cm_connecteds);
+ nes_debug(NES_DBG_CM, "QP%u attempting to connect to 0x%08X:0x%04X on"
+ " local port 0x%04X. jiffies = %lu.\n",
+ nesqp->hwqp.qp_id,
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohs(cm_id->local_addr.sin_port),
+ jiffies);
+
+ nes_cm_init_tsa_conn(nesqp, cm_node);
+
+ /* set the QP tsa context */
+ nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+ nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+ nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+
+ nesqp->nesqp_context->misc2 |= cpu_to_le32(
+ (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+ nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
+ nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0),
+ NULL, NES_ARP_RESOLVE) << 16);
+ nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
+ jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
+ nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
+ nesqp->nesqp_context->ird_ord_sizes |=
+ cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
+
+ /* Adjust tail for not having a LSMM */
+ nesqp->hwqp.sq_tail = 1;
+
+#if defined(NES_SEND_FIRST_WRITE)
+ if (cm_node->send_write0) {
+ nes_debug(NES_DBG_CM, "Sending first write.\n");
+ wqe = &nesqp->hwqp.sq_vbase[0];
+ u64temp = (unsigned long)nesqp;
+ u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
+ u64temp);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+ /* use the reserved spot on the WQ for the extra first WQE */
+ nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+ NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
+ nesqp->skip_lsmm = 1;
+ nesqp->hwqp.sq_tail = 0;
+ nes_write32(nesdev->regs + NES_WQE_ALLOC,
+ (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+ }
+#endif
+
+ memset(&nes_quad, 0, sizeof(nes_quad));
+
+ nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+ nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+ nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
+ nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
+
+ /* Produce hash key */
+ nesqp->hte_index = cpu_to_be32(
+ crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+ nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",
+ nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
+
+ nesqp->hte_index &= nesadapter->hte_index_mask;
+ nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
+
+ nesqp->ietf_frame = &cm_node->mpa_frame;
+ nesqp->private_data_len = (u8) cm_node->mpa_frame_size;
+ cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
+
+ /* modify QP state to rts */
+ attr.qp_state = IB_QPS_RTS;
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+
+ /* notify OF layer we successfully created the requested connection */
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr.sin_family = AF_INET;
+ cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
+ cm_event.remote_addr = cm_id->remote_addr;
+
+ cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
+ cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
+
+ cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr;
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n",
+ nesqp->hwqp.qp_id, jiffies );
+
+ nes_rem_ref(&nesqp->ibqp);
+
+ return;
+}
+
+
+/**
+ * cm_event_connect_error
+ */
+void cm_event_connect_error(struct nes_cm_event *event)
+{
+ struct nes_qp *nesqp;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ /* struct nes_cm_info cm_info; */
+ int ret;
+
+ if (!event->cm_node)
+ return;
+
+ cm_id = event->cm_node->cm_id;
+ if (!cm_id) {
+ return;
+ }
+
+ nes_debug(NES_DBG_CM, "cm_node=%p, cm_id=%p\n", event->cm_node, cm_id);
+ nesqp = cm_id->provider_data;
+
+ if (!nesqp) {
+ return;
+ }
+
+ /* notify OF layer about this connection error event */
+ /* cm_id->rem_ref(cm_id); */
+ nesqp->cm_id = NULL;
+ cm_id->provider_data = NULL;
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.status = IW_CM_EVENT_STATUS_REJECTED;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remove_addr=%08x\n",
+ cm_event.local_addr.sin_addr.s_addr, cm_event.remote_addr.sin_addr.s_addr);
+
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ nes_rem_ref(&nesqp->ibqp);
+ cm_id->rem_ref(cm_id);
+
+ return;
+}
+
+
+/**
+ * cm_event_reset
+ */
+void cm_event_reset(struct nes_cm_event *event)
+{
+ struct nes_qp *nesqp;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ /* struct nes_cm_info cm_info; */
+ int ret;
+
+ if (!event->cm_node)
+ return;
+
+ if (!event->cm_node->cm_id)
+ return;
+
+ cm_id = event->cm_node->cm_id;
+
+ nes_debug(NES_DBG_CM, "%p - cm_id = %p\n", event->cm_node, cm_id);
+ nesqp = cm_id->provider_data;
+
+ nesqp->cm_id = NULL;
+ /* cm_id->provider_data = NULL; */
+ cm_event.event = IW_CM_EVENT_DISCONNECT;
+ cm_event.status = IW_CM_EVENT_STATUS_RESET;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+
+
+ /* notify OF layer about this connection error event */
+ cm_id->rem_ref(cm_id);
+
+ return;
+}
+
+
+/**
+ * cm_event_mpa_req
+ */
+void cm_event_mpa_req(struct nes_cm_event *event)
+{
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ int ret;
+ struct nes_cm_node *cm_node;
+
+ cm_node = event->cm_node;
+ if (!cm_node)
+ return;
+ cm_id = cm_node->cm_id;
+
+ atomic_inc(&cm_connect_reqs);
+ nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
+ cm_node, cm_id, jiffies);
+
+ cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.provider_data = (void *)cm_node;
+
+ cm_event.local_addr.sin_family = AF_INET;
+ cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
+ cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);
+
+ cm_event.remote_addr.sin_family = AF_INET;
+ cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
+ cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
+
+ cm_event.private_data = cm_node->mpa_frame_buf;
+ cm_event.private_data_len = (u8) cm_node->mpa_frame_size;
+
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return;
+}
+
+
+static void nes_cm_event_handler(struct work_struct *);
+
+/**
+ * nes_cm_post_event
+ * post an event to the cm event handler
+ */
+int nes_cm_post_event(struct nes_cm_event *event)
+{
+ atomic_inc(&event->cm_node->cm_core->events_posted);
+ add_ref_cm_node(event->cm_node);
+ event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
+ INIT_WORK(&event->event_work, nes_cm_event_handler);
+ nes_debug(NES_DBG_CM, "queue_work, event=%p\n", event);
+
+ queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
+
+ nes_debug(NES_DBG_CM, "Exit\n");
+ return 0;
+}
+
+
+/**
+ * nes_cm_event_handler
+ * worker function to handle cm events
+ * will free instance of nes_cm_event
+ */
+static void nes_cm_event_handler(struct work_struct *work)
+{
+ struct nes_cm_event *event = container_of(work, struct nes_cm_event, event_work);
+ struct nes_cm_core *cm_core;
+
+ if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) {
+ return;
+ }
+ cm_core = event->cm_node->cm_core;
+ nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",
+ event, event->type, atomic_read(&cm_core->events_posted));
+
+ switch (event->type) {
+ case NES_CM_EVENT_MPA_REQ:
+ cm_event_mpa_req(event);
+ nes_debug(NES_DBG_CM, "CM Event: MPA REQUEST\n");
+ break;
+ case NES_CM_EVENT_RESET:
+ nes_debug(NES_DBG_CM, "CM Event: RESET\n");
+ cm_event_reset(event);
+ break;
+ case NES_CM_EVENT_CONNECTED:
+ if ((!event->cm_node->cm_id) ||
+ (event->cm_node->state != NES_CM_STATE_TSA)) {
+ break;
+ }
+ cm_event_connected(event);
+ nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
+ break;
+ case NES_CM_EVENT_ABORTED:
+ if ((!event->cm_node->cm_id) || (event->cm_node->state == NES_CM_STATE_TSA)) {
+ break;
+ }
+ cm_event_connect_error(event);
+ nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
+ break;
+ case NES_CM_EVENT_DROPPED_PKT:
+ nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
+ break;
+ default:
+ nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
+ break;
+ }
+
+ atomic_dec(&cm_core->events_posted);
+ event->cm_info.cm_id->rem_ref(event->cm_info.cm_id);
+ rem_ref_cm_node(cm_core, event->cm_node);
+ kfree(event);
+
+ return;
+}
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
new file mode 100644
index 0000000..a59f0a7
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_CM_H
+#define NES_CM_H
+
+#define QUEUE_EVENTS
+
+#define NES_MANAGE_APBVT_DEL 0
+#define NES_MANAGE_APBVT_ADD 1
+
+/* IETF MPA -- defines, enums, structs */
+#define IEFT_MPA_KEY_REQ "MPA ID Req Frame"
+#define IEFT_MPA_KEY_REP "MPA ID Rep Frame"
+#define IETF_MPA_KEY_SIZE 16
+#define IETF_MPA_VERSION 1
+
+enum ietf_mpa_flags {
+ IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */
+ IETF_MPA_FLAGS_CRC = 0x40, /* receive Markers */
+ IETF_MPA_FLAGS_REJECT = 0x20, /* Reject */
+};
+
+struct ietf_mpa_frame {
+ u8 key[IETF_MPA_KEY_SIZE];
+ u8 flags;
+ u8 rev;
+ __be16 priv_data_len;
+ u8 priv_data[0];
+};
+
+#define ietf_mpa_req_resp_frame ietf_mpa_frame
+
+struct nes_v4_quad {
+ u32 rsvd0;
+ __le32 DstIpAdrIndex; /* Only most significant 5 bits are valid */
+ __be32 SrcIpadr;
+ __be16 TcpPorts[2]; /* src is low, dest is high */
+};
+
+struct nes_cm_node;
+enum nes_timer_type {
+ NES_TIMER_TYPE_SEND,
+ NES_TIMER_TYPE_RECV,
+ NES_TIMER_NODE_CLEANUP,
+ NES_TIMER_TYPE_CLOSE,
+};
+
+#define MAX_NES_IFS 4
+
+#define SET_ACK 1
+#define SET_SYN 2
+#define SET_FIN 4
+#define SET_RST 8
+
+struct option_base {
+ u8 optionnum;
+ u8 length;
+};
+
+enum option_numbers {
+ OPTION_NUMBER_END,
+ OPTION_NUMBER_NONE,
+ OPTION_NUMBER_MSS,
+ OPTION_NUMBER_WINDOW_SCALE,
+ OPTION_NUMBER_SACK_PERM,
+ OPTION_NUMBER_SACK,
+ OPTION_NUMBER_WRITE0 = 0xbc
+};
+
+struct option_mss {
+ u8 optionnum;
+ u8 length;
+ __be16 mss;
+};
+
+struct option_windowscale {
+ u8 optionnum;
+ u8 length;
+ u8 shiftcount;
+};
+
+union all_known_options {
+ char as_end;
+ struct option_base as_base;
+ struct option_mss as_mss;
+ struct option_windowscale as_windowscale;
+};
+
+struct nes_timer_entry {
+ struct list_head list;
+ unsigned long timetosend; /* jiffies */
+ struct sk_buff *skb;
+ u32 type;
+ u32 retrycount;
+ u32 retranscount;
+ u32 context;
+ u32 seq_num;
+ u32 send_retrans;
+ int close_when_complete;
+ struct net_device *netdev;
+};
+
+#define NES_DEFAULT_RETRYS 64
+#define NES_DEFAULT_RETRANS 8
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+#define NES_RETRY_TIMEOUT (1000*HZ/1000)
+#else
+#define NES_RETRY_TIMEOUT (3000*HZ/1000)
+#endif
+#define NES_SHORT_TIME (10)
+#define NES_LONG_TIME (2000*HZ/1000)
+
+#define NES_CM_HASHTABLE_SIZE 1024
+#define NES_CM_TCP_TIMER_INTERVAL 3000
+#define NES_CM_DEFAULT_MTU 1540
+#define NES_CM_DEFAULT_FRAME_CNT 10
+#define NES_CM_THREAD_STACK_SIZE 256
+#define NES_CM_DEFAULT_RCV_WND 64240 // before we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALED 256960 // after we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALE 2
+#define NES_CM_DEFAULT_FREE_PKTS 0x000A
+#define NES_CM_FREE_PKT_LO_WATERMARK 2
+
+#define NES_CM_DEFAULT_MSS 536
+
+#define NES_CM_DEF_SEQ 0x159bf75f
+#define NES_CM_DEF_LOCAL_ID 0x3b47
+
+#define NES_CM_DEF_SEQ2 0x18ed5740
+#define NES_CM_DEF_LOCAL_ID2 0xb807
+
+typedef u32 nes_addr_t;
+
+#define nes_cm_tsa_context nes_qp_context
+
+struct nes_qp;
+
+/* cm node transition states */
+enum nes_cm_node_state {
+ NES_CM_STATE_UNKNOWN,
+ NES_CM_STATE_INITED,
+ NES_CM_STATE_LISTENING,
+ NES_CM_STATE_SYN_RCVD,
+ NES_CM_STATE_SYN_SENT,
+ NES_CM_STATE_ONE_SIDE_ESTABLISHED,
+ NES_CM_STATE_ESTABLISHED,
+ NES_CM_STATE_ACCEPTING,
+ NES_CM_STATE_MPAREQ_SENT,
+ NES_CM_STATE_TSA,
+ NES_CM_STATE_FIN_WAIT1,
+ NES_CM_STATE_FIN_WAIT2,
+ NES_CM_STATE_CLOSE_WAIT,
+ NES_CM_STATE_TIME_WAIT,
+ NES_CM_STATE_LAST_ACK,
+ NES_CM_STATE_CLOSING,
+ NES_CM_STATE_CLOSED
+};
+
+/* type of nes connection */
+enum nes_cm_conn_type {
+ NES_CM_IWARP_CONN_TYPE,
+};
+
+/* CM context params */
+struct nes_cm_tcp_context {
+ u8 client;
+
+ u32 loc_seq_num;
+ u32 loc_ack_num;
+ u32 rem_ack_num;
+ u32 rcv_nxt;
+
+ u32 loc_id;
+ u32 rem_id;
+
+ u32 snd_wnd;
+ u32 max_snd_wnd;
+
+ u32 rcv_wnd;
+ u32 mss;
+ u8 snd_wscale;
+ u8 rcv_wscale;
+
+ struct nes_cm_tsa_context tsa_cntxt;
+ struct timeval sent_ts;
+};
+
+
+enum nes_cm_listener_state {
+ NES_CM_LISTENER_PASSIVE_STATE=1,
+ NES_CM_LISTENER_ACTIVE_STATE=2,
+ NES_CM_LISTENER_EITHER_STATE=3
+};
+
+struct nes_cm_listener {
+ struct list_head list;
+ u64 session_id;
+ struct nes_cm_core *cm_core;
+ u8 loc_mac[ETH_ALEN];
+ nes_addr_t loc_addr;
+ u16 loc_port;
+ struct iw_cm_id *cm_id;
+ enum nes_cm_conn_type conn_type;
+ atomic_t ref_count;
+ struct nes_vnic *nesvnic;
+ atomic_t pend_accepts_cnt;
+ int backlog;
+ enum nes_cm_listener_state listener_state;
+ u32 reused_node;
+};
+
+/* per connection node and node state information */
+struct nes_cm_node {
+ u64 session_id;
+ u32 hashkey;
+
+ nes_addr_t loc_addr, rem_addr;
+ u16 loc_port, rem_port;
+
+ u8 loc_mac[ETH_ALEN];
+ u8 rem_mac[ETH_ALEN];
+
+ enum nes_cm_node_state state;
+ struct nes_cm_tcp_context tcp_cntxt;
+ struct nes_cm_core *cm_core;
+ struct sk_buff_head resend_list;
+ atomic_t ref_count;
+ struct net_device *netdev;
+
+ struct nes_cm_node *loopbackpartner;
+ struct list_head retrans_list;
+ spinlock_t retrans_list_lock;
+ struct list_head recv_list;
+ spinlock_t recv_list_lock;
+
+ int send_write0;
+ union {
+ struct ietf_mpa_frame mpa_frame;
+ u8 mpa_frame_buf[NES_CM_DEFAULT_MTU];
+ };
+ u16 mpa_frame_size;
+ struct iw_cm_id *cm_id;
+ struct list_head list;
+ int accelerated;
+ struct nes_cm_listener *listener;
+ enum nes_cm_conn_type conn_type;
+ struct nes_vnic *nesvnic;
+ int apbvt_set;
+ int accept_pend;
+};
+
+/* structure for client or CM to fill when making CM api calls. */
+/* - only need to set relevant data, based on op. */
+struct nes_cm_info {
+ union {
+ struct iw_cm_id *cm_id;
+ struct net_device *netdev;
+ };
+
+ u16 loc_port;
+ u16 rem_port;
+ nes_addr_t loc_addr;
+ nes_addr_t rem_addr;
+
+ enum nes_cm_conn_type conn_type;
+ int backlog;
+};
+
+/* CM event codes */
+enum nes_cm_event_type {
+ NES_CM_EVENT_UNKNOWN,
+ NES_CM_EVENT_ESTABLISHED,
+ NES_CM_EVENT_MPA_REQ,
+ NES_CM_EVENT_MPA_CONNECT,
+ NES_CM_EVENT_MPA_ACCEPT,
+ NES_CM_EVENT_MPA_ESTABLISHED,
+ NES_CM_EVENT_CONNECTED,
+ NES_CM_EVENT_CLOSED,
+ NES_CM_EVENT_RESET,
+ NES_CM_EVENT_DROPPED_PKT,
+ NES_CM_EVENT_CLOSE_IMMED,
+ NES_CM_EVENT_CLOSE_HARD,
+ NES_CM_EVENT_CLOSE_CLEAN,
+ NES_CM_EVENT_ABORTED,
+ NES_CM_EVENT_SEND_FIRST
+};
+
+/* event to post to CM event handler */
+struct nes_cm_event {
+ enum nes_cm_event_type type;
+
+ struct nes_cm_info cm_info;
+ struct work_struct event_work;
+ struct nes_cm_node *cm_node;
+};
+
+struct nes_cm_core {
+ enum nes_cm_node_state state;
+ atomic_t session_id;
+
+ atomic_t listen_node_cnt;
+ struct nes_cm_node listen_list;
+ spinlock_t listen_list_lock;
+
+ u32 mtu;
+ u32 free_tx_pkt_max;
+ u32 rx_pkt_posted;
+ struct sk_buff_head tx_free_list;
+ atomic_t ht_node_cnt;
+ struct list_head connected_nodes;
+ /* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */
+ spinlock_t ht_lock;
+
+ struct timer_list tcp_timer;
+
+ struct nes_cm_ops *api;
+
+ int (*post_event)(struct nes_cm_event *event);
+ atomic_t events_posted;
+ struct workqueue_struct *event_wq;
+ struct workqueue_struct *disconn_wq;
+
+ atomic_t node_cnt;
+ u64 aborted_connects;
+ u32 options;
+
+ struct nes_cm_node *current_listen_node;
+};
+
+
+#define NES_CM_SET_PKT_SIZE (1 << 1)
+#define NES_CM_SET_FREE_PKT_Q_SIZE (1 << 2)
+
+/* CM ops/API for client interface */
+struct nes_cm_ops {
+ int (*accelerated)(struct nes_cm_core *, struct nes_cm_node *);
+ struct nes_cm_listener * (*listen)(struct nes_cm_core *, struct nes_vnic *,
+ struct nes_cm_info *);
+ int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *);
+ struct nes_cm_node * (*connect)(struct nes_cm_core *,
+ struct nes_vnic *, struct ietf_mpa_frame *,
+ struct nes_cm_info *);
+ int (*close)(struct nes_cm_core *, struct nes_cm_node *);
+ int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *,
+ struct nes_cm_node *);
+ int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *,
+ struct nes_cm_node *);
+ int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
+ struct sk_buff *);
+ int (*destroy_cm_core)(struct nes_cm_core *);
+ int (*get)(struct nes_cm_core *);
+ int (*set)(struct nes_cm_core *, u32, u32);
+};
+
+
+int send_mpa_request(struct nes_cm_node *);
+struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+ void *, u32, void *, u32, u8);
+int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *,
+ enum nes_timer_type, int, int);
+void nes_cm_timer_tick(unsigned long);
+int send_syn(struct nes_cm_node *, u32);
+int send_reset(struct nes_cm_node *);
+int send_ack(struct nes_cm_node *);
+int send_fin(struct nes_cm_node *, struct sk_buff *);
+struct sk_buff *get_free_pkt(struct nes_cm_node *);
+int process_packet(struct nes_cm_node *, struct sk_buff *, struct nes_cm_core *);
+
+struct nes_cm_node * mini_cm_connect(struct nes_cm_core *,
+ struct nes_vnic *, struct ietf_mpa_frame *, struct nes_cm_info *);
+int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
+int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);
+struct nes_cm_core *mini_cm_alloc_core(struct nes_cm_info *);
+int mini_cm_dealloc_core(struct nes_cm_core *);
+int mini_cm_get(struct nes_cm_core *);
+int mini_cm_set(struct nes_cm_core *, u32, u32);
+
+int nes_cm_disconn(struct nes_qp *);
+void nes_disconnect_worker(struct work_struct *);
+int nes_cm_disconn_true(struct nes_qp *);
+int nes_disconnect(struct nes_qp *, int);
+
+int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *);
+int nes_reject(struct iw_cm_id *, const void *, u8);
+int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *);
+int nes_create_listen(struct iw_cm_id *, int);
+int nes_destroy_listen(struct iw_cm_id *);
+
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+int nes_cm_start(void);
+int nes_cm_stop(void);
+
+/* CM event handler functions */
+void cm_event_connected(struct nes_cm_event *);
+void cm_event_connect_error(struct nes_cm_event *);
+void cm_event_reset(struct nes_cm_event *);
+void cm_event_mpa_req(struct nes_cm_event *);
+int nes_cm_post_event(struct nes_cm_event *);
+
+#endif /* NES_CM_H */
diff --git a/drivers/infiniband/hw/nes/nes_context.h b/drivers/infiniband/hw/nes/nes_context.h
new file mode 100644
index 0000000..da9daba
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_context.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef NES_CONTEXT_H
+#define NES_CONTEXT_H
+
+struct nes_qp_context {
+ __le32 misc;
+ __le32 cqs;
+ __le32 sq_addr_low;
+ __le32 sq_addr_high;
+ __le32 rq_addr_low;
+ __le32 rq_addr_high;
+ __le32 misc2;
+ __le16 tcpPorts[2];
+ __le32 ip0;
+ __le32 ip1;
+ __le32 ip2;
+ __le32 ip3;
+ __le32 mss;
+ __le32 arp_index_vlan;
+ __le32 tcp_state_flow_label;
+ __le32 pd_index_wscale;
+ __le32 keepalive;
+ u32 ts_recent;
+ u32 ts_age;
+ __le32 snd_nxt;
+ __le32 snd_wnd;
+ __le32 rcv_nxt;
+ __le32 rcv_wnd;
+ __le32 snd_max;
+ __le32 snd_una;
+ u32 srtt;
+ __le32 rttvar;
+ __le32 ssthresh;
+ __le32 cwnd;
+ __le32 snd_wl1;
+ __le32 snd_wl2;
+ __le32 max_snd_wnd;
+ __le32 ts_val_delta;
+ u32 retransmit;
+ u32 probe_cnt;
+ u32 hte_index;
+ __le32 q2_addr_low;
+ __le32 q2_addr_high;
+ __le32 ird_index;
+ u32 Rsvd3;
+ __le32 ird_ord_sizes;
+ u32 mrkr_offset;
+ __le32 aeq_token_low;
+ __le32 aeq_token_high;
+};
+
+/* QP Context Misc Field */
+
+#define NES_QPCONTEXT_MISC_IWARP_VER_MASK 0x00000003
+#define NES_QPCONTEXT_MISC_IWARP_VER_SHIFT 0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_MASK 0x000000C0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_SHIFT 6
+#define NES_QPCONTEXT_MISC_RQ_SIZE_MASK 0x00000300
+#define NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT 8
+#define NES_QPCONTEXT_MISC_SQ_SIZE_MASK 0x00000c00
+#define NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT 10
+#define NES_QPCONTEXT_MISC_PCI_FCN_MASK 0x00007000
+#define NES_QPCONTEXT_MISC_PCI_FCN_SHIFT 12
+#define NES_QPCONTEXT_MISC_DUP_ACKS_MASK 0x00070000
+#define NES_QPCONTEXT_MISC_DUP_ACKS_SHIFT 16
+
+enum nes_qp_context_misc_bits {
+ NES_QPCONTEXT_MISC_RX_WQE_SIZE = 0x00000004,
+ NES_QPCONTEXT_MISC_IPV4 = 0x00000008,
+ NES_QPCONTEXT_MISC_DO_NOT_FRAG = 0x00000010,
+ NES_QPCONTEXT_MISC_INSERT_VLAN = 0x00000020,
+ NES_QPCONTEXT_MISC_DROS = 0x00008000,
+ NES_QPCONTEXT_MISC_WSCALE = 0x00080000,
+ NES_QPCONTEXT_MISC_KEEPALIVE = 0x00100000,
+ NES_QPCONTEXT_MISC_TIMESTAMP = 0x00200000,
+ NES_QPCONTEXT_MISC_SACK = 0x00400000,
+ NES_QPCONTEXT_MISC_RDMA_WRITE_EN = 0x00800000,
+ NES_QPCONTEXT_MISC_RDMA_READ_EN = 0x01000000,
+ NES_QPCONTEXT_MISC_WBIND_EN = 0x10000000,
+ NES_QPCONTEXT_MISC_FAST_REGISTER_EN = 0x20000000,
+ NES_QPCONTEXT_MISC_PRIV_EN = 0x40000000,
+ NES_QPCONTEXT_MISC_NO_NAGLE = 0x80000000
+};
+
+enum nes_qp_acc_wq_sizes {
+ HCONTEXT_TSA_WQ_SIZE_4 = 0,
+ HCONTEXT_TSA_WQ_SIZE_32 = 1,
+ HCONTEXT_TSA_WQ_SIZE_128 = 2,
+ HCONTEXT_TSA_WQ_SIZE_512 = 3
+};
+
+/* QP Context Misc2 Fields */
+#define NES_QPCONTEXT_MISC2_TTL_MASK 0x000000ff
+#define NES_QPCONTEXT_MISC2_TTL_SHIFT 0
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_MASK 0x000000ff
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_SHIFT 0
+#define NES_QPCONTEXT_MISC2_LIMIT_MASK 0x00000300
+#define NES_QPCONTEXT_MISC2_LIMIT_SHIFT 8
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_MASK 0x0000fc00
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT 10
+#define NES_QPCONTEXT_MISC2_SRC_IP_MASK 0x001f0000
+#define NES_QPCONTEXT_MISC2_SRC_IP_SHIFT 16
+#define NES_QPCONTEXT_MISC2_TOS_MASK 0xff000000
+#define NES_QPCONTEXT_MISC2_TOS_SHIFT 24
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_MASK 0xff000000
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_SHIFT 24
+
+/* QP Context Tcp State/Flow Label Fields */
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_MASK 0x000fffff
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_SHIFT 0
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_MASK 0xf0000000
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT 28
+
+enum nes_qp_tcp_state {
+ NES_QPCONTEXT_TCPSTATE_CLOSED = 1,
+ NES_QPCONTEXT_TCPSTATE_EST = 5,
+ NES_QPCONTEXT_TCPSTATE_TIME_WAIT = 11,
+};
+
+/* QP Context PD Index/wscale Fields */
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK 0x0000000f
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT 0
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK 0x00000f00
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT 8
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_MASK 0xffff0000
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_SHIFT 16
+
+/* QP Context Keepalive Fields */
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_MASK 0x0000ffff
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_SHIFT 0
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_MASK 0x00ff0000
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_SHIFT 16
+#define NES_QPCONTEXT_KEEPALIVE_INTV_MASK 0xff000000
+#define NES_QPCONTEXT_KEEPALIVE_INTV_SHIFT 24
+
+/* QP Context ORD/IRD Fields */
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_MASK 0x0000007f
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_SHIFT 0
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK 0x00030000
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT 16
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_MASK 0x30000000
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT 28
+
+enum nes_ord_ird_bits {
+ NES_QPCONTEXT_ORDIRD_WRPDU = 0x02000000,
+ NES_QPCONTEXT_ORDIRD_LSMM_PRESENT = 0x04000000,
+ NES_QPCONTEXT_ORDIRD_ALSMM = 0x08000000,
+ NES_QPCONTEXT_ORDIRD_AAH = 0x40000000,
+ NES_QPCONTEXT_ORDIRD_RNMC = 0x80000000
+};
+
+enum nes_iwarp_qp_state {
+ NES_QPCONTEXT_IWARP_STATE_NONEXIST = 0,
+ NES_QPCONTEXT_IWARP_STATE_IDLE = 1,
+ NES_QPCONTEXT_IWARP_STATE_RTS = 2,
+ NES_QPCONTEXT_IWARP_STATE_CLOSING = 3,
+ NES_QPCONTEXT_IWARP_STATE_TERMINATE = 5,
+ NES_QPCONTEXT_IWARP_STATE_ERROR = 6
+};
+
+
+#endif /* NES_CONTEXT_H */
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
new file mode 100644
index 0000000..7c4c0fb
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -0,0 +1,3080 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+
+#include "nes.h"
+
+u32 crit_err_count = 0;
+u32 int_mod_timer_init;
+u32 int_mod_cq_depth_256;
+u32 int_mod_cq_depth_128;
+u32 int_mod_cq_depth_32;
+u32 int_mod_cq_depth_24;
+u32 int_mod_cq_depth_16;
+u32 int_mod_cq_depth_4;
+u32 int_mod_cq_depth_1;
+
+#include "nes_cm.h"
+
+
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+static unsigned char *nes_iwarp_state_str[] = {
+ "Non-Existant",
+ "Idle",
+ "RTS",
+ "Closing",
+ "RSVD1",
+ "Terminate",
+ "Error",
+ "RSVD2",
+};
+
+static unsigned char *nes_tcp_state_str[] = {
+ "Non-Existant",
+ "Closed",
+ "Listen",
+ "SYN Sent",
+ "SYN Rcvd",
+ "Established",
+ "Close Wait",
+ "FIN Wait 1",
+ "Closing",
+ "Last Ack",
+ "FIN Wait 2",
+ "Time Wait",
+ "RSVD1",
+ "RSVD2",
+ "RSVD3",
+ "RSVD4",
+};
+#endif
+
+
+/**
+ * nes_nic_init_timer_defaults
+ */
+void nes_nic_init_timer_defaults(struct nes_device *nesdev, u8 jumbomode)
+{
+ unsigned long flags;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+ shared_timer->timer_in_use_min = NES_NIC_FAST_TIMER_LOW;
+ shared_timer->timer_in_use_max = NES_NIC_FAST_TIMER_HIGH;
+ if (jumbomode) {
+ shared_timer->threshold_low = DEFAULT_JUMBO_NES_QL_LOW;
+ shared_timer->threshold_target = DEFAULT_JUMBO_NES_QL_TARGET;
+ shared_timer->threshold_high = DEFAULT_JUMBO_NES_QL_HIGH;
+ } else {
+ shared_timer->threshold_low = DEFAULT_NES_QL_LOW;
+ shared_timer->threshold_target = DEFAULT_NES_QL_TARGET;
+ shared_timer->threshold_high = DEFAULT_NES_QL_HIGH;
+ }
+
+ /* todo use netdev->mtu to set thresholds */
+ spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_nic_init_timer
+ */
+static void nes_nic_init_timer(struct nes_device *nesdev)
+{
+ unsigned long flags;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+ if (shared_timer->timer_in_use_old == 0) {
+ nesdev->deepcq_count = 0;
+ shared_timer->timer_direction_upward = 0;
+ shared_timer->timer_direction_downward = 0;
+ shared_timer->timer_in_use = NES_NIC_FAST_TIMER;
+ shared_timer->timer_in_use_old = 0;
+
+ }
+ if (shared_timer->timer_in_use != shared_timer->timer_in_use_old) {
+ shared_timer->timer_in_use_old = shared_timer->timer_in_use;
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
+ 0x80000000 | ((u32)(shared_timer->timer_in_use*8)));
+ }
+ /* todo use netdev->mtu to set thresholds */
+ spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_nic_tune_timer
+ */
+static void nes_nic_tune_timer(struct nes_device *nesdev)
+{
+ unsigned long flags;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+ u16 cq_count = nesdev->currcq_count;
+
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+ if (shared_timer->cq_count_old < cq_count) {
+ if (cq_count > shared_timer->threshold_low)
+ shared_timer->cq_direction_downward=0;
+ }
+ if (shared_timer->cq_count_old >= cq_count)
+ shared_timer->cq_direction_downward++;
+ shared_timer->cq_count_old = cq_count;
+ if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
+ if (cq_count <= shared_timer->threshold_low) {
+ shared_timer->threshold_low = shared_timer->threshold_low/2;
+ shared_timer->cq_direction_downward=0;
+ nesdev->currcq_count = 0;
+ spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+ return;
+ }
+ }
+
+ if (cq_count > 1) {
+ nesdev->deepcq_count += cq_count;
+ if (cq_count <= shared_timer->threshold_low) { /* increase timer gently */
+ shared_timer->timer_direction_upward++;
+ shared_timer->timer_direction_downward = 0;
+ } else if (cq_count <= shared_timer->threshold_target) { /* balanced */
+ shared_timer->timer_direction_upward = 0;
+ shared_timer->timer_direction_downward = 0;
+ } else if (cq_count <= shared_timer->threshold_high) { /* decrease timer gently */
+ shared_timer->timer_direction_downward++;
+ shared_timer->timer_direction_upward = 0;
+ } else if (cq_count <= (shared_timer->threshold_high) * 2) {
+ shared_timer->timer_in_use -= 2;
+ shared_timer->timer_direction_upward = 0;
+ shared_timer->timer_direction_downward++;
+ } else {
+ shared_timer->timer_in_use -= 4;
+ shared_timer->timer_direction_upward = 0;
+ shared_timer->timer_direction_downward++;
+ }
+
+ if (shared_timer->timer_direction_upward > 3 ) { /* using history */
+ shared_timer->timer_in_use += 3;
+ shared_timer->timer_direction_upward = 0;
+ shared_timer->timer_direction_downward = 0;
+ }
+ if (shared_timer->timer_direction_downward > 5) { /* using history */
+ shared_timer->timer_in_use -= 4 ;
+ shared_timer->timer_direction_downward = 0;
+ shared_timer->timer_direction_upward = 0;
+ }
+ }
+
+ /* boundary checking */
+ if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH)
+ shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH;
+ else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) {
+ shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW;
+ }
+
+ nesdev->currcq_count = 0;
+
+ spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_init_adapter - initialize adapter
+ */
+struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
+ struct nes_adapter *nesadapter = NULL;
+ unsigned long num_pds;
+ u32 u32temp;
+ u32 port_count;
+ u16 max_rq_wrs;
+ u16 max_sq_wrs;
+ u32 max_mr;
+ u32 max_256pbl;
+ u32 max_4kpbl;
+ u32 max_qp;
+ u32 max_irrq;
+ u32 max_cq;
+ u32 hte_index_mask;
+ u32 adapter_size;
+ u32 arp_table_size;
+ u16 vendor_id;
+ u8 OneG_Mode;
+ u8 func_index;
+
+ /* search the list of existing adapters */
+ list_for_each_entry(nesadapter, &nes_adapter_list, list) {
+ nes_debug(NES_DBG_INIT, "Searching Adapter list for PCI devfn = 0x%X,"
+ " adapter PCI slot/bus = %u/%u, pci devices PCI slot/bus = %u/%u, .\n",
+ nesdev->pcidev->devfn,
+ PCI_SLOT(nesadapter->devfn),
+ nesadapter->bus_number,
+ PCI_SLOT(nesdev->pcidev->devfn),
+ nesdev->pcidev->bus->number );
+ if ((PCI_SLOT(nesadapter->devfn) == PCI_SLOT(nesdev->pcidev->devfn)) &&
+ (nesadapter->bus_number == nesdev->pcidev->bus->number)) {
+ nesadapter->ref_count++;
+ return nesadapter;
+ }
+ }
+
+ /* no adapter found */
+ num_pds = pci_resource_len(nesdev->pcidev, BAR_1) >> PAGE_SHIFT;
+ if ((hw_rev != NE020_REV) && (hw_rev != NE020_REV1)) {
+ nes_debug(NES_DBG_INIT, "NE020 driver detected unknown hardware revision 0x%x\n",
+ hw_rev);
+ return NULL;
+ }
+
+ nes_debug(NES_DBG_INIT, "Determine Soft Reset, QP_control=0x%x, CPU0=0x%x, CPU1=0x%x, CPU2=0x%x\n",
+ nes_read_indexed(nesdev, NES_IDX_QP_CONTROL + PCI_FUNC(nesdev->pcidev->devfn) * 8),
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS),
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 4),
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 8));
+
+ nes_debug(NES_DBG_INIT, "Reset and init NE020\n");
+
+
+ if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
+ return NULL;
+ if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
+ return NULL;
+ nes_init_csr_ne020(nesdev, hw_rev, port_count);
+
+ max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
+ nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_QUAD_HASH_TABLE_SIZE);
+ if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
+ nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to hash table size = 0x%08X\n",
+ max_qp, u32temp);
+ max_qp = (u32)1 << (u32temp & 0x001f);
+ }
+
+ hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
+ nes_debug(NES_DBG_INIT, "Max QP = %u, hte_index_mask = 0x%08X.\n",
+ max_qp, hte_index_mask);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_IRRQ_COUNT);
+
+ max_irrq = 1 << (u32temp & 0x001f);
+
+ if (max_qp > max_irrq) {
+ max_qp = max_irrq;
+ nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to Available Q1s.\n",
+ max_qp);
+ }
+
+ /* there should be no reason to allocate more pds than qps */
+ if (num_pds > max_qp)
+ num_pds = max_qp;
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MRT_SIZE);
+ max_mr = (u32)8192 << (u32temp & 0x7);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PBL_REGION_SIZE);
+ max_256pbl = (u32)1 << (u32temp & 0x0000001f);
+ max_4kpbl = (u32)1 << ((u32temp >> 16) & 0x0000001f);
+ max_cq = nes_read_indexed(nesdev, NES_IDX_CQ_CTX_SIZE);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_ARP_CACHE_SIZE);
+ arp_table_size = 1 << u32temp;
+
+ adapter_size = (sizeof(struct nes_adapter) +
+ (sizeof(unsigned long)-1)) & (~(sizeof(unsigned long)-1));
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
+ adapter_size += sizeof(struct nes_qp **) * max_qp;
+
+ /* allocate a new adapter struct */
+ nesadapter = kzalloc(adapter_size, GFP_KERNEL);
+ if (nesadapter == NULL) {
+ return NULL;
+ }
+
+ nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
+ nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
+
+ /* populate the new nesadapter */
+ nesadapter->devfn = nesdev->pcidev->devfn;
+ nesadapter->bus_number = nesdev->pcidev->bus->number;
+ nesadapter->ref_count = 1;
+ nesadapter->timer_int_req = 0xffff0000;
+ nesadapter->OneG_Mode = OneG_Mode;
+ nesadapter->doorbell_start = nesdev->doorbell_region;
+
+ /* nesadapter->tick_delta = clk_divisor; */
+ nesadapter->hw_rev = hw_rev;
+ nesadapter->port_count = port_count;
+
+ nesadapter->max_qp = max_qp;
+ nesadapter->hte_index_mask = hte_index_mask;
+ nesadapter->max_irrq = max_irrq;
+ nesadapter->max_mr = max_mr;
+ nesadapter->max_256pbl = max_256pbl - 1;
+ nesadapter->max_4kpbl = max_4kpbl - 1;
+ nesadapter->max_cq = max_cq;
+ nesadapter->free_256pbl = max_256pbl - 1;
+ nesadapter->free_4kpbl = max_4kpbl - 1;
+ nesadapter->max_pd = num_pds;
+ nesadapter->arp_table_size = arp_table_size;
+
+ nesadapter->et_pkt_rate_low = NES_TIMER_ENABLE_LIMIT;
+ if (nes_drv_opt & NES_DRV_OPT_DISABLE_INT_MOD) {
+ nesadapter->et_use_adaptive_rx_coalesce = 0;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
+ nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+ } else {
+ nesadapter->et_use_adaptive_rx_coalesce = 1;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
+ nesadapter->et_rx_coalesce_usecs_irq = 0;
+ printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __FUNCTION__);
+ }
+ /* Setup and enable the periodic timer */
+ if (nesadapter->et_rx_coalesce_usecs_irq)
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 |
+ ((u32)(nesadapter->et_rx_coalesce_usecs_irq * 8)));
+ else
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x00000000);
+
+ nesadapter->base_pd = 1;
+
+ nesadapter->device_cap_flags =
+ IB_DEVICE_ZERO_STAG | IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW;
+
+ nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
+ [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
+ nesadapter->allocated_cqs = &nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
+ nesadapter->allocated_mrs = &nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
+ nesadapter->allocated_pds = &nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
+ nesadapter->allocated_arps = &nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
+ nesadapter->qp_table = (struct nes_qp **)(&nesadapter->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
+
+
+ /* mark the usual suspect QPs and CQs as in use */
+ for (u32temp = 0; u32temp < NES_FIRST_QPN; u32temp++) {
+ set_bit(u32temp, nesadapter->allocated_qps);
+ set_bit(u32temp, nesadapter->allocated_cqs);
+ }
+
+ for (u32temp = 0; u32temp < 20; u32temp++)
+ set_bit(u32temp, nesadapter->allocated_pds);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_QP_MAX_CFG_SIZES);
+
+ max_rq_wrs = ((u32temp >> 8) & 3);
+ switch (max_rq_wrs) {
+ case 0:
+ max_rq_wrs = 4;
+ break;
+ case 1:
+ max_rq_wrs = 16;
+ break;
+ case 2:
+ max_rq_wrs = 32;
+ break;
+ case 3:
+ max_rq_wrs = 512;
+ break;
+ }
+
+ max_sq_wrs = (u32temp & 3);
+ switch (max_sq_wrs) {
+ case 0:
+ max_sq_wrs = 4;
+ break;
+ case 1:
+ max_sq_wrs = 16;
+ break;
+ case 2:
+ max_sq_wrs = 32;
+ break;
+ case 3:
+ max_sq_wrs = 512;
+ break;
+ }
+ nesadapter->max_qp_wr = min(max_rq_wrs, max_sq_wrs);
+ nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
+
+ nesadapter->max_sge = 4;
+ nesadapter->max_cqe = 32767;
+
+ if (nes_read_eeprom_values(nesdev, nesadapter)) {
+ printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
+ kfree(nesadapter);
+ return NULL;
+ }
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG);
+ nes_write_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG,
+ (u32temp & 0xff000000) | (nesadapter->tcp_timer_core_clk_divisor & 0x00ffffff));
+
+ /* setup port configuration */
+ if (nesadapter->port_count == 1) {
+ u32temp = 0x00000000;
+ if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
+ nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
+ else
+ nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+ } else {
+ if (nesadapter->port_count == 2)
+ u32temp = 0x00000044;
+ else
+ u32temp = 0x000000e4;
+ nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+ }
+
+ nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
+ nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
+ nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
+
+ spin_lock_init(&nesadapter->resource_lock);
+ spin_lock_init(&nesadapter->phy_lock);
+ spin_lock_init(&nesadapter->pbl_lock);
+ spin_lock_init(&nesadapter->periodic_timer_lock);
+
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[0]);
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[1]);
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[2]);
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[3]);
+
+ if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
+ u32 pcs_control_status0, pcs_control_status1;
+ u32 reset_value;
+ u32 i = 0;
+ u32 int_cnt = 0;
+ u32 ext_cnt = 0;
+ unsigned long flags;
+ u32 j = 0;
+
+ pcs_control_status0 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ pcs_control_status1 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+
+ for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
+ pcs_control_status0 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ pcs_control_status1 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+ if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
+ || (0x0F000100 == (pcs_control_status1 & 0x0F000100)))
+ int_cnt++;
+ msleep(1);
+ }
+ if (int_cnt > 1) {
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+ mh_detected++;
+ reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+ reset_value |= 0x0000003d;
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+ & 0x00000040) != 0x00000040) && (j++ < 5000));
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+ pcs_control_status0 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ pcs_control_status1 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+
+ for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
+ pcs_control_status0 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ pcs_control_status1 = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+ if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
+ || (0x0F000100 == (pcs_control_status1 & 0x0F000100))) {
+ if (++ext_cnt > int_cnt) {
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1,
+ 0x0000F0C8);
+ mh_detected++;
+ reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+ reset_value |= 0x0000003d;
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+ & 0x00000040) != 0x00000040) && (j++ < 5000));
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ break;
+ }
+ }
+ msleep(1);
+ }
+ }
+ }
+
+ if (nesadapter->hw_rev == NE020_REV) {
+ init_timer(&nesadapter->mh_timer);
+ nesadapter->mh_timer.function = nes_mh_fix;
+ nesadapter->mh_timer.expires = jiffies + (HZ/5); /* 1 second */
+ nesadapter->mh_timer.data = (unsigned long)nesdev;
+ add_timer(&nesadapter->mh_timer);
+ } else {
+ nes_write32(nesdev->regs+NES_INTF_INT_STAT, 0x0f000000);
+ }
+
+ init_timer(&nesadapter->lc_timer);
+ nesadapter->lc_timer.function = nes_clc;
+ nesadapter->lc_timer.expires = jiffies + 3600 * HZ; /* 1 hour */
+ nesadapter->lc_timer.data = (unsigned long)nesdev;
+ add_timer(&nesadapter->lc_timer);
+
+ list_add_tail(&nesadapter->list, &nes_adapter_list);
+
+ for (func_index = 0; func_index < 8; func_index++) {
+ pci_bus_read_config_word(nesdev->pcidev->bus,
+ PCI_DEVFN(PCI_SLOT(nesdev->pcidev->devfn),
+ func_index), 0, &vendor_id);
+ if (vendor_id == 0xffff)
+ break;
+ }
+ nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __FUNCTION__,
+ func_index, pci_name(nesdev->pcidev));
+ nesadapter->adapter_fcn_count = func_index;
+
+ return nesadapter;
+}
+
+
+/**
+ * nes_reset_adapter_ne020
+ */
+unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
+{
+ u32 port_count;
+ u32 u32temp;
+ u32 i;
+
+ u32temp = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+ port_count = ((u32temp & 0x00000300) >> 8) + 1;
+ /* TODO: assuming that both SERDES are set the same for now */
+ *OneG_Mode = (u32temp & 0x00003c00) ? 0 : 1;
+ nes_debug(NES_DBG_INIT, "Initial Software Reset = 0x%08X, port_count=%u\n",
+ u32temp, port_count);
+ if (*OneG_Mode)
+ nes_debug(NES_DBG_INIT, "Running in 1G mode.\n");
+ u32temp &= 0xff00ffc0;
+ switch (port_count) {
+ case 1:
+ u32temp |= 0x00ee0000;
+ break;
+ case 2:
+ u32temp |= 0x00cc0000;
+ break;
+ case 4:
+ u32temp |= 0x00000000;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ /* check and do full reset if needed */
+ if (nes_read_indexed(nesdev, NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8))) {
+ nes_debug(NES_DBG_INIT, "Issuing Full Soft reset = 0x%08X\n", u32temp | 0xd);
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+ i = 0;
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
+ mdelay(1);
+ if (i >= 10000) {
+ nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
+ return 0;
+ }
+ }
+
+ /* port reset */
+ switch (port_count) {
+ case 1:
+ u32temp |= 0x00ee0010;
+ break;
+ case 2:
+ u32temp |= 0x00cc0030;
+ break;
+ case 4:
+ u32temp |= 0x00000030;
+ break;
+ }
+
+ nes_debug(NES_DBG_INIT, "Issuing Port Soft reset = 0x%08X\n", u32temp | 0xd);
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+ i = 0;
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
+ mdelay(1);
+ if (i >= 10000) {
+ nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n");
+ return 0;
+ }
+
+ /* serdes 0 */
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+ & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+ mdelay(1);
+ if (i >= 5000) {
+ nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp);
+ return 0;
+ }
+
+ /* serdes 1 */
+ if (port_count > 1) {
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+ & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+ mdelay(1);
+ if (i >= 5000) {
+ nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp);
+ return 0;
+ }
+ }
+
+
+
+ i = 0;
+ while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
+ mdelay(1);
+ if (i >= 10000) {
+ printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
+ return 0;
+ }
+
+ return port_count;
+}
+
+
+/**
+ * nes_init_serdes
+ */
+int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, u8 OneG_Mode)
+{
+ int i;
+ u32 u32temp;
+
+ if (hw_rev != NE020_REV) {
+ /* init serdes 0 */
+
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
+ if (!OneG_Mode)
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
+ if (port_count > 1) {
+ /* init serdes 1 */
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
+ if (!OneG_Mode)
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
+ }
+ } else {
+ /* init serdes 0 */
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+ & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+ mdelay(1);
+ if (i >= 5000) {
+ nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp);
+ return 1;
+ }
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+ if (OneG_Mode)
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
+ else
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
+
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+ if (port_count > 1) {
+ /* init serdes 1 */
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x00000048);
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+ & 0x0000000f)) != 0x0000000f) && (i++ < 5000))
+ mdelay(1);
+ if (i >= 5000) {
+ printk("%s: Init: serdes 1 not ready, status=%x\n", __FUNCTION__, u32temp);
+ /* return 1; */
+ }
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE1, 0x9ce73000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE1, 0x0ff00000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET1, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS1, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL1, 0xf0002222);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000ff);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * nes_init_csr_ne020
+ * Initialize registers for ne020 hardware
+ */
+void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
+{
+ u32 u32temp;
+
+ nes_debug(NES_DBG_INIT, "port_count=%d\n", port_count);
+
+ nes_write_indexed(nesdev, 0x000001E4, 0x00000007);
+ /* nes_write_indexed(nesdev, 0x000001E8, 0x000208C4); */
+ nes_write_indexed(nesdev, 0x000001E8, 0x00020874);
+ nes_write_indexed(nesdev, 0x000001D8, 0x00048002);
+ /* nes_write_indexed(nesdev, 0x000001D8, 0x0004B002); */
+ nes_write_indexed(nesdev, 0x000001FC, 0x00050005);
+ nes_write_indexed(nesdev, 0x00000600, 0x55555555);
+ nes_write_indexed(nesdev, 0x00000604, 0x55555555);
+
+ /* TODO: move these MAC register settings to NIC bringup */
+ nes_write_indexed(nesdev, 0x00002000, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002004, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002008, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000200C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002010, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000201C, 0x75345678);
+ if (port_count > 1) {
+ nes_write_indexed(nesdev, 0x00002200, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002204, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002208, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000220C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002210, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000221C, 0x75345678);
+ nes_write_indexed(nesdev, 0x00000908, 0x20000001);
+ }
+ if (port_count > 2) {
+ nes_write_indexed(nesdev, 0x00002400, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002404, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002408, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000240C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002410, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000241C, 0x75345678);
+ nes_write_indexed(nesdev, 0x00000910, 0x20000001);
+
+ nes_write_indexed(nesdev, 0x00002600, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002604, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002608, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000260C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002610, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000261C, 0x75345678);
+ nes_write_indexed(nesdev, 0x00000918, 0x20000001);
+ }
+
+ nes_write_indexed(nesdev, 0x00005000, 0x00018000);
+ /* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
+ nes_write_indexed(nesdev, 0x00005004, 0x00020001);
+ nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00005020, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00006090, 0xFFFFFFFF);
+
+ /* TODO: move this to code, get from EEPROM */
+ nes_write_indexed(nesdev, 0x00000900, 0x20000001);
+ nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
+ nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
+ //
+ nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
+ /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
+
+ if (hw_rev != NE020_REV) {
+ u32temp = nes_read_indexed(nesdev, 0x000008e8);
+ u32temp |= 0x80000000;
+ nes_write_indexed(nesdev, 0x000008e8, u32temp);
+ u32temp = nes_read_indexed(nesdev, 0x000021f8);
+ u32temp &= 0x7fffffff;
+ u32temp |= 0x7fff0010;
+ nes_write_indexed(nesdev, 0x000021f8, u32temp);
+ }
+}
+
+
+/**
+ * nes_destroy_adapter - destroy the adapter structure
+ */
+void nes_destroy_adapter(struct nes_adapter *nesadapter)
+{
+ struct nes_adapter *tmp_adapter;
+
+ list_for_each_entry(tmp_adapter, &nes_adapter_list, list) {
+ nes_debug(NES_DBG_SHUTDOWN, "Nes Adapter list entry = 0x%p.\n",
+ tmp_adapter);
+ }
+
+ nesadapter->ref_count--;
+ if (!nesadapter->ref_count) {
+ if (nesadapter->hw_rev == NE020_REV) {
+ del_timer(&nesadapter->mh_timer);
+ }
+ del_timer(&nesadapter->lc_timer);
+
+ list_del(&nesadapter->list);
+ kfree(nesadapter);
+ }
+}
+
+
+/**
+ * nes_init_cqp
+ */
+int nes_init_cqp(struct nes_device *nesdev)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_qp_context *cqp_qp_context;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_ceq *ceq;
+ struct nes_hw_ceq *nic_ceq;
+ struct nes_hw_aeq *aeq;
+ void *vmem;
+ dma_addr_t pmem;
+ u32 count=0;
+ u32 cqp_head;
+ u64 u64temp;
+ u32 u32temp;
+
+ /* allocate CQP memory */
+ /* Need to add max_cq to the aeq size once cq overflow checking is added back */
+ /* SQ is 512 byte aligned, others are 256 byte aligned */
+ nesdev->cqp_mem_size = 512 +
+ (sizeof(struct nes_hw_cqp_wqe) * NES_CQP_SQ_SIZE) +
+ (sizeof(struct nes_hw_cqe) * NES_CCQ_SIZE) +
+ max(((u32)sizeof(struct nes_hw_ceqe) * NES_CCEQ_SIZE), (u32)256) +
+ max(((u32)sizeof(struct nes_hw_ceqe) * NES_NIC_CEQ_SIZE), (u32)256) +
+ (sizeof(struct nes_hw_aeqe) * nesadapter->max_qp) +
+ sizeof(struct nes_hw_cqp_qp_context);
+
+ nesdev->cqp_vbase = pci_alloc_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+ &nesdev->cqp_pbase);
+ if (!nesdev->cqp_vbase) {
+ nes_debug(NES_DBG_INIT, "Unable to allocate memory for host descriptor rings\n");
+ return -ENOMEM;
+ }
+ memset(nesdev->cqp_vbase, 0, nesdev->cqp_mem_size);
+
+ /* Allocate a twice the number of CQP requests as the SQ size */
+ nesdev->nes_cqp_requests = kzalloc(sizeof(struct nes_cqp_request) *
+ 2 * NES_CQP_SQ_SIZE, GFP_KERNEL);
+ if (nesdev->nes_cqp_requests == NULL) {
+ nes_debug(NES_DBG_INIT, "Unable to allocate memory CQP request entries.\n");
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+ nesdev->cqp.sq_pbase);
+ return -ENOMEM;
+ }
+
+ nes_debug(NES_DBG_INIT, "Allocated CQP structures at %p (phys = %016lX), size = %u.\n",
+ nesdev->cqp_vbase, (unsigned long)nesdev->cqp_pbase, nesdev->cqp_mem_size);
+
+ spin_lock_init(&nesdev->cqp.lock);
+ init_waitqueue_head(&nesdev->cqp.waitq);
+
+ /* Setup Various Structures */
+ vmem = (void *)(((unsigned long)nesdev->cqp_vbase + (512 - 1)) &
+ ~(unsigned long)(512 - 1));
+ pmem = (dma_addr_t)(((unsigned long long)nesdev->cqp_pbase + (512 - 1)) &
+ ~(unsigned long long)(512 - 1));
+
+ nesdev->cqp.sq_vbase = vmem;
+ nesdev->cqp.sq_pbase = pmem;
+ nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
+ nesdev->cqp.sq_head = 0;
+ nesdev->cqp.sq_tail = 0;
+ nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
+
+ vmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+ pmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+
+ nesdev->ccq.cq_vbase = vmem;
+ nesdev->ccq.cq_pbase = pmem;
+ nesdev->ccq.cq_size = NES_CCQ_SIZE;
+ nesdev->ccq.cq_head = 0;
+ nesdev->ccq.ce_handler = nes_cqp_ce_handler;
+ nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
+
+ vmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+ pmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+
+ nesdev->ceq_index = PCI_FUNC(nesdev->pcidev->devfn);
+ ceq = &nesadapter->ceq[nesdev->ceq_index];
+ ceq->ceq_vbase = vmem;
+ ceq->ceq_pbase = pmem;
+ ceq->ceq_size = NES_CCEQ_SIZE;
+ ceq->ceq_head = 0;
+
+ vmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+ pmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+
+ nesdev->nic_ceq_index = PCI_FUNC(nesdev->pcidev->devfn) + 8;
+ nic_ceq = &nesadapter->ceq[nesdev->nic_ceq_index];
+ nic_ceq->ceq_vbase = vmem;
+ nic_ceq->ceq_pbase = pmem;
+ nic_ceq->ceq_size = NES_NIC_CEQ_SIZE;
+ nic_ceq->ceq_head = 0;
+
+ vmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+ pmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+
+ aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
+ aeq->aeq_vbase = vmem;
+ aeq->aeq_pbase = pmem;
+ aeq->aeq_size = nesadapter->max_qp;
+ aeq->aeq_head = 0;
+
+ /* Setup QP Context */
+ vmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+ pmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+
+ cqp_qp_context = vmem;
+ cqp_qp_context->context_words[0] =
+ cpu_to_le32((PCI_FUNC(nesdev->pcidev->devfn) << 12) + (2 << 10));
+ cqp_qp_context->context_words[1] = 0;
+ cqp_qp_context->context_words[2] = cpu_to_le32((u32)nesdev->cqp.sq_pbase);
+ cqp_qp_context->context_words[3] = cpu_to_le32(((u64)nesdev->cqp.sq_pbase) >> 32);
+
+
+ /* Write the address to Create CQP */
+ if ((sizeof(dma_addr_t) > 4)) {
+ nes_write_indexed(nesdev,
+ NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+ ((u64)pmem) >> 32);
+ } else {
+ nes_write_indexed(nesdev,
+ NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8), 0);
+ }
+ nes_write_indexed(nesdev,
+ NES_IDX_CREATE_CQP_LOW + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+ (u32)pmem);
+
+ INIT_LIST_HEAD(&nesdev->cqp_avail_reqs);
+ INIT_LIST_HEAD(&nesdev->cqp_pending_reqs);
+
+ for (count = 0; count < 2*NES_CQP_SQ_SIZE; count++) {
+ init_waitqueue_head(&nesdev->nes_cqp_requests[count].waitq);
+ list_add_tail(&nesdev->nes_cqp_requests[count].list, &nesdev->cqp_avail_reqs);
+ }
+
+ /* Write Create CCQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ (NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+ NES_CQP_CQ_CHK_OVERFLOW | ((u32)nesdev->ccq.cq_size << 16)));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+ (nesdev->ccq.cq_number |
+ ((u32)nesdev->ceq_index << 16)));
+ u64temp = (u64)nesdev->ccq.cq_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+ u64temp = (unsigned long)&nesdev->ccq;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
+ cpu_to_le32((u32)(u64temp >> 1));
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+ cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+
+ /* Write Create CEQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ (NES_CQP_CREATE_CEQ + ((u32)nesdev->ceq_index << 8)));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, ceq->ceq_size);
+ u64temp = (u64)ceq->ceq_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+ /* Write Create AEQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ (NES_CQP_CREATE_AEQ + ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8)));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX, aeq->aeq_size);
+ u64temp = (u64)aeq->aeq_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+ /* Write Create NIC CEQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ (NES_CQP_CREATE_CEQ + ((u32)nesdev->nic_ceq_index << 8)));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, nic_ceq->ceq_size);
+ u64temp = (u64)nic_ceq->ceq_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+ /* Poll until CCQP done */
+ count = 0;
+ do {
+ if (count++ > 1000) {
+ printk(KERN_ERR PFX "Error creating CQP\n");
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+ nesdev->cqp_vbase, nesdev->cqp_pbase);
+ return -1;
+ }
+ udelay(10);
+ } while (!(nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn) * 8)) & (1 << 8)));
+
+ nes_debug(NES_DBG_INIT, "CQP Status = 0x%08X\n", nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+ u32temp = 0x04800000;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, u32temp | nesdev->cqp.qp_id);
+
+ /* wait for the CCQ, CEQ, and AEQ to get created */
+ count = 0;
+ do {
+ if (count++ > 1000) {
+ printk(KERN_ERR PFX "Error creating CCQ, CEQ, and AEQ\n");
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+ nesdev->cqp_vbase, nesdev->cqp_pbase);
+ return -1;
+ }
+ udelay(10);
+ } while (((nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)));
+
+ /* dump the QP status value */
+ nes_debug(NES_DBG_INIT, "QP Status = 0x%08X\n", nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+ nesdev->cqp.sq_tail++;
+
+ return 0;
+}
+
+
+/**
+ * nes_destroy_cqp
+ */
+int nes_destroy_cqp(struct nes_device *nesdev)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ u32 count = 0;
+ u32 cqp_head;
+ unsigned long flags;
+
+ do {
+ if (count++ > 1000)
+ break;
+ udelay(10);
+ } while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail));
+
+ /* Reset CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET |
+ nesdev->ccq.cq_number);
+
+ /* Disable device interrupts */
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ /* Destroy the AEQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ |
+ ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+
+ /* Destroy the NIC CEQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+ ((u32)nesdev->nic_ceq_index << 8));
+
+ /* Destroy the CEQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+ (nesdev->ceq_index << 8));
+
+ /* Destroy the CCQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->ccq.cq_number |
+ ((u32)nesdev->ceq_index << 16));
+
+ /* Destroy CQP */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP |
+ NES_CQP_QP_TYPE_CQP);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id);
+
+ barrier();
+ /* Ring doorbell (5 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x05800000 | nesdev->cqp.qp_id);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ /* wait for the CCQ, CEQ, and AEQ to get destroyed */
+ count = 0;
+ do {
+ if (count++ > 1000) {
+ printk(KERN_ERR PFX "Function%d: Error destroying CCQ, CEQ, and AEQ\n",
+ PCI_FUNC(nesdev->pcidev->devfn));
+ break;
+ }
+ udelay(10);
+ } while (((nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15 << 8)) != 0));
+
+ /* dump the QP status value */
+ nes_debug(NES_DBG_SHUTDOWN, "Function%d: QP Status = 0x%08X\n",
+ PCI_FUNC(nesdev->pcidev->devfn),
+ nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+ kfree(nesdev->nes_cqp_requests);
+
+ /* Free the control structures */
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+ nesdev->cqp.sq_pbase);
+
+ return 0;
+}
+
+
+/**
+ * nes_init_phy
+ */
+int nes_init_phy(struct nes_device *nesdev)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 counter = 0;
+ u32 mac_index = nesdev->mac_index;
+ u32 tx_config;
+ u16 phy_data;
+
+ if (nesadapter->OneG_Mode) {
+ nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
+ if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
+ printk(PFX "%s: Programming mdc config for 1G\n", __FUNCTION__);
+ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+ tx_config |= 0x04;
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+ }
+
+ nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+ nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
+
+ /* Reset the PHY */
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
+ udelay(100);
+ counter = 0;
+ do {
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
+ if (counter++ > 100) break;
+ } while (phy_data & 0x8000);
+
+ /* Setting no phy loopback */
+ phy_data &= 0xbfff;
+ phy_data |= 0x1140;
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data);
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0x17, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x17 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0x1e, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x1e = 0x%X.\n", phy_data);
+
+ /* Setting the interrupt mask */
+ nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
+ nes_write_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], 0xffee);
+
+ nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
+
+ /* turning on flow control */
+ nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
+ nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+ (phy_data & ~(0x03E0)) | 0xc00);
+ /* nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+ phy_data | 0xc00); */
+ nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
+ /* Clear Half duplex */
+ nes_write_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index],
+ phy_data & ~(0x0100));
+ nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
+ } else {
+ if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+ /* setup 10G MDIO operation */
+ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+ tx_config |= 0x14;
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * nes_replenish_nic_rq
+ */
+static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)
+{
+ unsigned long flags;
+ dma_addr_t bus_address;
+ struct sk_buff *skb;
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ struct nes_hw_nic *nesnic;
+ struct nes_device *nesdev;
+ u32 rx_wqes_posted = 0;
+
+ nesnic = &nesvnic->nic;
+ nesdev = nesvnic->nesdev;
+ spin_lock_irqsave(&nesnic->rq_lock, flags);
+ if (nesnic->replenishing_rq !=0) {
+ if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
+ (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
+ atomic_set(&nesvnic->rx_skb_timer_running, 1);
+ spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+ nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2); /* 1/2 second */
+ add_timer(&nesvnic->rq_wqes_timer);
+ } else
+ spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+ return;
+ }
+ nesnic->replenishing_rq = 1;
+ spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+ do {
+ skb = dev_alloc_skb(nesvnic->max_frame_size);
+ if (skb) {
+ skb->dev = nesvnic->netdev;
+
+ bus_address = pci_map_single(nesdev->pcidev,
+ skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+ nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
+ cpu_to_le32(nesvnic->max_frame_size);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
+ cpu_to_le32((u32)bus_address);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
+ cpu_to_le32((u32)((u64)bus_address >> 32));
+ nesnic->rx_skb[nesnic->rq_head] = skb;
+ nesnic->rq_head++;
+ nesnic->rq_head &= nesnic->rq_size - 1;
+ atomic_dec(&nesvnic->rx_skbs_needed);
+ barrier();
+ if (++rx_wqes_posted == 255) {
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
+ rx_wqes_posted = 0;
+ }
+ } else {
+ spin_lock_irqsave(&nesnic->rq_lock, flags);
+ if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
+ (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
+ atomic_set(&nesvnic->rx_skb_timer_running, 1);
+ spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+ nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2); /* 1/2 second */
+ add_timer(&nesvnic->rq_wqes_timer);
+ } else
+ spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+ break;
+ }
+ } while (atomic_read(&nesvnic->rx_skbs_needed));
+ barrier();
+ if (rx_wqes_posted)
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
+ nesnic->replenishing_rq = 0;
+}
+
+
+/**
+ * nes_rq_wqes_timeout
+ */
+static void nes_rq_wqes_timeout(unsigned long parm)
+{
+ struct nes_vnic *nesvnic = (struct nes_vnic *)parm;
+ printk("%s: Timer fired.\n", __FUNCTION__);
+ atomic_set(&nesvnic->rx_skb_timer_running, 0);
+ if (atomic_read(&nesvnic->rx_skbs_needed))
+ nes_replenish_nic_rq(nesvnic);
+}
+
+
+/**
+ * nes_init_nic_qp
+ */
+int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+ struct nes_hw_nic_qp_context *nic_context;
+ struct sk_buff *skb;
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ unsigned long flags;
+ void *vmem;
+ dma_addr_t pmem;
+ u64 u64temp;
+ int ret;
+ u32 cqp_head;
+ u32 counter;
+ u32 wqe_count;
+ u8 jumbomode=0;
+
+ /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */
+ nesvnic->nic_mem_size = 256 +
+ (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag)) +
+ (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
+ (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe)) +
+ (NES_NIC_WQ_SIZE * 2 * sizeof(struct nes_hw_nic_cqe)) +
+ sizeof(struct nes_hw_nic_qp_context);
+
+ nesvnic->nic_vbase = pci_alloc_consistent(nesdev->pcidev, nesvnic->nic_mem_size,
+ &nesvnic->nic_pbase);
+ if (!nesvnic->nic_vbase) {
+ nes_debug(NES_DBG_INIT, "Unable to allocate memory for NIC host descriptor rings\n");
+ return -ENOMEM;
+ }
+ memset(nesvnic->nic_vbase, 0, nesvnic->nic_mem_size);
+ nes_debug(NES_DBG_INIT, "Allocated NIC QP structures at %p (phys = %016lX), size = %u.\n",
+ nesvnic->nic_vbase, (unsigned long)nesvnic->nic_pbase, nesvnic->nic_mem_size);
+
+ vmem = (void *)(((unsigned long)nesvnic->nic_vbase + (256 - 1)) &
+ ~(unsigned long)(256 - 1));
+ pmem = (dma_addr_t)(((unsigned long long)nesvnic->nic_pbase + (256 - 1)) &
+ ~(unsigned long long)(256 - 1));
+
+ /* Setup the first Fragment buffers */
+ nesvnic->nic.first_frag_vbase = vmem;
+
+ for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+ nesvnic->nic.frag_paddr[counter] = pmem;
+ pmem += sizeof(struct nes_first_frag);
+ }
+
+ /* setup the SQ */
+ vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag));
+
+ nesvnic->nic.sq_vbase = (void *)vmem;
+ nesvnic->nic.sq_pbase = pmem;
+ nesvnic->nic.sq_head = 0;
+ nesvnic->nic.sq_tail = 0;
+ nesvnic->nic.sq_size = NES_NIC_WQ_SIZE;
+ for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+ nic_sqe = &nesvnic->nic.sq_vbase[counter];
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
+ cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM |
+ NES_NIC_SQ_WQE_COMPLETION);
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
+ cpu_to_le32((u32)NES_FIRST_FRAG_SIZE << 16);
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
+ cpu_to_le32((u32)nesvnic->nic.frag_paddr[counter]);
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
+ cpu_to_le32((u32)((u64)nesvnic->nic.frag_paddr[counter] >> 32));
+ }
+
+ nesvnic->get_cqp_request = nes_get_cqp_request;
+ nesvnic->post_cqp_request = nes_post_cqp_request;
+ nesvnic->mcrq_mcast_filter = NULL;
+
+ spin_lock_init(&nesvnic->nic.sq_lock);
+ spin_lock_init(&nesvnic->nic.rq_lock);
+
+ /* setup the RQ */
+ vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+ pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+
+
+ nesvnic->nic.rq_vbase = vmem;
+ nesvnic->nic.rq_pbase = pmem;
+ nesvnic->nic.rq_head = 0;
+ nesvnic->nic.rq_tail = 0;
+ nesvnic->nic.rq_size = NES_NIC_WQ_SIZE;
+
+ /* setup the CQ */
+ vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+ pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+
+ if (nesdev->nesadapter->netdev_count > 2)
+ nesvnic->mcrq_qp_id = nesvnic->nic_index + 32;
+ else
+ nesvnic->mcrq_qp_id = nesvnic->nic.qp_id + 4;
+
+ nesvnic->nic_cq.cq_vbase = vmem;
+ nesvnic->nic_cq.cq_pbase = pmem;
+ nesvnic->nic_cq.cq_head = 0;
+ nesvnic->nic_cq.cq_size = NES_NIC_WQ_SIZE * 2;
+
+ nesvnic->nic_cq.ce_handler = nes_nic_napi_ce_handler;
+
+ /* Send CreateCQ request to CQP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_head = nesdev->cqp.sq_head;
+
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
+ NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+ ((u32)nesvnic->nic_cq.cq_size << 16));
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(
+ nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16));
+ u64temp = (u64)nesvnic->nic_cq.cq_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+ u64temp = (unsigned long)&nesvnic->nic_cq;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] = cpu_to_le32((u32)(u64temp >> 1));
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+ cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+ /* Send CreateQP request to CQP */
+ nic_context = (void *)(&nesvnic->nic_cq.cq_vbase[nesvnic->nic_cq.cq_size]);
+ nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
+ cpu_to_le32((u32)NES_NIC_CTX_SIZE |
+ ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
+ nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
+ nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
+ nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
+ if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0) {
+ nic_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
+ }
+
+ u64temp = (u64)nesvnic->nic.sq_pbase;
+ nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+ u64temp = (u64)nesvnic->nic.rq_pbase;
+ nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
+ NES_CQP_QP_TYPE_NIC);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic.qp_id);
+ u64temp = (u64)nesvnic->nic_cq.cq_pbase +
+ (nesvnic->nic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+ nesdev->cqp.sq_head = cqp_head;
+
+ barrier();
+
+ /* Ring doorbell (2 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ nes_debug(NES_DBG_INIT, "Waiting for create NIC QP%u to complete.\n",
+ nesvnic->nic.qp_id);
+
+ ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_INIT, "Create NIC QP%u completed, wait_event_timeout ret = %u.\n",
+ nesvnic->nic.qp_id, ret);
+ if (!ret) {
+ nes_debug(NES_DBG_INIT, "NIC QP%u create timeout expired\n", nesvnic->nic.qp_id);
+ pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+ nesvnic->nic_pbase);
+ return -EIO;
+ }
+
+ /* Populate the RQ */
+ for (counter = 0; counter < (NES_NIC_WQ_SIZE - 1); counter++) {
+ skb = dev_alloc_skb(nesvnic->max_frame_size);
+ if (!skb) {
+ nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name);
+
+ nes_destroy_nic_qp(nesvnic);
+ return -ENOMEM;
+ }
+
+ skb->dev = netdev;
+
+ pmem = pci_map_single(nesdev->pcidev, skb->data,
+ nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+ nic_rqe = &nesvnic->nic.rq_vbase[counter];
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
+ nesvnic->nic.rx_skb[counter] = skb;
+ }
+
+ wqe_count = NES_NIC_WQ_SIZE - 1;
+ nesvnic->nic.rq_head = wqe_count;
+ barrier();
+ do {
+ counter = min(wqe_count, ((u32)255));
+ wqe_count -= counter;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter << 24) | nesvnic->nic.qp_id);
+ } while (wqe_count);
+ init_timer(&nesvnic->rq_wqes_timer);
+ nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
+ nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
+ nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
+
+ if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
+ {
+ nes_nic_init_timer(nesdev);
+ if (netdev->mtu > 1500)
+ jumbomode = 1;
+ nes_nic_init_timer_defaults(nesdev, jumbomode);
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_destroy_nic_qp
+ */
+void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
+{
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ u64 wqe_frag;
+ u32 cqp_head;
+ unsigned long flags;
+ int ret;
+
+ /* Free remaining NIC receive buffers */
+ while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
+ nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
+ wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+ wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+ pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
+ nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
+ nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
+ }
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ /* Destroy NIC QP */
+ cqp_head = nesdev->cqp.sq_head;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ (NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+ nesvnic->nic.qp_id);
+
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+ /* Destroy NIC CQ */
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ (NES_CQP_DESTROY_CQ | ((u32)nesvnic->nic_cq.cq_size << 16)));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+ (nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16)));
+
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+
+ nesdev->cqp.sq_head = cqp_head;
+ barrier();
+
+ /* Ring doorbell (2 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
+ " cqp.sq_tail=%u, cqp.sq_size=%u\n",
+ cqp_head, nesdev->cqp.sq_head,
+ nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
+
+ ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+ NES_EVENT_TIMEOUT);
+
+ nes_debug(NES_DBG_SHUTDOWN, "Destroy NIC QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
+ " cqp.sq_head=%u, cqp.sq_tail=%u\n",
+ ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+ if (!ret) {
+ nes_debug(NES_DBG_SHUTDOWN, "NIC QP%u destroy timeout expired\n",
+ nesvnic->nic.qp_id);
+ }
+
+ pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+ nesvnic->nic_pbase);
+}
+
+/**
+ * nes_napi_isr
+ */
+int nes_napi_isr(struct nes_device *nesdev)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 int_stat;
+
+ if (nesdev->napi_isr_ran) {
+ /* interrupt status has already been read in ISR */
+ int_stat = nesdev->int_stat;
+ } else {
+ int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+ nesdev->int_stat = int_stat;
+ nesdev->napi_isr_ran = 1;
+ }
+
+ int_stat &= nesdev->int_req;
+ /* iff NIC, process here, else wait for DPC */
+ if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
+ nesdev->napi_isr_ran = 0;
+ nes_write32(nesdev->regs+NES_INT_STAT,
+ (int_stat &
+ ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+
+ /* Process the CEQs */
+ nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
+
+ if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
+ (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+ ((nesadapter->et_use_adaptive_rx_coalesce) &&
+ (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) {
+ if ((nesdev->int_req & NES_INT_TIMER) == 0) {
+ /* Enable Periodic timer interrupts */
+ nesdev->int_req |= NES_INT_TIMER;
+ /* ack any pending periodic timer interrupts so we don't get an immediate interrupt */
+ /* TODO: need to also ack other unused periodic timer values, get from nesadapter */
+ nes_write32(nesdev->regs+NES_TIMER_STAT,
+ nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+ ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+ }
+
+ if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+ {
+ nes_nic_init_timer(nesdev);
+ }
+ /* Enable interrupts, except CEQs */
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+ } else {
+ /* Enable interrupts, make sure timer is off */
+ nesdev->int_req &= ~NES_INT_TIMER;
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ nesadapter->tune_timer.timer_in_use_old = 0;
+ }
+ nesdev->deepcq_count = 0;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * nes_dpc
+ */
+void nes_dpc(unsigned long param)
+{
+ struct nes_device *nesdev = (struct nes_device *)param;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 counter;
+ u32 loop_counter = 0;
+ u32 int_status_bit;
+ u32 int_stat;
+ u32 timer_stat;
+ u32 temp_int_stat;
+ u32 intf_int_stat;
+ u32 debug_error;
+ u32 processed_intf_int = 0;
+ u16 processed_timer_int = 0;
+ u16 completion_ints = 0;
+ u16 timer_ints = 0;
+
+ /* nes_debug(NES_DBG_ISR, "\n"); */
+
+ do {
+ timer_stat = 0;
+ if (nesdev->napi_isr_ran) {
+ nesdev->napi_isr_ran = 0;
+ int_stat = nesdev->int_stat;
+ } else
+ int_stat = nes_read32(nesdev->regs+NES_INT_STAT);
+ if (processed_intf_int != 0)
+ int_stat &= nesdev->int_req & ~NES_INT_INTF;
+ else
+ int_stat &= nesdev->int_req;
+ if (processed_timer_int == 0) {
+ processed_timer_int = 1;
+ if (int_stat & NES_INT_TIMER) {
+ timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+ if ((timer_stat & nesdev->timer_int_req) == 0) {
+ int_stat &= ~NES_INT_TIMER;
+ }
+ }
+ } else {
+ int_stat &= ~NES_INT_TIMER;
+ }
+
+ if (int_stat) {
+ if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
+ /* Ack the interrupts */
+ nes_write32(nesdev->regs+NES_INT_STAT,
+ (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+ }
+
+ temp_int_stat = int_stat;
+ for (counter = 0, int_status_bit = 1; counter < 16; counter++) {
+ if (int_stat & int_status_bit) {
+ nes_process_ceq(nesdev, &nesadapter->ceq[counter]);
+ temp_int_stat &= ~int_status_bit;
+ completion_ints = 1;
+ }
+ if (!(temp_int_stat & 0x0000ffff))
+ break;
+ int_status_bit <<= 1;
+ }
+
+ /* Process the AEQ for this pci function */
+ int_status_bit = 1 << (16 + PCI_FUNC(nesdev->pcidev->devfn));
+ if (int_stat & int_status_bit) {
+ nes_process_aeq(nesdev, &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
+ }
+
+ /* Process the MAC interrupt for this pci function */
+ int_status_bit = 1 << (24 + nesdev->mac_index);
+ if (int_stat & int_status_bit) {
+ nes_process_mac_intr(nesdev, nesdev->mac_index);
+ }
+
+ if (int_stat & NES_INT_TIMER) {
+ if (timer_stat & nesdev->timer_int_req) {
+ nes_write32(nesdev->regs + NES_TIMER_STAT,
+ (timer_stat & nesdev->timer_int_req) |
+ ~(nesdev->nesadapter->timer_int_req));
+ timer_ints = 1;
+ }
+ }
+
+ if (int_stat & NES_INT_INTF) {
+ processed_intf_int = 1;
+ intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+ intf_int_stat &= nesdev->intf_int_req;
+ if (NES_INTF_INT_CRITERR & intf_int_stat) {
+ debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
+ printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
+ (u16)debug_error);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
+ 0x01010000 | (debug_error & 0x0000ffff));
+ /* BUG(); */
+ if (crit_err_count++ > 10)
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+ }
+ if (NES_INTF_INT_PCIERR & intf_int_stat) {
+ printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
+ BUG();
+ }
+ if (NES_INTF_INT_AEQ_OFLOW & intf_int_stat) {
+ printk(KERN_ERR PFX "AEQ Overflow reported by device!!!\n");
+ BUG();
+ }
+ nes_write32(nesdev->regs+NES_INTF_INT_STAT, intf_int_stat);
+ }
+
+ if (int_stat & NES_INT_TSW) {
+ }
+ }
+ /* Don't use the interface interrupt bit stay in loop */
+ int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
+ } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
+
+ if (timer_ints == 1) {
+ if ((nesadapter->et_rx_coalesce_usecs_irq) || (nesadapter->et_use_adaptive_rx_coalesce)) {
+ if (completion_ints == 0) {
+ nesdev->timer_only_int_count++;
+ if (nesdev->timer_only_int_count>=nesadapter->timer_int_limit) {
+ nesdev->timer_only_int_count = 0;
+ nesdev->int_req &= ~NES_INT_TIMER;
+ nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ nesdev->nesadapter->tune_timer.timer_in_use_old = 0;
+ } else {
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ }
+ } else {
+ if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+ {
+ nes_nic_init_timer(nesdev);
+ }
+ nesdev->timer_only_int_count = 0;
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ }
+ } else {
+ nesdev->timer_only_int_count = 0;
+ nesdev->int_req &= ~NES_INT_TIMER;
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+ nes_write32(nesdev->regs+NES_TIMER_STAT,
+ nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ }
+ } else {
+ if ( (completion_ints == 1) &&
+ (((nesadapter->et_rx_coalesce_usecs_irq) &&
+ (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+ ((nesdev->deepcq_count > nesadapter->et_pkt_rate_low) &&
+ (nesadapter->et_use_adaptive_rx_coalesce) )) ) {
+ /* nes_debug(NES_DBG_ISR, "Enabling periodic timer interrupt.\n" ); */
+ nesdev->timer_only_int_count = 0;
+ nesdev->int_req |= NES_INT_TIMER;
+ nes_write32(nesdev->regs+NES_TIMER_STAT,
+ nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+ ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+ } else {
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ }
+ }
+ nesdev->deepcq_count = 0;
+}
+
+
+/**
+ * nes_process_ceq
+ */
+void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
+{
+ u64 u64temp;
+ struct nes_hw_cq *cq;
+ u32 head;
+ u32 ceq_size;
+
+ /* nes_debug(NES_DBG_CQ, "\n"); */
+ head = ceq->ceq_head;
+ ceq_size = ceq->ceq_size;
+
+ do {
+ if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
+ NES_CEQE_VALID) {
+ u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) |
+ ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
+ u64temp <<= 1;
+ cq = *((struct nes_hw_cq **)&u64temp);
+ /* nes_debug(NES_DBG_CQ, "pCQ = %p\n", cq); */
+ barrier();
+ ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
+
+ /* call the event handler */
+ cq->ce_handler(nesdev, cq);
+
+ if (++head >= ceq_size)
+ head = 0;
+ } else {
+ break;
+ }
+
+ } while (1);
+
+ ceq->ceq_head = head;
+}
+
+
+/**
+ * nes_process_aeq
+ */
+void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
+{
+// u64 u64temp;
+ u32 head;
+ u32 aeq_size;
+ u32 aeqe_misc;
+ u32 aeqe_cq_id;
+ struct nes_hw_aeqe volatile *aeqe;
+
+ head = aeq->aeq_head;
+ aeq_size = aeq->aeq_size;
+
+ do {
+ aeqe = &aeq->aeq_vbase[head];
+ if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) & NES_AEQE_VALID) == 0)
+ break;
+ aeqe_misc = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+ aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
+ if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
+ if (aeqe_cq_id >= NES_FIRST_QPN) {
+ /* dealing with an accelerated QP related AE */
+// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) |
+// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+ nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
+ } else {
+ /* TODO: dealing with a CQP related AE */
+ nes_debug(NES_DBG_AEQ, "Processing CQP related AE, misc = 0x%04X\n",
+ (u16)(aeqe_misc >> 16));
+ }
+ }
+
+ aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
+
+ if (++head >= aeq_size)
+ head = 0;
+ }
+ while (1);
+ aeq->aeq_head = head;
+}
+
+static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 reset_value;
+ u32 i=0;
+ u32 u32temp;
+
+ if (nesadapter->hw_rev == NE020_REV) {
+ return;
+ }
+ mh_detected++;
+
+ reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+
+ if ((mac_index == 0) || ((mac_index == 1) && (nesadapter->OneG_Mode)))
+ reset_value |= 0x0000001d;
+ else
+ reset_value |= 0x0000002d;
+
+ if (4 <= (nesadapter->link_interrupt_count[mac_index] / ((u16)NES_MAX_LINK_INTERRUPTS))) {
+ if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
+ nesadapter->link_interrupt_count[0] = 0;
+ nesadapter->link_interrupt_count[1] = 0;
+ u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+ if (0x00000040 & u32temp)
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+ else
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
+
+ reset_value |= 0x0000003d;
+ }
+ nesadapter->link_interrupt_count[mac_index] = 0;
+ }
+
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+ & 0x00000040) != 0x00000040) && (i++ < 5000));
+
+ if (0x0000003d == (reset_value & 0x0000003d)) {
+ u32 pcs_control_status0, pcs_control_status1;
+
+ for (i = 0; i < 10; i++) {
+ pcs_control_status0 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ pcs_control_status1 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+ if (((0x0F000000 == (pcs_control_status0 & 0x0F000000))
+ && (pcs_control_status0 & 0x00100000))
+ || ((0x0F000000 == (pcs_control_status1 & 0x0F000000))
+ && (pcs_control_status1 & 0x00100000)))
+ continue;
+ else
+ break;
+ }
+ if (10 == i) {
+ u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+ if (0x00000040 & u32temp)
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+ else
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
+
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+ while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET)
+ & 0x00000040) != 0x00000040) && (i++ < 5000));
+ }
+ }
+}
+
+/**
+ * nes_process_mac_intr
+ */
+void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
+{
+ unsigned long flags;
+ u32 pcs_control_status;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_vnic *nesvnic;
+ u32 mac_status;
+ u32 mac_index = nesdev->mac_index;
+ u32 u32temp;
+ u16 phy_data;
+ u16 temp_phy_data;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ return;
+ }
+ nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_INTERRUPT;
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+ /* ack the MAC interrupt */
+ mac_status = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200));
+ /* Clear the interrupt */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200), mac_status);
+
+ nes_debug(NES_DBG_PHY, "MAC%u interrupt status = 0x%X.\n", mac_number, mac_status);
+
+ if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
+ nesdev->link_status_interrupts++;
+ if (0 == (++nesadapter->link_interrupt_count[mac_index] % ((u16)NES_MAX_LINK_INTERRUPTS))) {
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ nes_reset_link(nesdev, mac_index);
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ }
+ /* read the PHY interrupt status register */
+ if (nesadapter->OneG_Mode) {
+ do {
+ nes_read_1G_phy_reg(nesdev, 0x1a,
+ nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1a = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+ } while (phy_data&0x8000);
+
+ temp_phy_data = 0;
+ do {
+ nes_read_1G_phy_reg(nesdev, 0x11,
+ nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy%d data from register 0x11 = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+ if (temp_phy_data == phy_data)
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+
+ nes_read_1G_phy_reg(nesdev, 0x1e,
+ nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1e = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 1,
+ nesadapter->phy_index[mac_index], &phy_data);
+ nes_debug(NES_DBG_PHY, "1G phy%u data from register 1 = 0x%X\n",
+ nesadapter->phy_index[mac_index], phy_data);
+
+ if (temp_phy_data & 0x1000) {
+ nes_debug(NES_DBG_PHY, "The Link is up according to the PHY\n");
+ phy_data = 4;
+ } else {
+ nes_debug(NES_DBG_PHY, "The Link is down according to the PHY\n");
+ }
+ }
+ nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
+ nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
+ nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+ nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
+ mac_index, pcs_control_status);
+ if (nesadapter->OneG_Mode) {
+ u32temp = 0x01010000;
+ if (nesadapter->port_count > 2) {
+ u32temp |= 0x02020000;
+ }
+ if ((pcs_control_status & u32temp)!= u32temp) {
+ phy_data = 0;
+ nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
+ }
+ } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+ nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
+ temp_phy_data = (u16)nes_read_indexed(nesdev,
+ NES_IDX_MAC_MDIO_CONTROL);
+ u32temp = 20;
+ do {
+ nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
+ phy_data = (u16)nes_read_indexed(nesdev,
+ NES_IDX_MAC_MDIO_CONTROL);
+ if ((phy_data == temp_phy_data) || (!(--u32temp)))
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+ nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+ __FUNCTION__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
+
+ } else {
+ phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
+ }
+
+ if (phy_data & 0x0004) {
+ nesadapter->mac_link_down[mac_index] = 0;
+ list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+ nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n",
+ nesvnic->linkup);
+ if (nesvnic->linkup == 0) {
+ printk(PFX "The Link is now up for port %u, netdev %p.\n",
+ mac_index, nesvnic->netdev);
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_start_queue(nesvnic->netdev);
+ nesvnic->linkup = 1;
+ netif_carrier_on(nesvnic->netdev);
+ }
+ }
+ } else {
+ nesadapter->mac_link_down[mac_index] = 1;
+ list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+ nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n",
+ nesvnic->linkup);
+ if (nesvnic->linkup == 1) {
+ printk(PFX "The Link is now down for port %u, netdev %p.\n",
+ mac_index, nesvnic->netdev);
+ if (!(netif_queue_stopped(nesvnic->netdev)))
+ netif_stop_queue(nesvnic->netdev);
+ nesvnic->linkup = 0;
+ netif_carrier_off(nesvnic->netdev);
+ }
+ }
+ }
+ }
+
+ nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
+}
+
+
+
+void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+{
+ struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
+
+ netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index], &nesvnic->napi);
+}
+
+
+/* The MAX_RQES_TO_PROCESS defines how many max read requests to complete before
+* getting out of nic_ce_handler
+*/
+#define MAX_RQES_TO_PROCESS 384
+
+/**
+ * nes_nic_ce_handler
+ */
+void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+{
+ u64 u64temp;
+ dma_addr_t bus_address;
+ struct nes_hw_nic *nesnic;
+ struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+ struct sk_buff *skb;
+ struct sk_buff *rx_skb;
+ __le16 *wqe_fragment_length;
+ u32 head;
+ u32 cq_size;
+ u32 rx_pkt_size;
+ u32 cqe_count=0;
+ u32 cqe_errv;
+ u32 cqe_misc;
+ u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
+ u16 vlan_tag;
+ u16 pkt_type;
+ u16 rqes_processed = 0;
+ u8 sq_cqes = 0;
+
+ head = cq->cq_head;
+ cq_size = cq->cq_size;
+ cq->cqes_pending = 1;
+ do {
+ if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
+ NES_NIC_CQE_VALID) {
+ nesnic = &nesvnic->nic;
+ cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
+ if (cqe_misc & NES_NIC_CQE_SQ) {
+ sq_cqes++;
+ wqe_fragment_index = 1;
+ nic_sqe = &nesnic->sq_vbase[nesnic->sq_tail];
+ skb = nesnic->tx_skb[nesnic->sq_tail];
+ wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+ if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
+ u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
+ u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+ bus_address = (dma_addr_t)u64temp;
+ if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) {
+ pci_unmap_single(nesdev->pcidev,
+ bus_address,
+ le16_to_cpu(wqe_fragment_length[wqe_fragment_index++]),
+ PCI_DMA_TODEVICE);
+ }
+ for (; wqe_fragment_index < 5; wqe_fragment_index++) {
+ if (wqe_fragment_length[wqe_fragment_index]) {
+ u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
+ u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+ bus_address = (dma_addr_t)u64temp;
+ pci_unmap_page(nesdev->pcidev,
+ bus_address,
+ le16_to_cpu(wqe_fragment_length[wqe_fragment_index]),
+ PCI_DMA_TODEVICE);
+ } else
+ break;
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+ nesnic->sq_tail++;
+ nesnic->sq_tail &= nesnic->sq_size-1;
+ if (sq_cqes > 128) {
+ barrier();
+ /* restart the queue if it had been stopped */
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_wake_queue(nesvnic->netdev);
+ sq_cqes = 0;
+ }
+ } else {
+ rqes_processed ++;
+
+ cq->rx_cqes_completed++;
+ cq->rx_pkts_indicated++;
+ rx_pkt_size = cqe_misc & 0x0000ffff;
+ nic_rqe = &nesnic->rq_vbase[nesnic->rq_tail];
+ /* Get the skb */
+ rx_skb = nesnic->rx_skb[nesnic->rq_tail];
+ nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_tail];
+ bus_address = (dma_addr_t)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+ bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+ pci_unmap_single(nesdev->pcidev, bus_address,
+ nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+ /* rx_skb->tail = rx_skb->data + rx_pkt_size; */
+ /* rx_skb->len = rx_pkt_size; */
+ rx_skb->len = 0; /* TODO: see if this is necessary */
+ skb_put(rx_skb, rx_pkt_size);
+ rx_skb->protocol = eth_type_trans(rx_skb, nesvnic->netdev);
+ nesnic->rq_tail++;
+ nesnic->rq_tail &= nesnic->rq_size - 1;
+
+ atomic_inc(&nesvnic->rx_skbs_needed);
+ if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) {
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ cq->cq_number | (cqe_count << 16));
+// nesadapter->tune_timer.cq_count += cqe_count;
+ nesdev->currcq_count += cqe_count;
+ cqe_count = 0;
+ nes_replenish_nic_rq(nesvnic);
+ }
+ pkt_type = (u16)(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]));
+ cqe_errv = (cqe_misc & NES_NIC_CQE_ERRV_MASK) >> NES_NIC_CQE_ERRV_SHIFT;
+ rx_skb->ip_summed = CHECKSUM_NONE;
+
+ if ((NES_PKT_TYPE_TCPV4_BITS == (pkt_type & NES_PKT_TYPE_TCPV4_MASK)) ||
+ (NES_PKT_TYPE_UDPV4_BITS == (pkt_type & NES_PKT_TYPE_UDPV4_MASK))) {
+ if ((cqe_errv &
+ (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |
+ NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
+ if (nesvnic->rx_checksum_disabled == 0) {
+ rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+ } else
+ nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
+ " errv = 0x%X, pkt_type = 0x%X.\n",
+ nesvnic->netdev->name, cqe_errv, pkt_type);
+
+ } else if ((pkt_type & NES_PKT_TYPE_IPV4_MASK) == NES_PKT_TYPE_IPV4_BITS) {
+ if ((cqe_errv &
+ (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR |
+ NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
+ if (nesvnic->rx_checksum_disabled == 0) {
+ rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ /* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n",
+ nesvnic->netdev->name); */
+ }
+ } else
+ nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
+ " errv = 0x%X, pkt_type = 0x%X.\n",
+ nesvnic->netdev->name, cqe_errv, pkt_type);
+ }
+ /* nes_debug(NES_DBG_CQ, "pkt_type=%x, APBVT_MASK=%x\n",
+ pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */
+
+ if ((pkt_type & NES_PKT_TYPE_APBVT_MASK) == NES_PKT_TYPE_APBVT_BITS) {
+ nes_cm_recv(rx_skb, nesvnic->netdev);
+ } else {
+ if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && (nesvnic->vlan_grp != NULL)) {
+ vlan_tag = (u16)(le32_to_cpu(
+ cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
+ >> 16);
+ nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
+ nesvnic->netdev->name, vlan_tag);
+ nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
+ } else {
+ nes_netif_rx(rx_skb);
+ }
+ }
+
+ nesvnic->netdev->last_rx = jiffies;
+ /* nesvnic->netstats.rx_packets++; */
+ /* nesvnic->netstats.rx_bytes += rx_pkt_size; */
+ }
+
+ cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
+ /* Accounting... */
+ cqe_count++;
+ if (++head >= cq_size)
+ head = 0;
+ if (cqe_count == 255) {
+ /* Replenish Nic CQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ cq->cq_number | (cqe_count << 16));
+// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+ nesdev->currcq_count += cqe_count;
+ cqe_count = 0;
+ }
+
+ if (cq->rx_cqes_completed >= nesvnic->budget)
+ break;
+ } else {
+ cq->cqes_pending = 0;
+ break;
+ }
+
+ } while (1);
+
+ if (sq_cqes) {
+ barrier();
+ /* restart the queue if it had been stopped */
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_wake_queue(nesvnic->netdev);
+ }
+
+ cq->cq_head = head;
+ /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
+ cq->cq_number, cqe_count, cq->cq_head); */
+ cq->cqe_allocs_pending = cqe_count;
+ if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+ {
+// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+ nesdev->currcq_count += cqe_count;
+ nes_nic_tune_timer(nesdev);
+ }
+ if (atomic_read(&nesvnic->rx_skbs_needed))
+ nes_replenish_nic_rq(nesvnic);
+ }
+
+
+/**
+ * nes_cqp_ce_handler
+ */
+void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
+{
+ u64 u64temp;
+ unsigned long flags;
+ struct nes_hw_cqp *cqp = NULL;
+ struct nes_cqp_request *cqp_request;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ u32 head;
+ u32 cq_size;
+ u32 cqe_count=0;
+ u32 error_code;
+ /* u32 counter; */
+
+ head = cq->cq_head;
+ cq_size = cq->cq_size;
+
+ do {
+ /* process the CQE */
+ /* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head,
+ le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */
+
+ if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
+ u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head].
+ cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+ ((u64)(le32_to_cpu(cq->cq_vbase[head].
+ cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX])));
+ cqp = *((struct nes_hw_cqp **)&u64temp);
+
+ error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+ if (error_code) {
+ nes_debug(NES_DBG_CQP, "Bad Completion code for opcode 0x%02X from CQP,"
+ " Major/Minor codes = 0x%04X:%04X.\n",
+ le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f,
+ (u16)(error_code >> 16),
+ (u16)error_code);
+ nes_debug(NES_DBG_CQP, "cqp: qp_id=%u, sq_head=%u, sq_tail=%u\n",
+ cqp->qp_id, cqp->sq_head, cqp->sq_tail);
+ }
+
+ u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
+ wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) |
+ ((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
+ wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX])));
+ cqp_request = *((struct nes_cqp_request **)&u64temp);
+ if (cqp_request) {
+ if (cqp_request->waiting) {
+ /* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */
+ cqp_request->major_code = (u16)(error_code >> 16);
+ cqp_request->minor_code = (u16)error_code;
+ barrier();
+ cqp_request->request_done = 1;
+ wake_up(&cqp_request->waitq);
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
+ cqp_request,
+ le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ } else if (cqp_request->callback) {
+ /* Envoke the callback routine */
+ cqp_request->cqp_callback(nesdev, cqp_request);
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ } else {
+ nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
+ cqp_request,
+ le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ } else {
+ wake_up(&nesdev->cqp.waitq);
+ }
+
+ cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16));
+ if (++cqp->sq_tail >= cqp->sq_size)
+ cqp->sq_tail = 0;
+
+ /* Accounting... */
+ cqe_count++;
+ if (++head >= cq_size)
+ head = 0;
+ } else {
+ break;
+ }
+ } while (1);
+ cq->cq_head = head;
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ while ((!list_empty(&nesdev->cqp_pending_reqs)) &&
+ ((((nesdev->cqp.sq_tail+nesdev->cqp.sq_size)-nesdev->cqp.sq_head) &
+ (nesdev->cqp.sq_size - 1)) != 1)) {
+ cqp_request = list_entry(nesdev->cqp_pending_reqs.next,
+ struct nes_cqp_request, list);
+ list_del_init(&cqp_request->list);
+ head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[head];
+ memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
+ barrier();
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
+ cpu_to_le32((u32)((unsigned long)cqp_request));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
+ cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request)));
+ nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n",
+ cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head);
+ /* Ring doorbell (1 WQEs) */
+ barrier();
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
+ }
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ /* Arm the CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ cq->cq_number);
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+}
+
+
+/**
+ * nes_process_iwarp_aeqe
+ */
+void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe)
+{
+ u64 context;
+ u64 aeqe_context = 0;
+ unsigned long flags;
+ struct nes_qp *nesqp;
+ int resource_allocated;
+ /* struct iw_cm_id *cm_id; */
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct ib_event ibevent;
+ /* struct iw_cm_event cm_event; */
+ u32 aeq_info;
+ u32 next_iwarp_state = 0;
+ u16 async_event_id;
+ u8 tcp_state;
+ u8 iwarp_state;
+
+ nes_debug(NES_DBG_AEQ, "\n");
+ aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+ if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) {
+ context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+ context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
+ } else {
+ aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+ aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
+ context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ BUG_ON(!context);
+ }
+
+ async_event_id = (u16)aeq_info;
+ tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
+ iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
+ nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
+ " Tcp state = %s, iWARP state = %s\n",
+ async_event_id,
+ le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
+ nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
+
+
+ switch (async_event_id) {
+ case NES_AEQE_AEID_LLP_FIN_RECEIVED:
+ nesqp = *((struct nes_qp **)&context);
+ if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
+ nesqp->cm_id->add_ref(nesqp->cm_id);
+ nes_add_ref(&nesqp->ibqp);
+ schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp,
+ NES_TIMER_TYPE_CLOSE, 1, 0);
+ nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d),"
+ " need ae to finish up, original_last_aeq = 0x%04X."
+ " last_aeq = 0x%04X, scheduling timer. TCP state = %d\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ async_event_id, nesqp->last_aeq, tcp_state);
+ }
+ if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ (nesqp->ibqp_state != IB_QPS_RTS)) {
+ /* FIN Received but tcp state or IB state moved on,
+ should expect a close complete */
+ return;
+ }
+ case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
+ case NES_AEQE_AEID_LLP_CONNECTION_RESET:
+ case NES_AEQE_AEID_TERMINATE_SENT:
+ case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE:
+ case NES_AEQE_AEID_RESET_SENT:
+ nesqp = *((struct nes_qp **)&context);
+ if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
+ tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ }
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+
+ if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+ (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) {
+ nesqp->hte_added = 0;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n",
+ nesqp->hwqp.qp_id);
+ nes_hw_modify_qp(nesdev, nesqp,
+ NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ }
+
+ if ((nesqp->ibqp_state == IB_QPS_RTS) &&
+ ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ switch (nesqp->hw_iwarp_state) {
+ case NES_AEQE_IWARP_STATE_RTS:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+ break;
+ case NES_AEQE_IWARP_STATE_TERMINATE:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
+ if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
+ next_iwarp_state |= 0x02000000;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ }
+ break;
+ default:
+ next_iwarp_state = 0;
+ }
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ if (next_iwarp_state) {
+ nes_add_ref(&nesqp->ibqp);
+ nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
+ " also added another reference\n",
+ nesqp->hwqp.qp_id, next_iwarp_state);
+ nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+ }
+ nes_cm_disconn(nesqp);
+ } else {
+ if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) {
+ /* FIN Received but ib state not RTS,
+ close complete will be on its way */
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_rem_ref(&nesqp->ibqp);
+ return;
+ }
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
+ " also added another reference\n",
+ nesqp->hwqp.qp_id, next_iwarp_state);
+ nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+ }
+ nes_cm_disconn(nesqp);
+ }
+ break;
+ case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED"
+ " event on QP%u \n Q2 Data:\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ ((nesqp->ibqp_state == IB_QPS_RTS)&&
+ (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ } else {
+ nesqp->in_disconnect = 0;
+ wake_up(&nesqp->kick_waitq);
+ }
+ break;
+ case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES:
+ nesqp = *((struct nes_qp **)&context);
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = async_event_id;
+ if (nesqp->cm_id) {
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES"
+ " event on QP%u, remote IP = 0x%08X \n",
+ nesqp->hwqp.qp_id,
+ ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr));
+ } else {
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES"
+ " event on QP%u \n",
+ nesqp->hwqp.qp_id);
+ }
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET;
+ nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
+ if (NES_AEQE_INBOUND_RDMA&aeq_info) {
+ nesqp = nesadapter->qp_table[le32_to_cpu(
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ } else {
+ /* TODO: get the actual WQE and mask off wqe index */
+ context &= ~((u64)511);
+ nesqp = *((struct nes_qp **)&context);
+ }
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
+ nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words
+ [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u,"
+ " nesqp = %p, AE reported %p\n",
+ nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context));
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_CQ_OPERATION_ERROR:
+ context <<= 1;
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n",
+ le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), (void *)(unsigned long)context);
+ resource_allocated = nes_is_resource_allocated(nesadapter, nesadapter->allocated_cqs,
+ le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
+ if (resource_allocated) {
+ printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n",
+ __FUNCTION__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
+ }
+ break;
+ case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
+ nesqp = nesadapter->qp_table[le32_to_cpu(
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG"
+ "_FOR_AVAILABLE_BUFFER event on QP%u\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ /* tell cm to disconnect, cm will queue work to thread */
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ break;
+ case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN"
+ "_NO_BUFFER_AVAILABLE event on QP%u\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ /* tell cm to disconnect, cm will queue work to thread */
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ break;
+ case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR"
+ " event on QP%u \n Q2 Data:\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ /* tell cm to disconnect, cm will queue work to thread */
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ break;
+ /* TODO: additional AEs need to be here */
+ default:
+ nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
+ async_event_id);
+ break;
+ }
+
+}
+
+
+/**
+ * nes_iwarp_ce_handler
+ */
+void nes_iwarp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *hw_cq)
+{
+ struct nes_cq *nescq = container_of(hw_cq, struct nes_cq, hw_cq);
+
+ /* nes_debug(NES_DBG_CQ, "Processing completion event for iWARP CQ%u.\n",
+ nescq->hw_cq.cq_number); */
+ nes_write32(nesdev->regs+NES_CQ_ACK, nescq->hw_cq.cq_number);
+
+ if (nescq->ibcq.comp_handler)
+ nescq->ibcq.comp_handler(&nescq->ibcq, nescq->ibcq.cq_context);
+
+ return;
+}
+
+
+/**
+ * nes_manage_apbvt()
+ */
+int nes_manage_apbvt(struct nes_vnic *nesvnic, u32 accel_local_port,
+ u32 nic_index, u32 add_port)
+{
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ unsigned long flags;
+ struct nes_cqp_request *cqp_request;
+ int ret = 0;
+ u16 major_code;
+
+ /* Send manage APBVT request to CQP */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+ return -ENOMEM;
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ nes_debug(NES_DBG_QP, "%s APBV for local port=%u(0x%04x), nic_index=%u\n",
+ (add_port == NES_MANAGE_APBVT_ADD) ? "ADD" : "DEL",
+ accel_local_port, accel_local_port, nic_index);
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, (NES_CQP_MANAGE_APBVT |
+ ((add_port == NES_MANAGE_APBVT_ADD) ? NES_CQP_APBVT_ADD : 0)));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+ ((nic_index << NES_CQP_APBVT_NIC_SHIFT) | accel_local_port));
+
+ nes_debug(NES_DBG_QP, "Waiting for CQP completion for APBVT.\n");
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ if (add_port == NES_MANAGE_APBVT_ADD)
+ ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_QP, "Completed, ret=%u, CQP Major:Minor codes = 0x%04X:0x%04X\n",
+ ret, cqp_request->major_code, cqp_request->minor_code);
+ major_code = cqp_request->major_code;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ if (!ret)
+ return -ETIME;
+ else if (major_code)
+ return -EIO;
+ else
+ return 0;
+}
+
+
+/**
+ * nes_manage_arp_cache
+ */
+void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
+ u32 ip_addr, u32 action)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev;
+ struct nes_cqp_request *cqp_request;
+ int arp_index;
+
+ nesdev = nesvnic->nesdev;
+ arp_index = nes_arp_table(nesdev, ip_addr, mac_addr, action);
+ if (arp_index == -1) {
+ return;
+ }
+
+ /* update the ARP entry */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_NETDEV, "Failed to get a cqp_request.\n");
+ return;
+ }
+ cqp_request->waiting = 0;
+ cqp_wqe = &cqp_request->cqp_wqe;
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
+ NES_CQP_MANAGE_ARP_CACHE | NES_CQP_ARP_PERM);
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(
+ (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_CQP_ARP_AEQ_INDEX_SHIFT);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(arp_index);
+
+ if (action == NES_ARP_ADD) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID);
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32(
+ (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
+ (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
+ (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]);
+ } else {
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
+ }
+
+ nes_debug(NES_DBG_NETDEV, "Not waiting for CQP, cqp.sq_head=%u, cqp.sq_tail=%u\n",
+ nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+
+ atomic_set(&cqp_request->refcount, 1);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+}
+
+
+/**
+ * flush_wqes
+ */
+void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp,
+ u32 which_wq, u32 wait_completion)
+{
+ unsigned long flags;
+ struct nes_cqp_request *cqp_request;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ int ret;
+
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+ return;
+ }
+ if (wait_completion) {
+ cqp_request->waiting = 1;
+ atomic_set(&cqp_request->refcount, 2);
+ } else {
+ cqp_request->waiting = 0;
+ }
+ cqp_wqe = &cqp_request->cqp_wqe;
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id);
+
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ if (wait_completion) {
+ /* Wait for CQP */
+ ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_QP, "Flush SQ QP WQEs completed, ret=%u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X\n",
+ ret, cqp_request->major_code, cqp_request->minor_code);
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+}
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
new file mode 100644
index 0000000..1e10df5
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -0,0 +1,1206 @@
+/*
+* Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+*
+* This software is available to you under a choice of one of two
+* licenses. You may choose to be licensed under the terms of the GNU
+* General Public License (GPL) Version 2, available from the file
+* COPYING in the main directory of this source tree, or the
+* OpenIB.org BSD license below:
+*
+* Redistribution and use in source and binary forms, with or
+* without modification, are permitted provided that the following
+* conditions are met:
+*
+* - Redistributions of source code must retain the above
+* copyright notice, this list of conditions and the following
+* disclaimer.
+*
+* - Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials
+* provided with the distribution.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*/
+
+#ifndef __NES_HW_H
+#define __NES_HW_H
+
+#define NES_PHY_TYPE_1G 2
+#define NES_PHY_TYPE_IRIS 3
+#define NES_PHY_TYPE_PUMA_10G 6
+
+#define NES_MULTICAST_PF_MAX 8
+
+enum pci_regs {
+ NES_INT_STAT = 0x0000,
+ NES_INT_MASK = 0x0004,
+ NES_INT_PENDING = 0x0008,
+ NES_INTF_INT_STAT = 0x000C,
+ NES_INTF_INT_MASK = 0x0010,
+ NES_TIMER_STAT = 0x0014,
+ NES_PERIODIC_CONTROL = 0x0018,
+ NES_ONE_SHOT_CONTROL = 0x001C,
+ NES_EEPROM_COMMAND = 0x0020,
+ NES_EEPROM_DATA = 0x0024,
+ NES_FLASH_COMMAND = 0x0028,
+ NES_FLASH_DATA = 0x002C,
+ NES_SOFTWARE_RESET = 0x0030,
+ NES_CQ_ACK = 0x0034,
+ NES_WQE_ALLOC = 0x0040,
+ NES_CQE_ALLOC = 0x0044,
+};
+
+enum indexed_regs {
+ NES_IDX_CREATE_CQP_LOW = 0x0000,
+ NES_IDX_CREATE_CQP_HIGH = 0x0004,
+ NES_IDX_QP_CONTROL = 0x0040,
+ NES_IDX_FLM_CONTROL = 0x0080,
+ NES_IDX_INT_CPU_STATUS = 0x00a0,
+ NES_IDX_GPIO_CONTROL = 0x00f0,
+ NES_IDX_GPIO_DATA = 0x00f4,
+ NES_IDX_TCP_CONFIG0 = 0x01e4,
+ NES_IDX_TCP_TIMER_CONFIG = 0x01ec,
+ NES_IDX_TCP_NOW = 0x01f0,
+ NES_IDX_QP_MAX_CFG_SIZES = 0x0200,
+ NES_IDX_QP_CTX_SIZE = 0x0218,
+ NES_IDX_TCP_TIMER_SIZE0 = 0x0238,
+ NES_IDX_TCP_TIMER_SIZE1 = 0x0240,
+ NES_IDX_ARP_CACHE_SIZE = 0x0258,
+ NES_IDX_CQ_CTX_SIZE = 0x0260,
+ NES_IDX_MRT_SIZE = 0x0278,
+ NES_IDX_PBL_REGION_SIZE = 0x0280,
+ NES_IDX_IRRQ_COUNT = 0x02b0,
+ NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x02f0,
+ NES_IDX_RX_WINDOW_BUFFER_SIZE = 0x0300,
+ NES_IDX_DST_IP_ADDR = 0x0400,
+ NES_IDX_PCIX_DIAG = 0x08e8,
+ NES_IDX_MPP_DEBUG = 0x0a00,
+ NES_IDX_PORT_RX_DISCARDS = 0x0a30,
+ NES_IDX_PORT_TX_DISCARDS = 0x0a34,
+ NES_IDX_MPP_LB_DEBUG = 0x0b00,
+ NES_IDX_DENALI_CTL_22 = 0x1058,
+ NES_IDX_MAC_TX_CONTROL = 0x2000,
+ NES_IDX_MAC_TX_CONFIG = 0x2004,
+ NES_IDX_MAC_TX_PAUSE_QUANTA = 0x2008,
+ NES_IDX_MAC_RX_CONTROL = 0x200c,
+ NES_IDX_MAC_RX_CONFIG = 0x2010,
+ NES_IDX_MAC_EXACT_MATCH_BOTTOM = 0x201c,
+ NES_IDX_MAC_MDIO_CONTROL = 0x2084,
+ NES_IDX_MAC_TX_OCTETS_LOW = 0x2100,
+ NES_IDX_MAC_TX_OCTETS_HIGH = 0x2104,
+ NES_IDX_MAC_TX_FRAMES_LOW = 0x2108,
+ NES_IDX_MAC_TX_FRAMES_HIGH = 0x210c,
+ NES_IDX_MAC_TX_PAUSE_FRAMES = 0x2118,
+ NES_IDX_MAC_TX_ERRORS = 0x2138,
+ NES_IDX_MAC_RX_OCTETS_LOW = 0x213c,
+ NES_IDX_MAC_RX_OCTETS_HIGH = 0x2140,
+ NES_IDX_MAC_RX_FRAMES_LOW = 0x2144,
+ NES_IDX_MAC_RX_FRAMES_HIGH = 0x2148,
+ NES_IDX_MAC_RX_BC_FRAMES_LOW = 0x214c,
+ NES_IDX_MAC_RX_MC_FRAMES_HIGH = 0x2150,
+ NES_IDX_MAC_RX_PAUSE_FRAMES = 0x2154,
+ NES_IDX_MAC_RX_SHORT_FRAMES = 0x2174,
+ NES_IDX_MAC_RX_OVERSIZED_FRAMES = 0x2178,
+ NES_IDX_MAC_RX_JABBER_FRAMES = 0x217c,
+ NES_IDX_MAC_RX_CRC_ERR_FRAMES = 0x2180,
+ NES_IDX_MAC_RX_LENGTH_ERR_FRAMES = 0x2184,
+ NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES = 0x2188,
+ NES_IDX_MAC_INT_STATUS = 0x21f0,
+ NES_IDX_MAC_INT_MASK = 0x21f4,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 = 0x2800,
+ NES_IDX_PHY_PCS_CONTROL_STATUS1 = 0x2a00,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL0 = 0x2808,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL1 = 0x2a08,
+ NES_IDX_ETH_SERDES_COMMON_STATUS0 = 0x280c,
+ NES_IDX_ETH_SERDES_COMMON_STATUS1 = 0x2a0c,
+ NES_IDX_ETH_SERDES_TX_EMP0 = 0x2810,
+ NES_IDX_ETH_SERDES_TX_EMP1 = 0x2a10,
+ NES_IDX_ETH_SERDES_TX_DRIVE0 = 0x2814,
+ NES_IDX_ETH_SERDES_TX_DRIVE1 = 0x2a14,
+ NES_IDX_ETH_SERDES_RX_MODE0 = 0x2818,
+ NES_IDX_ETH_SERDES_RX_MODE1 = 0x2a18,
+ NES_IDX_ETH_SERDES_RX_SIGDET0 = 0x281c,
+ NES_IDX_ETH_SERDES_RX_SIGDET1 = 0x2a1c,
+ NES_IDX_ETH_SERDES_BYPASS0 = 0x2820,
+ NES_IDX_ETH_SERDES_BYPASS1 = 0x2a20,
+ NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0 = 0x2824,
+ NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1 = 0x2a24,
+ NES_IDX_ETH_SERDES_RX_EQ_CONTROL0 = 0x2828,
+ NES_IDX_ETH_SERDES_RX_EQ_CONTROL1 = 0x2a28,
+ NES_IDX_ETH_SERDES_RX_EQ_STATUS0 = 0x282c,
+ NES_IDX_ETH_SERDES_RX_EQ_STATUS1 = 0x2a2c,
+ NES_IDX_ETH_SERDES_CDR_RESET0 = 0x2830,
+ NES_IDX_ETH_SERDES_CDR_RESET1 = 0x2a30,
+ NES_IDX_ETH_SERDES_CDR_CONTROL0 = 0x2834,
+ NES_IDX_ETH_SERDES_CDR_CONTROL1 = 0x2a34,
+ NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0 = 0x2838,
+ NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1 = 0x2a38,
+ NES_IDX_ENDNODE0_NSTAT_RX_DISCARD = 0x3080,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO = 0x3000,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI = 0x3004,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO = 0x3008,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI = 0x300c,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO = 0x7000,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
+ NES_IDX_CM_CONFIG = 0x5100,
+ NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
+ NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
+ NES_IDX_NIC_ACTIVE = 0x6010,
+ NES_IDX_NIC_UNICAST_ALL = 0x6018,
+ NES_IDX_NIC_MULTICAST_ALL = 0x6020,
+ NES_IDX_NIC_MULTICAST_ENABLE = 0x6028,
+ NES_IDX_NIC_BROADCAST_ON = 0x6030,
+ NES_IDX_USED_CHUNKS_TX = 0x60b0,
+ NES_IDX_TX_POOL_SIZE = 0x60b8,
+ NES_IDX_QUAD_HASH_TABLE_SIZE = 0x6148,
+ NES_IDX_PERFECT_FILTER_LOW = 0x6200,
+ NES_IDX_PERFECT_FILTER_HIGH = 0x6204,
+ NES_IDX_IPV4_TCP_REXMITS = 0x7080,
+ NES_IDX_DEBUG_ERROR_CONTROL_STATUS = 0x913c,
+ NES_IDX_DEBUG_ERROR_MASKS0 = 0x9140,
+ NES_IDX_DEBUG_ERROR_MASKS1 = 0x9144,
+ NES_IDX_DEBUG_ERROR_MASKS2 = 0x9148,
+ NES_IDX_DEBUG_ERROR_MASKS3 = 0x914c,
+ NES_IDX_DEBUG_ERROR_MASKS4 = 0x9150,
+ NES_IDX_DEBUG_ERROR_MASKS5 = 0x9154,
+};
+
+#define NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE 1
+#define NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE (1 << 17)
+
+enum nes_cqp_opcodes {
+ NES_CQP_CREATE_QP = 0x00,
+ NES_CQP_MODIFY_QP = 0x01,
+ NES_CQP_DESTROY_QP = 0x02,
+ NES_CQP_CREATE_CQ = 0x03,
+ NES_CQP_MODIFY_CQ = 0x04,
+ NES_CQP_DESTROY_CQ = 0x05,
+ NES_CQP_ALLOCATE_STAG = 0x09,
+ NES_CQP_REGISTER_STAG = 0x0a,
+ NES_CQP_QUERY_STAG = 0x0b,
+ NES_CQP_REGISTER_SHARED_STAG = 0x0c,
+ NES_CQP_DEALLOCATE_STAG = 0x0d,
+ NES_CQP_MANAGE_ARP_CACHE = 0x0f,
+ NES_CQP_SUSPEND_QPS = 0x11,
+ NES_CQP_UPLOAD_CONTEXT = 0x13,
+ NES_CQP_CREATE_CEQ = 0x16,
+ NES_CQP_DESTROY_CEQ = 0x18,
+ NES_CQP_CREATE_AEQ = 0x19,
+ NES_CQP_DESTROY_AEQ = 0x1b,
+ NES_CQP_LMI_ACCESS = 0x20,
+ NES_CQP_FLUSH_WQES = 0x22,
+ NES_CQP_MANAGE_APBVT = 0x23
+};
+
+enum nes_cqp_wqe_word_idx {
+ NES_CQP_WQE_OPCODE_IDX = 0,
+ NES_CQP_WQE_ID_IDX = 1,
+ NES_CQP_WQE_COMP_CTX_LOW_IDX = 2,
+ NES_CQP_WQE_COMP_CTX_HIGH_IDX = 3,
+ NES_CQP_WQE_COMP_SCRATCH_LOW_IDX = 4,
+ NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+};
+
+enum nes_cqp_cq_wqeword_idx {
+ NES_CQP_CQ_WQE_PBL_LOW_IDX = 6,
+ NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7,
+ NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX = 8,
+ NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX = 9,
+ NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX = 10,
+};
+
+enum nes_cqp_stag_wqeword_idx {
+ NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX = 1,
+ NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX = 6,
+ NES_CQP_STAG_WQE_LEN_LOW_IDX = 7,
+ NES_CQP_STAG_WQE_STAG_IDX = 8,
+ NES_CQP_STAG_WQE_VA_LOW_IDX = 10,
+ NES_CQP_STAG_WQE_VA_HIGH_IDX = 11,
+ NES_CQP_STAG_WQE_PA_LOW_IDX = 12,
+ NES_CQP_STAG_WQE_PA_HIGH_IDX = 13,
+ NES_CQP_STAG_WQE_PBL_LEN_IDX = 14
+};
+
+#define NES_CQP_OP_IWARP_STATE_SHIFT 28
+
+enum nes_cqp_qp_bits {
+ NES_CQP_QP_ARP_VALID = (1<<8),
+ NES_CQP_QP_WINBUF_VALID = (1<<9),
+ NES_CQP_QP_CONTEXT_VALID = (1<<10),
+ NES_CQP_QP_ORD_VALID = (1<<11),
+ NES_CQP_QP_WINBUF_DATAIND_EN = (1<<12),
+ NES_CQP_QP_VIRT_WQS = (1<<13),
+ NES_CQP_QP_DEL_HTE = (1<<14),
+ NES_CQP_QP_CQS_VALID = (1<<15),
+ NES_CQP_QP_TYPE_TSA = 0,
+ NES_CQP_QP_TYPE_IWARP = (1<<16),
+ NES_CQP_QP_TYPE_CQP = (4<<16),
+ NES_CQP_QP_TYPE_NIC = (5<<16),
+ NES_CQP_QP_MSS_CHG = (1<<20),
+ NES_CQP_QP_STATIC_RESOURCES = (1<<21),
+ NES_CQP_QP_IGNORE_MW_BOUND = (1<<22),
+ NES_CQP_QP_VWQ_USE_LMI = (1<<23),
+ NES_CQP_QP_IWARP_STATE_IDLE = (1<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_RTS = (2<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_CLOSING = (3<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_TERMINATE = (5<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_ERROR = (6<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_MASK = (7<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_RESET = (1<<31),
+};
+
+enum nes_cqp_qp_wqe_word_idx {
+ NES_CQP_QP_WQE_CONTEXT_LOW_IDX = 6,
+ NES_CQP_QP_WQE_CONTEXT_HIGH_IDX = 7,
+ NES_CQP_QP_WQE_NEW_MSS_IDX = 15,
+};
+
+enum nes_nic_ctx_bits {
+ NES_NIC_CTX_RQ_SIZE_32 = (3<<8),
+ NES_NIC_CTX_RQ_SIZE_512 = (3<<8),
+ NES_NIC_CTX_SQ_SIZE_32 = (1<<10),
+ NES_NIC_CTX_SQ_SIZE_512 = (3<<10),
+};
+
+enum nes_nic_qp_ctx_word_idx {
+ NES_NIC_CTX_MISC_IDX = 0,
+ NES_NIC_CTX_SQ_LOW_IDX = 2,
+ NES_NIC_CTX_SQ_HIGH_IDX = 3,
+ NES_NIC_CTX_RQ_LOW_IDX = 4,
+ NES_NIC_CTX_RQ_HIGH_IDX = 5,
+};
+
+enum nes_cqp_cq_bits {
+ NES_CQP_CQ_CEQE_MASK = (1<<9),
+ NES_CQP_CQ_CEQ_VALID = (1<<10),
+ NES_CQP_CQ_RESIZE = (1<<11),
+ NES_CQP_CQ_CHK_OVERFLOW = (1<<12),
+ NES_CQP_CQ_4KB_CHUNK = (1<<14),
+ NES_CQP_CQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_stag_bits {
+ NES_CQP_STAG_VA_TO = (1<<9),
+ NES_CQP_STAG_DEALLOC_PBLS = (1<<10),
+ NES_CQP_STAG_PBL_BLK_SIZE = (1<<11),
+ NES_CQP_STAG_MR = (1<<13),
+ NES_CQP_STAG_RIGHTS_LOCAL_READ = (1<<16),
+ NES_CQP_STAG_RIGHTS_LOCAL_WRITE = (1<<17),
+ NES_CQP_STAG_RIGHTS_REMOTE_READ = (1<<18),
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE = (1<<19),
+ NES_CQP_STAG_RIGHTS_WINDOW_BIND = (1<<20),
+ NES_CQP_STAG_REM_ACC_EN = (1<<21),
+ NES_CQP_STAG_LEAVE_PENDING = (1<<31),
+};
+
+enum nes_cqp_ceq_wqeword_idx {
+ NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX = 1,
+ NES_CQP_CEQ_WQE_PBL_LOW_IDX = 6,
+ NES_CQP_CEQ_WQE_PBL_HIGH_IDX = 7,
+};
+
+enum nes_cqp_ceq_bits {
+ NES_CQP_CEQ_4KB_CHUNK = (1<<14),
+ NES_CQP_CEQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_aeq_wqeword_idx {
+ NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX = 1,
+ NES_CQP_AEQ_WQE_PBL_LOW_IDX = 6,
+ NES_CQP_AEQ_WQE_PBL_HIGH_IDX = 7,
+};
+
+enum nes_cqp_aeq_bits {
+ NES_CQP_AEQ_4KB_CHUNK = (1<<14),
+ NES_CQP_AEQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_lmi_wqeword_idx {
+ NES_CQP_LMI_WQE_LMI_OFFSET_IDX = 1,
+ NES_CQP_LMI_WQE_FRAG_LOW_IDX = 8,
+ NES_CQP_LMI_WQE_FRAG_HIGH_IDX = 9,
+ NES_CQP_LMI_WQE_FRAG_LEN_IDX = 10,
+};
+
+enum nes_cqp_arp_wqeword_idx {
+ NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX = 6,
+ NES_CQP_ARP_WQE_MAC_HIGH_IDX = 7,
+ NES_CQP_ARP_WQE_REACHABILITY_MAX_IDX = 1,
+};
+
+enum nes_cqp_upload_wqeword_idx {
+ NES_CQP_UPLOAD_WQE_CTXT_LOW_IDX = 6,
+ NES_CQP_UPLOAD_WQE_CTXT_HIGH_IDX = 7,
+ NES_CQP_UPLOAD_WQE_HTE_IDX = 8,
+};
+
+enum nes_cqp_arp_bits {
+ NES_CQP_ARP_VALID = (1<<8),
+ NES_CQP_ARP_PERM = (1<<9),
+};
+
+enum nes_cqp_flush_bits {
+ NES_CQP_FLUSH_SQ = (1<<30),
+ NES_CQP_FLUSH_RQ = (1<<31),
+};
+
+enum nes_cqe_opcode_bits {
+ NES_CQE_STAG_VALID = (1<<6),
+ NES_CQE_ERROR = (1<<7),
+ NES_CQE_SQ = (1<<8),
+ NES_CQE_SE = (1<<9),
+ NES_CQE_PSH = (1<<29),
+ NES_CQE_FIN = (1<<30),
+ NES_CQE_VALID = (1<<31),
+};
+
+
+enum nes_cqe_word_idx {
+ NES_CQE_PAYLOAD_LENGTH_IDX = 0,
+ NES_CQE_COMP_COMP_CTX_LOW_IDX = 2,
+ NES_CQE_COMP_COMP_CTX_HIGH_IDX = 3,
+ NES_CQE_INV_STAG_IDX = 4,
+ NES_CQE_QP_ID_IDX = 5,
+ NES_CQE_ERROR_CODE_IDX = 6,
+ NES_CQE_OPCODE_IDX = 7,
+};
+
+enum nes_ceqe_word_idx {
+ NES_CEQE_CQ_CTX_LOW_IDX = 0,
+ NES_CEQE_CQ_CTX_HIGH_IDX = 1,
+};
+
+enum nes_ceqe_status_bit {
+ NES_CEQE_VALID = (1<<31),
+};
+
+enum nes_int_bits {
+ NES_INT_CEQ0 = (1<<0),
+ NES_INT_CEQ1 = (1<<1),
+ NES_INT_CEQ2 = (1<<2),
+ NES_INT_CEQ3 = (1<<3),
+ NES_INT_CEQ4 = (1<<4),
+ NES_INT_CEQ5 = (1<<5),
+ NES_INT_CEQ6 = (1<<6),
+ NES_INT_CEQ7 = (1<<7),
+ NES_INT_CEQ8 = (1<<8),
+ NES_INT_CEQ9 = (1<<9),
+ NES_INT_CEQ10 = (1<<10),
+ NES_INT_CEQ11 = (1<<11),
+ NES_INT_CEQ12 = (1<<12),
+ NES_INT_CEQ13 = (1<<13),
+ NES_INT_CEQ14 = (1<<14),
+ NES_INT_CEQ15 = (1<<15),
+ NES_INT_AEQ0 = (1<<16),
+ NES_INT_AEQ1 = (1<<17),
+ NES_INT_AEQ2 = (1<<18),
+ NES_INT_AEQ3 = (1<<19),
+ NES_INT_AEQ4 = (1<<20),
+ NES_INT_AEQ5 = (1<<21),
+ NES_INT_AEQ6 = (1<<22),
+ NES_INT_AEQ7 = (1<<23),
+ NES_INT_MAC0 = (1<<24),
+ NES_INT_MAC1 = (1<<25),
+ NES_INT_MAC2 = (1<<26),
+ NES_INT_MAC3 = (1<<27),
+ NES_INT_TSW = (1<<28),
+ NES_INT_TIMER = (1<<29),
+ NES_INT_INTF = (1<<30),
+};
+
+enum nes_intf_int_bits {
+ NES_INTF_INT_PCIERR = (1<<0),
+ NES_INTF_PERIODIC_TIMER = (1<<2),
+ NES_INTF_ONE_SHOT_TIMER = (1<<3),
+ NES_INTF_INT_CRITERR = (1<<14),
+ NES_INTF_INT_AEQ0_OFLOW = (1<<16),
+ NES_INTF_INT_AEQ1_OFLOW = (1<<17),
+ NES_INTF_INT_AEQ2_OFLOW = (1<<18),
+ NES_INTF_INT_AEQ3_OFLOW = (1<<19),
+ NES_INTF_INT_AEQ4_OFLOW = (1<<20),
+ NES_INTF_INT_AEQ5_OFLOW = (1<<21),
+ NES_INTF_INT_AEQ6_OFLOW = (1<<22),
+ NES_INTF_INT_AEQ7_OFLOW = (1<<23),
+ NES_INTF_INT_AEQ_OFLOW = (0xff<<16),
+};
+
+enum nes_mac_int_bits {
+ NES_MAC_INT_LINK_STAT_CHG = (1<<1),
+ NES_MAC_INT_XGMII_EXT = (1<<2),
+ NES_MAC_INT_TX_UNDERFLOW = (1<<6),
+ NES_MAC_INT_TX_ERROR = (1<<7),
+};
+
+enum nes_cqe_allocate_bits {
+ NES_CQE_ALLOC_INC_SELECT = (1<<28),
+ NES_CQE_ALLOC_NOTIFY_NEXT = (1<<29),
+ NES_CQE_ALLOC_NOTIFY_SE = (1<<30),
+ NES_CQE_ALLOC_RESET = (1<<31),
+};
+
+enum nes_nic_rq_wqe_word_idx {
+ NES_NIC_RQ_WQE_LENGTH_1_0_IDX = 0,
+ NES_NIC_RQ_WQE_LENGTH_3_2_IDX = 1,
+ NES_NIC_RQ_WQE_FRAG0_LOW_IDX = 2,
+ NES_NIC_RQ_WQE_FRAG0_HIGH_IDX = 3,
+ NES_NIC_RQ_WQE_FRAG1_LOW_IDX = 4,
+ NES_NIC_RQ_WQE_FRAG1_HIGH_IDX = 5,
+ NES_NIC_RQ_WQE_FRAG2_LOW_IDX = 6,
+ NES_NIC_RQ_WQE_FRAG2_HIGH_IDX = 7,
+ NES_NIC_RQ_WQE_FRAG3_LOW_IDX = 8,
+ NES_NIC_RQ_WQE_FRAG3_HIGH_IDX = 9,
+};
+
+enum nes_nic_sq_wqe_word_idx {
+ NES_NIC_SQ_WQE_MISC_IDX = 0,
+ NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX = 1,
+ NES_NIC_SQ_WQE_LSO_INFO_IDX = 2,
+ NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX = 3,
+ NES_NIC_SQ_WQE_LENGTH_2_1_IDX = 4,
+ NES_NIC_SQ_WQE_LENGTH_4_3_IDX = 5,
+ NES_NIC_SQ_WQE_FRAG0_LOW_IDX = 6,
+ NES_NIC_SQ_WQE_FRAG0_HIGH_IDX = 7,
+ NES_NIC_SQ_WQE_FRAG1_LOW_IDX = 8,
+ NES_NIC_SQ_WQE_FRAG1_HIGH_IDX = 9,
+ NES_NIC_SQ_WQE_FRAG2_LOW_IDX = 10,
+ NES_NIC_SQ_WQE_FRAG2_HIGH_IDX = 11,
+ NES_NIC_SQ_WQE_FRAG3_LOW_IDX = 12,
+ NES_NIC_SQ_WQE_FRAG3_HIGH_IDX = 13,
+ NES_NIC_SQ_WQE_FRAG4_LOW_IDX = 14,
+ NES_NIC_SQ_WQE_FRAG4_HIGH_IDX = 15,
+};
+
+enum nes_iwarp_sq_wqe_word_idx {
+ NES_IWARP_SQ_WQE_MISC_IDX = 0,
+ NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX = 1,
+ NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX = 2,
+ NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX = 3,
+ NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
+ NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+ NES_IWARP_SQ_WQE_INV_STAG_LOW_IDX = 7,
+ NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX = 8,
+ NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX = 9,
+ NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX = 10,
+ NES_IWARP_SQ_WQE_RDMA_STAG_IDX = 11,
+ NES_IWARP_SQ_WQE_IMM_DATA_START_IDX = 12,
+ NES_IWARP_SQ_WQE_FRAG0_LOW_IDX = 16,
+ NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX = 17,
+ NES_IWARP_SQ_WQE_LENGTH0_IDX = 18,
+ NES_IWARP_SQ_WQE_STAG0_IDX = 19,
+ NES_IWARP_SQ_WQE_FRAG1_LOW_IDX = 20,
+ NES_IWARP_SQ_WQE_FRAG1_HIGH_IDX = 21,
+ NES_IWARP_SQ_WQE_LENGTH1_IDX = 22,
+ NES_IWARP_SQ_WQE_STAG1_IDX = 23,
+ NES_IWARP_SQ_WQE_FRAG2_LOW_IDX = 24,
+ NES_IWARP_SQ_WQE_FRAG2_HIGH_IDX = 25,
+ NES_IWARP_SQ_WQE_LENGTH2_IDX = 26,
+ NES_IWARP_SQ_WQE_STAG2_IDX = 27,
+ NES_IWARP_SQ_WQE_FRAG3_LOW_IDX = 28,
+ NES_IWARP_SQ_WQE_FRAG3_HIGH_IDX = 29,
+ NES_IWARP_SQ_WQE_LENGTH3_IDX = 30,
+ NES_IWARP_SQ_WQE_STAG3_IDX = 31,
+};
+
+enum nes_iwarp_sq_bind_wqe_word_idx {
+ NES_IWARP_SQ_BIND_WQE_MR_IDX = 6,
+ NES_IWARP_SQ_BIND_WQE_MW_IDX = 7,
+ NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX = 8,
+ NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX = 9,
+ NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX = 10,
+ NES_IWARP_SQ_BIND_WQE_VA_FBO_HIGH_IDX = 11,
+};
+
+enum nes_iwarp_sq_fmr_wqe_word_idx {
+ NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX = 7,
+ NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX = 8,
+ NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX = 9,
+ NES_IWARP_SQ_FMR_WQE_VA_FBO_LOW_IDX = 10,
+ NES_IWARP_SQ_FMR_WQE_VA_FBO_HIGH_IDX = 11,
+ NES_IWARP_SQ_FMR_WQE_PBL_ADDR_LOW_IDX = 12,
+ NES_IWARP_SQ_FMR_WQE_PBL_ADDR_HIGH_IDX = 13,
+ NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX = 14,
+};
+
+enum nes_iwarp_sq_locinv_wqe_word_idx {
+ NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX = 6,
+};
+
+
+enum nes_iwarp_rq_wqe_word_idx {
+ NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX = 1,
+ NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX = 2,
+ NES_IWARP_RQ_WQE_COMP_CTX_HIGH_IDX = 3,
+ NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
+ NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+ NES_IWARP_RQ_WQE_FRAG0_LOW_IDX = 8,
+ NES_IWARP_RQ_WQE_FRAG0_HIGH_IDX = 9,
+ NES_IWARP_RQ_WQE_LENGTH0_IDX = 10,
+ NES_IWARP_RQ_WQE_STAG0_IDX = 11,
+ NES_IWARP_RQ_WQE_FRAG1_LOW_IDX = 12,
+ NES_IWARP_RQ_WQE_FRAG1_HIGH_IDX = 13,
+ NES_IWARP_RQ_WQE_LENGTH1_IDX = 14,
+ NES_IWARP_RQ_WQE_STAG1_IDX = 15,
+ NES_IWARP_RQ_WQE_FRAG2_LOW_IDX = 16,
+ NES_IWARP_RQ_WQE_FRAG2_HIGH_IDX = 17,
+ NES_IWARP_RQ_WQE_LENGTH2_IDX = 18,
+ NES_IWARP_RQ_WQE_STAG2_IDX = 19,
+ NES_IWARP_RQ_WQE_FRAG3_LOW_IDX = 20,
+ NES_IWARP_RQ_WQE_FRAG3_HIGH_IDX = 21,
+ NES_IWARP_RQ_WQE_LENGTH3_IDX = 22,
+ NES_IWARP_RQ_WQE_STAG3_IDX = 23,
+};
+
+enum nes_nic_sq_wqe_bits {
+ NES_NIC_SQ_WQE_PHDR_CS_READY = (1<<21),
+ NES_NIC_SQ_WQE_LSO_ENABLE = (1<<22),
+ NES_NIC_SQ_WQE_TAGVALUE_ENABLE = (1<<23),
+ NES_NIC_SQ_WQE_DISABLE_CHKSUM = (1<<30),
+ NES_NIC_SQ_WQE_COMPLETION = (1<<31),
+};
+
+enum nes_nic_cqe_word_idx {
+ NES_NIC_CQE_ACCQP_ID_IDX = 0,
+ NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2,
+ NES_NIC_CQE_MISC_IDX = 3,
+};
+
+#define NES_PKT_TYPE_APBVT_BITS 0xC112
+#define NES_PKT_TYPE_APBVT_MASK 0xff3e
+
+#define NES_PKT_TYPE_PVALID_BITS 0x10000000
+#define NES_PKT_TYPE_PVALID_MASK 0x30000000
+
+#define NES_PKT_TYPE_TCPV4_BITS 0x0110
+#define NES_PKT_TYPE_TCPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_UDPV4_BITS 0x0210
+#define NES_PKT_TYPE_UDPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_IPV4_BITS 0x0010
+#define NES_PKT_TYPE_IPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_OTHER_BITS 0x0000
+#define NES_PKT_TYPE_OTHER_MASK 0x0030
+
+#define NES_NIC_CQE_ERRV_SHIFT 16
+enum nes_nic_ev_bits {
+ NES_NIC_ERRV_BITS_MODE = (1<<0),
+ NES_NIC_ERRV_BITS_IPV4_CSUM_ERR = (1<<1),
+ NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR = (1<<2),
+ NES_NIC_ERRV_BITS_WQE_OVERRUN = (1<<3),
+ NES_NIC_ERRV_BITS_IPH_ERR = (1<<4),
+};
+
+enum nes_nic_cqe_bits {
+ NES_NIC_CQE_ERRV_MASK = (0xff<<NES_NIC_CQE_ERRV_SHIFT),
+ NES_NIC_CQE_SQ = (1<<24),
+ NES_NIC_CQE_ACCQP_PORT = (1<<28),
+ NES_NIC_CQE_ACCQP_VALID = (1<<29),
+ NES_NIC_CQE_TAG_VALID = (1<<30),
+ NES_NIC_CQE_VALID = (1<<31),
+};
+
+enum nes_aeqe_word_idx {
+ NES_AEQE_COMP_CTXT_LOW_IDX = 0,
+ NES_AEQE_COMP_CTXT_HIGH_IDX = 1,
+ NES_AEQE_COMP_QP_CQ_ID_IDX = 2,
+ NES_AEQE_MISC_IDX = 3,
+};
+
+enum nes_aeqe_bits {
+ NES_AEQE_QP = (1<<16),
+ NES_AEQE_CQ = (1<<17),
+ NES_AEQE_SQ = (1<<18),
+ NES_AEQE_INBOUND_RDMA = (1<<19),
+ NES_AEQE_IWARP_STATE_MASK = (7<<20),
+ NES_AEQE_TCP_STATE_MASK = (0xf<<24),
+ NES_AEQE_VALID = (1<<31),
+};
+
+#define NES_AEQE_IWARP_STATE_SHIFT 20
+#define NES_AEQE_TCP_STATE_SHIFT 24
+
+enum nes_aeqe_iwarp_state {
+ NES_AEQE_IWARP_STATE_NON_EXISTANT = 0,
+ NES_AEQE_IWARP_STATE_IDLE = 1,
+ NES_AEQE_IWARP_STATE_RTS = 2,
+ NES_AEQE_IWARP_STATE_CLOSING = 3,
+ NES_AEQE_IWARP_STATE_TERMINATE = 5,
+ NES_AEQE_IWARP_STATE_ERROR = 6
+};
+
+enum nes_aeqe_tcp_state {
+ NES_AEQE_TCP_STATE_NON_EXISTANT = 0,
+ NES_AEQE_TCP_STATE_CLOSED = 1,
+ NES_AEQE_TCP_STATE_LISTEN = 2,
+ NES_AEQE_TCP_STATE_SYN_SENT = 3,
+ NES_AEQE_TCP_STATE_SYN_RCVD = 4,
+ NES_AEQE_TCP_STATE_ESTABLISHED = 5,
+ NES_AEQE_TCP_STATE_CLOSE_WAIT = 6,
+ NES_AEQE_TCP_STATE_FIN_WAIT_1 = 7,
+ NES_AEQE_TCP_STATE_CLOSING = 8,
+ NES_AEQE_TCP_STATE_LAST_ACK = 9,
+ NES_AEQE_TCP_STATE_FIN_WAIT_2 = 10,
+ NES_AEQE_TCP_STATE_TIME_WAIT = 11
+};
+
+enum nes_aeqe_aeid {
+ NES_AEQE_AEID_AMP_UNALLOCATED_STAG = 0x0102,
+ NES_AEQE_AEID_AMP_INVALID_STAG = 0x0103,
+ NES_AEQE_AEID_AMP_BAD_QP = 0x0104,
+ NES_AEQE_AEID_AMP_BAD_PD = 0x0105,
+ NES_AEQE_AEID_AMP_BAD_STAG_KEY = 0x0106,
+ NES_AEQE_AEID_AMP_BAD_STAG_INDEX = 0x0107,
+ NES_AEQE_AEID_AMP_BOUNDS_VIOLATION = 0x0108,
+ NES_AEQE_AEID_AMP_RIGHTS_VIOLATION = 0x0109,
+ NES_AEQE_AEID_AMP_TO_WRAP = 0x010a,
+ NES_AEQE_AEID_AMP_FASTREG_SHARED = 0x010b,
+ NES_AEQE_AEID_AMP_FASTREG_VALID_STAG = 0x010c,
+ NES_AEQE_AEID_AMP_FASTREG_MW_STAG = 0x010d,
+ NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS = 0x010e,
+ NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW = 0x010f,
+ NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH = 0x0110,
+ NES_AEQE_AEID_AMP_INVALIDATE_SHARED = 0x0111,
+ NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS = 0x0112,
+ NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS = 0x0113,
+ NES_AEQE_AEID_AMP_MWBIND_VALID_STAG = 0x0114,
+ NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG = 0x0115,
+ NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG = 0x0116,
+ NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG = 0x0117,
+ NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS = 0x0118,
+ NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS = 0x0119,
+ NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT = 0x011a,
+ NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED = 0x011b,
+ NES_AEQE_AEID_BAD_CLOSE = 0x0201,
+ NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE = 0x0202,
+ NES_AEQE_AEID_CQ_OPERATION_ERROR = 0x0203,
+ NES_AEQE_AEID_PRIV_OPERATION_DENIED = 0x0204,
+ NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO = 0x0205,
+ NES_AEQE_AEID_STAG_ZERO_INVALID = 0x0206,
+ NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN = 0x0301,
+ NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID = 0x0302,
+ NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER = 0x0303,
+ NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION = 0x0304,
+ NES_AEQE_AEID_DDP_UBE_INVALID_MO = 0x0305,
+ NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE = 0x0306,
+ NES_AEQE_AEID_DDP_UBE_INVALID_QN = 0x0307,
+ NES_AEQE_AEID_DDP_NO_L_BIT = 0x0308,
+ NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION = 0x0311,
+ NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE = 0x0312,
+ NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST = 0x0313,
+ NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP = 0x0314,
+ NES_AEQE_AEID_INVALID_ARP_ENTRY = 0x0401,
+ NES_AEQE_AEID_INVALID_TCP_OPTION_RCVD = 0x0402,
+ NES_AEQE_AEID_STALE_ARP_ENTRY = 0x0403,
+ NES_AEQE_AEID_LLP_CLOSE_COMPLETE = 0x0501,
+ NES_AEQE_AEID_LLP_CONNECTION_RESET = 0x0502,
+ NES_AEQE_AEID_LLP_FIN_RECEIVED = 0x0503,
+ NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH = 0x0504,
+ NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR = 0x0505,
+ NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE = 0x0506,
+ NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL = 0x0507,
+ NES_AEQE_AEID_LLP_SYN_RECEIVED = 0x0508,
+ NES_AEQE_AEID_LLP_TERMINATE_RECEIVED = 0x0509,
+ NES_AEQE_AEID_LLP_TOO_MANY_RETRIES = 0x050a,
+ NES_AEQE_AEID_LLP_TOO_MANY_KEEPALIVE_RETRIES = 0x050b,
+ NES_AEQE_AEID_RESET_SENT = 0x0601,
+ NES_AEQE_AEID_TERMINATE_SENT = 0x0602,
+ NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC = 0x0700
+};
+
+enum nes_iwarp_sq_opcodes {
+ NES_IWARP_SQ_WQE_WRPDU = (1<<15),
+ NES_IWARP_SQ_WQE_PSH = (1<<21),
+ NES_IWARP_SQ_WQE_STREAMING = (1<<23),
+ NES_IWARP_SQ_WQE_IMM_DATA = (1<<28),
+ NES_IWARP_SQ_WQE_READ_FENCE = (1<<29),
+ NES_IWARP_SQ_WQE_LOCAL_FENCE = (1<<30),
+ NES_IWARP_SQ_WQE_SIGNALED_COMPL = (1<<31),
+};
+
+enum nes_iwarp_sq_wqe_bits {
+ NES_IWARP_SQ_OP_RDMAW = 0,
+ NES_IWARP_SQ_OP_RDMAR = 1,
+ NES_IWARP_SQ_OP_SEND = 3,
+ NES_IWARP_SQ_OP_SENDINV = 4,
+ NES_IWARP_SQ_OP_SENDSE = 5,
+ NES_IWARP_SQ_OP_SENDSEINV = 6,
+ NES_IWARP_SQ_OP_BIND = 8,
+ NES_IWARP_SQ_OP_FAST_REG = 9,
+ NES_IWARP_SQ_OP_LOCINV = 10,
+ NES_IWARP_SQ_OP_RDMAR_LOCINV = 11,
+ NES_IWARP_SQ_OP_NOP = 12,
+};
+
+#define NES_EEPROM_READ_REQUEST (1<<16)
+#define NES_MAC_ADDR_VALID (1<<20)
+
+/*
+ * NES index registers init values.
+ */
+struct nes_init_values {
+ u32 index;
+ u32 data;
+ u8 wrt;
+};
+
+/*
+ * NES registers in BAR0.
+ */
+struct nes_pci_regs {
+ u32 int_status;
+ u32 int_mask;
+ u32 int_pending;
+ u32 intf_int_status;
+ u32 intf_int_mask;
+ u32 other_regs[59]; /* pad out to 256 bytes for now */
+};
+
+#define NES_CQP_SQ_SIZE 128
+#define NES_CCQ_SIZE 128
+#define NES_NIC_WQ_SIZE 512
+#define NES_NIC_CTX_SIZE ((NES_NIC_CTX_RQ_SIZE_512) | (NES_NIC_CTX_SQ_SIZE_512))
+#define NES_NIC_BACK_STORE 0x00038000
+
+struct nes_device;
+
+struct nes_hw_nic_qp_context {
+ __le32 context_words[6];
+};
+
+struct nes_hw_nic_sq_wqe {
+ __le32 wqe_words[16];
+};
+
+struct nes_hw_nic_rq_wqe {
+ __le32 wqe_words[16];
+};
+
+struct nes_hw_nic_cqe {
+ __le32 cqe_words[4];
+};
+
+struct nes_hw_cqp_qp_context {
+ __le32 context_words[4];
+};
+
+struct nes_hw_cqp_wqe {
+ __le32 wqe_words[16];
+};
+
+struct nes_hw_qp_wqe {
+ __le32 wqe_words[32];
+};
+
+struct nes_hw_cqe {
+ __le32 cqe_words[8];
+};
+
+struct nes_hw_ceqe {
+ __le32 ceqe_words[2];
+};
+
+struct nes_hw_aeqe {
+ __le32 aeqe_words[4];
+};
+
+struct nes_cqp_request {
+ union {
+ u64 cqp_callback_context;
+ void *cqp_callback_pointer;
+ };
+ wait_queue_head_t waitq;
+ struct nes_hw_cqp_wqe cqp_wqe;
+ struct list_head list;
+ atomic_t refcount;
+ void (*cqp_callback)(struct nes_device *nesdev, struct nes_cqp_request *cqp_request);
+ u16 major_code;
+ u16 minor_code;
+ u8 waiting;
+ u8 request_done;
+ u8 dynamic;
+ u8 callback;
+};
+
+struct nes_hw_cqp {
+ struct nes_hw_cqp_wqe *sq_vbase;
+ dma_addr_t sq_pbase;
+ spinlock_t lock;
+ wait_queue_head_t waitq;
+ u16 qp_id;
+ u16 sq_head;
+ u16 sq_tail;
+ u16 sq_size;
+};
+
+#define NES_FIRST_FRAG_SIZE 128
+struct nes_first_frag {
+ u8 buffer[NES_FIRST_FRAG_SIZE];
+};
+
+struct nes_hw_nic {
+ struct nes_first_frag *first_frag_vbase; /* virtual address of first frags */
+ struct nes_hw_nic_sq_wqe *sq_vbase; /* virtual address of sq */
+ struct nes_hw_nic_rq_wqe *rq_vbase; /* virtual address of rq */
+ struct sk_buff *tx_skb[NES_NIC_WQ_SIZE];
+ struct sk_buff *rx_skb[NES_NIC_WQ_SIZE];
+ dma_addr_t frag_paddr[NES_NIC_WQ_SIZE];
+ unsigned long first_frag_overflow[BITS_TO_LONGS(NES_NIC_WQ_SIZE)];
+ dma_addr_t sq_pbase; /* PCI memory for host rings */
+ dma_addr_t rq_pbase; /* PCI memory for host rings */
+
+ u16 qp_id;
+ u16 sq_head;
+ u16 sq_tail;
+ u16 sq_size;
+ u16 rq_head;
+ u16 rq_tail;
+ u16 rq_size;
+ u8 replenishing_rq;
+ u8 reserved;
+
+ spinlock_t sq_lock;
+ spinlock_t rq_lock;
+};
+
+struct nes_hw_nic_cq {
+ struct nes_hw_nic_cqe volatile *cq_vbase; /* PCI memory for host rings */
+ void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
+ dma_addr_t cq_pbase; /* PCI memory for host rings */
+ int rx_cqes_completed;
+ int cqe_allocs_pending;
+ int rx_pkts_indicated;
+ u16 cq_head;
+ u16 cq_size;
+ u16 cq_number;
+ u8 cqes_pending;
+};
+
+struct nes_hw_qp {
+ struct nes_hw_qp_wqe *sq_vbase; /* PCI memory for host rings */
+ struct nes_hw_qp_wqe *rq_vbase; /* PCI memory for host rings */
+ void *q2_vbase; /* PCI memory for host rings */
+ dma_addr_t sq_pbase; /* PCI memory for host rings */
+ dma_addr_t rq_pbase; /* PCI memory for host rings */
+ dma_addr_t q2_pbase; /* PCI memory for host rings */
+ u32 qp_id;
+ u16 sq_head;
+ u16 sq_tail;
+ u16 sq_size;
+ u16 rq_head;
+ u16 rq_tail;
+ u16 rq_size;
+ u8 rq_encoded_size;
+ u8 sq_encoded_size;
+};
+
+struct nes_hw_cq {
+ struct nes_hw_cqe volatile *cq_vbase; /* PCI memory for host rings */
+ void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_cq *cq);
+ dma_addr_t cq_pbase; /* PCI memory for host rings */
+ u16 cq_head;
+ u16 cq_size;
+ u16 cq_number;
+};
+
+struct nes_hw_ceq {
+ struct nes_hw_ceqe volatile *ceq_vbase; /* PCI memory for host rings */
+ dma_addr_t ceq_pbase; /* PCI memory for host rings */
+ u16 ceq_head;
+ u16 ceq_size;
+};
+
+struct nes_hw_aeq {
+ struct nes_hw_aeqe volatile *aeq_vbase; /* PCI memory for host rings */
+ dma_addr_t aeq_pbase; /* PCI memory for host rings */
+ u16 aeq_head;
+ u16 aeq_size;
+};
+
+struct nic_qp_map {
+ u8 qpid;
+ u8 nic_index;
+ u8 logical_port;
+ u8 is_hnic;
+};
+
+#define NES_CQP_ARP_AEQ_INDEX_MASK 0x000f0000
+#define NES_CQP_ARP_AEQ_INDEX_SHIFT 16
+
+#define NES_CQP_APBVT_ADD 0x00008000
+#define NES_CQP_APBVT_NIC_SHIFT 16
+
+#define NES_ARP_ADD 1
+#define NES_ARP_DELETE 2
+#define NES_ARP_RESOLVE 3
+
+#define NES_MAC_SW_IDLE 0
+#define NES_MAC_SW_INTERRUPT 1
+#define NES_MAC_SW_MH 2
+
+struct nes_arp_entry {
+ u32 ip_addr;
+ u8 mac_addr[ETH_ALEN];
+};
+
+#define NES_NIC_FAST_TIMER 96
+#define NES_NIC_FAST_TIMER_LOW 40
+#define NES_NIC_FAST_TIMER_HIGH 1000
+#define DEFAULT_NES_QL_HIGH 256
+#define DEFAULT_NES_QL_LOW 16
+#define DEFAULT_NES_QL_TARGET 64
+#define DEFAULT_JUMBO_NES_QL_LOW 12
+#define DEFAULT_JUMBO_NES_QL_TARGET 40
+#define DEFAULT_JUMBO_NES_QL_HIGH 128
+#define NES_NIC_CQ_DOWNWARD_TREND 8
+
+struct nes_hw_tune_timer {
+ //u16 cq_count;
+ u16 threshold_low;
+ u16 threshold_target;
+ u16 threshold_high;
+ u16 timer_in_use;
+ u16 timer_in_use_old;
+ u16 timer_in_use_min;
+ u16 timer_in_use_max;
+ u8 timer_direction_upward;
+ u8 timer_direction_downward;
+ u16 cq_count_old;
+ u8 cq_direction_downward;
+};
+
+#define NES_TIMER_INT_LIMIT 2
+#define NES_TIMER_INT_LIMIT_DYNAMIC 10
+#define NES_TIMER_ENABLE_LIMIT 4
+#define NES_MAX_LINK_INTERRUPTS 128
+#define NES_MAX_LINK_CHECK 200
+
+struct nes_adapter {
+ u64 fw_ver;
+ unsigned long *allocated_qps;
+ unsigned long *allocated_cqs;
+ unsigned long *allocated_mrs;
+ unsigned long *allocated_pds;
+ unsigned long *allocated_arps;
+ struct nes_qp **qp_table;
+ struct workqueue_struct *work_q;
+
+ struct list_head list;
+ struct list_head active_listeners;
+ /* list of the netdev's associated with each logical port */
+ struct list_head nesvnic_list[4];
+
+ struct timer_list mh_timer;
+ struct timer_list lc_timer;
+ struct work_struct work;
+ spinlock_t resource_lock;
+ spinlock_t phy_lock;
+ spinlock_t pbl_lock;
+ spinlock_t periodic_timer_lock;
+
+ struct nes_arp_entry arp_table[NES_MAX_ARP_TABLE_SIZE];
+
+ /* Adapter CEQ and AEQs */
+ struct nes_hw_ceq ceq[16];
+ struct nes_hw_aeq aeq[8];
+
+ struct nes_hw_tune_timer tune_timer;
+
+ unsigned long doorbell_start;
+
+ u32 hw_rev;
+ u32 vendor_id;
+ u32 vendor_part_id;
+ u32 device_cap_flags;
+ u32 tick_delta;
+ u32 timer_int_req;
+ u32 arp_table_size;
+ u32 next_arp_index;
+
+ u32 max_mr;
+ u32 max_256pbl;
+ u32 max_4kpbl;
+ u32 free_256pbl;
+ u32 free_4kpbl;
+ u32 max_mr_size;
+ u32 max_qp;
+ u32 next_qp;
+ u32 max_irrq;
+ u32 max_qp_wr;
+ u32 max_sge;
+ u32 max_cq;
+ u32 next_cq;
+ u32 max_cqe;
+ u32 max_pd;
+ u32 base_pd;
+ u32 next_pd;
+ u32 hte_index_mask;
+
+ /* EEPROM information */
+ u32 rx_pool_size;
+ u32 tx_pool_size;
+ u32 rx_threshold;
+ u32 tcp_timer_core_clk_divisor;
+ u32 iwarp_config;
+ u32 cm_config;
+ u32 sws_timer_config;
+ u32 tcp_config1;
+ u32 wqm_wat;
+ u32 core_clock;
+ u32 firmware_version;
+
+ u32 nic_rx_eth_route_err;
+
+ u32 et_rx_coalesce_usecs;
+ u32 et_rx_max_coalesced_frames;
+ u32 et_rx_coalesce_usecs_irq;
+ u32 et_rx_max_coalesced_frames_irq;
+ u32 et_pkt_rate_low;
+ u32 et_rx_coalesce_usecs_low;
+ u32 et_rx_max_coalesced_frames_low;
+ u32 et_pkt_rate_high;
+ u32 et_rx_coalesce_usecs_high;
+ u32 et_rx_max_coalesced_frames_high;
+ u32 et_rate_sample_interval;
+ u32 timer_int_limit;
+
+ /* Adapter base MAC address */
+ u32 mac_addr_low;
+ u16 mac_addr_high;
+
+ u16 firmware_eeprom_offset;
+ u16 software_eeprom_offset;
+
+ u16 max_irrq_wr;
+
+ /* pd config for each port */
+ u16 pd_config_size[4];
+ u16 pd_config_base[4];
+
+ u16 link_interrupt_count[4];
+
+ /* the phy index for each port */
+ u8 phy_index[4];
+ u8 mac_sw_state[4];
+ u8 mac_link_down[4];
+ u8 phy_type[4];
+
+ /* PCI information */
+ unsigned int devfn;
+ unsigned char bus_number;
+ unsigned char OneG_Mode;
+
+ unsigned char ref_count;
+ u8 netdev_count;
+ u8 netdev_max; /* from host nic address count in EEPROM */
+ u8 port_count;
+ u8 virtwq;
+ u8 et_use_adaptive_rx_coalesce;
+ u8 adapter_fcn_count;
+};
+
+struct nes_pbl {
+ u64 *pbl_vbase;
+ dma_addr_t pbl_pbase;
+ struct page *page;
+ unsigned long user_base;
+ u32 pbl_size;
+ struct list_head list;
+ /* TODO: need to add list for two level tables */
+};
+
+struct nes_listener {
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ struct nes_vnic *nesvnic;
+ struct iw_cm_id *cm_id;
+ struct list_head list;
+ unsigned long socket;
+ u8 accept_failed;
+};
+
+struct nes_ib_device;
+
+struct nes_vnic {
+ struct nes_ib_device *nesibdev;
+ u64 sq_full;
+ u64 sq_locked;
+ u64 tso_requests;
+ u64 segmented_tso_requests;
+ u64 linearized_skbs;
+ u64 tx_sw_dropped;
+ u64 endnode_nstat_rx_discard;
+ u64 endnode_nstat_rx_octets;
+ u64 endnode_nstat_rx_frames;
+ u64 endnode_nstat_tx_octets;
+ u64 endnode_nstat_tx_frames;
+ u64 endnode_ipv4_tcp_retransmits;
+ /* void *mem; */
+ struct nes_device *nesdev;
+ struct net_device *netdev;
+ struct vlan_group *vlan_grp;
+ atomic_t rx_skbs_needed;
+ atomic_t rx_skb_timer_running;
+ int budget;
+ u32 msg_enable;
+ /* u32 tx_avail; */
+ __be32 local_ipaddr;
+ struct napi_struct napi;
+ spinlock_t tx_lock; /* could use netdev tx lock? */
+ struct timer_list rq_wqes_timer;
+ u32 nic_mem_size;
+ void *nic_vbase;
+ dma_addr_t nic_pbase;
+ struct nes_hw_nic nic;
+ struct nes_hw_nic_cq nic_cq;
+ u32 mcrq_qp_id;
+ struct nes_ucontext *mcrq_ucontext;
+ struct nes_cqp_request* (*get_cqp_request)(struct nes_device *nesdev);
+ void (*post_cqp_request)(struct nes_device*, struct nes_cqp_request *, int);
+ int (*mcrq_mcast_filter)( struct nes_vnic* nesvnic, __u8* dmi_addr );
+ struct net_device_stats netstats;
+ /* used to put the netdev on the adapters logical port list */
+ struct list_head list;
+ u16 max_frame_size;
+ u8 netdev_open;
+ u8 linkup;
+ u8 logical_port;
+ u8 netdev_index; /* might not be needed, indexes nesdev->netdev */
+ u8 perfect_filter_index;
+ u8 nic_index;
+ u8 qp_nic_index[4];
+ u8 next_qp_nic_index;
+ u8 of_device_registered;
+ u8 rdma_enabled;
+ u8 rx_checksum_disabled;
+};
+
+struct nes_ib_device {
+ struct ib_device ibdev;
+ struct nes_vnic *nesvnic;
+
+ /* Virtual RNIC Limits */
+ u32 max_mr;
+ u32 max_qp;
+ u32 max_cq;
+ u32 max_pd;
+ u32 num_mr;
+ u32 num_qp;
+ u32 num_cq;
+ u32 num_pd;
+};
+
+#define nes_vlan_rx vlan_hwaccel_receive_skb
+#define nes_netif_rx netif_receive_skb
+
+#endif /* __NES_HW_H */
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
new file mode 100644
index 0000000..b6cc265
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -0,0 +1,1703 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+#include <net/tcp.h>
+
+#include <net/inet_common.h>
+#include <linux/inet.h>
+
+#include "nes.h"
+
+static struct nic_qp_map nic_qp_mapping_0[] = {
+ {16,0,0,1},{24,4,0,0},{28,8,0,0},{32,12,0,0},
+ {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0},
+ {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
+ {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_1[] = {
+ {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
+ {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_2[] = {
+ {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_3[] = {
+ {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_4[] = {
+ {28,8,0,0},{32,12,0,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_5[] = {
+ {29,9,1,0},{33,13,1,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_6[] = {
+ {30,10,2,0},{34,14,2,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_7[] = {
+ {31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map *nic_qp_mapping_per_function[] = {
+ nic_qp_mapping_0, nic_qp_mapping_1, nic_qp_mapping_2, nic_qp_mapping_3,
+ nic_qp_mapping_4, nic_qp_mapping_5, nic_qp_mapping_6, nic_qp_mapping_7
+};
+
+static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+static int debug = -1;
+
+
+static int nes_netdev_open(struct net_device *);
+static int nes_netdev_stop(struct net_device *);
+static int nes_netdev_start_xmit(struct sk_buff *, struct net_device *);
+static struct net_device_stats *nes_netdev_get_stats(struct net_device *);
+static void nes_netdev_tx_timeout(struct net_device *);
+static int nes_netdev_set_mac_address(struct net_device *, void *);
+static int nes_netdev_change_mtu(struct net_device *, int);
+
+/**
+ * nes_netdev_poll
+ */
+static int nes_netdev_poll(struct napi_struct *napi, int budget)
+{
+ struct nes_vnic *nesvnic = container_of(napi, struct nes_vnic, napi);
+ struct net_device *netdev = nesvnic->netdev;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq;
+
+ nesvnic->budget = budget;
+ nescq->cqes_pending = 0;
+ nescq->rx_cqes_completed = 0;
+ nescq->cqe_allocs_pending = 0;
+ nescq->rx_pkts_indicated = 0;
+
+ nes_nic_ce_handler(nesdev, nescq);
+
+ if (nescq->cqes_pending == 0) {
+ netif_rx_complete(netdev, napi);
+ /* clear out completed cqes and arm */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ nescq->cq_number | (nescq->cqe_allocs_pending << 16));
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+ } else {
+ /* clear out completed cqes but don't arm */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ nescq->cq_number | (nescq->cqe_allocs_pending << 16));
+ nes_debug(NES_DBG_NETDEV, "%s: exiting with work pending\n",
+ nesvnic->netdev->name);
+ }
+ return nescq->rx_pkts_indicated;
+}
+
+
+/**
+ * nes_netdev_open - Activate the network interface; ifconfig
+ * ethx up.
+ */
+static int nes_netdev_open(struct net_device *netdev)
+{
+ u32 macaddr_low;
+ u16 macaddr_high;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ int ret;
+ int i;
+ struct nes_vnic *first_nesvnic;
+ u32 nic_active_bit;
+ u32 nic_active;
+
+ assert(nesdev != NULL);
+
+ first_nesvnic = list_entry(nesdev->nesadapter->nesvnic_list[nesdev->mac_index].next,
+ struct nes_vnic, list);
+
+ if (netif_msg_ifup(nesvnic))
+ printk(KERN_INFO PFX "%s: enabling interface\n", netdev->name);
+
+ ret = nes_init_nic_qp(nesdev, netdev);
+ if (ret) {
+ return ret;
+ }
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ if ((!nesvnic->of_device_registered) && (nesvnic->rdma_enabled)) {
+ nesvnic->nesibdev = nes_init_ofa_device(netdev);
+ if (nesvnic->nesibdev == NULL) {
+ printk(KERN_ERR PFX "%s: nesvnic->nesibdev alloc failed", netdev->name);
+ } else {
+ nesvnic->nesibdev->nesvnic = nesvnic;
+ ret = nes_register_ofa_device(nesvnic->nesibdev);
+ if (ret) {
+ printk(KERN_ERR PFX "%s: Unable to register RDMA device, ret = %d\n",
+ netdev->name, ret);
+ }
+ }
+ }
+ /* Set packet filters */
+ nic_active_bit = 1 << nesvnic->nic_index;
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
+
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high += (u16)netdev->dev_addr[1];
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
+
+ /* Program the various MAC regs */
+ for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
+ if (nesvnic->qp_nic_index[i] == 0xf) {
+ break;
+ }
+ nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW"
+ " (Addr:%08X) = %08X, HIGH = %08X.\n",
+ i, nesvnic->qp_nic_index[i],
+ NES_IDX_PERFECT_FILTER_LOW+((nesvnic->perfect_filter_index + i) * 8),
+ macaddr_low,
+ (u32)macaddr_high | NES_MAC_ADDR_VALID |
+ ((((u32)nesvnic->nic_index) << 16)));
+ nes_write_indexed(nesdev,
+ NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
+ macaddr_low);
+ nes_write_indexed(nesdev,
+ NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
+ (u32)macaddr_high | NES_MAC_ADDR_VALID |
+ ((((u32)nesvnic->nic_index) << 16)));
+ }
+
+
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ nesvnic->nic_cq.cq_number);
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+ if (first_nesvnic->linkup) {
+ /* Enable network packets */
+ nesvnic->linkup = 1;
+ netif_start_queue(netdev);
+ netif_carrier_on(netdev);
+ }
+ napi_enable(&nesvnic->napi);
+ nesvnic->netdev_open = 1;
+
+ return 0;
+}
+
+
+/**
+ * nes_netdev_stop
+ */
+static int nes_netdev_stop(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 nic_active_mask;
+ u32 nic_active;
+
+ nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",
+ nesvnic, nesdev, netdev, netdev->name);
+ if (nesvnic->netdev_open == 0)
+ return 0;
+
+ if (netif_msg_ifdown(nesvnic))
+ printk(KERN_INFO PFX "%s: disabling interface\n", netdev->name);
+
+ /* Disable network packets */
+ napi_disable(&nesvnic->napi);
+ netif_stop_queue(netdev);
+ if ((nesdev->netdev[0] == netdev) & (nesvnic->logical_port == nesdev->mac_index)) {
+ nes_write_indexed(nesdev,
+ NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
+ }
+
+ nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
+ nes_write_indexed(nesdev, NES_IDX_PERFECT_FILTER_HIGH+
+ (nesvnic->perfect_filter_index*8), 0);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
+
+
+ if (nesvnic->of_device_registered) {
+ nes_destroy_ofa_device(nesvnic->nesibdev);
+ nesvnic->nesibdev = NULL;
+ nesvnic->of_device_registered = 0;
+ }
+ nes_destroy_nic_qp(nesvnic);
+
+ nesvnic->netdev_open = 0;
+
+ return 0;
+}
+
+
+/**
+ * nes_nic_send
+ */
+static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_nic *nesnic = &nesvnic->nic;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+ struct tcphdr *tcph;
+ __le16 *wqe_fragment_length;
+ u32 wqe_misc;
+ u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
+ u16 skb_fragment_index;
+ dma_addr_t bus_address;
+
+ nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
+ wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+
+ /* setup the VLAN tag if present */
+ if (vlan_tx_tag_present(skb)) {
+ nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
+ netdev->name, vlan_tx_tag_get(skb));
+ wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
+ wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb);
+ } else
+ wqe_misc = 0;
+
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+ /* wqe_fragment_address = (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX]; */
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ tcph = tcp_hdr(skb);
+ if (1) {
+ if (skb_is_gso(skb)) {
+ /* nes_debug(NES_DBG_NIC_TX, "%s: TSO request... seg size = %u\n",
+ netdev->name, skb_is_gso(skb)); */
+ wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE |
+ NES_NIC_SQ_WQE_COMPLETION | (u16)skb_is_gso(skb);
+ set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX,
+ ((u32)tcph->doff) |
+ (((u32)(((unsigned char *)tcph) - skb->data)) << 4));
+ } else {
+ wqe_misc |= NES_NIC_SQ_WQE_COMPLETION;
+ }
+ }
+ } else { /* CHECKSUM_HW */
+ wqe_misc |= NES_NIC_SQ_WQE_DISABLE_CHKSUM | NES_NIC_SQ_WQE_COMPLETION;
+ }
+
+ set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX,
+ skb->len);
+ memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
+ skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE), skb_headlen(skb)));
+ wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
+ skb_headlen(skb)));
+ wqe_fragment_length[1] = 0;
+ if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
+ if ((skb_shinfo(skb)->nr_frags + 1) > 4) {
+ nes_debug(NES_DBG_NIC_TX, "%s: Packet with %u fragments not sent, skb_headlen=%u\n",
+ netdev->name, skb_shinfo(skb)->nr_frags + 2, skb_headlen(skb));
+ kfree_skb(skb);
+ nesvnic->tx_sw_dropped++;
+ return NETDEV_TX_LOCKED;
+ }
+ set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
+ bus_address = pci_map_single(nesdev->pcidev, skb->data + NES_FIRST_FRAG_SIZE,
+ skb_headlen(skb) - NES_FIRST_FRAG_SIZE, PCI_DMA_TODEVICE);
+ wqe_fragment_length[wqe_fragment_index++] =
+ cpu_to_le16(skb_headlen(skb) - NES_FIRST_FRAG_SIZE);
+ wqe_fragment_length[wqe_fragment_index] = 0;
+ set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
+ ((u64)(bus_address)));
+ nesnic->tx_skb[nesnic->sq_head] = skb;
+ }
+
+ if (skb_headlen(skb) == skb->len) {
+ if (skb_headlen(skb) <= NES_FIRST_FRAG_SIZE) {
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] = 0;
+ nesnic->tx_skb[nesnic->sq_head] = NULL;
+ dev_kfree_skb(skb);
+ }
+ } else {
+ /* Deal with Fragments */
+ nesnic->tx_skb[nesnic->sq_head] = skb;
+ for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;
+ skb_fragment_index++) {
+ bus_address = pci_map_page( nesdev->pcidev,
+ skb_shinfo(skb)->frags[skb_fragment_index].page,
+ skb_shinfo(skb)->frags[skb_fragment_index].page_offset,
+ skb_shinfo(skb)->frags[skb_fragment_index].size,
+ PCI_DMA_TODEVICE);
+ wqe_fragment_length[wqe_fragment_index] =
+ cpu_to_le16(skb_shinfo(skb)->frags[skb_fragment_index].size);
+ set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
+ bus_address);
+ wqe_fragment_index++;
+ if (wqe_fragment_index < 5)
+ wqe_fragment_length[wqe_fragment_index] = 0;
+ }
+ }
+
+ set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX, wqe_misc);
+ nesnic->sq_head++;
+ nesnic->sq_head &= nesnic->sq_size - 1;
+
+ return NETDEV_TX_OK;
+}
+
+
+/**
+ * nes_netdev_start_xmit
+ */
+static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_nic *nesnic = &nesvnic->nic;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+ struct tcphdr *tcph;
+ /* struct udphdr *udph; */
+#define NES_MAX_TSO_FRAGS 18
+ /* 64K segment plus overflow on each side */
+ dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
+ dma_addr_t bus_address;
+ u32 tso_frag_index;
+ u32 tso_frag_count;
+ u32 tso_wqe_length;
+ u32 curr_tcp_seq;
+ u32 wqe_count=1;
+ u32 send_rc;
+ struct iphdr *iph;
+ unsigned long flags;
+ __le16 *wqe_fragment_length;
+ u32 nr_frags;
+ u32 original_first_length;
+// u64 *wqe_fragment_address;
+ /* first fragment (0) is used by copy buffer */
+ u16 wqe_fragment_index=1;
+ u16 hoffset;
+ u16 nhoffset;
+ u16 wqes_needed;
+ u16 wqes_available;
+ u32 old_head;
+ u32 wqe_misc;
+
+ /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
+ " (%u frags), tso_size=%u\n",
+ netdev->name, skb->len, skb_headlen(skb),
+ skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
+ */
+
+ if (!netif_carrier_ok(netdev))
+ return NETDEV_TX_OK;
+
+ if (netif_queue_stopped(netdev))
+ return NETDEV_TX_BUSY;
+
+ local_irq_save(flags);
+ if (!spin_trylock(&nesnic->sq_lock)) {
+ local_irq_restore(flags);
+ nesvnic->sq_locked++;
+ return NETDEV_TX_LOCKED;
+ }
+
+ /* Check if SQ is full */
+ if ((((nesnic->sq_tail+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) == 1) {
+ if (!netif_queue_stopped(netdev)) {
+ netif_stop_queue(netdev);
+ barrier();
+ if ((((((volatile u16)nesnic->sq_tail)+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) != 1) {
+ netif_start_queue(netdev);
+ goto sq_no_longer_full;
+ }
+ }
+ nesvnic->sq_full++;
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+sq_no_longer_full:
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
+ nr_frags++;
+ }
+ /* Check if too many fragments */
+ if (unlikely((nr_frags > 4))) {
+ if (skb_is_gso(skb)) {
+ nesvnic->segmented_tso_requests++;
+ nesvnic->tso_requests++;
+ old_head = nesnic->sq_head;
+ /* Basically 4 fragments available per WQE with extended fragments */
+ wqes_needed = nr_frags >> 2;
+ wqes_needed += (nr_frags&3)?1:0;
+ wqes_available = (((nesnic->sq_tail+nesnic->sq_size)-nesnic->sq_head) - 1) &
+ (nesnic->sq_size - 1);
+
+ if (unlikely(wqes_needed > wqes_available)) {
+ if (!netif_queue_stopped(netdev)) {
+ netif_stop_queue(netdev);
+ barrier();
+ wqes_available = (((((volatile u16)nesnic->sq_tail)+nesnic->sq_size)-nesnic->sq_head) - 1) &
+ (nesnic->sq_size - 1);
+ if (wqes_needed <= wqes_available) {
+ netif_start_queue(netdev);
+ goto tso_sq_no_longer_full;
+ }
+ }
+ nesvnic->sq_full++;
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ nes_debug(NES_DBG_NIC_TX, "%s: HNIC SQ full- TSO request has too many frags!\n",
+ netdev->name);
+ return NETDEV_TX_BUSY;
+ }
+tso_sq_no_longer_full:
+ /* Map all the buffers */
+ for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
+ tso_frag_count++) {
+ tso_bus_address[tso_frag_count] = pci_map_page( nesdev->pcidev,
+ skb_shinfo(skb)->frags[tso_frag_count].page,
+ skb_shinfo(skb)->frags[tso_frag_count].page_offset,
+ skb_shinfo(skb)->frags[tso_frag_count].size,
+ PCI_DMA_TODEVICE);
+ }
+
+ tso_frag_index = 0;
+ curr_tcp_seq = ntohl(tcp_hdr(skb)->seq);
+ hoffset = skb_transport_header(skb) - skb->data;
+ nhoffset = skb_network_header(skb) - skb->data;
+ original_first_length = hoffset + ((((struct tcphdr *)skb_transport_header(skb))->doff)<<2);
+
+ for (wqe_count=0; wqe_count<((u32)wqes_needed); wqe_count++) {
+ tso_wqe_length = 0;
+ nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
+ wqe_fragment_length =
+ (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+ /* setup the VLAN tag if present */
+ if (vlan_tx_tag_present(skb)) {
+ nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
+ netdev->name, vlan_tx_tag_get(skb) );
+ wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
+ wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb);
+ } else
+ wqe_misc = 0;
+
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+
+ /* Assumes header totally fits in allocated buffer and is in first fragment */
+ if (original_first_length > NES_FIRST_FRAG_SIZE) {
+ nes_debug(NES_DBG_NIC_TX, "ERROR: SKB header too big, headlen=%u, FIRST_FRAG_SIZE=%u\n",
+ original_first_length, NES_FIRST_FRAG_SIZE);
+ nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
+ " (%u frags), tso_size=%u\n",
+ netdev->name,
+ skb->len, skb_headlen(skb),
+ skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
+ }
+ memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
+ skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE),
+ original_first_length));
+ iph = (struct iphdr *)
+ (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[nhoffset]);
+ tcph = (struct tcphdr *)
+ (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[hoffset]);
+ if ((wqe_count+1)!=(u32)wqes_needed) {
+ tcph->fin = 0;
+ tcph->psh = 0;
+ tcph->rst = 0;
+ tcph->urg = 0;
+ }
+ if (wqe_count) {
+ tcph->syn = 0;
+ }
+ tcph->seq = htonl(curr_tcp_seq);
+ wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
+ original_first_length));
+
+ wqe_fragment_index = 1;
+ if ((wqe_count==0) && (skb_headlen(skb) > original_first_length)) {
+ set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
+ bus_address = pci_map_single(nesdev->pcidev, skb->data + original_first_length,
+ skb_headlen(skb) - original_first_length, PCI_DMA_TODEVICE);
+ wqe_fragment_length[wqe_fragment_index++] =
+ cpu_to_le16(skb_headlen(skb) - original_first_length);
+ wqe_fragment_length[wqe_fragment_index] = 0;
+ set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
+ bus_address);
+ }
+ while (wqe_fragment_index < 5) {
+ wqe_fragment_length[wqe_fragment_index] =
+ cpu_to_le16(skb_shinfo(skb)->frags[tso_frag_index].size);
+ set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
+ (u64)tso_bus_address[tso_frag_index]);
+ wqe_fragment_index++;
+ tso_wqe_length += skb_shinfo(skb)->frags[tso_frag_index++].size;
+ if (wqe_fragment_index < 5)
+ wqe_fragment_length[wqe_fragment_index] = 0;
+ if (tso_frag_index == tso_frag_count)
+ break;
+ }
+ if ((wqe_count+1) == (u32)wqes_needed) {
+ nesnic->tx_skb[nesnic->sq_head] = skb;
+ } else {
+ nesnic->tx_skb[nesnic->sq_head] = NULL;
+ }
+ wqe_misc |= NES_NIC_SQ_WQE_COMPLETION | (u16)skb_is_gso(skb);
+ if ((tso_wqe_length + original_first_length) > skb_is_gso(skb)) {
+ wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE;
+ } else {
+ iph->tot_len = htons(tso_wqe_length + original_first_length - nhoffset);
+ }
+
+ set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX,
+ wqe_misc);
+ set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX,
+ ((u32)tcph->doff) | (((u32)hoffset) << 4));
+
+ set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX,
+ tso_wqe_length + original_first_length);
+ curr_tcp_seq += tso_wqe_length;
+ nesnic->sq_head++;
+ nesnic->sq_head &= nesnic->sq_size-1;
+ }
+ } else {
+ nesvnic->linearized_skbs++;
+ hoffset = skb_transport_header(skb) - skb->data;
+ nhoffset = skb_network_header(skb) - skb->data;
+ skb_linearize(skb);
+ skb_set_transport_header(skb, hoffset);
+ skb_set_network_header(skb, nhoffset);
+ send_rc = nes_nic_send(skb, netdev);
+ if (send_rc != NETDEV_TX_OK) {
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ return NETDEV_TX_OK;
+ }
+ }
+ } else {
+ send_rc = nes_nic_send(skb, netdev);
+ if (send_rc != NETDEV_TX_OK) {
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ return NETDEV_TX_OK;
+ }
+ }
+
+ barrier();
+
+ if (wqe_count)
+ nes_write32(nesdev->regs+NES_WQE_ALLOC,
+ (wqe_count << 24) | (1 << 23) | nesvnic->nic.qp_id);
+
+ netdev->trans_start = jiffies;
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+
+/**
+ * nes_netdev_get_stats
+ */
+static struct net_device_stats *nes_netdev_get_stats(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u64 u64temp;
+ u32 u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_DISCARD + (nesvnic->nic_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->endnode_nstat_rx_discard += u32temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_octets += u64temp;
+ nesvnic->netstats.rx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_frames += u64temp;
+ nesvnic->netstats.rx_packets += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_octets += u64temp;
+ nesvnic->netstats.tx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_frames += u64temp;
+ nesvnic->netstats.tx_packets += u64temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_SHORT_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_short_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_OVERSIZED_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_oversized_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_JABBER_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_jabber_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_symbol_err_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_LENGTH_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_length_errors += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_CRC_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_crc_errors += u32temp;
+ nesvnic->netstats.rx_crc_errors += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_ERRORS + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_tx_errors += u32temp;
+ nesvnic->netstats.tx_errors += u32temp;
+
+ return &nesvnic->netstats;
+}
+
+
+/**
+ * nes_netdev_tx_timeout
+ */
+static void nes_netdev_tx_timeout(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ if (netif_msg_timer(nesvnic))
+ nes_debug(NES_DBG_NIC_TX, "%s: tx timeout\n", netdev->name);
+}
+
+
+/**
+ * nes_netdev_set_mac_address
+ */
+static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct sockaddr *mac_addr = p;
+ int i;
+ u32 macaddr_low;
+ u16 macaddr_high;
+
+ if (!is_valid_ether_addr(mac_addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
+ printk(PFX "%s: Address length = %d, Address = %02X%02X%02X%02X%02X%02X..\n",
+ __FUNCTION__, netdev->addr_len,
+ mac_addr->sa_data[0], mac_addr->sa_data[1],
+ mac_addr->sa_data[2], mac_addr->sa_data[3],
+ mac_addr->sa_data[4], mac_addr->sa_data[5]);
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high += (u16)netdev->dev_addr[1];
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
+
+ for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
+ if (nesvnic->qp_nic_index[i] == 0xf) {
+ break;
+ }
+ nes_write_indexed(nesdev,
+ NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
+ macaddr_low);
+ nes_write_indexed(nesdev,
+ NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
+ (u32)macaddr_high | NES_MAC_ADDR_VALID |
+ ((((u32)nesvnic->nic_index) << 16)));
+ }
+ return 0;
+}
+
+
+/**
+ * nes_netdev_set_multicast_list
+ */
+void nes_netdev_set_multicast_list(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct dev_mc_list *multicast_addr;
+ u32 nic_active_bit;
+ u32 nic_active;
+ u32 perfect_filter_register_address;
+ u32 macaddr_low;
+ u16 macaddr_high;
+ u8 mc_all_on = 0;
+ u8 mc_index;
+ int mc_nic_index = -1;
+
+ nic_active_bit = 1 << nesvnic->nic_index;
+
+ if (netdev->flags & IFF_PROMISC) {
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+ mc_all_on = 1;
+ } else if ((netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > NES_MULTICAST_PF_MAX) ||
+ (nesvnic->nic_index > 3)) {
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+ nic_active &= ~nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+ mc_all_on = 1;
+ } else {
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active &= ~nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+ nic_active &= ~nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+ }
+
+ nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n",
+ netdev->mc_count, (netdev->flags & IFF_PROMISC)?1:0,
+ (netdev->flags & IFF_ALLMULTI)?1:0);
+ if (!mc_all_on) {
+ multicast_addr = netdev->mc_list;
+ perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW + 0x80;
+ perfect_filter_register_address += nesvnic->nic_index*0x40;
+ for (mc_index=0; mc_index < NES_MULTICAST_PF_MAX; mc_index++) {
+ while (multicast_addr && nesvnic->mcrq_mcast_filter && ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic, multicast_addr->dmi_addr)) == 0))
+ multicast_addr = multicast_addr->next;
+
+ if (mc_nic_index < 0)
+ mc_nic_index = nesvnic->nic_index;
+ if (multicast_addr) {
+ nes_debug(NES_DBG_NIC_RX, "Assigning MC Address = %02X%02X%02X%02X%02X%02X to register 0x%04X nic_idx=%d\n",
+ multicast_addr->dmi_addr[0], multicast_addr->dmi_addr[1],
+ multicast_addr->dmi_addr[2], multicast_addr->dmi_addr[3],
+ multicast_addr->dmi_addr[4], multicast_addr->dmi_addr[5],
+ perfect_filter_register_address+(mc_index * 8), mc_nic_index);
+ macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
+ macaddr_high += (u16)multicast_addr->dmi_addr[1];
+ macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
+ macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
+ macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
+ macaddr_low += (u32)multicast_addr->dmi_addr[5];
+ nes_write_indexed(nesdev,
+ perfect_filter_register_address+(mc_index * 8),
+ macaddr_low);
+ nes_write_indexed(nesdev,
+ perfect_filter_register_address+4+(mc_index * 8),
+ (u32)macaddr_high | NES_MAC_ADDR_VALID |
+ ((((u32)(1<<mc_nic_index)) << 16)));
+ multicast_addr = multicast_addr->next;
+ } else {
+ nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n",
+ perfect_filter_register_address+(mc_index * 8));
+ nes_write_indexed(nesdev,
+ perfect_filter_register_address+4+(mc_index * 8),
+ 0);
+ }
+ }
+ }
+}
+
+
+/**
+ * nes_netdev_change_mtu
+ */
+static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ int ret = 0;
+ u8 jumbomode=0;
+
+ if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
+ return -EINVAL;
+
+ netdev->mtu = new_mtu;
+ nesvnic->max_frame_size = new_mtu+ETH_HLEN;
+
+ if (netdev->mtu > 1500) {
+ jumbomode=1;
+ }
+ nes_nic_init_timer_defaults(nesdev, jumbomode);
+
+ if (netif_running(netdev)) {
+ nes_netdev_stop(netdev);
+ nes_netdev_open(netdev);
+ }
+
+ return ret;
+}
+
+
+/**
+ * nes_netdev_exit - destroy network device
+ */
+void nes_netdev_exit(struct nes_vnic *nesvnic)
+{
+ struct net_device *netdev = nesvnic->netdev;
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+ nes_debug(NES_DBG_SHUTDOWN, "\n");
+
+ // destroy the ibdevice if RDMA enabled
+ if ((nesvnic->rdma_enabled)&&(nesvnic->of_device_registered)) {
+ nes_destroy_ofa_device( nesibdev );
+ nesvnic->of_device_registered = 0;
+ nesvnic->nesibdev = NULL;
+ }
+ unregister_netdev(netdev);
+ nes_debug(NES_DBG_SHUTDOWN, "\n");
+}
+
+
+#define NES_ETHTOOL_STAT_COUNT 55
+static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = {
+ "Link Change Interrupts",
+ "Linearized SKBs",
+ "T/GSO Requests",
+ "Pause Frames Sent",
+ "Pause Frames Received",
+ "Internal Routing Errors",
+ "SQ SW Dropped SKBs",
+ "SQ Locked",
+ "SQ Full",
+ "Segmented TSO Requests",
+ "Rx Symbol Errors",
+ "Rx Jabber Errors",
+ "Rx Oversized Frames",
+ "Rx Short Frames",
+ "Endnode Rx Discards",
+ "Endnode Rx Octets",
+ "Endnode Rx Frames",
+ "Endnode Tx Octets",
+ "Endnode Tx Frames",
+ "mh detected",
+ "mh pauses",
+ "Retransmission Count",
+ "CM Connects",
+ "CM Accepts",
+ "Disconnects",
+ "Connected Events",
+ "Connect Requests",
+ "CM Rejects",
+ "ModifyQP Timeouts",
+ "CreateQPs",
+ "SW DestroyQPs",
+ "DestroyQPs",
+ "CM Closes",
+ "CM Packets Sent",
+ "CM Packets Bounced",
+ "CM Packets Created",
+ "CM Packets Rcvd",
+ "CM Packets Dropped",
+ "CM Packets Retrans",
+ "CM Listens Created",
+ "CM Listens Destroyed",
+ "CM Backlog Drops",
+ "CM Loopbacks",
+ "CM Nodes Created",
+ "CM Nodes Destroyed",
+ "CM Accel Drops",
+ "CM Resets Received",
+ "Timer Inits",
+ "CQ Depth 1",
+ "CQ Depth 4",
+ "CQ Depth 16",
+ "CQ Depth 24",
+ "CQ Depth 32",
+ "CQ Depth 128",
+ "CQ Depth 256",
+};
+
+
+/**
+ * nes_netdev_get_rx_csum
+ */
+static u32 nes_netdev_get_rx_csum (struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ if (nesvnic->rx_checksum_disabled)
+ return 0;
+ else
+ return 1;
+}
+
+
+/**
+ * nes_netdev_set_rc_csum
+ */
+static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ if (enable)
+ nesvnic->rx_checksum_disabled = 0;
+ else
+ nesvnic->rx_checksum_disabled = 1;
+ return 0;
+}
+
+
+/**
+ * nes_netdev_get_stats_count
+ */
+static int nes_netdev_get_stats_count(struct net_device *netdev)
+{
+ return NES_ETHTOOL_STAT_COUNT;
+}
+
+
+/**
+ * nes_netdev_get_strings
+ */
+static void nes_netdev_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *ethtool_strings)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(ethtool_strings,
+ &nes_ethtool_stringset,
+ sizeof(nes_ethtool_stringset));
+}
+
+
+/**
+ * nes_netdev_get_ethtool_stats
+ */
+static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *target_ethtool_stats, u64 *target_stat_values)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 nic_count;
+ u32 u32temp;
+
+ target_ethtool_stats->n_stats = NES_ETHTOOL_STAT_COUNT;
+ target_stat_values[0] = nesvnic->nesdev->link_status_interrupts;
+ target_stat_values[1] = nesvnic->linearized_skbs;
+ target_stat_values[2] = nesvnic->tso_requests;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_pause_frames_sent += u32temp;
+ target_stat_values[3] = nesvnic->nesdev->mac_pause_frames_sent;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_pause_frames_received += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_PORT_RX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
+ nesvnic->nesdev->port_rx_discards += u32temp;
+ nesvnic->netstats.rx_dropped += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_PORT_TX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
+ nesvnic->nesdev->port_tx_discards += u32temp;
+ nesvnic->netstats.tx_dropped += u32temp;
+
+ for (nic_count = 0; nic_count < NES_MAX_PORT_COUNT; nic_count++) {
+ if (nesvnic->qp_nic_index[nic_count] == 0xf)
+ break;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_DISCARD +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->endnode_nstat_rx_discard += u32temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_octets += u64temp;
+ nesvnic->netstats.rx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_frames += u64temp;
+ nesvnic->netstats.rx_packets += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_octets += u64temp;
+ nesvnic->netstats.tx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_frames += u64temp;
+ nesvnic->netstats.tx_packets += u64temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_IPV4_TCP_REXMITS + (nesvnic->qp_nic_index[nic_count]*0x200));
+ nesvnic->endnode_ipv4_tcp_retransmits += u32temp;
+ }
+
+ target_stat_values[4] = nesvnic->nesdev->mac_pause_frames_received;
+ target_stat_values[5] = nesdev->nesadapter->nic_rx_eth_route_err;
+ target_stat_values[6] = nesvnic->tx_sw_dropped;
+ target_stat_values[7] = nesvnic->sq_locked;
+ target_stat_values[8] = nesvnic->sq_full;
+ target_stat_values[9] = nesvnic->segmented_tso_requests;
+ target_stat_values[10] = nesvnic->nesdev->mac_rx_symbol_err_frames;
+ target_stat_values[11] = nesvnic->nesdev->mac_rx_jabber_frames;
+ target_stat_values[12] = nesvnic->nesdev->mac_rx_oversized_frames;
+ target_stat_values[13] = nesvnic->nesdev->mac_rx_short_frames;
+ target_stat_values[14] = nesvnic->endnode_nstat_rx_discard;
+ target_stat_values[15] = nesvnic->endnode_nstat_rx_octets;
+ target_stat_values[16] = nesvnic->endnode_nstat_rx_frames;
+ target_stat_values[17] = nesvnic->endnode_nstat_tx_octets;
+ target_stat_values[18] = nesvnic->endnode_nstat_tx_frames;
+ target_stat_values[19] = mh_detected;
+ target_stat_values[20] = mh_pauses_sent;
+ target_stat_values[21] = nesvnic->endnode_ipv4_tcp_retransmits;
+ target_stat_values[22] = atomic_read(&cm_connects);
+ target_stat_values[23] = atomic_read(&cm_accepts);
+ target_stat_values[24] = atomic_read(&cm_disconnects);
+ target_stat_values[25] = atomic_read(&cm_connecteds);
+ target_stat_values[26] = atomic_read(&cm_connect_reqs);
+ target_stat_values[27] = atomic_read(&cm_rejects);
+ target_stat_values[28] = atomic_read(&mod_qp_timouts);
+ target_stat_values[29] = atomic_read(&qps_created);
+ target_stat_values[30] = atomic_read(&sw_qps_destroyed);
+ target_stat_values[31] = atomic_read(&qps_destroyed);
+ target_stat_values[32] = atomic_read(&cm_closes);
+ target_stat_values[33] = cm_packets_sent;
+ target_stat_values[34] = cm_packets_bounced;
+ target_stat_values[35] = cm_packets_created;
+ target_stat_values[36] = cm_packets_received;
+ target_stat_values[37] = cm_packets_dropped;
+ target_stat_values[38] = cm_packets_retrans;
+ target_stat_values[39] = cm_listens_created;
+ target_stat_values[40] = cm_listens_destroyed;
+ target_stat_values[41] = cm_backlog_drops;
+ target_stat_values[42] = atomic_read(&cm_loopbacks);
+ target_stat_values[43] = atomic_read(&cm_nodes_created);
+ target_stat_values[44] = atomic_read(&cm_nodes_destroyed);
+ target_stat_values[45] = atomic_read(&cm_accel_dropped_pkts);
+ target_stat_values[46] = atomic_read(&cm_resets_recvd);
+ target_stat_values[47] = int_mod_timer_init;
+ target_stat_values[48] = int_mod_cq_depth_1;
+ target_stat_values[49] = int_mod_cq_depth_4;
+ target_stat_values[50] = int_mod_cq_depth_16;
+ target_stat_values[51] = int_mod_cq_depth_24;
+ target_stat_values[52] = int_mod_cq_depth_32;
+ target_stat_values[53] = int_mod_cq_depth_128;
+ target_stat_values[54] = int_mod_cq_depth_256;
+
+}
+
+
+/**
+ * nes_netdev_get_drvinfo
+ */
+static void nes_netdev_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ strcpy(drvinfo->driver, DRV_NAME);
+ strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
+ strcpy(drvinfo->fw_version, "TBD");
+ strcpy(drvinfo->version, DRV_VERSION);
+ drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
+ drvinfo->testinfo_len = 0;
+ drvinfo->eedump_len = 0;
+ drvinfo->regdump_len = 0;
+}
+
+
+/**
+ * nes_netdev_set_coalesce
+ */
+static int nes_netdev_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *et_coalesce)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+ if (et_coalesce->rx_max_coalesced_frames_low) {
+ shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low;
+ }
+ if (et_coalesce->rx_max_coalesced_frames_irq) {
+ shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq;
+ }
+ if (et_coalesce->rx_max_coalesced_frames_high) {
+ shared_timer->threshold_high = et_coalesce->rx_max_coalesced_frames_high;
+ }
+ if (et_coalesce->rx_coalesce_usecs_low) {
+ shared_timer->timer_in_use_min = et_coalesce->rx_coalesce_usecs_low;
+ }
+ if (et_coalesce->rx_coalesce_usecs_high) {
+ shared_timer->timer_in_use_max = et_coalesce->rx_coalesce_usecs_high;
+ }
+ spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+
+ /* using this to drive total interrupt moderation */
+ nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq;
+ if (et_coalesce->use_adaptive_rx_coalesce) {
+ nesadapter->et_use_adaptive_rx_coalesce = 1;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
+ nesadapter->et_rx_coalesce_usecs_irq = 0;
+ if (et_coalesce->pkt_rate_low) {
+ nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low;
+ }
+ } else {
+ nesadapter->et_use_adaptive_rx_coalesce = 0;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
+ if (nesadapter->et_rx_coalesce_usecs_irq) {
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
+ 0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8)));
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * nes_netdev_get_coalesce
+ */
+static int nes_netdev_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *et_coalesce)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct ethtool_coalesce temp_et_coalesce;
+ struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+ unsigned long flags;
+
+ memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce));
+ temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
+ temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce;
+ temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
+ temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low;
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+ temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low;
+ temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target;
+ temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high;
+ temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
+ temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max;
+ if (nesadapter->et_use_adaptive_rx_coalesce) {
+ temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use;
+ }
+ spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+ memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
+ return 0;
+}
+
+
+/**
+ * nes_netdev_get_pauseparam
+ */
+static void nes_netdev_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *et_pauseparam)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ et_pauseparam->autoneg = 0;
+ et_pauseparam->rx_pause = (nesvnic->nesdev->disable_rx_flow_control == 0) ? 1:0;
+ et_pauseparam->tx_pause = (nesvnic->nesdev->disable_tx_flow_control == 0) ? 1:0;
+}
+
+
+/**
+ * nes_netdev_set_pauseparam
+ */
+static int nes_netdev_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *et_pauseparam)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 u32temp;
+
+ if (et_pauseparam->autoneg) {
+ /* TODO: should return unsupported */
+ return 0;
+ }
+ if ((et_pauseparam->tx_pause == 1) && (nesdev->disable_tx_flow_control == 1)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
+ u32temp |= NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp);
+ nesdev->disable_tx_flow_control = 0;
+ } else if ((et_pauseparam->tx_pause == 0) && (nesdev->disable_tx_flow_control == 0)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
+ u32temp &= ~NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp);
+ nesdev->disable_tx_flow_control = 1;
+ }
+ if ((et_pauseparam->rx_pause == 1) && (nesdev->disable_rx_flow_control == 1)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
+ u32temp &= ~NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
+ nesdev->disable_rx_flow_control = 0;
+ } else if ((et_pauseparam->rx_pause == 0) && (nesdev->disable_rx_flow_control == 0)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
+ u32temp |= NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
+ nesdev->disable_rx_flow_control = 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_netdev_get_settings
+ */
+static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u16 phy_data;
+
+ et_cmd->duplex = DUPLEX_FULL;
+ et_cmd->port = PORT_MII;
+ if (nesadapter->OneG_Mode) {
+ et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg;
+ et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg;
+ et_cmd->speed = SPEED_1000;
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+ &phy_data);
+ if (phy_data&0x1000) {
+ et_cmd->autoneg = AUTONEG_ENABLE;
+ } else {
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ }
+ et_cmd->transceiver = XCVR_EXTERNAL;
+ et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
+ } else {
+ if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+ et_cmd->transceiver = XCVR_EXTERNAL;
+ et_cmd->port = PORT_FIBRE;
+ et_cmd->supported = SUPPORTED_FIBRE;
+ et_cmd->advertising = ADVERTISED_FIBRE;
+ et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
+ } else {
+ et_cmd->transceiver = XCVR_INTERNAL;
+ et_cmd->supported = SUPPORTED_10000baseT_Full;
+ et_cmd->advertising = ADVERTISED_10000baseT_Full;
+ et_cmd->phy_address = nesdev->mac_index;
+ }
+ et_cmd->speed = SPEED_10000;
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ }
+ et_cmd->maxtxpkt = 511;
+ et_cmd->maxrxpkt = 511;
+ return 0;
+}
+
+
+/**
+ * nes_netdev_set_settings
+ */
+static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u16 phy_data;
+
+ if (nesadapter->OneG_Mode) {
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+ &phy_data);
+ if (et_cmd->autoneg) {
+ /* Turn on Full duplex, Autoneg, and restart autonegotiation */
+ phy_data |= 0x1300;
+ } else {
+ // Turn off autoneg
+ phy_data &= ~0x1000;
+ }
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+ phy_data);
+ }
+
+ return 0;
+}
+
+
+static struct ethtool_ops nes_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_settings = nes_netdev_get_settings,
+ .set_settings = nes_netdev_set_settings,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_rx_csum = nes_netdev_get_rx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_strings = nes_netdev_get_strings,
+ .get_stats_count = nes_netdev_get_stats_count,
+ .get_ethtool_stats = nes_netdev_get_ethtool_stats,
+ .get_drvinfo = nes_netdev_get_drvinfo,
+ .get_coalesce = nes_netdev_get_coalesce,
+ .set_coalesce = nes_netdev_set_coalesce,
+ .get_pauseparam = nes_netdev_get_pauseparam,
+ .set_pauseparam = nes_netdev_set_pauseparam,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_rx_csum = nes_netdev_set_rx_csum,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+};
+
+
+static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 u32temp;
+
+ nesvnic->vlan_grp = grp;
+
+ /* Enable/Disable VLAN Stripping */
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
+ if (grp)
+ u32temp &= 0xfdffffff;
+ else
+ u32temp |= 0x02000000;
+
+ nes_write_indexed(nesdev, NES_IDX_PCIX_DIAG, u32temp);
+}
+
+
+/**
+ * nes_netdev_init - initialize network device
+ */
+struct net_device *nes_netdev_init(struct nes_device *nesdev,
+ void __iomem *mmio_addr)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = NULL;
+ struct net_device *netdev;
+ struct nic_qp_map *curr_qp_map;
+ u32 u32temp;
+ u16 phy_data;
+ u16 temp_phy_data;
+
+ netdev = alloc_etherdev(sizeof(struct nes_vnic));
+ if (!netdev) {
+ printk(KERN_ERR PFX "nesvnic etherdev alloc failed");
+ return NULL;
+ }
+
+ nes_debug(NES_DBG_INIT, "netdev = %p, %s\n", netdev, netdev->name);
+
+ SET_NETDEV_DEV(netdev, &nesdev->pcidev->dev);
+
+ nesvnic = netdev_priv(netdev);
+ memset(nesvnic, 0, sizeof(*nesvnic));
+
+ netdev->open = nes_netdev_open;
+ netdev->stop = nes_netdev_stop;
+ netdev->hard_start_xmit = nes_netdev_start_xmit;
+ netdev->get_stats = nes_netdev_get_stats;
+ netdev->tx_timeout = nes_netdev_tx_timeout;
+ netdev->set_mac_address = nes_netdev_set_mac_address;
+ netdev->set_multicast_list = nes_netdev_set_multicast_list;
+ netdev->change_mtu = nes_netdev_change_mtu;
+ netdev->watchdog_timeo = NES_TX_TIMEOUT;
+ netdev->irq = nesdev->pcidev->irq;
+ netdev->mtu = ETH_DATA_LEN;
+ netdev->hard_header_len = ETH_HLEN;
+ netdev->addr_len = ETH_ALEN;
+ netdev->type = ARPHRD_ETHER;
+ netdev->features = NETIF_F_HIGHDMA;
+ netdev->ethtool_ops = &nes_ethtool_ops;
+ netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
+ nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
+ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->vlan_rx_register = nes_netdev_vlan_rx_register;
+ netdev->features |= NETIF_F_LLTX;
+
+ /* Fill in the port structure */
+ nesvnic->netdev = netdev;
+ nesvnic->nesdev = nesdev;
+ nesvnic->msg_enable = netif_msg_init(debug, default_msg);
+ nesvnic->netdev_index = nesdev->netdev_count;
+ nesvnic->perfect_filter_index = nesdev->nesadapter->netdev_count;
+ nesvnic->max_frame_size = netdev->mtu+netdev->hard_header_len;
+
+ curr_qp_map = nic_qp_mapping_per_function[PCI_FUNC(nesdev->pcidev->devfn)];
+ nesvnic->nic.qp_id = curr_qp_map[nesdev->netdev_count].qpid;
+ nesvnic->nic_index = curr_qp_map[nesdev->netdev_count].nic_index;
+ nesvnic->logical_port = curr_qp_map[nesdev->netdev_count].logical_port;
+
+ /* Setup the burned in MAC address */
+ u64temp = (u64)nesdev->nesadapter->mac_addr_low;
+ u64temp += ((u64)nesdev->nesadapter->mac_addr_high) << 32;
+ u64temp += nesvnic->nic_index;
+ netdev->dev_addr[0] = (u8)(u64temp>>40);
+ netdev->dev_addr[1] = (u8)(u64temp>>32);
+ netdev->dev_addr[2] = (u8)(u64temp>>24);
+ netdev->dev_addr[3] = (u8)(u64temp>>16);
+ netdev->dev_addr[4] = (u8)(u64temp>>8);
+ netdev->dev_addr[5] = (u8)u64temp;
+ memcpy(netdev->perm_addr, netdev->dev_addr, 6);
+
+ if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) {
+ netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
+ } else {
+ netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+ }
+
+ nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"
+ " nic_index = %d, logical_port = %d, mac_index = %d.\n",
+ nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
+ nesvnic->nic_index, nesvnic->logical_port, nesdev->mac_index);
+
+ if (nesvnic->nesdev->nesadapter->port_count == 1) {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
+ if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
+ } else {
+ nesvnic->qp_nic_index[2] = nesvnic->nic_index + 2;
+ nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
+ }
+ } else {
+ if (nesvnic->nesdev->nesadapter->port_count == 2) {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = nesvnic->nic_index + 2;
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
+ } else {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = 0xf;
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
+ }
+ }
+ nesvnic->next_qp_nic_index = 0;
+
+ if (nesdev->netdev_count == 0) {
+ nesvnic->rdma_enabled = 1;
+ } else {
+ nesvnic->rdma_enabled = 0;
+ }
+ nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id;
+ spin_lock_init(&nesvnic->tx_lock);
+ nesdev->netdev[nesdev->netdev_count] = netdev;
+
+ nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n",
+ nesvnic, nesdev->mac_index);
+ list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
+
+ if ((nesdev->netdev_count == 0) &&
+ (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
+ nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
+ NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1)));
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200*(nesvnic->logical_port&1)));
+ u32temp |= 0x00200000;
+ nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200*(nesvnic->logical_port&1)), u32temp);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200*(nesvnic->logical_port&1)) );
+ if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
+ if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+ nes_init_phy(nesdev);
+ nes_read_10G_phy_reg(nesdev, 1,
+ nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+ temp_phy_data = (u16)nes_read_indexed(nesdev,
+ NES_IDX_MAC_MDIO_CONTROL);
+ u32temp = 20;
+ do {
+ nes_read_10G_phy_reg(nesdev, 1,
+ nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+ phy_data = (u16)nes_read_indexed(nesdev,
+ NES_IDX_MAC_MDIO_CONTROL);
+ if ((phy_data == temp_phy_data) || (!(--u32temp)))
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+ if (phy_data & 4) {
+ nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
+ nesvnic->linkup = 1;
+ } else {
+ nes_debug(NES_DBG_INIT, "The Link is DOWN!!.\n");
+ }
+ } else {
+ nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
+ nesvnic->linkup = 1;
+ }
+ }
+ nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n");
+ /* clear the MAC interrupt status, assumes direct logical to physical mapping */
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port));
+ nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port), u32temp);
+
+ if (nesdev->nesadapter->phy_type[nesvnic->logical_port] != NES_PHY_TYPE_IRIS)
+ nes_init_phy(nesdev);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesvnic->logical_port),
+ ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
+ NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
+ }
+
+ return netdev;
+}
+
+
+/**
+ * nes_netdev_destroy - destroy network device structure
+ */
+void nes_netdev_destroy(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ /* make sure 'stop' method is called by Linux stack */
+ /* nes_netdev_stop(netdev); */
+
+ list_del(&nesvnic->list);
+
+ if (nesvnic->of_device_registered) {
+ nes_destroy_ofa_device(nesvnic->nesibdev);
+ }
+
+ free_netdev(netdev);
+}
+
+
+/**
+ * nes_nic_cm_xmit -- CM calls this to send out pkts
+ */
+int nes_nic_cm_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ int ret;
+
+ skb->dev = netdev;
+ ret = dev_queue_xmit(skb);
+ if (ret) {
+ nes_debug(NES_DBG_CM, "Bad return code from dev_queue_xmit %d\n", ret);
+ }
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h
new file mode 100644
index 0000000..e64306b
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_user.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect. All rights reserved.
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_USER_H
+#define NES_USER_H
+
+#include <linux/types.h>
+
+#define NES_ABI_USERSPACE_VER 1
+#define NES_ABI_KERNEL_VER 1
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct nes_alloc_ucontext_req {
+ __u32 reserved32;
+ __u8 userspace_ver;
+ __u8 reserved8[3];
+};
+
+struct nes_alloc_ucontext_resp {
+ __u32 max_pds; /* maximum pds allowed for this user process */
+ __u32 max_qps; /* maximum qps allowed for this user process */
+ __u32 wq_size; /* size of the WQs (sq+rq) allocated to the mmaped area */
+ __u8 virtwq; /* flag to indicate if virtual WQ are to be used or not */
+ __u8 kernel_ver;
+ __u8 reserved[2];
+};
+
+struct nes_alloc_pd_resp {
+ __u32 pd_id;
+ __u32 mmap_db_index;
+};
+
+struct nes_create_cq_req {
+ __u64 user_cq_buffer;
+ __u32 mcrqf;
+ __u8 reserved[4];
+};
+
+struct nes_create_qp_req {
+ __u64 user_wqe_buffers;
+};
+
+enum iwnes_memreg_type {
+ IWNES_MEMREG_TYPE_MEM = 0x0000,
+ IWNES_MEMREG_TYPE_QP = 0x0001,
+ IWNES_MEMREG_TYPE_CQ = 0x0002,
+ IWNES_MEMREG_TYPE_MW = 0x0003,
+ IWNES_MEMREG_TYPE_FMR = 0x0004,
+};
+
+struct nes_mem_reg_req {
+ __u32 reg_type; /* indicates if id is memory, QP or CQ */
+ __u32 reserved;
+};
+
+struct nes_create_cq_resp {
+ __u32 cq_id;
+ __u32 cq_size;
+ __u32 mmap_db_index;
+ __u32 reserved;
+};
+
+struct nes_create_qp_resp {
+ __u32 qp_id;
+ __u32 actual_sq_size;
+ __u32 actual_rq_size;
+ __u32 mmap_sq_db_index;
+ __u32 mmap_rq_db_index;
+ __u32 nes_drv_opt;
+};
+
+#endif /* NES_USER_H */
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
new file mode 100644
index 0000000..c4ec6ac
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include "nes.h"
+
+
+
+static u16 nes_read16_eeprom(void __iomem *addr, u16 offset);
+
+u32 mh_detected;
+u32 mh_pauses_sent;
+
+/**
+ * nes_read_eeprom_values -
+ */
+int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesadapter)
+{
+ u32 mac_addr_low;
+ u16 mac_addr_high;
+ u16 eeprom_data;
+ u16 eeprom_offset;
+ u16 next_section_address;
+ u16 sw_section_ver;
+ u8 major_ver = 0;
+ u8 minor_ver = 0;
+
+ /* TODO: deal with EEPROM endian issues */
+ if (nesadapter->firmware_eeprom_offset == 0) {
+ /* Read the EEPROM Parameters */
+ eeprom_data = nes_read16_eeprom(nesdev->regs, 0);
+ nes_debug(NES_DBG_HW, "EEPROM Offset 0 = 0x%04X\n", eeprom_data);
+ eeprom_offset = 2 + (((eeprom_data & 0x007f) << 3) <<
+ ((eeprom_data & 0x0080) >> 7));
+ nes_debug(NES_DBG_HW, "Firmware Offset = 0x%04X\n", eeprom_offset);
+ nesadapter->firmware_eeprom_offset = eeprom_offset;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
+ if (eeprom_data != 0x5746) {
+ nes_debug(NES_DBG_HW, "Not a valid Firmware Image = 0x%04X\n", eeprom_data);
+ return -1;
+ }
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ eeprom_offset += ((eeprom_data & 0x00ff) << 3) << ((eeprom_data & 0x0100) >> 8);
+ nes_debug(NES_DBG_HW, "Software Offset = 0x%04X\n", eeprom_offset);
+ nesadapter->software_eeprom_offset = eeprom_offset;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
+ if (eeprom_data != 0x5753) {
+ printk("Not a valid Software Image = 0x%04X\n", eeprom_data);
+ return -1;
+ }
+ sw_section_ver = nes_read16_eeprom(nesdev->regs, nesadapter->software_eeprom_offset + 6);
+ nes_debug(NES_DBG_HW, "Software section version number = 0x%04X\n",
+ sw_section_ver);
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ next_section_address = eeprom_offset + (((eeprom_data & 0x00ff) << 3) <<
+ ((eeprom_data & 0x0100) >> 8));
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+ if (eeprom_data != 0x414d) {
+ nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x414d but was 0x%04X\n",
+ eeprom_data);
+ goto no_fw_rev;
+ }
+ eeprom_offset = next_section_address;
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ next_section_address = eeprom_offset + (((eeprom_data & 0x00ff) << 3) <<
+ ((eeprom_data & 0x0100) >> 8));
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+ if (eeprom_data != 0x4f52) {
+ nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x4f52 but was 0x%04X\n",
+ eeprom_data);
+ goto no_fw_rev;
+ }
+ eeprom_offset = next_section_address;
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+ if (eeprom_data != 0x5746) {
+ nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x5746 but was 0x%04X\n",
+ eeprom_data);
+ goto no_fw_rev;
+ }
+ eeprom_offset = next_section_address;
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+ if (eeprom_data != 0x5753) {
+ nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x5753 but was 0x%04X\n",
+ eeprom_data);
+ goto no_fw_rev;
+ }
+ eeprom_offset = next_section_address;
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+ if (eeprom_data != 0x414d) {
+ nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x414d but was 0x%04X\n",
+ eeprom_data);
+ goto no_fw_rev;
+ }
+ eeprom_offset = next_section_address;
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section) = 0x%04X\n",
+ eeprom_offset + 2, eeprom_data);
+ next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+ if (eeprom_data != 0x464e) {
+ nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x464e but was 0x%04X\n",
+ eeprom_data);
+ goto no_fw_rev;
+ }
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 8);
+ printk(PFX "Firmware version %u.%u\n", (u8)(eeprom_data>>8), (u8)eeprom_data);
+ major_ver = (u8)(eeprom_data >> 8);
+ minor_ver = (u8)(eeprom_data);
+
+ if (nes_drv_opt & NES_DRV_OPT_DISABLE_VIRT_WQ) {
+ nes_debug(NES_DBG_HW, "Virtual WQs have been disabled\n");
+ } else if (((major_ver == 2) && (minor_ver > 21)) || ((major_ver > 2) && (major_ver != 255))) {
+ nesadapter->virtwq = 1;
+ }
+ nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) +
+ (u32)((u8)eeprom_data);
+
+no_fw_rev:
+ /* eeprom is valid */
+ eeprom_offset = nesadapter->software_eeprom_offset;
+ eeprom_offset += 8;
+ nesadapter->netdev_max = (u8)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ mac_addr_high = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ mac_addr_low = (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ mac_addr_low <<= 16;
+ mac_addr_low += (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "Base MAC Address = 0x%04X%08X\n",
+ mac_addr_high, mac_addr_low);
+ nes_debug(NES_DBG_HW, "MAC Address count = %u\n", nesadapter->netdev_max);
+
+ nesadapter->mac_addr_low = mac_addr_low;
+ nesadapter->mac_addr_high = mac_addr_high;
+
+ /* Read the Phy Type array */
+ eeprom_offset += 10;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->phy_type[0] = (u8)(eeprom_data >> 8);
+ nesadapter->phy_type[1] = (u8)eeprom_data;
+
+ /* Read the port array */
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->phy_type[2] = (u8)(eeprom_data >> 8);
+ nesadapter->phy_type[3] = (u8)eeprom_data;
+ /* port_count is set by soft reset reg */
+ nes_debug(NES_DBG_HW, "port_count = %u, port 0 -> %u, port 1 -> %u,"
+ " port 2 -> %u, port 3 -> %u\n",
+ nesadapter->port_count,
+ nesadapter->phy_type[0], nesadapter->phy_type[1],
+ nesadapter->phy_type[2], nesadapter->phy_type[3]);
+
+ /* Read PD config array */
+ eeprom_offset += 10;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_size[0] = eeprom_data;
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_base[0] = eeprom_data;
+ nes_debug(NES_DBG_HW, "PD0 config, size=0x%04x, base=0x%04x\n",
+ nesadapter->pd_config_size[0], nesadapter->pd_config_base[0]);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_size[1] = eeprom_data;
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_base[1] = eeprom_data;
+ nes_debug(NES_DBG_HW, "PD1 config, size=0x%04x, base=0x%04x\n",
+ nesadapter->pd_config_size[1], nesadapter->pd_config_base[1]);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_size[2] = eeprom_data;
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_base[2] = eeprom_data;
+ nes_debug(NES_DBG_HW, "PD2 config, size=0x%04x, base=0x%04x\n",
+ nesadapter->pd_config_size[2], nesadapter->pd_config_base[2]);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_size[3] = eeprom_data;
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->pd_config_base[3] = eeprom_data;
+ nes_debug(NES_DBG_HW, "PD3 config, size=0x%04x, base=0x%04x\n",
+ nesadapter->pd_config_size[3], nesadapter->pd_config_base[3]);
+
+ /* Read Rx Pool Size */
+ eeprom_offset += 22; /* 46 */
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->rx_pool_size = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "rx_pool_size = 0x%08X\n", nesadapter->rx_pool_size);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->tx_pool_size = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "tx_pool_size = 0x%08X\n", nesadapter->tx_pool_size);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->rx_threshold = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "rx_threshold = 0x%08X\n", nesadapter->rx_threshold);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->tcp_timer_core_clk_divisor = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "tcp_timer_core_clk_divisor = 0x%08X\n",
+ nesadapter->tcp_timer_core_clk_divisor);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->iwarp_config = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "iwarp_config = 0x%08X\n", nesadapter->iwarp_config);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->cm_config = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "cm_config = 0x%08X\n", nesadapter->cm_config);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->sws_timer_config = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "sws_timer_config = 0x%08X\n", nesadapter->sws_timer_config);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->tcp_config1 = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "tcp_config1 = 0x%08X\n", nesadapter->tcp_config1);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->wqm_wat = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "wqm_wat = 0x%08X\n", nesadapter->wqm_wat);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->core_clock = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nes_debug(NES_DBG_HW, "core_clock = 0x%08X\n", nesadapter->core_clock);
+
+ if ((sw_section_ver) && (nesadapter->hw_rev != NE020_REV)) {
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->phy_index[0] = (eeprom_data & 0xff00)>>8;
+ nesadapter->phy_index[1] = eeprom_data & 0x00ff;
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ nesadapter->phy_index[2] = (eeprom_data & 0xff00)>>8;
+ nesadapter->phy_index[3] = eeprom_data & 0x00ff;
+ } else {
+ nesadapter->phy_index[0] = 4;
+ nesadapter->phy_index[1] = 5;
+ nesadapter->phy_index[2] = 6;
+ nesadapter->phy_index[3] = 7;
+ }
+ nes_debug(NES_DBG_HW, "Phy address map = 0 > %u, 1 > %u, 2 > %u, 3 > %u\n",
+ nesadapter->phy_index[0],nesadapter->phy_index[1],
+ nesadapter->phy_index[2],nesadapter->phy_index[3]);
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_read16_eeprom
+ */
+static u16 nes_read16_eeprom(void __iomem *addr, u16 offset)
+{
+ writel(NES_EEPROM_READ_REQUEST + (offset >> 1),
+ (void __iomem *)addr + NES_EEPROM_COMMAND);
+
+ do {
+ } while (readl((void __iomem *)addr + NES_EEPROM_COMMAND) &
+ NES_EEPROM_READ_REQUEST);
+
+ return readw((void __iomem *)addr + NES_EEPROM_DATA);
+}
+
+
+/**
+ * nes_write_1G_phy_reg
+ */
+void nes_write_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 data)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 u32temp;
+ u32 counter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x50020000 | data | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+ u32temp);
+
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
+
+
+/**
+ * nes_read_1G_phy_reg
+ * This routine only issues the read, the data must be read
+ * separately.
+ */
+void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 *data)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 u32temp;
+ u32 counter;
+ unsigned long flags;
+
+ /* nes_debug(NES_DBG_PHY, "phy addr = %d, mac_index = %d\n",
+ phy_addr, nesdev->mac_index); */
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x60020000 | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1)) {
+ nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+ u32temp);
+ *data = 0xffff;
+ } else {
+ *data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ }
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
+
+
+/**
+ * nes_write_10G_phy_reg
+ */
+void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg,
+ u8 phy_addr, u16 data)
+{
+ u32 dev_addr;
+ u32 port_addr;
+ u32 u32temp;
+ u32 counter;
+
+ dev_addr = 1;
+ port_addr = phy_addr;
+
+ /* set address */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x00020000 | (u32)phy_reg | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+ u32temp);
+
+ /* set data */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x10020000 | (u32)data | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+ u32temp);
+}
+
+
+/**
+ * nes_read_10G_phy_reg
+ * This routine only issues the read, the data must be read
+ * separately.
+ */
+void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr)
+{
+ u32 dev_addr;
+ u32 port_addr;
+ u32 u32temp;
+ u32 counter;
+
+ dev_addr = 1;
+ port_addr = phy_addr;
+
+ /* set address */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x00020000 | (u32)phy_reg | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+ u32temp);
+
+ /* issue read */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x30020000 | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+ u32temp);
+}
+
+
+/**
+ * nes_get_cqp_request
+ */
+struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev)
+{
+ unsigned long flags;
+ struct nes_cqp_request *cqp_request = NULL;
+
+ if (!list_empty(&nesdev->cqp_avail_reqs)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_request = list_entry(nesdev->cqp_avail_reqs.next,
+ struct nes_cqp_request, list);
+ list_del_init(&cqp_request->list);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ } else {
+ cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_KERNEL);
+ if (cqp_request) {
+ cqp_request->dynamic = 1;
+ INIT_LIST_HEAD(&cqp_request->list);
+ }
+ }
+
+ if (cqp_request) {
+ init_waitqueue_head(&cqp_request->waitq);
+ cqp_request->waiting = 0;
+ cqp_request->request_done = 0;
+ cqp_request->callback = 0;
+ init_waitqueue_head(&cqp_request->waitq);
+ nes_debug(NES_DBG_CQP, "Got cqp request %p from the available list \n",
+ cqp_request);
+ } else
+ printk(KERN_ERR PFX "%s: Could not allocated a CQP request.\n",
+ __FUNCTION__);
+
+ return cqp_request;
+}
+
+
+/**
+ * nes_post_cqp_request
+ */
+void nes_post_cqp_request(struct nes_device *nesdev,
+ struct nes_cqp_request *cqp_request, int ring_doorbell)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ unsigned long flags;
+ u32 cqp_head;
+ u64 u64temp;
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ if (((((nesdev->cqp.sq_tail+(nesdev->cqp.sq_size*2))-nesdev->cqp.sq_head) &
+ (nesdev->cqp.sq_size - 1)) != 1)
+ && (list_empty(&nesdev->cqp_pending_reqs))) {
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
+ barrier();
+ u64temp = (unsigned long)cqp_request;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_SCRATCH_LOW_IDX,
+ u64temp);
+ nes_debug(NES_DBG_CQP, "CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ,"
+ " request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u,"
+ " waiting = %d, refcount = %d.\n",
+ le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f,
+ le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request,
+ nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size,
+ cqp_request->waiting, atomic_read(&cqp_request->refcount));
+ barrier();
+ if (ring_doorbell) {
+ /* Ring doorbell (1 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
+ }
+
+ barrier();
+ } else {
+ nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X), line 1 = 0x%08X"
+ " put on the pending queue.\n",
+ cqp_request,
+ le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f,
+ le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_ID_IDX]));
+ list_add_tail(&cqp_request->list, &nesdev->cqp_pending_reqs);
+ }
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ return;
+}
+
+
+/**
+ * nes_arp_table
+ */
+int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 action)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ int arp_index;
+ int err = 0;
+
+ for (arp_index = 0; (u32) arp_index < nesadapter->arp_table_size; arp_index++) {
+ if (nesadapter->arp_table[arp_index].ip_addr == ip_addr)
+ break;
+ }
+
+ if (action == NES_ARP_ADD) {
+ if (arp_index != nesadapter->arp_table_size) {
+ return -1;
+ }
+
+ arp_index = 0;
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_arps,
+ nesadapter->arp_table_size, (u32 *)&arp_index, &nesadapter->next_arp_index);
+ if (err) {
+ nes_debug(NES_DBG_NETDEV, "nes_alloc_resource returned error = %u\n", err);
+ return err;
+ }
+ nes_debug(NES_DBG_NETDEV, "ADD, arp_index=%d\n", arp_index);
+
+ nesadapter->arp_table[arp_index].ip_addr = ip_addr;
+ memcpy(nesadapter->arp_table[arp_index].mac_addr, mac_addr, ETH_ALEN);
+ return arp_index;
+ }
+
+ /* DELETE or RESOLVE */
+ if (arp_index == nesadapter->arp_table_size) {
+ nes_debug(NES_DBG_NETDEV, "mac address not in ARP table - cannot delete or resolve\n");
+ return -1;
+ }
+
+ if (action == NES_ARP_RESOLVE) {
+ nes_debug(NES_DBG_NETDEV, "RESOLVE, arp_index=%d\n", arp_index);
+ return arp_index;
+ }
+
+ if (action == NES_ARP_DELETE) {
+ nes_debug(NES_DBG_NETDEV, "DELETE, arp_index=%d\n", arp_index);
+ nesadapter->arp_table[arp_index].ip_addr = 0;
+ memset(nesadapter->arp_table[arp_index].mac_addr, 0x00, ETH_ALEN);
+ nes_free_resource(nesadapter, nesadapter->allocated_arps, arp_index);
+ return arp_index;
+ }
+
+ return -1;
+}
+
+
+/**
+ * nes_mh_fix
+ */
+void nes_mh_fix(unsigned long parm)
+{
+ unsigned long flags;
+ struct nes_device *nesdev = (struct nes_device *)parm;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_vnic *nesvnic;
+ u32 used_chunks_tx;
+ u32 temp_used_chunks_tx;
+ u32 temp_last_used_chunks_tx;
+ u32 used_chunks_mask;
+ u32 mac_tx_frames_low;
+ u32 mac_tx_frames_high;
+ u32 mac_tx_pauses;
+ u32 serdes_status;
+ u32 reset_value;
+ u32 tx_control;
+ u32 tx_config;
+ u32 tx_pause_quanta;
+ u32 rx_control;
+ u32 rx_config;
+ u32 mac_exact_match;
+ u32 mpp_debug;
+ u32 i=0;
+ u32 chunks_tx_progress = 0;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ if ((nesadapter->mac_sw_state[0] != NES_MAC_SW_IDLE) || (nesadapter->mac_link_down[0])) {
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ goto no_mh_work;
+ }
+ nesadapter->mac_sw_state[0] = NES_MAC_SW_MH;
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ do {
+ mac_tx_frames_low = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_LOW);
+ mac_tx_frames_high = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_HIGH);
+ mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+ used_chunks_tx = nes_read_indexed(nesdev, NES_IDX_USED_CHUNKS_TX);
+ nesdev->mac_pause_frames_sent += mac_tx_pauses;
+ used_chunks_mask = 0;
+ temp_used_chunks_tx = used_chunks_tx;
+ temp_last_used_chunks_tx = nesdev->last_used_chunks_tx;
+
+ if (nesdev->netdev[0]) {
+ nesvnic = netdev_priv(nesdev->netdev[0]);
+ } else {
+ break;
+ }
+
+ for (i=0; i<4; i++) {
+ used_chunks_mask <<= 8;
+ if (nesvnic->qp_nic_index[i] != 0xff) {
+ used_chunks_mask |= 0xff;
+ if ((temp_used_chunks_tx&0xff)<(temp_last_used_chunks_tx&0xff)) {
+ chunks_tx_progress = 1;
+ }
+ }
+ temp_used_chunks_tx >>= 8;
+ temp_last_used_chunks_tx >>= 8;
+ }
+ if ((mac_tx_frames_low) || (mac_tx_frames_high) ||
+ (!(used_chunks_tx&used_chunks_mask)) ||
+ (!(nesdev->last_used_chunks_tx&used_chunks_mask)) ||
+ (chunks_tx_progress) ) {
+ nesdev->last_used_chunks_tx = used_chunks_tx;
+ break;
+ }
+ nesdev->last_used_chunks_tx = used_chunks_tx;
+ barrier();
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000005);
+ mh_pauses_sent++;
+ mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+ if (mac_tx_pauses) {
+ nesdev->mac_pause_frames_sent += mac_tx_pauses;
+ break;
+ }
+
+ tx_control = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONTROL);
+ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+ tx_pause_quanta = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA);
+ rx_control = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONTROL);
+ rx_config = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONFIG);
+ mac_exact_match = nes_read_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM);
+ mpp_debug = nes_read_indexed(nesdev, NES_IDX_MPP_DEBUG);
+
+ /* one last ditch effort to avoid a false positive */
+ mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+ if (mac_tx_pauses) {
+ nesdev->last_mac_tx_pauses = nesdev->mac_pause_frames_sent;
+ nes_debug(NES_DBG_HW, "failsafe caught slow outbound pause\n");
+ break;
+ }
+ mh_detected++;
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, 0x00000000);
+ reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value | 0x0000001d);
+
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+ & 0x00000040) != 0x00000040) && (i++ < 5000)) {
+ /* mdelay(1); */
+ }
+
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+ serdes_status = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0);
+
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+ if (nesadapter->OneG_Mode) {
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
+ } else {
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
+ }
+ serdes_status = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_STATUS0);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, tx_control);
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA, tx_pause_quanta);
+ nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONTROL, rx_control);
+ nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONFIG, rx_config);
+ nes_write_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM, mac_exact_match);
+ nes_write_indexed(nesdev, NES_IDX_MPP_DEBUG, mpp_debug);
+
+ } while (0);
+
+ nesadapter->mac_sw_state[0] = NES_MAC_SW_IDLE;
+no_mh_work:
+ nesdev->nesadapter->mh_timer.expires = jiffies + (HZ/5);
+ add_timer(&nesdev->nesadapter->mh_timer);
+}
+
+/**
+ * nes_clc
+ */
+void nes_clc(unsigned long parm)
+{
+ unsigned long flags;
+ struct nes_device *nesdev = (struct nes_device *)parm;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ nesadapter->link_interrupt_count[0] = 0;
+ nesadapter->link_interrupt_count[1] = 0;
+ nesadapter->link_interrupt_count[2] = 0;
+ nesadapter->link_interrupt_count[3] = 0;
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+ nesadapter->lc_timer.expires = jiffies + 3600 * HZ; /* 1 hour */
+ add_timer(&nesadapter->lc_timer);
+}
+
+
+/**
+ * nes_dump_mem
+ */
+void nes_dump_mem(unsigned int dump_debug_level, void *addr, int length)
+{
+ char xlate[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'};
+ char *ptr;
+ char hex_buf[80];
+ char ascii_buf[20];
+ int num_char;
+ int num_ascii;
+ int num_hex;
+
+ if (!(nes_debug_level & dump_debug_level)) {
+ return;
+ }
+
+ ptr = addr;
+ if (length > 0x100) {
+ nes_debug(dump_debug_level, "Length truncated from %x to %x\n", length, 0x100);
+ length = 0x100;
+ }
+ nes_debug(dump_debug_level, "Address=0x%p, length=0x%x (%d)\n", ptr, length, length);
+
+ memset(ascii_buf, 0, 20);
+ memset(hex_buf, 0, 80);
+
+ num_ascii = 0;
+ num_hex = 0;
+ for (num_char = 0; num_char < length; num_char++) {
+ if (num_ascii == 8) {
+ ascii_buf[num_ascii++] = ' ';
+ hex_buf[num_hex++] = '-';
+ hex_buf[num_hex++] = ' ';
+ }
+
+ if (*ptr < 0x20 || *ptr > 0x7e)
+ ascii_buf[num_ascii++] = '.';
+ else
+ ascii_buf[num_ascii++] = *ptr;
+ hex_buf[num_hex++] = xlate[((*ptr & 0xf0) >> 4)];
+ hex_buf[num_hex++] = xlate[*ptr & 0x0f];
+ hex_buf[num_hex++] = ' ';
+ ptr++;
+
+ if (num_ascii >= 17) {
+ /* output line and reset */
+ nes_debug(dump_debug_level, " %s | %s\n", hex_buf, ascii_buf);
+ memset(ascii_buf, 0, 20);
+ memset(hex_buf, 0, 80);
+ num_ascii = 0;
+ num_hex = 0;
+ }
+ }
+
+ /* output the rest */
+ if (num_ascii) {
+ while (num_ascii < 17) {
+ if (num_ascii == 8) {
+ hex_buf[num_hex++] = ' ';
+ hex_buf[num_hex++] = ' ';
+ }
+ hex_buf[num_hex++] = ' ';
+ hex_buf[num_hex++] = ' ';
+ hex_buf[num_hex++] = ' ';
+ num_ascii++;
+ }
+
+ nes_debug(dump_debug_level, " %s | %s\n", hex_buf, ascii_buf);
+ }
+}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
new file mode 100644
index 0000000..ffd4b42
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -0,0 +1,3917 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <linux/highmem.h>
+#include <asm/byteorder.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/iw_cm.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "nes.h"
+
+#include <rdma/ib_umem.h>
+
+atomic_t mod_qp_timouts;
+atomic_t qps_created;
+atomic_t sw_qps_destroyed;
+
+
+/**
+ * nes_alloc_mw
+ */
+static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd) {
+ unsigned long flags;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_cqp_request *cqp_request;
+ struct nes_mr *nesmr;
+ struct ib_mw *ibmw;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ int ret;
+ u32 stag;
+ u32 stag_index = 0;
+ u32 next_stag_index = 0;
+ u32 driver_key = 0;
+ u8 stag_key = 0;
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+
+ ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+ nesadapter->max_mr, &stag_index, &next_stag_index);
+ if (ret) {
+ return ERR_PTR(ret);
+ }
+
+ nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+
+ nes_debug(NES_DBG_MR, "Registering STag 0x%08X, index = 0x%08X\n",
+ stag, stag_index);
+
+ /* Register the region with the adapter */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ kfree(nesmr);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32( NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_RIGHTS_REMOTE_READ |
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_VA_TO |
+ NES_CQP_STAG_REM_ACC_EN);
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX, (nespd->pd_id & 0x00007fff));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ stag, ret, cqp_request->major_code, cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ kfree(nesmr);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ if (!ret) {
+ return ERR_PTR(-ETIME);
+ } else {
+ return ERR_PTR(-ENOMEM);
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+
+ nesmr->ibmw.rkey = stag;
+ nesmr->mode = IWNES_MEMREG_TYPE_MW;
+ ibmw = &nesmr->ibmw;
+ nesmr->pbl_4k = 0;
+ nesmr->pbls_used = 0;
+
+ return ibmw;
+}
+
+
+/**
+ * nes_dealloc_mw
+ */
+static int nes_dealloc_mw(struct ib_mw *ibmw)
+{
+ struct nes_mr *nesmr = to_nesmw(ibmw);
+ struct nes_vnic *nesvnic = to_nesvnic(ibmw->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ int err = 0;
+ unsigned long flags;
+ int ret;
+
+ /* Deallocate the window with the adapter */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+ return -ENOMEM;
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, NES_CQP_DEALLOCATE_STAG);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, ibmw->rkey);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ nes_debug(NES_DBG_MR, "Waiting for deallocate STag 0x%08X to complete.\n",
+ ibmw->rkey);
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_MR, "Deallocate STag completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ ret, cqp_request->major_code, cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ if (!ret) {
+ err = -ETIME;
+ } else {
+ err = -EIO;
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ (ibmw->rkey & 0x0fffff00) >> 8);
+ kfree(nesmr);
+
+ return err;
+}
+
+
+/**
+ * nes_bind_mw
+ */
+static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw,
+ struct ib_mw_bind *ibmw_bind)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ /* struct nes_mr *nesmr = to_nesmw(ibmw); */
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ struct nes_hw_qp_wqe *wqe;
+ unsigned long flags = 0;
+ u32 head;
+ u32 wqe_misc = 0;
+ u32 qsize;
+
+ if (nesqp->ibqp_state > IB_QPS_RTS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+
+ head = nesqp->hwqp.sq_head;
+ qsize = nesqp->hwqp.sq_tail;
+
+ /* Check for SQ overflow */
+ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ return -EINVAL;
+ }
+
+ wqe = &nesqp->hwqp.sq_vbase[head];
+ /* nes_debug(NES_DBG_MR, "processing sq wqe at %p, head = %u.\n", wqe, head); */
+ nes_fill_init_qp_wqe(wqe, nesqp, head);
+ u64temp = ibmw_bind->wr_id;
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX, u64temp);
+ wqe_misc = NES_IWARP_SQ_OP_BIND;
+
+ wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+
+ if (ibmw_bind->send_flags & IB_SEND_SIGNALED)
+ wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
+
+ if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_WRITE) {
+ wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE;
+ }
+ if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_READ) {
+ wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_READ;
+ }
+
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_MISC_IDX, wqe_misc);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MR_IDX, ibmw_bind->mr->lkey);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MW_IDX, ibmw->rkey);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX,
+ ibmw_bind->length);
+ wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX] = 0;
+ u64temp = (u64)ibmw_bind->addr;
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX, u64temp);
+
+ head++;
+ if (head >= qsize)
+ head = 0;
+
+ nesqp->hwqp.sq_head = head;
+ barrier();
+
+ nes_write32(nesdev->regs+NES_WQE_ALLOC,
+ (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+
+ return 0;
+}
+
+
+/**
+ * nes_alloc_fmr
+ */
+static struct ib_fmr *nes_alloc_fmr(struct ib_pd *ibpd,
+ int ibmr_access_flags,
+ struct ib_fmr_attr *ibfmr_attr)
+{
+ unsigned long flags;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_fmr *nesfmr;
+ struct nes_cqp_request *cqp_request;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ int ret;
+ u32 stag;
+ u32 stag_index = 0;
+ u32 next_stag_index = 0;
+ u32 driver_key = 0;
+ u32 opcode = 0;
+ u8 stag_key = 0;
+ int i=0;
+ struct nes_vpbl vpbl;
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+
+ ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+ nesadapter->max_mr, &stag_index, &next_stag_index);
+ if (ret) {
+ goto failed_resource_alloc;
+ }
+
+ nesfmr = kzalloc(sizeof(*nesfmr), GFP_KERNEL);
+ if (!nesfmr) {
+ ret = -ENOMEM;
+ goto failed_fmr_alloc;
+ }
+
+ nesfmr->nesmr.mode = IWNES_MEMREG_TYPE_FMR;
+ if (ibfmr_attr->max_pages == 1) {
+ /* use zero length PBL */
+ nesfmr->nesmr.pbl_4k = 0;
+ nesfmr->nesmr.pbls_used = 0;
+ } else if (ibfmr_attr->max_pages <= 32) {
+ /* use PBL 256 */
+ nesfmr->nesmr.pbl_4k = 0;
+ nesfmr->nesmr.pbls_used = 1;
+ } else if (ibfmr_attr->max_pages <= 512) {
+ /* use 4K PBLs */
+ nesfmr->nesmr.pbl_4k = 1;
+ nesfmr->nesmr.pbls_used = 1;
+ } else {
+ /* use two level 4K PBLs */
+ /* add support for two level 256B PBLs */
+ nesfmr->nesmr.pbl_4k = 1;
+ nesfmr->nesmr.pbls_used = 1 + (ibfmr_attr->max_pages >> 9) +
+ ((ibfmr_attr->max_pages & 511) ? 1 : 0);
+ }
+ /* Register the region with the adapter */
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+
+ /* track PBL resources */
+ if (nesfmr->nesmr.pbls_used != 0) {
+ if (nesfmr->nesmr.pbl_4k) {
+ if (nesfmr->nesmr.pbls_used > nesadapter->free_4kpbl) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ ret = -ENOMEM;
+ goto failed_vpbl_alloc;
+ } else {
+ nesadapter->free_4kpbl -= nesfmr->nesmr.pbls_used;
+ }
+ } else {
+ if (nesfmr->nesmr.pbls_used > nesadapter->free_256pbl) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ ret = -ENOMEM;
+ goto failed_vpbl_alloc;
+ } else {
+ nesadapter->free_256pbl -= nesfmr->nesmr.pbls_used;
+ }
+ }
+ }
+
+ /* one level pbl */
+ if (nesfmr->nesmr.pbls_used == 0) {
+ nesfmr->root_vpbl.pbl_vbase = NULL;
+ nes_debug(NES_DBG_MR, "zero level pbl \n");
+ } else if (nesfmr->nesmr.pbls_used == 1) {
+ /* can change it to kmalloc & dma_map_single */
+ nesfmr->root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &nesfmr->root_vpbl.pbl_pbase);
+ if (!nesfmr->root_vpbl.pbl_vbase) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ ret = -ENOMEM;
+ goto failed_vpbl_alloc;
+ }
+ nesfmr->leaf_pbl_cnt = 0;
+ nes_debug(NES_DBG_MR, "one level pbl, root_vpbl.pbl_vbase=%p \n",
+ nesfmr->root_vpbl.pbl_vbase);
+ }
+ /* two level pbl */
+ else {
+ nesfmr->root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 8192,
+ &nesfmr->root_vpbl.pbl_pbase);
+ if (!nesfmr->root_vpbl.pbl_vbase) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ ret = -ENOMEM;
+ goto failed_vpbl_alloc;
+ }
+
+ nesfmr->root_vpbl.leaf_vpbl = kzalloc(sizeof(*nesfmr->root_vpbl.leaf_vpbl)*1024, GFP_KERNEL);
+ if (!nesfmr->root_vpbl.leaf_vpbl) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ ret = -ENOMEM;
+ goto failed_leaf_vpbl_alloc;
+ }
+
+ nesfmr->leaf_pbl_cnt = nesfmr->nesmr.pbls_used-1;
+ nes_debug(NES_DBG_MR, "two level pbl, root_vpbl.pbl_vbase=%p"
+ " leaf_pbl_cnt=%d root_vpbl.leaf_vpbl=%p\n",
+ nesfmr->root_vpbl.pbl_vbase, nesfmr->leaf_pbl_cnt, nesfmr->root_vpbl.leaf_vpbl);
+
+ for (i=0; i<nesfmr->leaf_pbl_cnt; i++)
+ nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase = NULL;
+
+ for (i=0; i<nesfmr->leaf_pbl_cnt; i++) {
+ vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &vpbl.pbl_pbase);
+
+ if (!vpbl.pbl_vbase) {
+ ret = -ENOMEM;
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ goto failed_leaf_vpbl_pages_alloc;
+ }
+
+ nesfmr->root_vpbl.pbl_vbase[i].pa_low = cpu_to_le32((u32)vpbl.pbl_pbase);
+ nesfmr->root_vpbl.pbl_vbase[i].pa_high = cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
+ nesfmr->root_vpbl.leaf_vpbl[i] = vpbl;
+
+ nes_debug(NES_DBG_MR, "pbase_low=0x%x, pbase_high=0x%x, vpbl=%p\n",
+ nesfmr->root_vpbl.pbl_vbase[i].pa_low,
+ nesfmr->root_vpbl.pbl_vbase[i].pa_high,
+ &nesfmr->root_vpbl.leaf_vpbl[i]);
+ }
+ }
+ nesfmr->ib_qp = NULL;
+ nesfmr->access_rights =0;
+
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+ ret = -ENOMEM;
+ goto failed_leaf_vpbl_pages_alloc;
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ nes_debug(NES_DBG_MR, "Registering STag 0x%08X, index = 0x%08X\n",
+ stag, stag_index);
+
+ opcode = NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
+
+ if (nesfmr->nesmr.pbl_4k == 1)
+ opcode |= NES_CQP_STAG_PBL_BLK_SIZE;
+
+ if (ibmr_access_flags & IB_ACCESS_REMOTE_WRITE) {
+ opcode |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE |
+ NES_CQP_STAG_RIGHTS_LOCAL_WRITE | NES_CQP_STAG_REM_ACC_EN;
+ nesfmr->access_rights |=
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_RIGHTS_LOCAL_WRITE |
+ NES_CQP_STAG_REM_ACC_EN;
+ }
+
+ if (ibmr_access_flags & IB_ACCESS_REMOTE_READ) {
+ opcode |= NES_CQP_STAG_RIGHTS_REMOTE_READ |
+ NES_CQP_STAG_RIGHTS_LOCAL_READ | NES_CQP_STAG_REM_ACC_EN;
+ nesfmr->access_rights |=
+ NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_RIGHTS_LOCAL_READ |
+ NES_CQP_STAG_REM_ACC_EN;
+ }
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX, (nespd->pd_id & 0x00007fff));
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
+
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] =
+ cpu_to_le32((nesfmr->nesmr.pbls_used>1) ?
+ (nesfmr->nesmr.pbls_used-1) : nesfmr->nesmr.pbls_used);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ stag, ret, cqp_request->major_code, cqp_request->minor_code);
+
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ ret = (!ret) ? -ETIME : -EIO;
+ goto failed_leaf_vpbl_pages_alloc;
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+
+ nesfmr->nesmr.ibfmr.lkey = stag;
+ nesfmr->nesmr.ibfmr.rkey = stag;
+ nesfmr->attr = *ibfmr_attr;
+
+ return &nesfmr->nesmr.ibfmr;
+
+ failed_leaf_vpbl_pages_alloc:
+ /* unroll all allocated pages */
+ for (i=0; i<nesfmr->leaf_pbl_cnt; i++) {
+ if (nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase) {
+ pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase,
+ nesfmr->root_vpbl.leaf_vpbl[i].pbl_pbase);
+ }
+ }
+ if (nesfmr->root_vpbl.leaf_vpbl)
+ kfree(nesfmr->root_vpbl.leaf_vpbl);
+
+ failed_leaf_vpbl_alloc:
+ if (nesfmr->leaf_pbl_cnt == 0) {
+ if (nesfmr->root_vpbl.pbl_vbase)
+ pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.pbl_vbase,
+ nesfmr->root_vpbl.pbl_pbase);
+ } else
+ pci_free_consistent(nesdev->pcidev, 8192, nesfmr->root_vpbl.pbl_vbase,
+ nesfmr->root_vpbl.pbl_pbase);
+
+ failed_vpbl_alloc:
+ kfree(nesfmr);
+
+ failed_fmr_alloc:
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+
+ failed_resource_alloc:
+ return ERR_PTR(ret);
+}
+
+
+/**
+ * nes_dealloc_fmr
+ */
+static int nes_dealloc_fmr(struct ib_fmr *ibfmr)
+{
+ struct nes_mr *nesmr = to_nesmr_from_ibfmr(ibfmr);
+ struct nes_fmr *nesfmr = to_nesfmr(nesmr);
+ struct nes_vnic *nesvnic = to_nesvnic(ibfmr->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_mr temp_nesmr = *nesmr;
+ int i = 0;
+
+ temp_nesmr.ibmw.device = ibfmr->device;
+ temp_nesmr.ibmw.pd = ibfmr->pd;
+ temp_nesmr.ibmw.rkey = ibfmr->rkey;
+ temp_nesmr.ibmw.uobject = NULL;
+
+ /* free the resources */
+ if (nesfmr->leaf_pbl_cnt == 0) {
+ /* single PBL case */
+ if (nesfmr->root_vpbl.pbl_vbase)
+ pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.pbl_vbase,
+ nesfmr->root_vpbl.pbl_pbase);
+ } else {
+ for (i = 0; i < nesfmr->leaf_pbl_cnt; i++) {
+ pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase,
+ nesfmr->root_vpbl.leaf_vpbl[i].pbl_pbase);
+ }
+ kfree(nesfmr->root_vpbl.leaf_vpbl);
+ pci_free_consistent(nesdev->pcidev, 8192, nesfmr->root_vpbl.pbl_vbase,
+ nesfmr->root_vpbl.pbl_pbase);
+ }
+
+ return nes_dealloc_mw(&temp_nesmr.ibmw);
+}
+
+
+/**
+ * nes_map_phys_fmr
+ */
+static int nes_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+ int list_len, u64 iova)
+{
+ return 0;
+}
+
+
+/**
+ * nes_unmap_frm
+ */
+static int nes_unmap_fmr(struct list_head *ibfmr_list)
+{
+ return 0;
+}
+
+
+
+/**
+ * nes_query_device
+ */
+static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+ memset(props, 0, sizeof(*props));
+ memcpy(&props->sys_image_guid, nesvnic->netdev->dev_addr, 6);
+
+ props->fw_ver = nesdev->nesadapter->fw_ver;
+ props->device_cap_flags = nesdev->nesadapter->device_cap_flags;
+ props->vendor_id = nesdev->nesadapter->vendor_id;
+ props->vendor_part_id = nesdev->nesadapter->vendor_part_id;
+ props->hw_ver = nesdev->nesadapter->hw_rev;
+ props->max_mr_size = 0x80000000;
+ props->max_qp = nesibdev->max_qp;
+ props->max_qp_wr = nesdev->nesadapter->max_qp_wr - 2;
+ props->max_sge = nesdev->nesadapter->max_sge;
+ props->max_cq = nesibdev->max_cq;
+ props->max_cqe = nesdev->nesadapter->max_cqe - 1;
+ props->max_mr = nesibdev->max_mr;
+ props->max_mw = nesibdev->max_mr;
+ props->max_pd = nesibdev->max_pd;
+ props->max_sge_rd = 1;
+ switch (nesdev->nesadapter->max_irrq_wr) {
+ case 0:
+ props->max_qp_rd_atom = 1;
+ break;
+ case 1:
+ props->max_qp_rd_atom = 4;
+ break;
+ case 2:
+ props->max_qp_rd_atom = 16;
+ break;
+ case 3:
+ props->max_qp_rd_atom = 32;
+ break;
+ default:
+ props->max_qp_rd_atom = 0;
+ }
+ props->max_qp_init_rd_atom = props->max_qp_wr;
+ props->atomic_cap = IB_ATOMIC_NONE;
+ props->max_map_per_fmr = 1;
+
+ return 0;
+}
+
+
+/**
+ * nes_query_port
+ */
+static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props)
+{
+ memset(props, 0, sizeof(*props));
+
+ props->max_mtu = IB_MTU_2048;
+ props->active_mtu = IB_MTU_2048;
+ props->lid = 1;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = 0;
+ props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
+ IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
+ props->gid_tbl_len = 1;
+ props->pkey_tbl_len = 1;
+ props->qkey_viol_cntr = 0;
+ props->active_width = IB_WIDTH_4X;
+ props->active_speed = 1;
+ props->max_msg_sz = 0x80000000;
+
+ return 0;
+}
+
+
+/**
+ * nes_modify_port
+ */
+static int nes_modify_port(struct ib_device *ibdev, u8 port,
+ int port_modify_mask, struct ib_port_modify *props)
+{
+ return 0;
+}
+
+
+/**
+ * nes_query_pkey
+ */
+static int nes_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+ *pkey = 0;
+ return 0;
+}
+
+
+/**
+ * nes_query_gid
+ */
+static int nes_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+
+ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+ memcpy(&(gid->raw[0]), nesvnic->netdev->dev_addr, 6);
+
+ return 0;
+}
+
+
+/**
+ * nes_alloc_ucontext - Allocate the user context data structure. This keeps track
+ * of all objects associated with a particular user-mode client.
+ */
+static struct ib_ucontext *nes_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_alloc_ucontext_req req;
+ struct nes_alloc_ucontext_resp uresp;
+ struct nes_ucontext *nes_ucontext;
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+
+ if (ib_copy_from_udata(&req, udata, sizeof(struct nes_alloc_ucontext_req))) {
+ printk(KERN_ERR PFX "Invalid structure size on allocate user context.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (req.userspace_ver != NES_ABI_USERSPACE_VER) {
+ printk(KERN_ERR PFX "Invalid userspace driver version detected. Detected version %d, should be %d\n",
+ req.userspace_ver, NES_ABI_USERSPACE_VER);
+ return ERR_PTR(-EINVAL);
+ }
+
+
+ memset(&uresp, 0, sizeof uresp);
+
+ uresp.max_qps = nesibdev->max_qp;
+ uresp.max_pds = nesibdev->max_pd;
+ uresp.wq_size = nesdev->nesadapter->max_qp_wr * 2;
+ uresp.virtwq = nesadapter->virtwq;
+ uresp.kernel_ver = NES_ABI_KERNEL_VER;
+
+ nes_ucontext = kzalloc(sizeof *nes_ucontext, GFP_KERNEL);
+ if (!nes_ucontext)
+ return ERR_PTR(-ENOMEM);
+
+ nes_ucontext->nesdev = nesdev;
+ nes_ucontext->mmap_wq_offset = uresp.max_pds;
+ nes_ucontext->mmap_cq_offset = nes_ucontext->mmap_wq_offset +
+ ((sizeof(struct nes_hw_qp_wqe) * uresp.max_qps * 2) + PAGE_SIZE-1) /
+ PAGE_SIZE;
+
+
+ if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+ kfree(nes_ucontext);
+ return ERR_PTR(-EFAULT);
+ }
+
+ INIT_LIST_HEAD(&nes_ucontext->cq_reg_mem_list);
+ INIT_LIST_HEAD(&nes_ucontext->qp_reg_mem_list);
+ atomic_set(&nes_ucontext->usecnt, 1);
+ return &nes_ucontext->ibucontext;
+}
+
+
+/**
+ * nes_dealloc_ucontext
+ */
+static int nes_dealloc_ucontext(struct ib_ucontext *context)
+{
+ /* struct nes_vnic *nesvnic = to_nesvnic(context->device); */
+ /* struct nes_device *nesdev = nesvnic->nesdev; */
+ struct nes_ucontext *nes_ucontext = to_nesucontext(context);
+
+ if (!atomic_dec_and_test(&nes_ucontext->usecnt))
+ return 0;
+ kfree(nes_ucontext);
+ return 0;
+}
+
+
+/**
+ * nes_mmap
+ */
+static int nes_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ unsigned long index;
+ struct nes_vnic *nesvnic = to_nesvnic(context->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ /* struct nes_adapter *nesadapter = nesdev->nesadapter; */
+ struct nes_ucontext *nes_ucontext;
+ struct nes_qp *nesqp;
+
+ nes_ucontext = to_nesucontext(context);
+
+
+ if (vma->vm_pgoff >= nes_ucontext->mmap_wq_offset) {
+ index = (vma->vm_pgoff - nes_ucontext->mmap_wq_offset) * PAGE_SIZE;
+ index /= ((sizeof(struct nes_hw_qp_wqe) * nesdev->nesadapter->max_qp_wr * 2) +
+ PAGE_SIZE-1) & (~(PAGE_SIZE-1));
+ if (!test_bit(index, nes_ucontext->allocated_wqs)) {
+ nes_debug(NES_DBG_MMAP, "wq %lu not allocated\n", index);
+ return -EFAULT;
+ }
+ nesqp = nes_ucontext->mmap_nesqp[index];
+ if (nesqp == NULL) {
+ nes_debug(NES_DBG_MMAP, "wq %lu has a NULL QP base.\n", index);
+ return -EFAULT;
+ }
+ if (remap_pfn_range(vma, vma->vm_start,
+ virt_to_phys(nesqp->hwqp.sq_vbase) >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ nes_debug(NES_DBG_MMAP, "remap_pfn_range failed.\n");
+ return -EAGAIN;
+ }
+ vma->vm_private_data = nesqp;
+ return 0;
+ } else {
+ index = vma->vm_pgoff;
+ if (!test_bit(index, nes_ucontext->allocated_doorbells))
+ return -EFAULT;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (io_remap_pfn_range(vma, vma->vm_start,
+ (nesdev->doorbell_start +
+ ((nes_ucontext->mmap_db_index[index] - nesdev->base_doorbell_index) * 4096))
+ >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot))
+ return -EAGAIN;
+ vma->vm_private_data = nes_ucontext;
+ return 0;
+ }
+
+ return -ENOSYS;
+}
+
+
+/**
+ * nes_alloc_pd
+ */
+static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context, struct ib_udata *udata)
+{
+ struct nes_pd *nespd;
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_ucontext *nesucontext;
+ struct nes_alloc_pd_resp uresp;
+ u32 pd_num = 0;
+ int err;
+
+ nes_debug(NES_DBG_PD, "nesvnic=%p, netdev=%p %s, ibdev=%p, context=%p, netdev refcnt=%u\n",
+ nesvnic, nesdev->netdev[0], nesdev->netdev[0]->name, ibdev, context,
+ atomic_read(&nesvnic->netdev->refcnt));
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_pds,
+ nesadapter->max_pd, &pd_num, &nesadapter->next_pd);
+ if (err) {
+ return ERR_PTR(err);
+ }
+
+ nespd = kzalloc(sizeof (struct nes_pd), GFP_KERNEL);
+ if (!nespd) {
+ nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ nes_debug(NES_DBG_PD, "Allocating PD (%p) for ib device %s\n",
+ nespd, nesvnic->nesibdev->ibdev.name);
+
+ nespd->pd_id = (pd_num << (PAGE_SHIFT-12)) + nesadapter->base_pd;
+
+ if (context) {
+ nesucontext = to_nesucontext(context);
+ nespd->mmap_db_index = find_next_zero_bit(nesucontext->allocated_doorbells,
+ NES_MAX_USER_DB_REGIONS, nesucontext->first_free_db);
+ nes_debug(NES_DBG_PD, "find_first_zero_biton doorbells returned %u, mapping pd_id %u.\n",
+ nespd->mmap_db_index, nespd->pd_id);
+ if (nespd->mmap_db_index > NES_MAX_USER_DB_REGIONS) {
+ nes_debug(NES_DBG_PD, "mmap_db_index > MAX\n");
+ nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+ kfree(nespd);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ uresp.pd_id = nespd->pd_id;
+ uresp.mmap_db_index = nespd->mmap_db_index;
+ if (ib_copy_to_udata(udata, &uresp, sizeof (struct nes_alloc_pd_resp))) {
+ nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+ kfree(nespd);
+ return ERR_PTR(-EFAULT);
+ }
+
+ set_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
+ nesucontext->mmap_db_index[nespd->mmap_db_index] = nespd->pd_id;
+ nesucontext->first_free_db = nespd->mmap_db_index + 1;
+ }
+
+ nes_debug(NES_DBG_PD, "PD%u structure located @%p.\n", nespd->pd_id, nespd);
+ return &nespd->ibpd;
+}
+
+
+/**
+ * nes_dealloc_pd
+ */
+static int nes_dealloc_pd(struct ib_pd *ibpd)
+{
+ struct nes_ucontext *nesucontext;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+ if ((ibpd->uobject) && (ibpd->uobject->context)) {
+ nesucontext = to_nesucontext(ibpd->uobject->context);
+ nes_debug(NES_DBG_PD, "Clearing bit %u from allocated doorbells\n",
+ nespd->mmap_db_index);
+ clear_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
+ nesucontext->mmap_db_index[nespd->mmap_db_index] = 0;
+ if (nesucontext->first_free_db > nespd->mmap_db_index) {
+ nesucontext->first_free_db = nespd->mmap_db_index;
+ }
+ }
+
+ nes_debug(NES_DBG_PD, "Deallocating PD%u structure located @%p.\n",
+ nespd->pd_id, nespd);
+ nes_free_resource(nesadapter, nesadapter->allocated_pds,
+ (nespd->pd_id-nesadapter->base_pd)>>(PAGE_SHIFT-12));
+ kfree(nespd);
+
+ return 0;
+}
+
+
+/**
+ * nes_create_ah
+ */
+static struct ib_ah *nes_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+
+/**
+ * nes_destroy_ah
+ */
+static int nes_destroy_ah(struct ib_ah *ah)
+{
+ return -ENOSYS;
+}
+
+
+/**
+ * nes_get_encoded_size
+ */
+static inline u8 nes_get_encoded_size(int *size)
+{
+ u8 encoded_size = 0;
+ if (*size <= 32) {
+ *size = 32;
+ encoded_size = 1;
+ } else if (*size <= 128) {
+ *size = 128;
+ encoded_size = 2;
+ } else if (*size <= 512) {
+ *size = 512;
+ encoded_size = 3;
+ }
+ return (encoded_size);
+}
+
+
+
+/**
+ * nes_setup_virt_qp
+ */
+static int nes_setup_virt_qp(struct nes_qp *nesqp, struct nes_pbl *nespbl,
+ struct nes_vnic *nesvnic, int sq_size, int rq_size)
+{
+ unsigned long flags;
+ void *mem;
+ __le64 *pbl = NULL;
+ __le64 *tpbl;
+ __le64 *pblbuffer;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 pbl_entries;
+ u8 rq_pbl_entries;
+ u8 sq_pbl_entries;
+
+ pbl_entries = nespbl->pbl_size >> 3;
+ nes_debug(NES_DBG_QP, "Userspace PBL, pbl_size=%u, pbl_entries = %d pbl_vbase=%p, pbl_pbase=%p\n",
+ nespbl->pbl_size, pbl_entries,
+ (void *)nespbl->pbl_vbase,
+ (void *)nespbl->pbl_pbase);
+ pbl = (__le64 *) nespbl->pbl_vbase; /* points to first pbl entry */
+ /* now lets set the sq_vbase as well as rq_vbase addrs we will assign */
+ /* the first pbl to be fro the rq_vbase... */
+ rq_pbl_entries = (rq_size * sizeof(struct nes_hw_qp_wqe)) >> 12;
+ sq_pbl_entries = (sq_size * sizeof(struct nes_hw_qp_wqe)) >> 12;
+ nesqp->hwqp.sq_pbase = (le32_to_cpu(((__le32 *)pbl)[0])) | ((u64)((le32_to_cpu(((__le32 *)pbl)[1]))) << 32);
+ if (!nespbl->page) {
+ nes_debug(NES_DBG_QP, "QP nespbl->page is NULL \n");
+ kfree(nespbl);
+ return -ENOMEM;
+ }
+
+ nesqp->hwqp.sq_vbase = kmap(nespbl->page);
+ nesqp->page = nespbl->page;
+ if (!nesqp->hwqp.sq_vbase) {
+ nes_debug(NES_DBG_QP, "QP sq_vbase kmap failed\n");
+ kfree(nespbl);
+ return -ENOMEM;
+ }
+
+ /* Now to get to sq.. we need to calculate how many */
+ /* PBL entries were used by the rq.. */
+ pbl += sq_pbl_entries;
+ nesqp->hwqp.rq_pbase = (le32_to_cpu(((__le32 *)pbl)[0])) | ((u64)((le32_to_cpu(((__le32 *)pbl)[1]))) << 32);
+ /* nesqp->hwqp.rq_vbase = bus_to_virt(*pbl); */
+ /*nesqp->hwqp.rq_vbase = phys_to_virt(*pbl); */
+
+ nes_debug(NES_DBG_QP, "QP sq_vbase= %p sq_pbase=%p rq_vbase=%p rq_pbase=%p\n",
+ nesqp->hwqp.sq_vbase, (void *)nesqp->hwqp.sq_pbase,
+ nesqp->hwqp.rq_vbase, (void *)nesqp->hwqp.rq_pbase);
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ if (!nesadapter->free_256pbl) {
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+ nespbl->pbl_pbase);
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kunmap(nesqp->page);
+ kfree(nespbl);
+ return -ENOMEM;
+ }
+ nesadapter->free_256pbl--;
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+ nesqp->pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 256, &nesqp->pbl_pbase);
+ pblbuffer = nesqp->pbl_vbase;
+ if (!nesqp->pbl_vbase) {
+ /* memory allocated during nes_reg_user_mr() */
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+ nespbl->pbl_pbase);
+ kfree(nespbl);
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ nesadapter->free_256pbl++;
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kunmap(nesqp->page);
+ return -ENOMEM;
+ }
+ memset(nesqp->pbl_vbase, 0, 256);
+ /* fill in the page address in the pbl buffer.. */
+ tpbl = pblbuffer + 16;
+ pbl = (__le64 *)nespbl->pbl_vbase;
+ while (sq_pbl_entries--)
+ *tpbl++ = *pbl++;
+ tpbl = pblbuffer;
+ while (rq_pbl_entries--)
+ *tpbl++ = *pbl++;
+
+ /* done with memory allocated during nes_reg_user_mr() */
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+ nespbl->pbl_pbase);
+ kfree(nespbl);
+
+ nesqp->qp_mem_size =
+ max((u32)sizeof(struct nes_qp_context), ((u32)256)) + 256; /* this is Q2 */
+ /* Round up to a multiple of a page */
+ nesqp->qp_mem_size += PAGE_SIZE - 1;
+ nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
+
+ mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ &nesqp->hwqp.q2_pbase);
+
+ if (!mem) {
+ pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
+ nesqp->pbl_vbase = NULL;
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ nesadapter->free_256pbl++;
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kunmap(nesqp->page);
+ return -ENOMEM;
+ }
+ nesqp->hwqp.q2_vbase = mem;
+ mem += 256;
+ memset(nesqp->hwqp.q2_vbase, 0, 256);
+ nesqp->nesqp_context = mem;
+ memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
+ nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
+
+ return 0;
+}
+
+
+/**
+ * nes_setup_mmap_qp
+ */
+static int nes_setup_mmap_qp(struct nes_qp *nesqp, struct nes_vnic *nesvnic,
+ int sq_size, int rq_size)
+{
+ void *mem;
+ struct nes_device *nesdev = nesvnic->nesdev;
+
+ nesqp->qp_mem_size = (sizeof(struct nes_hw_qp_wqe) * sq_size) +
+ (sizeof(struct nes_hw_qp_wqe) * rq_size) +
+ max((u32)sizeof(struct nes_qp_context), ((u32)256)) +
+ 256; /* this is Q2 */
+ /* Round up to a multiple of a page */
+ nesqp->qp_mem_size += PAGE_SIZE - 1;
+ nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
+
+ mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ &nesqp->hwqp.sq_pbase);
+ if (!mem)
+ return -ENOMEM;
+ nes_debug(NES_DBG_QP, "PCI consistent memory for "
+ "host descriptor rings located @ %p (pa = 0x%08lX.) size = %u.\n",
+ mem, (unsigned long)nesqp->hwqp.sq_pbase, nesqp->qp_mem_size);
+
+ memset(mem, 0, nesqp->qp_mem_size);
+
+ nesqp->hwqp.sq_vbase = mem;
+ mem += sizeof(struct nes_hw_qp_wqe) * sq_size;
+
+ nesqp->hwqp.rq_vbase = mem;
+ nesqp->hwqp.rq_pbase = nesqp->hwqp.sq_pbase +
+ sizeof(struct nes_hw_qp_wqe) * sq_size;
+ mem += sizeof(struct nes_hw_qp_wqe) * rq_size;
+
+ nesqp->hwqp.q2_vbase = mem;
+ nesqp->hwqp.q2_pbase = nesqp->hwqp.rq_pbase +
+ sizeof(struct nes_hw_qp_wqe) * rq_size;
+ mem += 256;
+ memset(nesqp->hwqp.q2_vbase, 0, 256);
+
+ nesqp->nesqp_context = mem;
+ nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
+ memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
+ return 0;
+}
+
+
+/**
+ * nes_free_qp_mem() is to free up the qp's pci_alloc_consistent() memory.
+ */
+static inline void nes_free_qp_mem(struct nes_device *nesdev,
+ struct nes_qp *nesqp, int virt_wqs)
+{
+ unsigned long flags;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ if (!virt_wqs) {
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+ }else {
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ nesadapter->free_256pbl++;
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size, nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
+ pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase );
+ nesqp->pbl_vbase = NULL;
+ kunmap(nesqp->page);
+ }
+}
+
+
+/**
+ * nes_create_qp
+ */
+static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr, struct ib_udata *udata)
+{
+ u64 u64temp= 0;
+ u64 u64nesqp = 0;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_qp *nesqp;
+ struct nes_cq *nescq;
+ struct nes_ucontext *nes_ucontext;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ struct nes_create_qp_req req;
+ struct nes_create_qp_resp uresp;
+ struct nes_pbl *nespbl = NULL;
+ u32 qp_num = 0;
+ u32 opcode = 0;
+ /* u32 counter = 0; */
+ void *mem;
+ unsigned long flags;
+ int ret;
+ int err;
+ int virt_wqs = 0;
+ int sq_size;
+ int rq_size;
+ u8 sq_encoded_size;
+ u8 rq_encoded_size;
+ /* int counter; */
+
+ atomic_inc(&qps_created);
+ switch (init_attr->qp_type) {
+ case IB_QPT_RC:
+ if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) {
+ init_attr->cap.max_inline_data = 0;
+ } else {
+ init_attr->cap.max_inline_data = 64;
+ }
+ sq_size = init_attr->cap.max_send_wr;
+ rq_size = init_attr->cap.max_recv_wr;
+
+ // check if the encoded sizes are OK or not...
+ sq_encoded_size = nes_get_encoded_size(&sq_size);
+ rq_encoded_size = nes_get_encoded_size(&rq_size);
+
+ if ((!sq_encoded_size) || (!rq_encoded_size)) {
+ nes_debug(NES_DBG_QP, "ERROR bad rq (%u) or sq (%u) size\n",
+ rq_size, sq_size);
+ return ERR_PTR(-EINVAL);
+ }
+
+ init_attr->cap.max_send_wr = sq_size -2;
+ init_attr->cap.max_recv_wr = rq_size -1;
+ nes_debug(NES_DBG_QP, "RQ size=%u, SQ Size=%u\n", rq_size, sq_size);
+
+ ret = nes_alloc_resource(nesadapter, nesadapter->allocated_qps,
+ nesadapter->max_qp, &qp_num, &nesadapter->next_qp);
+ if (ret) {
+ return ERR_PTR(ret);
+ }
+
+ /* Need 512 (actually now 1024) byte alignment on this structure */
+ mem = kzalloc(sizeof(*nesqp)+NES_SW_CONTEXT_ALIGN-1, GFP_KERNEL);
+ if (!mem) {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ nes_debug(NES_DBG_QP, "Unable to allocate QP\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ u64nesqp = (unsigned long)mem;
+ u64nesqp += ((u64)NES_SW_CONTEXT_ALIGN) - 1;
+ u64temp = ((u64)NES_SW_CONTEXT_ALIGN) - 1;
+ u64nesqp &= ~u64temp;
+ nesqp = (struct nes_qp *)(unsigned long)u64nesqp;
+ /* nes_debug(NES_DBG_QP, "nesqp=%p, allocated buffer=%p. Rounded to closest %u\n",
+ nesqp, mem, NES_SW_CONTEXT_ALIGN); */
+ nesqp->allocated_buffer = mem;
+
+ if (udata) {
+ if (ib_copy_from_udata(&req, udata, sizeof(struct nes_create_qp_req))) {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n");
+ return NULL;
+ }
+ if (req.user_wqe_buffers) {
+ virt_wqs = 1;
+ }
+ if ((ibpd->uobject) && (ibpd->uobject->context)) {
+ nesqp->user_mode = 1;
+ nes_ucontext = to_nesucontext(ibpd->uobject->context);
+ if (virt_wqs) {
+ err = 1;
+ list_for_each_entry(nespbl, &nes_ucontext->qp_reg_mem_list, list) {
+ if (nespbl->user_base == (unsigned long )req.user_wqe_buffers) {
+ list_del(&nespbl->list);
+ err = 0;
+ nes_debug(NES_DBG_QP, "Found PBL for virtual QP. nespbl=%p. user_base=0x%lx\n",
+ nespbl, nespbl->user_base);
+ break;
+ }
+ }
+ if (err) {
+ nes_debug(NES_DBG_QP, "Didn't Find PBL for virtual QP. address = %llx.\n",
+ (long long unsigned int)req.user_wqe_buffers);
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ nes_ucontext = to_nesucontext(ibpd->uobject->context);
+ nesqp->mmap_sq_db_index =
+ find_next_zero_bit(nes_ucontext->allocated_wqs,
+ NES_MAX_USER_WQ_REGIONS, nes_ucontext->first_free_wq);
+ /* nes_debug(NES_DBG_QP, "find_first_zero_biton wqs returned %u\n",
+ nespd->mmap_db_index); */
+ if (nesqp->mmap_sq_db_index > NES_MAX_USER_WQ_REGIONS) {
+ nes_debug(NES_DBG_QP,
+ "db index > max user regions, failing create QP\n");
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ if (virt_wqs) {
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+ nespbl->pbl_pbase);
+ kfree(nespbl);
+ }
+ kfree(nesqp->allocated_buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ set_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
+ nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = nesqp;
+ nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index + 1;
+ } else {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+ err = (!virt_wqs) ? nes_setup_mmap_qp(nesqp, nesvnic, sq_size, rq_size) :
+ nes_setup_virt_qp(nesqp, nespbl, nesvnic, sq_size, rq_size);
+ if (err) {
+ nes_debug(NES_DBG_QP,
+ "error geting qp mem code = %d\n", err);
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ nesqp->hwqp.sq_size = sq_size;
+ nesqp->hwqp.sq_encoded_size = sq_encoded_size;
+ nesqp->hwqp.sq_head = 1;
+ nesqp->hwqp.rq_size = rq_size;
+ nesqp->hwqp.rq_encoded_size = rq_encoded_size;
+ /* nes_debug(NES_DBG_QP, "nesqp->nesqp_context_pbase = %p\n",
+ (void *)nesqp->nesqp_context_pbase);
+ */
+ nesqp->hwqp.qp_id = qp_num;
+ nesqp->ibqp.qp_num = nesqp->hwqp.qp_id;
+ nesqp->nespd = nespd;
+
+ nescq = to_nescq(init_attr->send_cq);
+ nesqp->nesscq = nescq;
+ nescq = to_nescq(init_attr->recv_cq);
+ nesqp->nesrcq = nescq;
+
+ nesqp->nesqp_context->misc |= cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+ NES_QPCONTEXT_MISC_PCI_FCN_SHIFT);
+ nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.rq_encoded_size <<
+ NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT);
+ nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.sq_encoded_size <<
+ NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT);
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_PRIV_EN);
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_FAST_REGISTER_EN);
+ nesqp->nesqp_context->cqs = cpu_to_le32(nesqp->nesscq->hw_cq.cq_number +
+ ((u32)nesqp->nesrcq->hw_cq.cq_number << 16));
+ u64temp = (u64)nesqp->hwqp.sq_pbase;
+ nesqp->nesqp_context->sq_addr_low = cpu_to_le32((u32)u64temp);
+ nesqp->nesqp_context->sq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+
+
+ if (!virt_wqs) {
+ u64temp = (u64)nesqp->hwqp.sq_pbase;
+ nesqp->nesqp_context->sq_addr_low = cpu_to_le32((u32)u64temp);
+ nesqp->nesqp_context->sq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+ u64temp = (u64)nesqp->hwqp.rq_pbase;
+ nesqp->nesqp_context->rq_addr_low = cpu_to_le32((u32)u64temp);
+ nesqp->nesqp_context->rq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+ } else {
+ u64temp = (u64)nesqp->pbl_pbase;
+ nesqp->nesqp_context->rq_addr_low = cpu_to_le32((u32)u64temp);
+ nesqp->nesqp_context->rq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+ }
+
+ /* nes_debug(NES_DBG_QP, "next_qp_nic_index=%u, using nic_index=%d\n",
+ nesvnic->next_qp_nic_index,
+ nesvnic->qp_nic_index[nesvnic->next_qp_nic_index]); */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ nesqp->nesqp_context->misc2 |= cpu_to_le32(
+ (u32)nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] <<
+ NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT);
+ nesvnic->next_qp_nic_index++;
+ if ((nesvnic->next_qp_nic_index > 3) ||
+ (nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] == 0xf)) {
+ nesvnic->next_qp_nic_index = 0;
+ }
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32((u32)nesqp->nespd->pd_id << 16);
+ u64temp = (u64)nesqp->hwqp.q2_pbase;
+ nesqp->nesqp_context->q2_addr_low = cpu_to_le32((u32)u64temp);
+ nesqp->nesqp_context->q2_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+ nesqp->nesqp_context->aeq_token_low = cpu_to_le32((u32)((unsigned long)(nesqp)));
+ nesqp->nesqp_context->aeq_token_high = cpu_to_le32((u32)(upper_32_bits((unsigned long)(nesqp))));
+ nesqp->nesqp_context->ird_ord_sizes = cpu_to_le32(NES_QPCONTEXT_ORDIRD_ALSMM |
+ ((((u32)nesadapter->max_irrq_wr) <<
+ NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT) & NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK));
+ if (disable_mpa_crc) {
+ nes_debug(NES_DBG_QP, "Disabling MPA crc checking due to module option.\n");
+ nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(NES_QPCONTEXT_ORDIRD_RNMC);
+ }
+
+
+ /* Create the QP */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_QP, "Failed to get a cqp_request\n");
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ nes_free_qp_mem(nesdev, nesqp,virt_wqs);
+ kfree(nesqp->allocated_buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ if (!virt_wqs) {
+ opcode = NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP |
+ NES_CQP_QP_IWARP_STATE_IDLE;
+ } else {
+ opcode = NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_VIRT_WQS |
+ NES_CQP_QP_IWARP_STATE_IDLE;
+ }
+ opcode |= NES_CQP_QP_CQS_VALID;
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+
+ u64temp = (u64)nesqp->nesqp_context_pbase;
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ nes_debug(NES_DBG_QP, "Waiting for create iWARP QP%u to complete.\n",
+ nesqp->hwqp.qp_id);
+ ret = wait_event_timeout(cqp_request->waitq,
+ (cqp_request->request_done != 0), NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_QP, "Create iwarp QP%u completed, wait_event_timeout ret=%u,"
+ " nesdev->cqp_head = %u, nesdev->cqp.sq_tail = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ nesqp->hwqp.qp_id, ret, nesdev->cqp.sq_head, nesdev->cqp.sq_tail,
+ cqp_request->major_code, cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ nes_free_qp_mem(nesdev, nesqp,virt_wqs);
+ kfree(nesqp->allocated_buffer);
+ if (!ret) {
+ return ERR_PTR(-ETIME);
+ } else {
+ return ERR_PTR(-EIO);
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+
+ if (ibpd->uobject) {
+ uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+ uresp.actual_sq_size = sq_size;
+ uresp.actual_rq_size = rq_size;
+ uresp.qp_id = nesqp->hwqp.qp_id;
+ uresp.nes_drv_opt = nes_drv_opt;
+ if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ nes_free_qp_mem(nesdev, nesqp,virt_wqs);
+ kfree(nesqp->allocated_buffer);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ nes_debug(NES_DBG_QP, "QP%u structure located @%p.Size = %u.\n",
+ nesqp->hwqp.qp_id, nesqp, (u32)sizeof(*nesqp));
+ spin_lock_init(&nesqp->lock);
+ init_waitqueue_head(&nesqp->state_waitq);
+ init_waitqueue_head(&nesqp->kick_waitq);
+ nes_add_ref(&nesqp->ibqp);
+ break;
+ default:
+ nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ break;
+ }
+
+ /* update the QP table */
+ nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp;
+ nes_debug(NES_DBG_QP, "netdev refcnt=%u\n",
+ atomic_read(&nesvnic->netdev->refcnt));
+
+ return &nesqp->ibqp;
+}
+
+
+/**
+ * nes_destroy_qp
+ */
+static int nes_destroy_qp(struct ib_qp *ibqp)
+{
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ /* struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); */
+ struct nes_ucontext *nes_ucontext;
+ struct ib_qp_attr attr;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ int ret;
+
+ atomic_inc(&sw_qps_destroyed);
+ nesqp->destroyed = 1;
+
+ /* Blow away the connection if it exists. */
+ if (nesqp->ibqp_state >= IB_QPS_INIT && nesqp->ibqp_state <= IB_QPS_RTS) {
+ /* if (nesqp->ibqp_state == IB_QPS_RTS) { */
+ attr.qp_state = IB_QPS_ERR;
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+ }
+
+ if (((nesqp->ibqp_state == IB_QPS_INIT) ||
+ (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {
+ cm_id = nesqp->cm_id;
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ nes_debug(NES_DBG_QP, "Generating a CM Timeout Event for "
+ "QP%u. cm_id = %p, refcount = %u. \n",
+ nesqp->hwqp.qp_id, cm_id, atomic_read(&nesqp->refcount));
+
+ cm_id->rem_ref(cm_id);
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ nes_debug(NES_DBG_QP, "OFA CM event_handler returned, ret=%d\n", ret);
+ }
+
+
+ if (nesqp->user_mode) {
+ if ((ibqp->uobject)&&(ibqp->uobject->context)) {
+ nes_ucontext = to_nesucontext(ibqp->uobject->context);
+ clear_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
+ nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = NULL;
+ if (nes_ucontext->first_free_wq > nesqp->mmap_sq_db_index) {
+ nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index;
+ }
+ }
+ if (nesqp->pbl_pbase)
+ kunmap(nesqp->page);
+ }
+
+ nes_rem_ref(&nesqp->ibqp);
+ return 0;
+}
+
+
+/**
+ * nes_create_cq
+ */
+static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
+ int comp_vector,
+ struct ib_ucontext *context, struct ib_udata *udata)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_cq *nescq;
+ struct nes_ucontext *nes_ucontext = NULL;
+ struct nes_cqp_request *cqp_request;
+ void *mem = NULL;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_pbl *nespbl = NULL;
+ struct nes_create_cq_req req;
+ struct nes_create_cq_resp resp;
+ u32 cq_num = 0;
+ u32 opcode = 0;
+ u32 pbl_entries = 1;
+ int err;
+ unsigned long flags;
+ int ret;
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_cqs,
+ nesadapter->max_cq, &cq_num, &nesadapter->next_cq);
+ if (err) {
+ return ERR_PTR(err);
+ }
+
+ nescq = kzalloc(sizeof(struct nes_cq), GFP_KERNEL);
+ if (!nescq) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ nes_debug(NES_DBG_CQ, "Unable to allocate nes_cq struct\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ nescq->hw_cq.cq_size = max(entries + 1, 5);
+ nescq->hw_cq.cq_number = cq_num;
+ nescq->ibcq.cqe = nescq->hw_cq.cq_size - 1;
+
+
+ if (context) {
+ nes_ucontext = to_nesucontext(context);
+ if (ib_copy_from_udata(&req, udata, sizeof (struct nes_create_cq_req))) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-EFAULT);
+ }
+ nesvnic->mcrq_ucontext = nes_ucontext;
+ nes_ucontext->mcrqf = req.mcrqf;
+ if (nes_ucontext->mcrqf) {
+ if (nes_ucontext->mcrqf & 0x80000000)
+ nescq->hw_cq.cq_number = nesvnic->nic.qp_id + 12 + (nes_ucontext->mcrqf & 0xf) - 1;
+ else if (nes_ucontext->mcrqf & 0x40000000)
+ nescq->hw_cq.cq_number = nes_ucontext->mcrqf & 0xffff;
+ else
+ nescq->hw_cq.cq_number = nesvnic->mcrq_qp_id + nes_ucontext->mcrqf-1;
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ }
+ nes_debug(NES_DBG_CQ, "CQ Virtual Address = %08lX, size = %u.\n",
+ (unsigned long)req.user_cq_buffer, entries);
+ list_for_each_entry(nespbl, &nes_ucontext->cq_reg_mem_list, list) {
+ if (nespbl->user_base == (unsigned long )req.user_cq_buffer) {
+ list_del(&nespbl->list);
+ err = 0;
+ nes_debug(NES_DBG_CQ, "Found PBL for virtual CQ. nespbl=%p.\n",
+ nespbl);
+ break;
+ }
+ }
+ if (err) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(err);
+ }
+
+ pbl_entries = nespbl->pbl_size >> 3;
+ nescq->cq_mem_size = 0;
+ } else {
+ nescq->cq_mem_size = nescq->hw_cq.cq_size * sizeof(struct nes_hw_cqe);
+ nes_debug(NES_DBG_CQ, "Attempting to allocate pci memory (%u entries, %u bytes) for CQ%u.\n",
+ entries, nescq->cq_mem_size, nescq->hw_cq.cq_number);
+
+ /* allocate the physical buffer space */
+ mem = pci_alloc_consistent(nesdev->pcidev, nescq->cq_mem_size,
+ &nescq->hw_cq.cq_pbase);
+ if (!mem) {
+ printk(KERN_ERR PFX "Unable to allocate pci memory for cq\n");
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(mem, 0, nescq->cq_mem_size);
+ nescq->hw_cq.cq_vbase = mem;
+ nescq->hw_cq.cq_head = 0;
+ nes_debug(NES_DBG_CQ, "CQ%u virtual address @ %p, phys = 0x%08X\n",
+ nescq->hw_cq.cq_number, nescq->hw_cq.cq_vbase,
+ (u32)nescq->hw_cq.cq_pbase);
+ }
+
+ nescq->hw_cq.ce_handler = nes_iwarp_ce_handler;
+ spin_lock_init(&nescq->lock);
+
+ /* send CreateCQ request to CQP */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_CQ, "Failed to get a cqp_request.\n");
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ opcode = NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+ NES_CQP_CQ_CHK_OVERFLOW |
+ NES_CQP_CQ_CEQE_MASK | ((u32)nescq->hw_cq.cq_size << 16);
+
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+
+ if (pbl_entries != 1) {
+ if (pbl_entries > 32) {
+ /* use 4k pbl */
+ nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 4k PBL\n", pbl_entries);
+ if (nesadapter->free_4kpbl == 0) {
+ if (cqp_request->dynamic) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kfree(cqp_request);
+ } else {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ }
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-ENOMEM);
+ } else {
+ opcode |= (NES_CQP_CQ_VIRT | NES_CQP_CQ_4KB_CHUNK);
+ nescq->virtual_cq = 2;
+ nesadapter->free_4kpbl--;
+ }
+ } else {
+ /* use 256 byte pbl */
+ nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 256 byte PBL\n", pbl_entries);
+ if (nesadapter->free_256pbl == 0) {
+ if (cqp_request->dynamic) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kfree(cqp_request);
+ } else {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ }
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-ENOMEM);
+ } else {
+ opcode |= NES_CQP_CQ_VIRT;
+ nescq->virtual_cq = 1;
+ nesadapter->free_256pbl--;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+ (nescq->hw_cq.cq_number | ((u32)nesdev->ceq_index << 16)));
+
+ if (context) {
+ if (pbl_entries != 1)
+ u64temp = (u64)nespbl->pbl_pbase;
+ else
+ u64temp = le64_to_cpu(nespbl->pbl_vbase[0]);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX,
+ nes_ucontext->mmap_db_index[0]);
+ } else {
+ u64temp = (u64)nescq->hw_cq.cq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+ }
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+ u64temp = (u64)(unsigned long)&nescq->hw_cq;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
+ cpu_to_le32((u32)(u64temp >> 1));
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+ cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ nes_debug(NES_DBG_CQ, "Waiting for create iWARP CQ%u to complete.\n",
+ nescq->hw_cq.cq_number);
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT * 2);
+ nes_debug(NES_DBG_CQ, "Create iWARP CQ%u completed, wait_event_timeout ret = %d.\n",
+ nescq->hw_cq.cq_number, ret);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ nes_debug(NES_DBG_CQ, "iWARP CQ%u create timeout expired, major code = 0x%04X,"
+ " minor code = 0x%04X\n",
+ nescq->hw_cq.cq_number, cqp_request->major_code, cqp_request->minor_code);
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-EIO);
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+
+ if (context) {
+ /* free the nespbl */
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+ nespbl->pbl_pbase);
+ kfree(nespbl);
+ resp.cq_id = nescq->hw_cq.cq_number;
+ resp.cq_size = nescq->hw_cq.cq_size;
+ resp.mmap_db_index = 0;
+ if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ return &nescq->ibcq;
+}
+
+
+/**
+ * nes_destroy_cq
+ */
+static int nes_destroy_cq(struct ib_cq *ib_cq)
+{
+ struct nes_cq *nescq;
+ struct nes_device *nesdev;
+ struct nes_vnic *nesvnic;
+ struct nes_adapter *nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ u32 opcode = 0;
+ int ret;
+
+ if (ib_cq == NULL)
+ return 0;
+
+ nescq = to_nescq(ib_cq);
+ nesvnic = to_nesvnic(ib_cq->device);
+ nesdev = nesvnic->nesdev;
+ nesadapter = nesdev->nesadapter;
+
+ nes_debug(NES_DBG_CQ, "Destroy CQ%u\n", nescq->hw_cq.cq_number);
+
+ /* Send DestroyCQ request to CQP */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_CQ, "Failed to get a cqp_request.\n");
+ return -ENOMEM;
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+ opcode = NES_CQP_DESTROY_CQ | (nescq->hw_cq.cq_size << 16);
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ if (nescq->virtual_cq == 1) {
+ nesadapter->free_256pbl++;
+ if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
+ printk(KERN_ERR PFX "%s: free 256B PBLs(%u) has exceeded the max(%u)\n",
+ __FUNCTION__, nesadapter->free_256pbl, nesadapter->max_256pbl);
+ }
+ } else if (nescq->virtual_cq == 2) {
+ nesadapter->free_4kpbl++;
+ if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
+ printk(KERN_ERR PFX "%s: free 4K PBLs(%u) has exceeded the max(%u)\n",
+ __FUNCTION__, nesadapter->free_4kpbl, nesadapter->max_4kpbl);
+ }
+ opcode |= NES_CQP_CQ_4KB_CHUNK;
+ }
+
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+ (nescq->hw_cq.cq_number | ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 16)));
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, nescq->hw_cq.cq_number);
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ nes_debug(NES_DBG_CQ, "Waiting for destroy iWARP CQ%u to complete.\n",
+ nescq->hw_cq.cq_number);
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_CQ, "Destroy iWARP CQ%u completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ nescq->hw_cq.cq_number, ret, cqp_request->major_code,
+ cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ if (!ret) {
+ nes_debug(NES_DBG_CQ, "iWARP CQ%u destroy timeout expired\n",
+ nescq->hw_cq.cq_number);
+ ret = -ETIME;
+ } else {
+ nes_debug(NES_DBG_CQ, "iWARP CQ%u destroy failed\n",
+ nescq->hw_cq.cq_number);
+ ret = -EIO;
+ }
+ } else {
+ ret = 0;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ }
+
+ if (nescq->cq_mem_size)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size,
+ (void *)nescq->hw_cq.cq_vbase, nescq->hw_cq.cq_pbase);
+ kfree(nescq);
+
+ return ret;
+}
+
+
+/**
+ * nes_reg_mr
+ */
+static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
+ u32 stag, u64 region_length, struct nes_root_vpbl *root_vpbl,
+ dma_addr_t single_buffer, u16 pbl_count, u16 residual_page_count,
+ int acc, u64 *iova_start)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ /* int count; */
+ u32 opcode = 0;
+ u16 major_code;
+
+ /* Register the region with the adapter */
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+ return -ENOMEM;
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ /* track PBL resources */
+ if (pbl_count != 0) {
+ if (pbl_count > 1) {
+ /* Two level PBL */
+ if ((pbl_count+1) > nesadapter->free_4kpbl) {
+ nes_debug(NES_DBG_MR, "Out of 4KB Pbls for two level request.\n");
+ if (cqp_request->dynamic) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kfree(cqp_request);
+ } else {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ }
+ return -ENOMEM;
+ } else {
+ nesadapter->free_4kpbl -= pbl_count+1;
+ }
+ } else if (residual_page_count > 32) {
+ if (pbl_count > nesadapter->free_4kpbl) {
+ nes_debug(NES_DBG_MR, "Out of 4KB Pbls.\n");
+ if (cqp_request->dynamic) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kfree(cqp_request);
+ } else {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ }
+ return -ENOMEM;
+ } else {
+ nesadapter->free_4kpbl -= pbl_count;
+ }
+ } else {
+ if (pbl_count > nesadapter->free_256pbl) {
+ nes_debug(NES_DBG_MR, "Out of 256B Pbls.\n");
+ if (cqp_request->dynamic) {
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ kfree(cqp_request);
+ } else {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ }
+ return -ENOMEM;
+ } else {
+ nesadapter->free_256pbl -= pbl_count;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+ opcode = NES_CQP_REGISTER_STAG | NES_CQP_STAG_RIGHTS_LOCAL_READ |
+ NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
+ if (acc & IB_ACCESS_LOCAL_WRITE)
+ opcode |= NES_CQP_STAG_RIGHTS_LOCAL_WRITE;
+ if (acc & IB_ACCESS_REMOTE_WRITE)
+ opcode |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_REM_ACC_EN;
+ if (acc & IB_ACCESS_REMOTE_READ)
+ opcode |= NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_REM_ACC_EN;
+ if (acc & IB_ACCESS_MW_BIND)
+ opcode |= NES_CQP_STAG_RIGHTS_WINDOW_BIND | NES_CQP_STAG_REM_ACC_EN;
+
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_VA_LOW_IDX, *iova_start);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_LOW_IDX, region_length);
+
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
+ cpu_to_le32((u32)(region_length >> 8) & 0xff000000);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] |=
+ cpu_to_le32(nespd->pd_id & 0x00007fff);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
+
+ if (pbl_count == 0) {
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, single_buffer);
+ } else {
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, root_vpbl->pbl_pbase);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX, pbl_count);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX,
+ (((pbl_count - 1) * 4096) + (residual_page_count*8)));
+
+ if ((pbl_count > 1) || (residual_page_count > 32))
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_STAG_PBL_BLK_SIZE);
+ }
+ barrier();
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ stag, ret, cqp_request->major_code, cqp_request->minor_code);
+ major_code = cqp_request->major_code;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ if (!ret)
+ return -ETIME;
+ else if (major_code)
+ return -EIO;
+ else
+ return 0;
+
+ return 0;
+}
+
+
+/**
+ * nes_reg_phys_mr
+ */
+static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
+ struct ib_phys_buf *buffer_list, int num_phys_buf, int acc,
+ u64 * iova_start)
+{
+ u64 region_length;
+ struct nes_pd *nespd = to_nespd(ib_pd);
+ struct nes_vnic *nesvnic = to_nesvnic(ib_pd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_mr *nesmr;
+ struct ib_mr *ibmr;
+ struct nes_vpbl vpbl;
+ struct nes_root_vpbl root_vpbl;
+ u32 stag;
+ u32 i;
+ u32 stag_index = 0;
+ u32 next_stag_index = 0;
+ u32 driver_key = 0;
+ u32 root_pbl_index = 0;
+ u32 cur_pbl_index = 0;
+ int err = 0, pbl_depth = 0;
+ int ret = 0;
+ u16 pbl_count = 0;
+ u8 single_page = 1;
+ u8 stag_key = 0;
+
+ pbl_depth = 0;
+ region_length = 0;
+ vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_pbase = 0;
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+ if (num_phys_buf > (1024*512)) {
+ return ERR_PTR(-E2BIG);
+ }
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, nesadapter->max_mr,
+ &stag_index, &next_stag_index);
+ if (err) {
+ return ERR_PTR(err);
+ }
+
+ nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < num_phys_buf; i++) {
+
+ if ((i & 0x01FF) == 0) {
+ if (root_pbl_index == 1) {
+ /* Allocate the root PBL */
+ root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 8192,
+ &root_vpbl.pbl_pbase);
+ nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
+ root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
+ if (!root_vpbl.pbl_vbase) {
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ return ERR_PTR(-ENOMEM);
+ }
+ root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024, GFP_KERNEL);
+ if (!root_vpbl.leaf_vpbl) {
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ return ERR_PTR(-ENOMEM);
+ }
+ root_vpbl.pbl_vbase[0].pa_low = cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[0].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[0] = vpbl;
+ }
+ /* Allocate a 4K buffer for the PBL */
+ vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &vpbl.pbl_pbase);
+ nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%016lX\n",
+ vpbl.pbl_vbase, (unsigned long)vpbl.pbl_pbase);
+ if (!vpbl.pbl_vbase) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ ibmr = ERR_PTR(-ENOMEM);
+ kfree(nesmr);
+ goto reg_phys_err;
+ }
+ /* Fill in the root table */
+ if (1 <= root_pbl_index) {
+ root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+ }
+ root_pbl_index++;
+ cur_pbl_index = 0;
+ }
+ if (buffer_list[i].addr & ~PAGE_MASK) {
+ /* TODO: Unwind allocated buffers */
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
+ (unsigned int) buffer_list[i].addr);
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_phys_err;
+ }
+
+ if (!buffer_list[i].size) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_phys_err;
+ }
+
+ region_length += buffer_list[i].size;
+ if ((i != 0) && (single_page)) {
+ if ((buffer_list[i-1].addr+PAGE_SIZE) != buffer_list[i].addr)
+ single_page = 0;
+ }
+ vpbl.pbl_vbase[cur_pbl_index].pa_low = cpu_to_le32((u32)buffer_list[i].addr);
+ vpbl.pbl_vbase[cur_pbl_index++].pa_high =
+ cpu_to_le32((u32)((((u64)buffer_list[i].addr) >> 32)));
+ }
+
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+
+ nes_debug(NES_DBG_MR, "Registering STag 0x%08X, VA = 0x%016lX,"
+ " length = 0x%016lX, index = 0x%08X\n",
+ stag, (unsigned long)*iova_start, (unsigned long)region_length, stag_index);
+
+ region_length -= (*iova_start)&PAGE_MASK;
+
+ /* Make the leaf PBL the root if only one PBL */
+ if (root_pbl_index == 1) {
+ root_vpbl.pbl_pbase = vpbl.pbl_pbase;
+ }
+
+ if (single_page) {
+ pbl_count = 0;
+ } else {
+ pbl_count = root_pbl_index;
+ }
+ ret = nes_reg_mr(nesdev, nespd, stag, region_length, &root_vpbl,
+ buffer_list[0].addr, pbl_count, (u16)cur_pbl_index, acc, iova_start);
+
+ if (ret == 0) {
+ nesmr->ibmr.rkey = stag;
+ nesmr->ibmr.lkey = stag;
+ nesmr->mode = IWNES_MEMREG_TYPE_MEM;
+ ibmr = &nesmr->ibmr;
+ nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
+ nesmr->pbls_used = pbl_count;
+ if (pbl_count > 1) {
+ nesmr->pbls_used++;
+ }
+ } else {
+ kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
+ }
+
+ reg_phys_err:
+ /* free the resources */
+ if (root_pbl_index == 1) {
+ /* single PBL case */
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, vpbl.pbl_pbase);
+ } else {
+ for (i=0; i<root_pbl_index; i++) {
+ pci_free_consistent(nesdev->pcidev, 4096, root_vpbl.leaf_vpbl[i].pbl_vbase,
+ root_vpbl.leaf_vpbl[i].pbl_pbase);
+ }
+ kfree(root_vpbl.leaf_vpbl);
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ }
+
+ return ibmr;
+}
+
+
+/**
+ * nes_get_dma_mr
+ */
+static struct ib_mr *nes_get_dma_mr(struct ib_pd *pd, int acc)
+{
+ struct ib_phys_buf bl;
+ u64 kva = 0;
+
+ nes_debug(NES_DBG_MR, "\n");
+
+ bl.size = (u64)0xffffffffffULL;
+ bl.addr = 0;
+ return nes_reg_phys_mr(pd, &bl, 1, acc, &kva);
+}
+
+
+/**
+ * nes_reg_user_mr
+ */
+static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt, int acc, struct ib_udata *udata)
+{
+ u64 iova_start;
+ __le64 *pbl;
+ u64 region_length;
+ dma_addr_t last_dma_addr = 0;
+ dma_addr_t first_dma_addr = 0;
+ struct nes_pd *nespd = to_nespd(pd);
+ struct nes_vnic *nesvnic = to_nesvnic(pd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct ib_mr *ibmr = ERR_PTR(-EINVAL);
+ struct ib_umem_chunk *chunk;
+ struct nes_ucontext *nes_ucontext;
+ struct nes_pbl *nespbl;
+ struct nes_mr *nesmr;
+ struct ib_umem *region;
+ struct nes_mem_reg_req req;
+ struct nes_vpbl vpbl;
+ struct nes_root_vpbl root_vpbl;
+ int nmap_index, page_index;
+ int page_count = 0;
+ int err, pbl_depth = 0;
+ int chunk_pages;
+ int ret;
+ u32 stag;
+ u32 stag_index = 0;
+ u32 next_stag_index;
+ u32 driver_key;
+ u32 root_pbl_index = 0;
+ u32 cur_pbl_index = 0;
+ u32 skip_pages;
+ u16 pbl_count;
+ u8 single_page = 1;
+ u8 stag_key;
+
+ region = ib_umem_get(pd->uobject->context, start, length, acc);
+ if (IS_ERR(region)) {
+ return (struct ib_mr *)region;
+ }
+
+ nes_debug(NES_DBG_MR, "User base = 0x%lX, Virt base = 0x%lX, length = %u,"
+ " offset = %u, page size = %u.\n",
+ (unsigned long int)start, (unsigned long int)virt, (u32)length,
+ region->offset, region->page_size);
+
+ skip_pages = ((u32)region->offset) >> 12;
+
+ if (ib_copy_from_udata(&req, udata, sizeof(req)))
+ return ERR_PTR(-EFAULT);
+ nes_debug(NES_DBG_MR, "Memory Registration type = %08X.\n", req.reg_type);
+
+ switch (req.reg_type) {
+ case IWNES_MEMREG_TYPE_MEM:
+ pbl_depth = 0;
+ region_length = 0;
+ vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_pbase = 0;
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = next_stag_index & 0x70000000;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+ nesadapter->max_mr, &stag_index, &next_stag_index);
+ if (err) {
+ ib_umem_release(region);
+ return ERR_PTR(err);
+ }
+
+ nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return ERR_PTR(-ENOMEM);
+ }
+ nesmr->region = region;
+
+ list_for_each_entry(chunk, ®ion->chunk_list, list) {
+ nes_debug(NES_DBG_MR, "Chunk: nents = %u, nmap = %u .\n",
+ chunk->nents, chunk->nmap);
+ for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) {
+ if (sg_dma_address(&chunk->page_list[nmap_index]) & ~PAGE_MASK) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
+ (unsigned int) sg_dma_address(&chunk->page_list[nmap_index]));
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+
+ if (!sg_dma_len(&chunk->page_list[nmap_index])) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+
+ region_length += sg_dma_len(&chunk->page_list[nmap_index]);
+ chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12;
+ region_length -= skip_pages << 12;
+ for (page_index=skip_pages; page_index < chunk_pages; page_index++) {
+ skip_pages = 0;
+ if ((page_count!=0)&&(page_count<<12)-(region->offset&(4096-1))>=region->length)
+ goto enough_pages;
+ if ((page_count&0x01FF) == 0) {
+ if (page_count>(1024*512)) {
+ ib_umem_release(region);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter,
+ nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ ibmr = ERR_PTR(-E2BIG);
+ goto reg_user_mr_err;
+ }
+ if (root_pbl_index == 1) {
+ root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
+ 8192, &root_vpbl.pbl_pbase);
+ nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
+ root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
+ if (!root_vpbl.pbl_vbase) {
+ ib_umem_release(region);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
+ goto reg_user_mr_err;
+ }
+ root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024,
+ GFP_KERNEL);
+ if (!root_vpbl.leaf_vpbl) {
+ ib_umem_release(region);
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
+ goto reg_user_mr_err;
+ }
+ root_vpbl.pbl_vbase[0].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[0].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[0] = vpbl;
+ }
+ vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &vpbl.pbl_pbase);
+ nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n",
+ vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase);
+ if (!vpbl.pbl_vbase) {
+ ib_umem_release(region);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ ibmr = ERR_PTR(-ENOMEM);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+ if (1 <= root_pbl_index) {
+ root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
+ root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+ }
+ root_pbl_index++;
+ cur_pbl_index = 0;
+ }
+ if (single_page) {
+ if (page_count != 0) {
+ if ((last_dma_addr+4096) !=
+ (sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096)))
+ single_page = 0;
+ last_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096);
+ } else {
+ first_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096);
+ last_dma_addr = first_dma_addr;
+ }
+ }
+
+ vpbl.pbl_vbase[cur_pbl_index].pa_low =
+ cpu_to_le32((u32)(sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096)));
+ vpbl.pbl_vbase[cur_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)(sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096))) >> 32)));
+ cur_pbl_index++;
+ page_count++;
+ }
+ }
+ }
+ enough_pages:
+ nes_debug(NES_DBG_MR, "calculating stag, stag_index=0x%08x, driver_key=0x%08x,"
+ " stag_key=0x%08x\n",
+ stag_index, driver_key, stag_key);
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+ if (stag == 0) {
+ stag = 1;
+ }
+
+ iova_start = virt;
+ /* Make the leaf PBL the root if only one PBL */
+ if (root_pbl_index == 1) {
+ root_vpbl.pbl_pbase = vpbl.pbl_pbase;
+ }
+
+ if (single_page) {
+ pbl_count = 0;
+ } else {
+ pbl_count = root_pbl_index;
+ first_dma_addr = 0;
+ }
+ nes_debug(NES_DBG_MR, "Registering STag 0x%08X, VA = 0x%08X, length = 0x%08X,"
+ " index = 0x%08X, region->length=0x%08llx, pbl_count = %u\n",
+ stag, (unsigned int)iova_start,
+ (unsigned int)region_length, stag_index,
+ (unsigned long long)region->length, pbl_count);
+ ret = nes_reg_mr( nesdev, nespd, stag, region->length, &root_vpbl,
+ first_dma_addr, pbl_count, (u16)cur_pbl_index, acc, &iova_start);
+
+ nes_debug(NES_DBG_MR, "ret=%d\n", ret);
+
+ if (ret == 0) {
+ nesmr->ibmr.rkey = stag;
+ nesmr->ibmr.lkey = stag;
+ nesmr->mode = IWNES_MEMREG_TYPE_MEM;
+ ibmr = &nesmr->ibmr;
+ nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
+ nesmr->pbls_used = pbl_count;
+ if (pbl_count > 1) {
+ nesmr->pbls_used++;
+ }
+ } else {
+ ib_umem_release(region);
+ kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
+ }
+
+ reg_user_mr_err:
+ /* free the resources */
+ if (root_pbl_index == 1) {
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ } else {
+ for (page_index=0; page_index<root_pbl_index; page_index++) {
+ pci_free_consistent(nesdev->pcidev, 4096,
+ root_vpbl.leaf_vpbl[page_index].pbl_vbase,
+ root_vpbl.leaf_vpbl[page_index].pbl_pbase);
+ }
+ kfree(root_vpbl.leaf_vpbl);
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ }
+
+ nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr);
+
+ return ibmr;
+ break;
+ case IWNES_MEMREG_TYPE_QP:
+ case IWNES_MEMREG_TYPE_CQ:
+ nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
+ if (!nespbl) {
+ nes_debug(NES_DBG_MR, "Unable to allocate PBL\n");
+ ib_umem_release(region);
+ return ERR_PTR(-ENOMEM);
+ }
+ nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ ib_umem_release(region);
+ kfree(nespbl);
+ nes_debug(NES_DBG_MR, "Unable to allocate nesmr\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ nesmr->region = region;
+ nes_ucontext = to_nesucontext(pd->uobject->context);
+ pbl_depth = region->length >> 12;
+ pbl_depth += (region->length & (4096-1)) ? 1 : 0;
+ nespbl->pbl_size = pbl_depth*sizeof(u64);
+ if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
+ nes_debug(NES_DBG_MR, "Attempting to allocate QP PBL memory");
+ } else {
+ nes_debug(NES_DBG_MR, "Attempting to allocate CP PBL memory");
+ }
+
+ nes_debug(NES_DBG_MR, " %u bytes, %u entries.\n",
+ nespbl->pbl_size, pbl_depth);
+ pbl = pci_alloc_consistent(nesdev->pcidev, nespbl->pbl_size,
+ &nespbl->pbl_pbase);
+ if (!pbl) {
+ ib_umem_release(region);
+ kfree(nesmr);
+ kfree(nespbl);
+ nes_debug(NES_DBG_MR, "Unable to allocate PBL memory\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ nespbl->pbl_vbase = (u64 *)pbl;
+ nespbl->user_base = start;
+ nes_debug(NES_DBG_MR, "Allocated PBL memory, %u bytes, pbl_pbase=%p,"
+ " pbl_vbase=%p user_base=0x%lx\n",
+ nespbl->pbl_size, (void *)nespbl->pbl_pbase,
+ (void*)nespbl->pbl_vbase, nespbl->user_base);
+
+ list_for_each_entry(chunk, ®ion->chunk_list, list) {
+ for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) {
+ chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12;
+ chunk_pages += (sg_dma_len(&chunk->page_list[nmap_index]) & (4096-1)) ? 1 : 0;
+ nespbl->page = sg_page(&chunk->page_list[0]);
+ for (page_index=0; page_index<chunk_pages; page_index++) {
+ ((__le32 *)pbl)[0] = cpu_to_le32((u32)
+ (sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096)));
+ ((__le32 *)pbl)[1] = cpu_to_le32(((u64)
+ (sg_dma_address(&chunk->page_list[nmap_index])+
+ (page_index*4096)))>>32);
+ nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl,
+ (unsigned long long)*pbl,
+ le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0]));
+ pbl++;
+ }
+ }
+ }
+ if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
+ list_add_tail(&nespbl->list, &nes_ucontext->qp_reg_mem_list);
+ } else {
+ list_add_tail(&nespbl->list, &nes_ucontext->cq_reg_mem_list);
+ }
+ nesmr->ibmr.rkey = -1;
+ nesmr->ibmr.lkey = -1;
+ nesmr->mode = req.reg_type;
+ return &nesmr->ibmr;
+ break;
+ }
+
+ return ERR_PTR(-ENOSYS);
+}
+
+
+/**
+ * nes_dereg_mr
+ */
+static int nes_dereg_mr(struct ib_mr *ib_mr)
+{
+ struct nes_mr *nesmr = to_nesmr(ib_mr);
+ struct nes_vnic *nesvnic = to_nesvnic(ib_mr->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+ u16 major_code;
+ u16 minor_code;
+
+ if (nesmr->region) {
+ ib_umem_release(nesmr->region);
+ }
+ if (nesmr->mode != IWNES_MEMREG_TYPE_MEM) {
+ kfree(nesmr);
+ return 0;
+ }
+
+ /* Deallocate the region with the adapter */
+
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+ return -ENOMEM;
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+ if (nesmr->pbls_used != 0) {
+ if (nesmr->pbl_4k) {
+ nesadapter->free_4kpbl += nesmr->pbls_used;
+ if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
+ printk(KERN_ERR PFX "free 4KB PBLs(%u) has exceeded the max(%u)\n",
+ nesadapter->free_4kpbl, nesadapter->max_4kpbl);
+ }
+ } else {
+ nesadapter->free_256pbl += nesmr->pbls_used;
+ if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
+ printk(KERN_ERR PFX "free 256B PBLs(%u) has exceeded the max(%u)\n",
+ nesadapter->free_256pbl, nesadapter->max_256pbl);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ NES_CQP_DEALLOCATE_STAG | NES_CQP_STAG_VA_TO |
+ NES_CQP_STAG_DEALLOC_PBLS | NES_CQP_STAG_MR);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, ib_mr->rkey);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ nes_debug(NES_DBG_MR, "Waiting for deallocate STag 0x%08X completed\n", ib_mr->rkey);
+ ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_MR, "Deallocate STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X\n",
+ ib_mr->rkey, ret, cqp_request->major_code, cqp_request->minor_code);
+
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ (ib_mr->rkey & 0x0fffff00) >> 8);
+
+ kfree(nesmr);
+
+ major_code = cqp_request->major_code;
+ minor_code = cqp_request->minor_code;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ if (!ret) {
+ nes_debug(NES_DBG_MR, "Timeout waiting to destroy STag,"
+ " ib_mr=%p, rkey = 0x%08X\n",
+ ib_mr, ib_mr->rkey);
+ return -ETIME;
+ } else if (major_code) {
+ nes_debug(NES_DBG_MR, "Error (0x%04X:0x%04X) while attempting"
+ " to destroy STag, ib_mr=%p, rkey = 0x%08X\n",
+ major_code, minor_code, ib_mr, ib_mr->rkey);
+ return -EIO;
+ } else
+ return 0;
+}
+
+
+/**
+ * show_rev
+ */
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+ struct nes_ib_device *nesibdev =
+ container_of(cdev, struct nes_ib_device, ibdev.class_dev);
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+ nes_debug(NES_DBG_INIT, "\n");
+ return sprintf(buf, "%x\n", nesvnic->nesdev->nesadapter->hw_rev);
+}
+
+
+/**
+ * show_fw_ver
+ */
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+ struct nes_ib_device *nesibdev =
+ container_of(cdev, struct nes_ib_device, ibdev.class_dev);
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+ nes_debug(NES_DBG_INIT, "\n");
+ return sprintf(buf, "%x.%x.%x\n",
+ (int)(nesvnic->nesdev->nesadapter->fw_ver >> 32),
+ (int)(nesvnic->nesdev->nesadapter->fw_ver >> 16) & 0xffff,
+ (int)(nesvnic->nesdev->nesadapter->fw_ver & 0xffff));
+}
+
+
+/**
+ * show_hca
+ */
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+ nes_debug(NES_DBG_INIT, "\n");
+ return sprintf(buf, "NES020\n");
+}
+
+
+/**
+ * show_board
+ */
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+ nes_debug(NES_DBG_INIT, "\n");
+ return sprintf(buf, "%.*s\n", 32, "NES020 Board ID");
+}
+
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *nes_class_attributes[] = {
+ &class_device_attr_hw_rev,
+ &class_device_attr_fw_ver,
+ &class_device_attr_hca_type,
+ &class_device_attr_board_id
+};
+
+
+/**
+ * nes_query_qp
+ */
+static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr)
+{
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+
+ nes_debug(NES_DBG_QP, "\n");
+
+ attr->qp_access_flags = 0;
+ attr->cap.max_send_wr = nesqp->hwqp.sq_size;
+ attr->cap.max_recv_wr = nesqp->hwqp.rq_size;
+ attr->cap.max_recv_sge = 1;
+ if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) {
+ init_attr->cap.max_inline_data = 0;
+ } else {
+ init_attr->cap.max_inline_data = 64;
+ }
+
+ init_attr->event_handler = nesqp->ibqp.event_handler;
+ init_attr->qp_context = nesqp->ibqp.qp_context;
+ init_attr->send_cq = nesqp->ibqp.send_cq;
+ init_attr->recv_cq = nesqp->ibqp.recv_cq;
+ init_attr->srq = nesqp->ibqp.srq = nesqp->ibqp.srq;
+ init_attr->cap = attr->cap;
+
+ return 0;
+}
+
+
+/**
+ * nes_hw_modify_qp
+ */
+int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp,
+ u32 next_iwarp_state, u32 wait_completion)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ /* struct iw_cm_id *cm_id = nesqp->cm_id; */
+ /* struct iw_cm_event cm_event; */
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+ u16 major_code;
+
+ nes_debug(NES_DBG_MOD_QP, "QP%u, refcount=%d\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+ cqp_request = nes_get_cqp_request(nesdev);
+ if (cqp_request == NULL) {
+ nes_debug(NES_DBG_MOD_QP, "Failed to get a cqp_request.\n");
+ return -ENOMEM;
+ }
+ if (wait_completion) {
+ cqp_request->waiting = 1;
+ } else {
+ cqp_request->waiting = 0;
+ }
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+ NES_CQP_MODIFY_QP | NES_CQP_QP_TYPE_IWARP | next_iwarp_state);
+ nes_debug(NES_DBG_MOD_QP, "using next_iwarp_state=%08x, wqe_words=%08x\n",
+ next_iwarp_state, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]));
+ nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+ set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+ set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ if (wait_completion) {
+ /* nes_debug(NES_DBG_MOD_QP, "Waiting for modify iWARP QP%u to complete.\n",
+ nesqp->hwqp.qp_id); */
+ ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+ NES_EVENT_TIMEOUT);
+ nes_debug(NES_DBG_MOD_QP, "Modify iwarp QP%u completed, wait_event_timeout ret=%u, "
+ "CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ nesqp->hwqp.qp_id, ret, cqp_request->major_code, cqp_request->minor_code);
+ major_code = cqp_request->major_code;
+ if (major_code) {
+ nes_debug(NES_DBG_MOD_QP, "Modify iwarp QP%u failed"
+ "CQP Major:Minor codes = 0x%04X:0x%04X, intended next state = 0x%08X.\n",
+ nesqp->hwqp.qp_id, cqp_request->major_code,
+ cqp_request->minor_code, next_iwarp_state);
+ }
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+ if (!ret)
+ return -ETIME;
+ else if (major_code)
+ return -EIO;
+ else
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * nes_modify_qp
+ */
+int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ /* u32 cqp_head; */
+ /* u32 counter; */
+ u32 next_iwarp_state = 0;
+ int err;
+ unsigned long qplockflags;
+ int ret;
+ u16 original_last_aeq;
+ u8 issue_modify_qp = 0;
+ u8 issue_disconnect = 0;
+ u8 dont_wait = 0;
+
+ nes_debug(NES_DBG_MOD_QP, "QP%u: QP State=%u, cur QP State=%u,"
+ " iwarp_state=0x%X, refcount=%d\n",
+ nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state,
+ nesqp->iwarp_state, atomic_read(&nesqp->refcount));
+
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+
+ nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X,"
+ " QP Access Flags=0x%X, attr_mask = 0x%0x\n",
+ nesqp->hwqp.qp_id, nesqp->hw_iwarp_state,
+ nesqp->hw_tcp_state, attr->qp_access_flags, attr_mask);
+
+ if (attr_mask & IB_QP_STATE) {
+ switch (attr->qp_state) {
+ case IB_QPS_INIT:
+ nes_debug(NES_DBG_MOD_QP, "QP%u: new state = init\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_RTR:
+ nes_debug(NES_DBG_MOD_QP, "QP%u: new state = rtr\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_RTS:
+ nes_debug(NES_DBG_MOD_QP, "QP%u: new state = rts\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ if (nesqp->cm_id == NULL) {
+ nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n",
+ nesqp->hwqp.qp_id );
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS;
+ if (nesqp->iwarp_state != NES_CQP_QP_IWARP_STATE_RTS)
+ next_iwarp_state |= NES_CQP_QP_CONTEXT_VALID |
+ NES_CQP_QP_ARP_VALID | NES_CQP_QP_ORD_VALID;
+ issue_modify_qp = 1;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_ESTABLISHED;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_RTS;
+ nesqp->hte_added = 1;
+ break;
+ case IB_QPS_SQD:
+ issue_modify_qp = 1;
+ nes_debug(NES_DBG_MOD_QP, "QP%u: new state=closing. SQ head=%u, SQ tail=%u\n",
+ nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail);
+ if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return 0;
+ } else {
+ if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
+ nes_debug(NES_DBG_MOD_QP, "QP%u: State change to closing"
+ " ignored due to current iWARP state\n",
+ nesqp->hwqp.qp_id);
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) {
+ nes_debug(NES_DBG_MOD_QP, "QP%u: State change to closing"
+ " already done based on hw state.\n",
+ nesqp->hwqp.qp_id);
+ issue_modify_qp = 0;
+ nesqp->in_disconnect = 0;
+ }
+ switch (nesqp->hw_iwarp_state) {
+ case NES_AEQE_IWARP_STATE_CLOSING:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+ case NES_AEQE_IWARP_STATE_TERMINATE:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+ break;
+ case NES_AEQE_IWARP_STATE_ERROR:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
+ break;
+ default:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+ nesqp->in_disconnect = 1;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+ break;
+ }
+ }
+ break;
+ case IB_QPS_SQE:
+ nes_debug(NES_DBG_MOD_QP, "QP%u: new state = terminate\n",
+ nesqp->hwqp.qp_id);
+ if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
+ issue_modify_qp = 1;
+ nesqp->in_disconnect = 1;
+ break;
+ case IB_QPS_ERR:
+ case IB_QPS_RESET:
+ if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ }
+ nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n",
+ nesqp->hwqp.qp_id);
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
+ /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
+ if (nesqp->hte_added) {
+ nes_debug(NES_DBG_MOD_QP, "set CQP_QP_DEL_HTE\n");
+ next_iwarp_state |= NES_CQP_QP_DEL_HTE;
+ nesqp->hte_added = 0;
+ }
+ if ((nesqp->hw_tcp_state > NES_AEQE_TCP_STATE_CLOSED) &&
+ (nesqp->hw_tcp_state != NES_AEQE_TCP_STATE_TIME_WAIT)) {
+ next_iwarp_state |= NES_CQP_QP_RESET;
+ nesqp->in_disconnect = 1;
+ } else {
+ nes_debug(NES_DBG_MOD_QP, "QP%u NOT setting NES_CQP_QP_RESET since TCP state = %u\n",
+ nesqp->hwqp.qp_id, nesqp->hw_tcp_state);
+ dont_wait = 1;
+ }
+ issue_modify_qp = 1;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
+ break;
+ default:
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -EINVAL;
+ break;
+ }
+
+ nesqp->ibqp_state = attr->qp_state;
+ if (((nesqp->iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) ==
+ (u32)NES_CQP_QP_IWARP_STATE_RTS) &&
+ ((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) >
+ (u32)NES_CQP_QP_IWARP_STATE_RTS)) {
+ nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
+ nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
+ nesqp->iwarp_state);
+ issue_disconnect = 1;
+ } else {
+ nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
+ nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
+ nesqp->iwarp_state);
+ }
+ }
+
+ if (attr_mask & IB_QP_ACCESS_FLAGS) {
+ if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE) {
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
+ NES_QPCONTEXT_MISC_RDMA_READ_EN);
+ issue_modify_qp = 1;
+ }
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) {
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN);
+ issue_modify_qp = 1;
+ }
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ) {
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_READ_EN);
+ issue_modify_qp = 1;
+ }
+ if (attr->qp_access_flags & IB_ACCESS_MW_BIND) {
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WBIND_EN);
+ issue_modify_qp = 1;
+ }
+
+ if (nesqp->user_mode) {
+ nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
+ NES_QPCONTEXT_MISC_RDMA_READ_EN);
+ issue_modify_qp = 1;
+ }
+ }
+
+ original_last_aeq = nesqp->last_aeq;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+
+ nes_debug(NES_DBG_MOD_QP, "issue_modify_qp=%u\n", issue_modify_qp);
+
+ ret = 0;
+
+
+ if (issue_modify_qp) {
+ nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n");
+ ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1);
+ if (ret)
+ nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)"
+ " failed for QP%u.\n",
+ next_iwarp_state, nesqp->hwqp.qp_id);
+
+ }
+
+ if ((issue_modify_qp) && (nesqp->ibqp_state > IB_QPS_RTS)) {
+ nes_debug(NES_DBG_MOD_QP, "QP%u Issued ModifyQP refcount (%d),"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ if ((!ret) ||
+ ((original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) &&
+ (ret))) {
+ if (dont_wait) {
+ if (nesqp->cm_id && nesqp->hw_tcp_state != 0) {
+ nes_debug(NES_DBG_MOD_QP, "QP%u Queuing fake disconnect for QP refcount (%d),"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ /* this one is for the cm_disconnect thread */
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_cm_disconn(nesqp);
+ } else {
+ nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ } else {
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ if (nesqp->cm_id) {
+ /* These two are for the timer thread */
+ if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
+ nes_add_ref(&nesqp->ibqp);
+ nesqp->cm_id->add_ref(nesqp->cm_id);
+ nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
+ " need ae to finish up, original_last_aeq = 0x%04X."
+ " last_aeq = 0x%04X, scheduling timer.\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ schedule_nes_timer(nesqp->cm_node, (struct sk_buff *) nesqp, NES_TIMER_TYPE_CLOSE, 1, 0);
+ }
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
+ " need ae to finish up, original_last_aeq = 0x%04X."
+ " last_aeq = 0x%04X.\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ }
+ }
+ } else {
+ nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ } else {
+ nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+
+ err = 0;
+
+ nes_debug(NES_DBG_MOD_QP, "QP%u Leaving, refcount=%d\n",
+ nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+ return err;
+}
+
+
+/**
+ * nes_muticast_attach
+ */
+static int nes_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ nes_debug(NES_DBG_INIT, "\n");
+ return -ENOSYS;
+}
+
+
+/**
+ * nes_multicast_detach
+ */
+static int nes_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ nes_debug(NES_DBG_INIT, "\n");
+ return -ENOSYS;
+}
+
+
+/**
+ * nes_process_mad
+ */
+static int nes_process_mad(struct ib_device *ibdev, int mad_flags,
+ u8 port_num, struct ib_wc *in_wc, struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ nes_debug(NES_DBG_INIT, "\n");
+ return -ENOSYS;
+}
+
+static inline void
+fill_wqe_sg_send(struct nes_hw_qp_wqe *wqe, struct ib_send_wr *ib_wr, u32 uselkey)
+{
+ int sge_index;
+ int total_payload_length = 0;
+ for (sge_index = 0; sge_index < ib_wr->num_sge; sge_index++) {
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX+(sge_index*4),
+ ib_wr->sg_list[sge_index].addr);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_LENGTH0_IDX + (sge_index*4),
+ ib_wr->sg_list[sge_index].length);
+ if (uselkey)
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX + (sge_index*4),
+ (ib_wr->sg_list[sge_index].lkey));
+ else
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX + (sge_index*4), 0);
+
+ total_payload_length += ib_wr->sg_list[sge_index].length;
+ }
+ nes_debug(NES_DBG_IW_TX, "UC UC UC, sending total_payload_length=%u \n",
+ total_payload_length);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
+ total_payload_length);
+}
+
+/**
+ * nes_post_send
+ */
+static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+ struct ib_send_wr **bad_wr)
+{
+ u64 u64temp;
+ unsigned long flags = 0;
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ struct nes_hw_qp_wqe *wqe;
+ int err;
+ u32 qsize = nesqp->hwqp.sq_size;
+ u32 head;
+ u32 wqe_misc;
+ u32 wqe_count;
+ u32 counter;
+ u32 total_payload_length;
+
+ err = 0;
+ wqe_misc = 0;
+ wqe_count = 0;
+ total_payload_length = 0;
+
+ if (nesqp->ibqp_state > IB_QPS_RTS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+
+ head = nesqp->hwqp.sq_head;
+
+ while (ib_wr) {
+ /* Check for SQ overflow */
+ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
+ err = -EINVAL;
+ break;
+ }
+
+ wqe = &nesqp->hwqp.sq_vbase[head];
+ /* nes_debug(NES_DBG_IW_TX, "processing sq wqe for QP%u at %p, head = %u.\n",
+ nesqp->hwqp.qp_id, wqe, head); */
+ nes_fill_init_qp_wqe(wqe, nesqp, head);
+ u64temp = (u64)(ib_wr->wr_id);
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX,
+ u64temp);
+ switch (ib_wr->opcode) {
+ case IB_WR_SEND:
+ if (ib_wr->send_flags & IB_SEND_SOLICITED) {
+ wqe_misc = NES_IWARP_SQ_OP_SENDSE;
+ } else {
+ wqe_misc = NES_IWARP_SQ_OP_SEND;
+ }
+ if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+ err = -EINVAL;
+ break;
+ }
+ if (ib_wr->send_flags & IB_SEND_FENCE) {
+ wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+ }
+ if ((ib_wr->send_flags & IB_SEND_INLINE) &&
+ ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
+ (ib_wr->sg_list[0].length <= 64)) {
+ memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
+ (void *)(unsigned long)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
+ ib_wr->sg_list[0].length);
+ wqe_misc |= NES_IWARP_SQ_WQE_IMM_DATA;
+ } else {
+ fill_wqe_sg_send(wqe, ib_wr, 1);
+ }
+
+ break;
+ case IB_WR_RDMA_WRITE:
+ wqe_misc = NES_IWARP_SQ_OP_RDMAW;
+ if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+ nes_debug(NES_DBG_IW_TX, "Exceeded max sge, ib_wr=%u, max=%u\n",
+ ib_wr->num_sge,
+ nesdev->nesadapter->max_sge);
+ err = -EINVAL;
+ break;
+ }
+ if (ib_wr->send_flags & IB_SEND_FENCE) {
+ wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+ }
+
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
+ ib_wr->wr.rdma.rkey);
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
+ ib_wr->wr.rdma.remote_addr);
+
+ if ((ib_wr->send_flags & IB_SEND_INLINE) &&
+ ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
+ (ib_wr->sg_list[0].length <= 64)) {
+ memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
+ (void *)(unsigned long)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
+ ib_wr->sg_list[0].length);
+ wqe_misc |= NES_IWARP_SQ_WQE_IMM_DATA;
+ } else {
+ fill_wqe_sg_send(wqe, ib_wr, 1);
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] =
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX];
+ break;
+ case IB_WR_RDMA_READ:
+ /* iWARP only supports 1 sge for RDMA reads */
+ if (ib_wr->num_sge > 1) {
+ nes_debug(NES_DBG_IW_TX, "Exceeded max sge, ib_wr=%u, max=1\n",
+ ib_wr->num_sge);
+ err = -EINVAL;
+ break;
+ }
+ wqe_misc = NES_IWARP_SQ_OP_RDMAR;
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
+ ib_wr->wr.rdma.remote_addr);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
+ ib_wr->wr.rdma.rkey);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX,
+ ib_wr->sg_list->length);
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
+ ib_wr->sg_list->addr);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX,
+ ib_wr->sg_list->lkey);
+ break;
+ default:
+ /* error */
+ err = -EINVAL;
+ break;
+ }
+
+ if (ib_wr->send_flags & IB_SEND_SIGNALED) {
+ wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(wqe_misc);
+
+ ib_wr = ib_wr->next;
+ head++;
+ wqe_count++;
+ if (head >= qsize)
+ head = 0;
+
+ }
+
+ nesqp->hwqp.sq_head = head;
+ barrier();
+ while (wqe_count) {
+ counter = min(wqe_count, ((u32)255));
+ wqe_count -= counter;
+ nes_write32(nesdev->regs + NES_WQE_ALLOC,
+ (counter << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+ }
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+
+ if (err)
+ *bad_wr = ib_wr;
+ return err;
+}
+
+
+/**
+ * nes_post_recv
+ */
+static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+ struct ib_recv_wr **bad_wr)
+{
+ u64 u64temp;
+ unsigned long flags = 0;
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ struct nes_hw_qp_wqe *wqe;
+ int err = 0;
+ int sge_index;
+ u32 qsize = nesqp->hwqp.rq_size;
+ u32 head;
+ u32 wqe_count = 0;
+ u32 counter;
+ u32 total_payload_length;
+
+ if (nesqp->ibqp_state > IB_QPS_RTS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+
+ head = nesqp->hwqp.rq_head;
+
+ while (ib_wr) {
+ if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+ err = -EINVAL;
+ break;
+ }
+ /* Check for RQ overflow */
+ if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) {
+ err = -EINVAL;
+ break;
+ }
+
+ nes_debug(NES_DBG_IW_RX, "ibwr sge count = %u.\n", ib_wr->num_sge);
+ wqe = &nesqp->hwqp.rq_vbase[head];
+
+ /* nes_debug(NES_DBG_IW_RX, "QP%u:processing rq wqe at %p, head = %u.\n",
+ nesqp->hwqp.qp_id, wqe, head); */
+ nes_fill_init_qp_wqe(wqe, nesqp, head);
+ u64temp = (u64)(ib_wr->wr_id);
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX,
+ u64temp);
+ total_payload_length = 0;
+ for (sge_index=0; sge_index < ib_wr->num_sge; sge_index++) {
+ set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_FRAG0_LOW_IDX+(sge_index*4),
+ ib_wr->sg_list[sge_index].addr);
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_LENGTH0_IDX+(sge_index*4),
+ ib_wr->sg_list[sge_index].length);
+ set_wqe_32bit_value(wqe->wqe_words,NES_IWARP_RQ_WQE_STAG0_IDX+(sge_index*4),
+ ib_wr->sg_list[sge_index].lkey);
+
+ total_payload_length += ib_wr->sg_list[sge_index].length;
+ }
+ set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX,
+ total_payload_length);
+
+ ib_wr = ib_wr->next;
+ head++;
+ wqe_count++;
+ if (head >= qsize)
+ head = 0;
+ }
+
+ nesqp->hwqp.rq_head = head;
+ barrier();
+ while (wqe_count) {
+ counter = min(wqe_count, ((u32)255));
+ wqe_count -= counter;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter<<24) | nesqp->hwqp.qp_id);
+ }
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+
+ if (err)
+ *bad_wr = ib_wr;
+ return err;
+}
+
+
+/**
+ * nes_poll_cq
+ */
+static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+{
+ u64 u64temp;
+ u64 wrid;
+ /* u64 u64temp; */
+ unsigned long flags = 0;
+ struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_cq *nescq = to_nescq(ibcq);
+ struct nes_qp *nesqp;
+ struct nes_hw_cqe cqe;
+ u32 head;
+ u32 wq_tail;
+ u32 cq_size;
+ u32 cqe_count = 0;
+ u32 wqe_index;
+ u32 u32temp;
+ /* u32 counter; */
+
+ nes_debug(NES_DBG_CQ, "\n");
+
+ spin_lock_irqsave(&nescq->lock, flags);
+
+ head = nescq->hw_cq.cq_head;
+ cq_size = nescq->hw_cq.cq_size;
+
+ while (cqe_count < num_entries) {
+ if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
+ NES_CQE_VALID) {
+ cqe = nescq->hw_cq.cq_vbase[head];
+ nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+ u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+ wqe_index = u32temp &
+ (nesdev->nesadapter->max_qp_wr - 1);
+ u32temp &= ~(NES_SW_CONTEXT_ALIGN-1);
+ /* parse CQE, get completion context from WQE (either rq or sq */
+ u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+ ((u64)u32temp);
+ nesqp = *((struct nes_qp **)&u64temp);
+ memset(entry, 0, sizeof *entry);
+ if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) {
+ entry->status = IB_WC_SUCCESS;
+ } else {
+ entry->status = IB_WC_WR_FLUSH_ERR;
+ }
+
+ entry->qp = &nesqp->ibqp;
+ entry->src_qp = nesqp->hwqp.qp_id;
+
+ if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) {
+ if (nesqp->skip_lsmm) {
+ nesqp->skip_lsmm = 0;
+ wq_tail = nesqp->hwqp.sq_tail++;
+ }
+
+ /* Working on a SQ Completion*/
+ wq_tail = wqe_index;
+ nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1);
+ wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) |
+ ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX])));
+ entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]);
+
+ switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) {
+ case NES_IWARP_SQ_OP_RDMAW:
+ nes_debug(NES_DBG_CQ, "Operation = RDMA WRITE.\n");
+ entry->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case NES_IWARP_SQ_OP_RDMAR:
+ nes_debug(NES_DBG_CQ, "Operation = RDMA READ.\n");
+ entry->opcode = IB_WC_RDMA_READ;
+ entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]);
+ break;
+ case NES_IWARP_SQ_OP_SENDINV:
+ case NES_IWARP_SQ_OP_SENDSEINV:
+ case NES_IWARP_SQ_OP_SEND:
+ case NES_IWARP_SQ_OP_SENDSE:
+ nes_debug(NES_DBG_CQ, "Operation = Send.\n");
+ entry->opcode = IB_WC_SEND;
+ break;
+ }
+ } else {
+ /* Working on a RQ Completion*/
+ wq_tail = wqe_index;
+ nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1);
+ entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]);
+ wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) |
+ ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32);
+ entry->opcode = IB_WC_RECV;
+ }
+ entry->wr_id = wrid;
+
+ if (++head >= cq_size)
+ head = 0;
+ cqe_count++;
+ nescq->polled_completions++;
+ if ((nescq->polled_completions > (cq_size / 2)) ||
+ (nescq->polled_completions == 255)) {
+ nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes"
+ " are pending %u of %u.\n",
+ nescq->hw_cq.cq_number, nescq->polled_completions, cq_size);
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+ nescq->polled_completions = 0;
+ }
+ entry++;
+ } else
+ break;
+ }
+
+ if (nescq->polled_completions) {
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+ nescq->polled_completions = 0;
+ }
+
+ nescq->hw_cq.cq_head = head;
+ nes_debug(NES_DBG_CQ, "Reporting %u completions for CQ%u.\n",
+ cqe_count, nescq->hw_cq.cq_number);
+
+ spin_unlock_irqrestore(&nescq->lock, flags);
+
+ return cqe_count;
+}
+
+
+/**
+ * nes_req_notify_cq
+ */
+static int nes_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
+ {
+ struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_cq *nescq = to_nescq(ibcq);
+ u32 cq_arm;
+
+ nes_debug(NES_DBG_CQ, "Requesting notification for CQ%u.\n",
+ nescq->hw_cq.cq_number);
+
+ cq_arm = nescq->hw_cq.cq_number;
+ if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
+ cq_arm |= NES_CQE_ALLOC_NOTIFY_NEXT;
+ else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
+ cq_arm |= NES_CQE_ALLOC_NOTIFY_SE;
+ else
+ return -EINVAL;
+
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq_arm);
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+ return 0;
+}
+
+
+/**
+ * nes_init_ofa_device
+ */
+struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
+{
+ struct nes_ib_device *nesibdev;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+
+ nesibdev = (struct nes_ib_device *)ib_alloc_device(sizeof(struct nes_ib_device));
+ if (nesibdev == NULL) {
+ return NULL;
+ }
+ strlcpy(nesibdev->ibdev.name, "nes%d", IB_DEVICE_NAME_MAX);
+ nesibdev->ibdev.owner = THIS_MODULE;
+
+ nesibdev->ibdev.node_type = RDMA_NODE_RNIC;
+ memset(&nesibdev->ibdev.node_guid, 0, sizeof(nesibdev->ibdev.node_guid));
+ memcpy(&nesibdev->ibdev.node_guid, netdev->dev_addr, 6);
+
+ nesibdev->ibdev.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_AH) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_AH) |
+ (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_MW) |
+ (1ull << IB_USER_VERBS_CMD_BIND_MW) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_MW) |
+ (1ull << IB_USER_VERBS_CMD_POST_RECV) |
+ (1ull << IB_USER_VERBS_CMD_POST_SEND);
+
+ nesibdev->ibdev.phys_port_cnt = 1;
+ nesibdev->ibdev.num_comp_vectors = 1;
+ nesibdev->ibdev.dma_device = &nesdev->pcidev->dev;
+ nesibdev->ibdev.class_dev.dev = &nesdev->pcidev->dev;
+ nesibdev->ibdev.query_device = nes_query_device;
+ nesibdev->ibdev.query_port = nes_query_port;
+ nesibdev->ibdev.modify_port = nes_modify_port;
+ nesibdev->ibdev.query_pkey = nes_query_pkey;
+ nesibdev->ibdev.query_gid = nes_query_gid;
+ nesibdev->ibdev.alloc_ucontext = nes_alloc_ucontext;
+ nesibdev->ibdev.dealloc_ucontext = nes_dealloc_ucontext;
+ nesibdev->ibdev.mmap = nes_mmap;
+ nesibdev->ibdev.alloc_pd = nes_alloc_pd;
+ nesibdev->ibdev.dealloc_pd = nes_dealloc_pd;
+ nesibdev->ibdev.create_ah = nes_create_ah;
+ nesibdev->ibdev.destroy_ah = nes_destroy_ah;
+ nesibdev->ibdev.create_qp = nes_create_qp;
+ nesibdev->ibdev.modify_qp = nes_modify_qp;
+ nesibdev->ibdev.query_qp = nes_query_qp;
+ nesibdev->ibdev.destroy_qp = nes_destroy_qp;
+ nesibdev->ibdev.create_cq = nes_create_cq;
+ nesibdev->ibdev.destroy_cq = nes_destroy_cq;
+ nesibdev->ibdev.poll_cq = nes_poll_cq;
+ nesibdev->ibdev.get_dma_mr = nes_get_dma_mr;
+ nesibdev->ibdev.reg_phys_mr = nes_reg_phys_mr;
+ nesibdev->ibdev.reg_user_mr = nes_reg_user_mr;
+ nesibdev->ibdev.dereg_mr = nes_dereg_mr;
+ nesibdev->ibdev.alloc_mw = nes_alloc_mw;
+ nesibdev->ibdev.dealloc_mw = nes_dealloc_mw;
+ nesibdev->ibdev.bind_mw = nes_bind_mw;
+
+ nesibdev->ibdev.alloc_fmr = nes_alloc_fmr;
+ nesibdev->ibdev.unmap_fmr = nes_unmap_fmr;
+ nesibdev->ibdev.dealloc_fmr = nes_dealloc_fmr;
+ nesibdev->ibdev.map_phys_fmr = nes_map_phys_fmr;
+
+ nesibdev->ibdev.attach_mcast = nes_multicast_attach;
+ nesibdev->ibdev.detach_mcast = nes_multicast_detach;
+ nesibdev->ibdev.process_mad = nes_process_mad;
+
+ nesibdev->ibdev.req_notify_cq = nes_req_notify_cq;
+ nesibdev->ibdev.post_send = nes_post_send;
+ nesibdev->ibdev.post_recv = nes_post_recv;
+
+ nesibdev->ibdev.iwcm = kzalloc(sizeof(*nesibdev->ibdev.iwcm), GFP_KERNEL);
+ if (nesibdev->ibdev.iwcm == NULL) {
+ ib_dealloc_device(&nesibdev->ibdev);
+ return NULL;
+ }
+ nesibdev->ibdev.iwcm->add_ref = nes_add_ref;
+ nesibdev->ibdev.iwcm->rem_ref = nes_rem_ref;
+ nesibdev->ibdev.iwcm->get_qp = nes_get_qp;
+ nesibdev->ibdev.iwcm->connect = nes_connect;
+ nesibdev->ibdev.iwcm->accept = nes_accept;
+ nesibdev->ibdev.iwcm->reject = nes_reject;
+ nesibdev->ibdev.iwcm->create_listen = nes_create_listen;
+ nesibdev->ibdev.iwcm->destroy_listen = nes_destroy_listen;
+
+ return nesibdev;
+}
+
+
+/**
+ * nes_destroy_ofa_device
+ */
+void nes_destroy_ofa_device(struct nes_ib_device *nesibdev)
+{
+ if (nesibdev == NULL)
+ return;
+
+ nes_unregister_ofa_device(nesibdev);
+
+ kfree(nesibdev->ibdev.iwcm);
+ ib_dealloc_device(&nesibdev->ibdev);
+}
+
+
+/**
+ * nes_register_ofa_device
+ */
+int nes_register_ofa_device(struct nes_ib_device *nesibdev)
+{
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ int i, ret;
+
+ ret = ib_register_device(&nesvnic->nesibdev->ibdev);
+ if (ret) {
+ return ret;
+ }
+
+ /* Get the resources allocated to this device */
+ nesibdev->max_cq = (nesadapter->max_cq-NES_FIRST_QPN) / nesadapter->port_count;
+ nesibdev->max_mr = nesadapter->max_mr / nesadapter->port_count;
+ nesibdev->max_qp = (nesadapter->max_qp-NES_FIRST_QPN) / nesadapter->port_count;
+ nesibdev->max_pd = nesadapter->max_pd / nesadapter->port_count;
+
+ for (i = 0; i < ARRAY_SIZE(nes_class_attributes); ++i) {
+ ret = class_device_create_file(&nesibdev->ibdev.class_dev, nes_class_attributes[i]);
+ if (ret) {
+ while (i > 0) {
+ i--;
+ class_device_remove_file(&nesibdev->ibdev.class_dev,
+ nes_class_attributes[i]);
+ }
+ ib_unregister_device(&nesibdev->ibdev);
+ return ret;
+ }
+ }
+
+ nesvnic->of_device_registered = 1;
+
+ return 0;
+}
+
+
+/**
+ * nes_unregister_ofa_device
+ */
+void nes_unregister_ofa_device(struct nes_ib_device *nesibdev)
+{
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+ int i;
+
+ if (nesibdev == NULL)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(nes_class_attributes); ++i) {
+ class_device_remove_file(&nesibdev->ibdev.class_dev, nes_class_attributes[i]);
+ }
+
+ if (nesvnic->of_device_registered) {
+ ib_unregister_device(&nesibdev->ibdev);
+ }
+
+ nesvnic->of_device_registered = 0;
+}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h
new file mode 100644
index 0000000..6c6b4da
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_verbs.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_VERBS_H
+#define NES_VERBS_H
+
+struct nes_device;
+
+#define NES_MAX_USER_DB_REGIONS 4096
+#define NES_MAX_USER_WQ_REGIONS 4096
+
+struct nes_ucontext {
+ struct ib_ucontext ibucontext;
+ struct nes_device *nesdev;
+ unsigned long mmap_wq_offset;
+ unsigned long mmap_cq_offset; /* to be removed */
+ int index; /* rnic index (minor) */
+ unsigned long allocated_doorbells[BITS_TO_LONGS(NES_MAX_USER_DB_REGIONS)];
+ u16 mmap_db_index[NES_MAX_USER_DB_REGIONS];
+ u16 first_free_db;
+ unsigned long allocated_wqs[BITS_TO_LONGS(NES_MAX_USER_WQ_REGIONS)];
+ struct nes_qp *mmap_nesqp[NES_MAX_USER_WQ_REGIONS];
+ u16 first_free_wq;
+ struct list_head cq_reg_mem_list;
+ struct list_head qp_reg_mem_list;
+ u32 mcrqf;
+ atomic_t usecnt;
+};
+
+struct nes_pd {
+ struct ib_pd ibpd;
+ u16 pd_id;
+ atomic_t sqp_count;
+ u16 mmap_db_index;
+};
+
+struct nes_mr {
+ union {
+ struct ib_mr ibmr;
+ struct ib_mw ibmw;
+ struct ib_fmr ibfmr;
+ };
+ struct ib_umem *region;
+ u16 pbls_used;
+ u8 mode;
+ u8 pbl_4k;
+};
+
+struct nes_hw_pb {
+ __le32 pa_low;
+ __le32 pa_high;
+};
+
+struct nes_vpbl {
+ dma_addr_t pbl_pbase;
+ struct nes_hw_pb *pbl_vbase;
+};
+
+struct nes_root_vpbl {
+ dma_addr_t pbl_pbase;
+ struct nes_hw_pb *pbl_vbase;
+ struct nes_vpbl *leaf_vpbl;
+};
+
+struct nes_fmr {
+ struct nes_mr nesmr;
+ u32 leaf_pbl_cnt;
+ struct nes_root_vpbl root_vpbl;
+ struct ib_qp *ib_qp;
+ int access_rights;
+ struct ib_fmr_attr attr;
+};
+
+struct nes_av;
+
+struct nes_cq {
+ struct ib_cq ibcq;
+ struct nes_hw_cq hw_cq;
+ u32 polled_completions;
+ u32 cq_mem_size;
+ spinlock_t lock;
+ u8 virtual_cq;
+ u8 pad[3];
+};
+
+struct nes_wq {
+ spinlock_t lock;
+};
+
+struct iw_cm_id;
+struct ietf_mpa_frame;
+
+struct nes_qp {
+ struct ib_qp ibqp;
+ void *allocated_buffer;
+ struct iw_cm_id *cm_id;
+ struct workqueue_struct *wq;
+ struct work_struct disconn_work;
+ struct nes_cq *nesscq;
+ struct nes_cq *nesrcq;
+ struct nes_pd *nespd;
+ void *cm_node; /* handle of the node this QP is associated with */
+ struct ietf_mpa_frame *ietf_frame;
+ dma_addr_t ietf_frame_pbase;
+ wait_queue_head_t state_waitq;
+ unsigned long socket;
+ struct nes_hw_qp hwqp;
+ struct work_struct work;
+ struct work_struct ae_work;
+ enum ib_qp_state ibqp_state;
+ u32 iwarp_state;
+ u32 hte_index;
+ u32 last_aeq;
+ u32 qp_mem_size;
+ atomic_t refcount;
+ atomic_t close_timer_started;
+ u32 mmap_sq_db_index;
+ u32 mmap_rq_db_index;
+ spinlock_t lock;
+ struct nes_qp_context *nesqp_context;
+ dma_addr_t nesqp_context_pbase;
+ void *pbl_vbase;
+ dma_addr_t pbl_pbase;
+ struct page *page;
+ wait_queue_head_t kick_waitq;
+ u16 in_disconnect;
+ u16 private_data_len;
+ u8 active_conn;
+ u8 skip_lsmm;
+ u8 user_mode;
+ u8 hte_added;
+ u8 hw_iwarp_state;
+ u8 flush_issued;
+ u8 hw_tcp_state;
+ u8 disconn_pending;
+ u8 destroyed;
+};
+#endif /* NES_VERBS_H */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index a082466..09f5371 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -680,12 +680,7 @@
neigh = *to_ipoib_neigh(skb->dst->neighbour);
- if (ipoib_cm_get(neigh)) {
- if (ipoib_cm_up(neigh)) {
- ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
- goto out;
- }
- } else if (neigh->ah) {
+ if (neigh->ah)
if (unlikely((memcmp(&neigh->dgid.raw,
skb->dst->neighbour->ha + 4,
sizeof(union ib_gid))) ||
@@ -706,6 +701,12 @@
goto out;
}
+ if (ipoib_cm_get(neigh)) {
+ if (ipoib_cm_up(neigh)) {
+ ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
+ goto out;
+ }
+ } else if (neigh->ah) {
ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
goto out;
}
@@ -813,11 +814,9 @@
struct ipoib_ah *ah = NULL;
neigh = *to_ipoib_neigh(n);
- if (neigh) {
+ if (neigh)
priv = netdev_priv(neigh->dev);
- ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n",
- n->dev->name);
- } else
+ else
return;
ipoib_dbg(priv,
"neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 195ce7c..fd4a49f 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -204,6 +204,22 @@
return ret;
}
+static int srp_new_cm_id(struct srp_target_port *target)
+{
+ struct ib_cm_id *new_cm_id;
+
+ new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
+ srp_cm_handler, target);
+ if (IS_ERR(new_cm_id))
+ return PTR_ERR(new_cm_id);
+
+ if (target->cm_id)
+ ib_destroy_cm_id(target->cm_id);
+ target->cm_id = new_cm_id;
+
+ return 0;
+}
+
static int srp_create_target_ib(struct srp_target_port *target)
{
struct ib_qp_init_attr *init_attr;
@@ -436,6 +452,7 @@
static int srp_connect_target(struct srp_target_port *target)
{
+ int retries = 3;
int ret;
ret = srp_lookup_path(target);
@@ -468,6 +485,21 @@
case SRP_DLID_REDIRECT:
break;
+ case SRP_STALE_CONN:
+ /* Our current CM id was stale, and is now in timewait.
+ * Try to reconnect with a new one.
+ */
+ if (!retries-- || srp_new_cm_id(target)) {
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "giving up on stale connection\n");
+ target->status = -ECONNRESET;
+ return target->status;
+ }
+
+ shost_printk(KERN_ERR, target->scsi_host, PFX
+ "retrying stale connection\n");
+ break;
+
default:
return target->status;
}
@@ -507,7 +539,6 @@
static int srp_reconnect_target(struct srp_target_port *target)
{
- struct ib_cm_id *new_cm_id;
struct ib_qp_attr qp_attr;
struct srp_request *req, *tmp;
struct ib_wc wc;
@@ -526,14 +557,9 @@
* Now get a new local CM ID so that we avoid confusing the
* target in case things are really fouled up.
*/
- new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
- srp_cm_handler, target);
- if (IS_ERR(new_cm_id)) {
- ret = PTR_ERR(new_cm_id);
+ ret = srp_new_cm_id(target);
+ if (ret)
goto err;
- }
- ib_destroy_cm_id(target->cm_id);
- target->cm_id = new_cm_id;
qp_attr.qp_state = IB_QPS_RESET;
ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE);
@@ -1171,6 +1197,11 @@
target->status = -ECONNRESET;
break;
+ case IB_CM_REJ_STALE_CONN:
+ shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n");
+ target->status = SRP_STALE_CONN;
+ break;
+
default:
shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n",
event->param.rej_rcvd.reason);
@@ -1862,11 +1893,9 @@
if (ret)
goto err;
- target->cm_id = ib_create_cm_id(host->dev->dev, srp_cm_handler, target);
- if (IS_ERR(target->cm_id)) {
- ret = PTR_ERR(target->cm_id);
+ ret = srp_new_cm_id(target);
+ if (ret)
goto err_free;
- }
target->qp_in_error = 0;
ret = srp_connect_target(target);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 4a3c1f3..cb6eb81 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -54,6 +54,7 @@
SRP_PORT_REDIRECT = 1,
SRP_DLID_REDIRECT = 2,
+ SRP_STALE_CONN = 3,
SRP_MAX_LUN = 512,
SRP_DEF_SG_TABLESIZE = 12,
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 1dc2ac9..c5600ac 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -17,7 +17,6 @@
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/wait.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/kthread.h>
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index e5f4da928..05e3494 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -42,7 +42,6 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
-#include <linux/irq.h>
#include <asm/portmux.h>
#include <asm/mach/bf54x_keys.h>
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index e6696b3..986f93c 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -17,7 +17,6 @@
*/
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/input.h>
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 3e99df6..adc3bd6 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -141,7 +141,7 @@
/*
* gscps2_writeb_output() - write a byte to the port
*
- * returns 1 on sucess, 0 on error
+ * returns 1 on success, 0 on error
*/
static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index 2ae6c60..28ae15e 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -109,7 +109,7 @@
static irqreturn_t action_button_handler(int irq, void *dev_id)
{
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
- struct input_dev *dev = (struct input_dev *) dev_id;
+ struct input_dev *dev = dev_id;
input_report_key(dev, KEY_ENTER, down);
input_sync(dev);
@@ -120,7 +120,7 @@
static irqreturn_t npower_button_handler(int irq, void *dev_id)
{
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
- struct input_dev *dev = (struct input_dev *) dev_id;
+ struct input_dev *dev = dev_id;
/*
* This interrupt is only called when we release the key. So we have
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index ee2b0b9..8325022 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -310,7 +310,7 @@
}
break;
case ISDN_CMD_DIAL:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -339,7 +339,7 @@
}
return ret;
case ISDN_CMD_ACCEPTD:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -347,11 +347,11 @@
actcapi_select_b2_protocol_req(card, chan);
return 0;
case ISDN_CMD_ACCEPTB:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return 0;
case ISDN_CMD_HANGUP:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -366,7 +366,7 @@
}
return 0;
case ISDN_CMD_SETEAZ:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -386,7 +386,7 @@
actcapi_listen_req(card);
return 0;
case ISDN_CMD_CLREAZ:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
@@ -394,14 +394,14 @@
actcapi_listen_req(card);
return 0;
case ISDN_CMD_SETL2:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
chan->l2prot = (c->arg >> 8);
return 0;
case ISDN_CMD_SETL3:
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
printk(KERN_WARNING "L3 protocol unknown\n");
@@ -524,7 +524,7 @@
act2000_card *card = act2000_findcard(id);
if (card) {
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return (len);
}
@@ -539,7 +539,7 @@
act2000_card *card = act2000_findcard(id);
if (card) {
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return (act2000_readstatus(buf, len, card));
}
@@ -554,7 +554,7 @@
act2000_card *card = act2000_findcard(id);
if (card) {
- if (!card->flags & ACT2000_FLAGS_RUNNING)
+ if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return (act2000_sendbuf(card, channel, ack, skb));
}
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index 00a3be5..091deb9 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -350,8 +350,8 @@
unsigned char *src, c;
int procbytes;
- head = atomic_read(&inbuf->head);
- tail = atomic_read(&inbuf->tail);
+ head = inbuf->head;
+ tail = inbuf->tail;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head != tail) {
@@ -361,7 +361,7 @@
gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
while (numbytes) {
- if (atomic_read(&cs->mstate) == MS_LOCKED) {
+ if (cs->mstate == MS_LOCKED) {
procbytes = lock_loop(src, numbytes, inbuf);
src += procbytes;
numbytes -= procbytes;
@@ -436,7 +436,7 @@
}
gig_dbg(DEBUG_INTR, "setting head to %u", head);
- atomic_set(&inbuf->head, head);
+ inbuf->head = head;
}
}
EXPORT_SYMBOL_GPL(gigaset_m10x_input);
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index af76482..5255b5e 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -73,6 +73,14 @@
/* Function will be called if the device is unplugged */
static void gigaset_disconnect(struct usb_interface *interface);
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+
+/* functions called before/after device reset */
+static int gigaset_pre_reset(struct usb_interface *intf);
+static int gigaset_post_reset(struct usb_interface *intf);
+
static int atread_submit(struct cardstate *, int);
static void stopurbs(struct bas_bc_state *);
static int req_submit(struct bc_state *, int, int, int);
@@ -105,8 +113,9 @@
unsigned char int_in_buf[3];
spinlock_t lock; /* locks all following */
- atomic_t basstate; /* bitmap (BS_*) */
+ int basstate; /* bitmap (BS_*) */
int pending; /* uncompleted base request */
+ wait_queue_head_t waitqueue;
int rcvbuf_size; /* size of AT receive buffer */
/* 0: no receive in progress */
int retry_cmd_in; /* receive req retry count */
@@ -121,10 +130,10 @@
#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */
#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */
#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */
+#define BS_SUSPEND 0x100 /* USB port suspended */
static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = {
@@ -132,6 +141,11 @@
.probe = gigaset_probe,
.disconnect = gigaset_disconnect,
.id_table = gigaset_table,
+ .suspend = gigaset_suspend,
+ .resume = gigaset_resume,
+ .reset_resume = gigaset_post_reset,
+ .pre_reset = gigaset_pre_reset,
+ .post_reset = gigaset_post_reset,
};
/* get message text for usb_submit_urb return code
@@ -248,12 +262,12 @@
if (urb) {
gig_dbg(level,
" dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
- "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+ "hcpriv=0x%08lx, transfer_flags=0x%x,",
(unsigned long) urb->dev,
usb_pipetype_str(urb->pipe),
usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
- urb->status, (unsigned long) urb->hcpriv,
+ (unsigned long) urb->hcpriv,
urb->transfer_flags);
gig_dbg(level,
" transfer_buffer=0x%08lx[%d], actual_length=%d, "
@@ -355,27 +369,27 @@
case 0:
break;
case HD_OPEN_ATCHANNEL:
- if (atomic_read(&ucs->basstate) & BS_ATOPEN)
+ if (ucs->basstate & BS_ATOPEN)
ucs->pending = 0;
break;
case HD_OPEN_B1CHANNEL:
- if (atomic_read(&ucs->basstate) & BS_B1OPEN)
+ if (ucs->basstate & BS_B1OPEN)
ucs->pending = 0;
break;
case HD_OPEN_B2CHANNEL:
- if (atomic_read(&ucs->basstate) & BS_B2OPEN)
+ if (ucs->basstate & BS_B2OPEN)
ucs->pending = 0;
break;
case HD_CLOSE_ATCHANNEL:
- if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
+ if (!(ucs->basstate & BS_ATOPEN))
ucs->pending = 0;
break;
case HD_CLOSE_B1CHANNEL:
- if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
+ if (!(ucs->basstate & BS_B1OPEN))
ucs->pending = 0;
break;
case HD_CLOSE_B2CHANNEL:
- if (!(atomic_read(&ucs->basstate) & BS_B2OPEN))
+ if (!(ucs->basstate & BS_B2OPEN))
ucs->pending = 0;
break;
case HD_DEVICE_INIT_ACK: /* no reply expected */
@@ -441,8 +455,8 @@
int state;
spin_lock_irqsave(&ucs->lock, flags);
- state = atomic_read(&ucs->basstate);
- atomic_set(&ucs->basstate, (state & ~clear) | set);
+ state = ucs->basstate;
+ ucs->basstate = (state & ~clear) | set;
spin_unlock_irqrestore(&ucs->lock, flags);
return state;
}
@@ -459,11 +473,13 @@
struct inbuf_t *inbuf = urb->context;
struct cardstate *cs = inbuf->cs;
struct bas_cardstate *ucs = cs->hw.bas;
+ int status = urb->status;
int have_data = 0;
unsigned numbytes;
int rc;
update_basstate(ucs, 0, BS_ATRDPEND);
+ wake_up(&ucs->waitqueue);
if (!ucs->rcvbuf_size) {
dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
@@ -472,7 +488,7 @@
del_timer(&ucs->timer_cmd_in);
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
numbytes = urb->actual_length;
if (unlikely(numbytes != ucs->rcvbuf_size)) {
@@ -506,12 +522,12 @@
case -ESHUTDOWN: /* device shut down */
/* no action necessary */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
break;
default: /* severe trouble */
dev_warn(cs->dev, "control read: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
if (ucs->retry_cmd_in++ < BAS_RETRY) {
dev_notice(cs->dev, "control read: retry %d\n",
ucs->retry_cmd_in);
@@ -550,17 +566,28 @@
static int atread_submit(struct cardstate *cs, int timeout)
{
struct bas_cardstate *ucs = cs->hw.bas;
+ int basstate;
int ret;
gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
ucs->rcvbuf_size);
- if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) {
+ basstate = update_basstate(ucs, BS_ATRDPEND, 0);
+ if (basstate & BS_ATRDPEND) {
dev_err(cs->dev,
"could not submit HD_READ_ATMESSAGE: URB busy\n");
return -EBUSY;
}
+ if (basstate & BS_SUSPEND) {
+ dev_notice(cs->dev,
+ "HD_READ_ATMESSAGE not submitted, "
+ "suspend in progress\n");
+ update_basstate(ucs, 0, BS_ATRDPEND);
+ /* treat like disconnect */
+ return -ENODEV;
+ }
+
ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
ucs->dr_cmd_in.wValue = 0;
@@ -601,12 +628,13 @@
struct cardstate *cs = urb->context;
struct bas_cardstate *ucs = cs->hw.bas;
struct bc_state *bcs;
+ int status = urb->status;
unsigned long flags;
int rc;
unsigned l;
int channel;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ENOENT: /* cancelled */
@@ -614,7 +642,7 @@
case -EINPROGRESS: /* pending */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
case -ENODEV: /* device removed */
case -ESHUTDOWN: /* device shut down */
@@ -623,7 +651,7 @@
return;
default: /* severe trouble */
dev_warn(cs->dev, "interrupt read: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
//FIXME corrective action? resubmission always ok?
goto resubmit;
}
@@ -745,6 +773,7 @@
}
check_pending(ucs);
+ wake_up(&ucs->waitqueue);
resubmit:
rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -766,17 +795,18 @@
{
struct bc_state *bcs;
struct bas_bc_state *ubc;
+ int status = urb->status;
unsigned long flags;
int i, rc;
/* status codes not worth bothering the tasklet with */
- if (unlikely(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS ||
- urb->status == -ENODEV ||
- urb->status == -ESHUTDOWN)) {
+ if (unlikely(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -EINPROGRESS ||
+ status == -ENODEV ||
+ status == -ESHUTDOWN)) {
gig_dbg(DEBUG_ISO, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
}
@@ -787,10 +817,11 @@
if (likely(ubc->isoindone == NULL)) {
/* pass URB to tasklet */
ubc->isoindone = urb;
+ ubc->isoinstatus = status;
tasklet_schedule(&ubc->rcvd_tasklet);
} else {
/* tasklet still busy, drop data and resubmit URB */
- ubc->loststatus = urb->status;
+ ubc->loststatus = status;
for (i = 0; i < BAS_NUMFRAMES; i++) {
ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
if (unlikely(urb->iso_frame_desc[i].status != 0 &&
@@ -800,7 +831,7 @@
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
- if (likely(atomic_read(&ubc->running))) {
+ if (likely(ubc->running)) {
/* urb->dev is clobbered by USB subsystem */
urb->dev = bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
@@ -831,22 +862,24 @@
{
struct isow_urbctx_t *ucx;
struct bas_bc_state *ubc;
+ int status = urb->status;
unsigned long flags;
/* status codes not worth bothering the tasklet with */
- if (unlikely(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS ||
- urb->status == -ENODEV ||
- urb->status == -ESHUTDOWN)) {
+ if (unlikely(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -EINPROGRESS ||
+ status == -ENODEV ||
+ status == -ESHUTDOWN)) {
gig_dbg(DEBUG_ISO, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
}
/* pass URB context to tasklet */
ucx = urb->context;
ubc = ucx->bcs->hw.bas;
+ ucx->status = status;
spin_lock_irqsave(&ubc->isooutlock, flags);
ubc->isooutovfl = ubc->isooutdone;
@@ -875,7 +908,7 @@
bcs->inputstate |= INS_flag_hunt;
/* submit all isochronous input URBs */
- atomic_set(&ubc->running, 1);
+ ubc->running = 1;
for (k = 0; k < BAS_INURBS; k++) {
urb = ubc->isoinurbs[k];
if (!urb) {
@@ -932,15 +965,15 @@
ubc->isoouturbs[k].limit = -1;
}
- /* submit two URBs, keep third one */
- for (k = 0; k < 2; ++k) {
+ /* keep one URB free, submit the others */
+ for (k = 0; k < BAS_OUTURBS-1; ++k) {
dump_urb(DEBUG_ISO, "Initial isoc write", urb);
rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC);
if (rc != 0)
goto error;
}
dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
- ubc->isooutfree = &ubc->isoouturbs[2];
+ ubc->isooutfree = &ubc->isoouturbs[BAS_OUTURBS-1];
ubc->isooutdone = ubc->isooutovfl = NULL;
return 0;
error:
@@ -958,7 +991,7 @@
{
int k, rc;
- atomic_set(&ubc->running, 0);
+ ubc->running = 0;
for (k = 0; k < BAS_INURBS; ++k) {
rc = usb_unlink_urb(ubc->isoinurbs[k]);
@@ -1034,7 +1067,7 @@
}
break;
}
- ucx->limit = atomic_read(&ubc->isooutbuf->nextread);
+ ucx->limit = ubc->isooutbuf->nextread;
ifd->status = 0;
ifd->actual_length = 0;
}
@@ -1070,6 +1103,7 @@
struct cardstate *cs = bcs->cs;
struct isow_urbctx_t *done, *next, *ovfl;
struct urb *urb;
+ int status;
struct usb_iso_packet_descriptor *ifd;
int offset;
unsigned long flags;
@@ -1080,7 +1114,7 @@
/* loop while completed URBs arrive in time */
for (;;) {
- if (unlikely(!(atomic_read(&ubc->running)))) {
+ if (unlikely(!(ubc->running))) {
gig_dbg(DEBUG_ISO, "%s: not running", __func__);
return;
}
@@ -1126,7 +1160,8 @@
/* process completed URB */
urb = done->urb;
- switch (urb->status) {
+ status = done->status;
+ switch (status) {
case -EXDEV: /* partial completion */
gig_dbg(DEBUG_ISO, "%s: URB partially completed",
__func__);
@@ -1179,12 +1214,12 @@
break;
default: /* severe trouble */
dev_warn(cs->dev, "isochronous write: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
}
/* mark the write buffer area covered by this URB as free */
if (done->limit >= 0)
- atomic_set(&ubc->isooutbuf->read, done->limit);
+ ubc->isooutbuf->read = done->limit;
/* mark URB as free */
spin_lock_irqsave(&ubc->isooutlock, flags);
@@ -1233,6 +1268,7 @@
struct bas_bc_state *ubc = bcs->hw.bas;
struct cardstate *cs = bcs->cs;
struct urb *urb;
+ int status;
char *rcvbuf;
unsigned long flags;
int totleft, numbytes, offset, frame, rc;
@@ -1245,6 +1281,7 @@
spin_unlock_irqrestore(&ubc->isoinlock, flags);
return;
}
+ status = ubc->isoinstatus;
ubc->isoindone = NULL;
if (unlikely(ubc->loststatus != -EINPROGRESS)) {
dev_warn(cs->dev,
@@ -1256,15 +1293,15 @@
}
spin_unlock_irqrestore(&ubc->isoinlock, flags);
- if (unlikely(!(atomic_read(&ubc->running)))) {
+ if (unlikely(!(ubc->running))) {
gig_dbg(DEBUG_ISO,
"%s: channel not running, "
"dropped URB with status: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
}
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
break;
case -EXDEV: /* inspect individual frames
@@ -1276,7 +1313,7 @@
case -ECONNRESET:
case -EINPROGRESS:
gig_dbg(DEBUG_ISO, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
continue; /* -> skip */
case -EPIPE:
dev_err(cs->dev, "isochronous read stalled\n");
@@ -1284,7 +1321,7 @@
continue; /* -> skip */
default: /* severe trouble */
dev_warn(cs->dev, "isochronous read: %s\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
goto error;
}
@@ -1406,6 +1443,8 @@
dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
pending);
}
+
+ wake_up(&ucs->waitqueue);
}
/* write_ctrl_callback
@@ -1418,11 +1457,12 @@
static void write_ctrl_callback(struct urb *urb)
{
struct bas_cardstate *ucs = urb->context;
+ int status = urb->status;
int rc;
unsigned long flags;
/* check status */
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
spin_lock_irqsave(&ucs->lock, flags);
switch (ucs->pending) {
@@ -1441,20 +1481,22 @@
case -ESHUTDOWN: /* device shut down */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
break;
default: /* any failure */
- if (++ucs->retry_ctrl > BAS_RETRY) {
+ /* don't retry if suspend requested */
+ if (++ucs->retry_ctrl > BAS_RETRY ||
+ (ucs->basstate & BS_SUSPEND)) {
dev_err(&ucs->interface->dev,
"control request 0x%02x failed: %s\n",
ucs->dr_ctrl.bRequest,
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
break; /* give up */
}
dev_notice(&ucs->interface->dev,
"control request 0x%02x: %s, retry %d\n",
- ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
+ ucs->dr_ctrl.bRequest, get_usb_statmsg(status),
ucs->retry_ctrl);
/* urb->dev is clobbered by USB subsystem */
urb->dev = ucs->udev;
@@ -1474,6 +1516,7 @@
del_timer(&ucs->timer_ctrl);
ucs->pending = 0;
spin_unlock_irqrestore(&ucs->lock, flags);
+ wake_up(&ucs->waitqueue);
}
/* req_submit
@@ -1548,37 +1591,46 @@
*/
static int gigaset_init_bchannel(struct bc_state *bcs)
{
+ struct cardstate *cs = bcs->cs;
int req, ret;
unsigned long flags;
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (unlikely(!bcs->cs->connected)) {
+ spin_lock_irqsave(&cs->lock, flags);
+ if (unlikely(!cs->connected)) {
gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return -ENODEV;
}
+ if (cs->hw.bas->basstate & BS_SUSPEND) {
+ dev_notice(cs->dev,
+ "not starting isochronous I/O, "
+ "suspend in progress\n");
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return -EHOSTUNREACH;
+ }
+
if ((ret = starturbs(bcs)) < 0) {
- dev_err(bcs->cs->dev,
+ dev_err(cs->dev,
"could not start isochronous I/O for channel B%d: %s\n",
bcs->channel + 1,
ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret));
if (ret != -ENODEV)
error_hangup(bcs);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
- dev_err(bcs->cs->dev, "could not open channel B%d\n",
+ dev_err(cs->dev, "could not open channel B%d\n",
bcs->channel + 1);
stopurbs(bcs->hw.bas);
if (ret != -ENODEV)
error_hangup(bcs);
}
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
@@ -1594,20 +1646,20 @@
*/
static int gigaset_close_bchannel(struct bc_state *bcs)
{
+ struct cardstate *cs = bcs->cs;
int req, ret;
unsigned long flags;
- spin_lock_irqsave(&bcs->cs->lock, flags);
- if (unlikely(!bcs->cs->connected)) {
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_lock_irqsave(&cs->lock, flags);
+ if (unlikely(!cs->connected)) {
+ spin_unlock_irqrestore(&cs->lock, flags);
gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
return -ENODEV;
}
- if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
- (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
+ if (!(cs->hw.bas->basstate & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
/* channel not running: just signal common.c */
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
gigaset_bchannel_down(bcs);
return 0;
}
@@ -1615,10 +1667,10 @@
/* channel running: tell device to close it */
req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
- dev_err(bcs->cs->dev, "closing channel B%d failed\n",
+ dev_err(cs->dev, "closing channel B%d failed\n",
bcs->channel + 1);
- spin_unlock_irqrestore(&bcs->cs->lock, flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
return ret;
}
@@ -1665,12 +1717,14 @@
{
struct cardstate *cs = urb->context;
struct bas_cardstate *ucs = cs->hw.bas;
+ int status = urb->status;
unsigned long flags;
update_basstate(ucs, 0, BS_ATWRPEND);
+ wake_up(&ucs->waitqueue);
/* check status */
- switch (urb->status) {
+ switch (status) {
case 0: /* normal completion */
break;
case -ENOENT: /* cancelled */
@@ -1680,26 +1734,33 @@
case -ESHUTDOWN: /* device shut down */
/* ignore silently */
gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
+ __func__, get_usb_statmsg(status));
return;
default: /* any failure */
if (++ucs->retry_cmd_out > BAS_RETRY) {
dev_warn(cs->dev,
"command write: %s, "
"giving up after %d retries\n",
- get_usb_statmsg(urb->status),
+ get_usb_statmsg(status),
ucs->retry_cmd_out);
break;
}
+ if (ucs->basstate & BS_SUSPEND) {
+ dev_warn(cs->dev,
+ "command write: %s, "
+ "won't retry - suspend requested\n",
+ get_usb_statmsg(status));
+ break;
+ }
if (cs->cmdbuf == NULL) {
dev_warn(cs->dev,
"command write: %s, "
"cannot retry - cmdbuf gone\n",
- get_usb_statmsg(urb->status));
+ get_usb_statmsg(status));
break;
}
dev_notice(cs->dev, "command write: %s, retry %d\n",
- get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+ get_usb_statmsg(status), ucs->retry_cmd_out);
if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
/* resubmitted - bypass regular exit block */
return;
@@ -1799,8 +1860,14 @@
int rc;
int retval = 0;
+ /* check if suspend requested */
+ if (ucs->basstate & BS_SUSPEND) {
+ gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending");
+ return -EHOSTUNREACH;
+ }
+
/* check if AT channel is open */
- if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
+ if (!(ucs->basstate & BS_ATOPEN)) {
gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
if (rc < 0) {
@@ -1816,8 +1883,7 @@
/* try to send first command in queue */
spin_lock_irqsave(&cs->cmdlock, flags);
- while ((cb = cs->cmdbuf) != NULL &&
- atomic_read(&ucs->basstate) & BS_ATREADY) {
+ while ((cb = cs->cmdbuf) != NULL && (ucs->basstate & BS_ATREADY)) {
ucs->retry_cmd_out = 0;
rc = atwrite_submit(cs, cb->buf, cb->len);
if (unlikely(rc)) {
@@ -1855,7 +1921,7 @@
unsigned long flags;
int rc;
- gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
@@ -1970,7 +2036,7 @@
return 0;
/* kill URBs and tasklets before freeing - better safe than sorry */
- atomic_set(&ubc->running, 0);
+ ubc->running = 0;
gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
for (i = 0; i < BAS_OUTURBS; ++i) {
usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2005,7 +2071,7 @@
return 0;
}
- atomic_set(&ubc->running, 0);
+ ubc->running = 0;
atomic_set(&ubc->corrbytes, 0);
spin_lock_init(&ubc->isooutlock);
for (i = 0; i < BAS_OUTURBS; ++i) {
@@ -2050,7 +2116,7 @@
{
struct bas_bc_state *ubc = bcs->hw.bas;
- atomic_set(&bcs->hw.bas->running, 0);
+ bcs->hw.bas->running = 0;
atomic_set(&bcs->hw.bas->corrbytes, 0);
bcs->hw.bas->numsub = 0;
spin_lock_init(&ubc->isooutlock);
@@ -2081,10 +2147,11 @@
spin_lock_init(&ucs->lock);
ucs->pending = 0;
- atomic_set(&ucs->basstate, 0);
+ ucs->basstate = 0;
init_timer(&ucs->timer_ctrl);
init_timer(&ucs->timer_atrdy);
init_timer(&ucs->timer_cmd_in);
+ init_waitqueue_head(&ucs->waitqueue);
return 1;
}
@@ -2102,7 +2169,7 @@
int i, j;
gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__);
- for (j = 0; j < 2; ++j) {
+ for (j = 0; j < BAS_CHANNELS; ++j) {
ubc = cs->bcs[j].hw.bas;
for (i = 0; i < BAS_OUTURBS; ++i) {
usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2179,11 +2246,11 @@
__func__, le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- cs = gigaset_getunassignedcs(driver);
- if (!cs) {
- dev_err(&udev->dev, "no free cardstate\n");
+ /* allocate memory for our device state and intialize it */
+ cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
+ GIGASET_MODULENAME);
+ if (!cs)
return -ENODEV;
- }
ucs = cs->hw.bas;
/* save off device structure ptrs for later use */
@@ -2203,7 +2270,7 @@
!(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL)))
goto allocerr;
- for (j = 0; j < 2; ++j) {
+ for (j = 0; j < BAS_CHANNELS; ++j) {
ubc = cs->bcs[j].hw.bas;
for (i = 0; i < BAS_OUTURBS; ++i)
if (!(ubc->isoouturbs[i].urb =
@@ -2237,7 +2304,7 @@
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
- atomic_set(&cs->mstate, MS_LOCKED);
+ cs->mstate = MS_LOCKED;
/* save address of controller structure */
usb_set_intfdata(interface, cs);
@@ -2252,7 +2319,7 @@
error:
freeurbs(cs);
usb_set_intfdata(interface, NULL);
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
return -ENODEV;
}
@@ -2272,11 +2339,10 @@
dev_info(cs->dev, "disconnecting Gigaset base\n");
/* mark base as not ready, all channels disconnected */
- atomic_set(&ucs->basstate, 0);
+ ucs->basstate = 0;
/* tell LL all channels are down */
- //FIXME shouldn't gigaset_stop() do this?
- for (j = 0; j < 2; ++j)
+ for (j = 0; j < BAS_CHANNELS; ++j)
gigaset_bchannel_down(cs->bcs + j);
/* stop driver (common part) */
@@ -2295,9 +2361,113 @@
ucs->interface = NULL;
ucs->udev = NULL;
cs->dev = NULL;
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
}
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int rc;
+
+ /* set suspend flag; this stops AT command/response traffic */
+ if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) {
+ gig_dbg(DEBUG_SUSPEND, "already suspended");
+ return 0;
+ }
+
+ /* wait a bit for blocking conditions to go away */
+ rc = wait_event_timeout(ucs->waitqueue,
+ !(ucs->basstate &
+ (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)),
+ BAS_TIMEOUT*HZ/10);
+ gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc);
+
+ /* check for conditions preventing suspend */
+ if (ucs->basstate & (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)) {
+ dev_warn(cs->dev, "cannot suspend:\n");
+ if (ucs->basstate & BS_B1OPEN)
+ dev_warn(cs->dev, " B channel 1 open\n");
+ if (ucs->basstate & BS_B2OPEN)
+ dev_warn(cs->dev, " B channel 2 open\n");
+ if (ucs->basstate & BS_ATRDPEND)
+ dev_warn(cs->dev, " receiving AT reply\n");
+ if (ucs->basstate & BS_ATWRPEND)
+ dev_warn(cs->dev, " sending AT command\n");
+ update_basstate(ucs, 0, BS_SUSPEND);
+ return -EBUSY;
+ }
+
+ /* close AT channel if open */
+ if (ucs->basstate & BS_ATOPEN) {
+ gig_dbg(DEBUG_SUSPEND, "closing AT channel");
+ rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0);
+ if (rc) {
+ update_basstate(ucs, 0, BS_SUSPEND);
+ return rc;
+ }
+ wait_event_timeout(ucs->waitqueue, !ucs->pending,
+ BAS_TIMEOUT*HZ/10);
+ /* in case of timeout, proceed anyway */
+ }
+
+ /* kill all URBs and timers that might still be pending */
+ usb_kill_urb(ucs->urb_ctrl);
+ usb_kill_urb(ucs->urb_int_in);
+ del_timer_sync(&ucs->timer_ctrl);
+
+ gig_dbg(DEBUG_SUSPEND, "suspend complete");
+ return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int rc;
+
+ /* resubmit interrupt URB for spontaneous messages from base */
+ rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
+ if (rc) {
+ dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
+ get_usb_rcmsg(rc));
+ return rc;
+ }
+
+ /* clear suspend flag to reallow activity */
+ update_basstate(ucs, 0, BS_SUSPEND);
+
+ gig_dbg(DEBUG_SUSPEND, "resume complete");
+ return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+ /* handle just like suspend */
+ return gigaset_suspend(intf, PMSG_ON);
+}
+
+/* gigaset_post_reset
+ * This function is called after the USB connection has been reset.
+ */
+static int gigaset_post_reset(struct usb_interface *intf)
+{
+ /* FIXME: send HD_DEVICE_INIT_ACK? */
+
+ /* resume operations */
+ return gigaset_resume(intf);
+}
+
+
static const struct gigaset_ops gigops = {
gigaset_write_cmd,
gigaset_write_room,
@@ -2330,12 +2500,6 @@
&gigops, THIS_MODULE)) == NULL)
goto error;
- /* allocate memory for our device state and intialize it */
- cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode,
- GIGASET_MODULENAME);
- if (!cardstate)
- goto error;
-
/* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver);
if (result < 0) {
@@ -2347,9 +2511,7 @@
info(DRIVER_DESC);
return 0;
-error: if (cardstate)
- gigaset_freecs(cardstate);
- cardstate = NULL;
+error:
if (driver)
gigaset_freedriver(driver);
driver = NULL;
@@ -2361,43 +2523,50 @@
*/
static void __exit bas_gigaset_exit(void)
{
- struct bas_cardstate *ucs = cardstate->hw.bas;
+ struct bas_cardstate *ucs;
+ int i;
gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more
*/
- gigaset_shutdown(cardstate);
- /* from now on, no isdn callback should be possible */
+ /* stop all connected devices */
+ for (i = 0; i < driver->minors; i++) {
+ if (gigaset_shutdown(driver->cs + i) < 0)
+ continue; /* no device */
+ /* from now on, no isdn callback should be possible */
- /* close all still open channels */
- if (atomic_read(&ucs->basstate) & BS_B1OPEN) {
- gig_dbg(DEBUG_INIT, "closing B1 channel");
- usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
- HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0,
- NULL, 0, BAS_TIMEOUT);
+ /* close all still open channels */
+ ucs = driver->cs[i].hw.bas;
+ if (ucs->basstate & BS_B1OPEN) {
+ gig_dbg(DEBUG_INIT, "closing B1 channel");
+ usb_control_msg(ucs->udev,
+ usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ,
+ 0, 0, NULL, 0, BAS_TIMEOUT);
+ }
+ if (ucs->basstate & BS_B2OPEN) {
+ gig_dbg(DEBUG_INIT, "closing B2 channel");
+ usb_control_msg(ucs->udev,
+ usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ,
+ 0, 0, NULL, 0, BAS_TIMEOUT);
+ }
+ if (ucs->basstate & BS_ATOPEN) {
+ gig_dbg(DEBUG_INIT, "closing AT channel");
+ usb_control_msg(ucs->udev,
+ usb_sndctrlpipe(ucs->udev, 0),
+ HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ,
+ 0, 0, NULL, 0, BAS_TIMEOUT);
+ }
+ ucs->basstate = 0;
}
- if (atomic_read(&ucs->basstate) & BS_B2OPEN) {
- gig_dbg(DEBUG_INIT, "closing B2 channel");
- usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
- HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0,
- NULL, 0, BAS_TIMEOUT);
- }
- if (atomic_read(&ucs->basstate) & BS_ATOPEN) {
- gig_dbg(DEBUG_INIT, "closing AT channel");
- usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
- HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0,
- NULL, 0, BAS_TIMEOUT);
- }
- atomic_set(&ucs->basstate, 0);
/* deregister this driver with the USB subsystem */
usb_deregister(&gigaset_usb_driver);
/* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */
- gigaset_freecs(cardstate);
- cardstate = NULL;
gigaset_freedriver(driver);
driver = NULL;
}
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index acd4171..aacedec 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -31,7 +31,6 @@
/* driver state flags */
#define VALID_MINOR 0x01
#define VALID_ID 0x02
-#define ASSIGNED 0x04
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf)
@@ -178,7 +177,7 @@
unsigned long flags;
spin_lock_irqsave(&bcs->cs->lock, flags);
- if (bcs->use_count) {
+ if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
gig_dbg(DEBUG_ANY, "could not allocate channel %d",
bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
@@ -203,6 +202,7 @@
}
--bcs->use_count;
bcs->busy = 0;
+ module_put(bcs->cs->driver->owner);
gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
}
@@ -356,31 +356,28 @@
{
unsigned long flags;
unsigned i;
+ struct cardstate *cs;
struct cardstate *ret = NULL;
spin_lock_irqsave(&drv->lock, flags);
+ if (drv->blocked)
+ goto exit;
for (i = 0; i < drv->minors; ++i) {
- if (!(drv->flags[i] & VALID_MINOR)) {
- if (try_module_get(drv->owner)) {
- drv->flags[i] = VALID_MINOR;
- ret = drv->cs + i;
- }
+ cs = drv->cs + i;
+ if (!(cs->flags & VALID_MINOR)) {
+ cs->flags = VALID_MINOR;
+ ret = cs;
break;
}
}
+exit:
spin_unlock_irqrestore(&drv->lock, flags);
return ret;
}
static void free_cs(struct cardstate *cs)
{
- unsigned long flags;
- struct gigaset_driver *drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- if (drv->flags[cs->minor_index] & VALID_MINOR)
- module_put(drv->owner);
- drv->flags[cs->minor_index] = 0;
- spin_unlock_irqrestore(&drv->lock, flags);
+ cs->flags = 0;
}
static void make_valid(struct cardstate *cs, unsigned mask)
@@ -388,7 +385,7 @@
unsigned long flags;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] |= mask;
+ cs->flags |= mask;
spin_unlock_irqrestore(&drv->lock, flags);
}
@@ -397,7 +394,7 @@
unsigned long flags;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] &= ~mask;
+ cs->flags &= ~mask;
spin_unlock_irqrestore(&drv->lock, flags);
}
@@ -501,11 +498,11 @@
struct cardstate *cs, int inputstate)
/* inbuf->read must be allocated before! */
{
- atomic_set(&inbuf->head, 0);
- atomic_set(&inbuf->tail, 0);
+ inbuf->head = 0;
+ inbuf->tail = 0;
inbuf->cs = cs;
inbuf->bcs = bcs; /*base driver: NULL*/
- inbuf->rcvbuf = NULL; //FIXME
+ inbuf->rcvbuf = NULL;
inbuf->inputstate = inputstate;
}
@@ -521,8 +518,8 @@
return 0;
bytesleft = numbytes;
- tail = atomic_read(&inbuf->tail);
- head = atomic_read(&inbuf->head);
+ tail = inbuf->tail;
+ head = inbuf->head;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
while (bytesleft) {
@@ -546,7 +543,7 @@
src += n;
}
gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
- atomic_set(&inbuf->tail, tail);
+ inbuf->tail = tail;
return numbytes != bytesleft;
}
EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
@@ -668,7 +665,7 @@
tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
(unsigned long) cs);
- atomic_set(&cs->commands_pending, 0);
+ cs->commands_pending = 0;
cs->cur_at_seq = 0;
cs->gotfwver = -1;
cs->open_count = 0;
@@ -688,8 +685,8 @@
init_waitqueue_head(&cs->waitqueue);
cs->waiting = 0;
- atomic_set(&cs->mode, M_UNKNOWN);
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
+ cs->mode = M_UNKNOWN;
+ cs->mstate = MS_UNINITIALIZED;
for (i = 0; i < channels; ++i) {
gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
@@ -806,8 +803,8 @@
spin_lock_irqsave(&cs->lock, flags);
- atomic_set(&cs->mode, M_UNKNOWN);
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
+ cs->mode = M_UNKNOWN;
+ cs->mstate = MS_UNINITIALIZED;
clear_at_state(&cs->at_state);
dealloc_at_states(cs);
@@ -817,8 +814,8 @@
kfree(cs->inbuf->rcvbuf);
cs->inbuf->rcvbuf = NULL;
cs->inbuf->inputstate = INS_command;
- atomic_set(&cs->inbuf->head, 0);
- atomic_set(&cs->inbuf->tail, 0);
+ cs->inbuf->head = 0;
+ cs->inbuf->tail = 0;
cb = cs->cmdbuf;
while (cb) {
@@ -832,7 +829,7 @@
cs->gotfwver = -1;
cs->dle = 0;
cs->cur_at_seq = 0;
- atomic_set(&cs->commands_pending, 0);
+ cs->commands_pending = 0;
cs->cbytes = 0;
spin_unlock_irqrestore(&cs->lock, flags);
@@ -862,7 +859,7 @@
cs->connected = 1;
spin_unlock_irqrestore(&cs->lock, flags);
- if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ if (cs->mstate != MS_LOCKED) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8);
@@ -893,10 +890,17 @@
}
EXPORT_SYMBOL_GPL(gigaset_start);
-void gigaset_shutdown(struct cardstate *cs)
+/* gigaset_shutdown
+ * check if a device is associated to the cardstate structure and stop it
+ * return value: 0 if ok, -1 if no device was associated
+ */
+int gigaset_shutdown(struct cardstate *cs)
{
mutex_lock(&cs->mutex);
+ if (!(cs->flags & VALID_MINOR))
+ return -1;
+
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
@@ -913,6 +917,7 @@
exit:
mutex_unlock(&cs->mutex);
+ return 0;
}
EXPORT_SYMBOL_GPL(gigaset_shutdown);
@@ -954,13 +959,11 @@
list_for_each_entry(drv, &drivers, list) {
spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) {
- if (drv->flags[i] & VALID_ID) {
- cs = drv->cs + i;
- if (cs->myid == id)
- ret = cs;
- }
- if (ret)
+ cs = drv->cs + i;
+ if ((cs->flags & VALID_ID) && cs->myid == id) {
+ ret = cs;
break;
+ }
}
spin_unlock(&drv->lock);
if (ret)
@@ -983,10 +986,9 @@
spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) {
gig_dbg(DEBUG_DRIVER, " index %u", i);
- gig_dbg(DEBUG_DRIVER, " flags 0x%02x",
- drv->flags[i]);
cs = drv->cs + i;
gig_dbg(DEBUG_DRIVER, " cardstate %p", cs);
+ gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags);
gig_dbg(DEBUG_DRIVER, " minor_index %u",
cs->minor_index);
gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver);
@@ -1010,7 +1012,7 @@
continue;
index = minor - drv->minor;
spin_lock(&drv->lock);
- if (drv->flags[index] & VALID_MINOR)
+ if (drv->cs[index].flags & VALID_MINOR)
ret = drv->cs + index;
spin_unlock(&drv->lock);
if (ret)
@@ -1038,7 +1040,6 @@
gigaset_if_freedriver(drv);
kfree(drv->cs);
- kfree(drv->flags);
kfree(drv);
}
EXPORT_SYMBOL_GPL(gigaset_freedriver);
@@ -1080,12 +1081,8 @@
if (!drv->cs)
goto error;
- drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
- if (!drv->flags)
- goto error;
-
for (i = 0; i < minors; ++i) {
- drv->flags[i] = 0;
+ drv->cs[i].flags = 0;
drv->cs[i].driver = drv;
drv->cs[i].ops = drv->ops;
drv->cs[i].minor_index = i;
@@ -1106,53 +1103,9 @@
}
EXPORT_SYMBOL_GPL(gigaset_initdriver);
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
-{
- unsigned long flags;
- struct cardstate *cs = NULL;
- unsigned i;
-
- spin_lock_irqsave(&drv->lock, flags);
- if (drv->blocked)
- goto exit;
- for (i = 0; i < drv->minors; ++i) {
- if ((drv->flags[i] & VALID_MINOR) &&
- !(drv->flags[i] & ASSIGNED)) {
- drv->flags[i] |= ASSIGNED;
- cs = drv->cs + i;
- break;
- }
- }
-exit:
- spin_unlock_irqrestore(&drv->lock, flags);
- return cs;
-}
-EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
-
-void gigaset_unassign(struct cardstate *cs)
-{
- unsigned long flags;
- unsigned *minor_flags;
- struct gigaset_driver *drv;
-
- if (!cs)
- return;
- drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- minor_flags = drv->flags + cs->minor_index;
- if (*minor_flags & VALID_MINOR)
- *minor_flags &= ~ASSIGNED;
- spin_unlock_irqrestore(&drv->lock, flags);
-}
-EXPORT_SYMBOL_GPL(gigaset_unassign);
-
void gigaset_blockdriver(struct gigaset_driver *drv)
{
- unsigned long flags;
- spin_lock_irqsave(&drv->lock, flags);
drv->blocked = 1;
- spin_unlock_irqrestore(&drv->lock, flags);
}
EXPORT_SYMBOL_GPL(gigaset_blockdriver);
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index cec1ef3..5cbf64d8 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -735,7 +735,7 @@
/* revert to selected idle mode */
if (!cs->cidmode) {
cs->at_state.pending_commands |= PC_UMMODE;
- atomic_set(&cs->commands_pending, 1); //FIXME
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -793,15 +793,15 @@
struct at_state_t *at_state;
cs->at_state.pending_commands &= ~PC_INIT;
- atomic_set(&cs->mode, mode);
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
+ cs->mode = mode;
+ cs->mstate = MS_UNINITIALIZED;
gigaset_free_channels(cs);
for (i = 0; i < cs->channels; ++i) {
at_state = &cs->bcs[i].at_state;
if (at_state->pending_commands & PC_CID) {
at_state->pending_commands &= ~PC_CID;
at_state->pending_commands |= PC_NOCID;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
}
}
}
@@ -812,11 +812,11 @@
gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again");
return;
}
- atomic_set(&cs->mstate, state);
- atomic_set(&cs->mode, M_UNKNOWN);
+ cs->mstate = state;
+ cs->mode = M_UNKNOWN;
gigaset_block_channels(cs);
cs->at_state.pending_commands |= PC_INIT;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_INIT");
}
@@ -953,13 +953,13 @@
at_state->pending_commands |= PC_CID;
gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
return;
error:
at_state->pending_commands |= PC_NOCID;
gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
return;
}
@@ -973,12 +973,12 @@
if (retval == 0) {
at_state->pending_commands |= PC_ACCEPT;
gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
} else {
- //FIXME
+ /* error reset */
at_state->pending_commands |= PC_HUP;
gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
}
}
@@ -986,7 +986,7 @@
{
gigaset_free_channels(cs);
- if (atomic_read(&cs->mstate) != MS_LOCKED)
+ if (cs->mstate != MS_LOCKED)
schedule_init(cs, MS_INIT);
cs->isdn_up = 1;
@@ -1000,9 +1000,9 @@
static void finish_shutdown(struct cardstate *cs)
{
- if (atomic_read(&cs->mstate) != MS_LOCKED) {
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
- atomic_set(&cs->mode, M_UNKNOWN);
+ if (cs->mstate != MS_LOCKED) {
+ cs->mstate = MS_UNINITIALIZED;
+ cs->mode = M_UNKNOWN;
}
/* Tell the LL that the device is not available .. */
@@ -1022,10 +1022,10 @@
{
gigaset_block_channels(cs);
- if (atomic_read(&cs->mstate) == MS_READY) {
- atomic_set(&cs->mstate, MS_SHUTDOWN);
+ if (cs->mstate == MS_READY) {
+ cs->mstate = MS_SHUTDOWN;
cs->at_state.pending_commands |= PC_SHUTDOWN;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");
} else
finish_shutdown(cs);
@@ -1120,7 +1120,7 @@
* In fact it doesn't.
*/
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
}
}
@@ -1130,7 +1130,7 @@
int mode;
int i;
- switch (atomic_read(&cs->mstate)) {
+ switch (cs->mstate) {
case MS_UNINITIALIZED:
case MS_READY:
if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||
@@ -1152,20 +1152,20 @@
return -EBUSY;
}
- mode = atomic_read(&cs->mode);
- atomic_set(&cs->mstate, MS_LOCKED);
- atomic_set(&cs->mode, M_UNKNOWN);
+ mode = cs->mode;
+ cs->mstate = MS_LOCKED;
+ cs->mode = M_UNKNOWN;
return mode;
}
static int do_unlock(struct cardstate *cs)
{
- if (atomic_read(&cs->mstate) != MS_LOCKED)
+ if (cs->mstate != MS_LOCKED)
return -EINVAL;
- atomic_set(&cs->mstate, MS_UNINITIALIZED);
- atomic_set(&cs->mode, M_UNKNOWN);
+ cs->mstate = MS_UNINITIALIZED;
+ cs->mode = M_UNKNOWN;
gigaset_free_channels(cs);
if (cs->connected)
schedule_init(cs, MS_INIT);
@@ -1198,17 +1198,17 @@
case ACT_INIT:
cs->at_state.pending_commands &= ~PC_INIT;
cs->cur_at_seq = SEQ_NONE;
- atomic_set(&cs->mode, M_UNIMODEM);
+ cs->mode = M_UNIMODEM;
spin_lock_irqsave(&cs->lock, flags);
if (!cs->cidmode) {
spin_unlock_irqrestore(&cs->lock, flags);
gigaset_free_channels(cs);
- atomic_set(&cs->mstate, MS_READY);
+ cs->mstate = MS_READY;
break;
}
spin_unlock_irqrestore(&cs->lock, flags);
cs->at_state.pending_commands |= PC_CIDMODE;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
break;
case ACT_FAILINIT:
@@ -1234,22 +1234,20 @@
| INS_command;
break;
case ACT_CMODESET:
- if (atomic_read(&cs->mstate) == MS_INIT ||
- atomic_read(&cs->mstate) == MS_RECOVER) {
+ if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
gigaset_free_channels(cs);
- atomic_set(&cs->mstate, MS_READY);
+ cs->mstate = MS_READY;
}
- atomic_set(&cs->mode, M_CID);
+ cs->mode = M_CID;
cs->cur_at_seq = SEQ_NONE;
break;
case ACT_UMODESET:
- atomic_set(&cs->mode, M_UNIMODEM);
+ cs->mode = M_UNIMODEM;
cs->cur_at_seq = SEQ_NONE;
break;
case ACT_FAILCMODE:
cs->cur_at_seq = SEQ_NONE;
- if (atomic_read(&cs->mstate) == MS_INIT ||
- atomic_read(&cs->mstate) == MS_RECOVER) {
+ if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
init_failed(cs, M_UNKNOWN);
break;
}
@@ -1307,7 +1305,7 @@
case ACT_CONNECT:
if (cs->onechannel) {
at_state->pending_commands |= PC_DLE1;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
}
bcs->chstate |= CHS_D_UP;
@@ -1333,7 +1331,7 @@
* DLE only used for M10x with one B channel.
*/
at_state->pending_commands |= PC_DLE0;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
} else
disconnect(p_at_state);
break;
@@ -1369,7 +1367,7 @@
"Could not enter DLE mode. Trying to hang up.\n");
channel = cs->curchannel;
cs->bcs[channel].at_state.pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
case ACT_CID: /* got cid; start dialing */
@@ -1379,7 +1377,7 @@
cs->bcs[channel].at_state.cid = ev->parameter;
cs->bcs[channel].at_state.pending_commands |=
PC_DIAL;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
}
/* fall through */
@@ -1411,14 +1409,14 @@
case ACT_ABORTDIAL: /* error/timeout during dial preparation */
cs->cur_at_seq = SEQ_NONE;
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
case ACT_REMOTEREJECT: /* DISCONNECT_IND after dialling */
case ACT_CONNTIMEOUT: /* timeout waiting for ZSAU=ACTIVE */
case ACT_REMOTEHUP: /* DISCONNECT_IND with established connection */
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
break;
case ACT_GETSTRING: /* warning: RING, ZDLE, ...
are not handled properly anymore */
@@ -1515,7 +1513,7 @@
break;
case ACT_HUP:
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
break;
@@ -1558,7 +1556,7 @@
cs->at_state.pending_commands |= PC_UMMODE;
gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
}
spin_unlock_irqrestore(&cs->lock, flags);
cs->waiting = 0;
@@ -1741,7 +1739,7 @@
int sequence;
unsigned long flags;
- atomic_set(&cs->commands_pending, 0);
+ cs->commands_pending = 0;
if (cs->cur_at_seq) {
gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy");
@@ -1779,7 +1777,7 @@
~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
if (at_state->cid > 0)
at_state->pending_commands |= PC_HUP;
- if (atomic_read(&cs->mstate) == MS_RECOVER) {
+ if (cs->mstate == MS_RECOVER) {
if (at_state->pending_commands & PC_CID) {
at_state->pending_commands |= PC_NOCID;
at_state->pending_commands &= ~PC_CID;
@@ -1793,7 +1791,7 @@
if (cs->at_state.pending_commands == PC_UMMODE
&& !cs->cidmode
&& list_empty(&cs->temp_at_states)
- && atomic_read(&cs->mode) == M_CID) {
+ && cs->mode == M_CID) {
sequence = SEQ_UMMODE;
at_state = &cs->at_state;
for (i = 0; i < cs->channels; ++i) {
@@ -1860,7 +1858,7 @@
}
if (cs->at_state.pending_commands & PC_CIDMODE) {
cs->at_state.pending_commands &= ~PC_CIDMODE;
- if (atomic_read(&cs->mode) == M_UNIMODEM) {
+ if (cs->mode == M_UNIMODEM) {
cs->retry_count = 1;
schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
return;
@@ -1886,11 +1884,11 @@
return;
}
if (bcs->at_state.pending_commands & PC_CID) {
- switch (atomic_read(&cs->mode)) {
+ switch (cs->mode) {
case M_UNIMODEM:
cs->at_state.pending_commands |= PC_CIDMODE;
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
- atomic_set(&cs->commands_pending, 1);
+ cs->commands_pending = 1;
return;
#ifdef GIG_MAYINITONDIAL
case M_UNKNOWN:
@@ -1926,7 +1924,7 @@
for (i = 0; i < 2 * MAX_EVENTS; ++i) {
tail = cs->ev_tail;
if (tail == head) {
- if (!check_flags && !atomic_read(&cs->commands_pending))
+ if (!check_flags && !cs->commands_pending)
break;
check_flags = 0;
spin_unlock_irqrestore(&cs->ev_lock, flags);
@@ -1934,7 +1932,7 @@
spin_lock_irqsave(&cs->ev_lock, flags);
tail = cs->ev_tail;
if (tail == head) {
- if (!atomic_read(&cs->commands_pending))
+ if (!cs->commands_pending)
break;
continue;
}
@@ -1971,7 +1969,7 @@
struct cardstate *cs = (struct cardstate *) data;
/* handle incoming data on control/common channel */
- if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
+ if (cs->inbuf->head != cs->inbuf->tail) {
gig_dbg(DEBUG_INTR, "processing new data");
cs->ops->handle_input(cs->inbuf);
}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 02bdaf2..f365993 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -70,22 +70,13 @@
extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
-/* any combination of these can be given with the 'debug=' parameter to insmod,
- * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
- * DEBUG_INTR.
- */
+/* debug flags, combine by adding/bitwise OR */
enum debuglevel {
- DEBUG_REG = 0x0002, /* serial port I/O register operations */
- DEBUG_OPEN = 0x0004, /* open/close serial port */
- DEBUG_INTR = 0x0008, /* interrupt processing */
- DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on
- interrupt requests, not available as
- run-time option */
+ DEBUG_INTR = 0x00008, /* interrupt processing */
DEBUG_CMD = 0x00020, /* sent/received LL commands */
DEBUG_STREAM = 0x00040, /* application data stream I/O events */
DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
DEBUG_LLDATA = 0x00100, /* sent/received LL data */
- DEBUG_INTR_0 = 0x00200, /* serial port interrupt processing */
DEBUG_DRIVER = 0x00400, /* driver structure */
DEBUG_HDLC = 0x00800, /* M10x HDLC processing */
DEBUG_WRITE = 0x01000, /* M105 data write */
@@ -93,7 +84,7 @@
DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data
structures */
- DEBUG_LOCK = 0x10000, /* semaphore operations */
+ DEBUG_SUSPEND = 0x10000, /* suspend/resume processing */
DEBUG_OUTPUT = 0x20000, /* output to device */
DEBUG_ISO = 0x40000, /* isochronous transfers */
DEBUG_IF = 0x80000, /* character device operations */
@@ -191,6 +182,9 @@
#define HD_OPEN_ATCHANNEL (0x28) // 3070
#define HD_CLOSE_ATCHANNEL (0x29) // 3070
+/* number of B channels supported by base driver */
+#define BAS_CHANNELS 2
+
/* USB frames for isochronous transfer */
#define BAS_FRAMETIME 1 /* number of milliseconds between frames */
#define BAS_NUMFRAMES 8 /* number of frames per URB */
@@ -313,7 +307,7 @@
struct bc_state *bcs;
struct cardstate *cs;
int inputstate;
- atomic_t head, tail;
+ int head, tail;
unsigned char data[RBUFSIZE];
};
@@ -335,9 +329,9 @@
* are also filled with that value
*/
struct isowbuf_t {
- atomic_t read;
- atomic_t nextread;
- atomic_t write;
+ int read;
+ int nextread;
+ int write;
atomic_t writesem;
int wbits;
unsigned char data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
@@ -350,11 +344,13 @@
* - urb: pointer to the URB itself
* - bcs: pointer to the B Channel control structure
* - limit: end of write buffer area covered by this URB
+ * - status: URB completion status
*/
struct isow_urbctx_t {
struct urb *urb;
struct bc_state *bcs;
int limit;
+ int status;
};
/* AT state structure
@@ -439,14 +435,15 @@
unsigned minor_index;
struct device *dev;
struct device *tty_dev;
+ unsigned flags;
const struct gigaset_ops *ops;
/* Stuff to handle communication */
wait_queue_head_t waitqueue;
int waiting;
- atomic_t mode; /* see M_XXXX */
- atomic_t mstate; /* Modem state: see MS_XXXX */
+ int mode; /* see M_XXXX */
+ int mstate; /* Modem state: see MS_XXXX */
/* only changed by the event layer */
int cmd_result;
@@ -503,7 +500,7 @@
processed */
int curchannel; /* channel those commands are meant
for */
- atomic_t commands_pending; /* flag(s) in xxx.commands_pending have
+ int commands_pending; /* flag(s) in xxx.commands_pending have
been set */
struct tasklet_struct event_tasklet;
/* tasklet for serializing AT commands.
@@ -543,7 +540,6 @@
unsigned minor;
unsigned minors;
struct cardstate *cs;
- unsigned *flags;
int blocked;
const struct gigaset_ops *ops;
@@ -559,7 +555,7 @@
struct bas_bc_state {
/* isochronous output state */
- atomic_t running;
+ int running;
atomic_t corrbytes;
spinlock_t isooutlock;
struct isow_urbctx_t isoouturbs[BAS_OUTURBS];
@@ -574,6 +570,7 @@
struct urb *isoinurbs[BAS_INURBS];
unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
struct urb *isoindone; /* completed isoc read URB */
+ int isoinstatus; /* status of completed URB */
int loststatus; /* status of dropped URB */
unsigned isoinlost; /* number of bytes lost */
/* state of bit unstuffing algorithm
@@ -770,10 +767,6 @@
void gigaset_debugdrivers(void);
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
struct cardstate *gigaset_get_cs_by_id(int id);
-
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
-void gigaset_unassign(struct cardstate *cs);
void gigaset_blockdriver(struct gigaset_driver *drv);
/* Allocate and initialize card state. Calls hardware dependent
@@ -792,7 +785,7 @@
void gigaset_stop(struct cardstate *cs);
/* Tell common.c that the driver is being unloaded. */
-void gigaset_shutdown(struct cardstate *cs);
+int gigaset_shutdown(struct cardstate *cs);
/* Tell common.c that an skb has been sent. */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index eb50f3d..af195b0 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -28,12 +28,11 @@
return -EINVAL;
if (cmd < 0) {
- *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
+ *arg = cs->mstate == MS_LOCKED;
return 0;
}
- if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
- && cs->connected) {
+ if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8);
@@ -104,7 +103,7 @@
if (*arg != 1)
return -EINVAL;
- if (atomic_read(&cs->mstate) != MS_LOCKED)
+ if (cs->mstate != MS_LOCKED)
return -EBUSY;
if (!cs->connected) {
@@ -162,7 +161,7 @@
tty->driver_data = NULL;
cs = gigaset_get_cs_by_tty(tty);
- if (!cs)
+ if (!cs || !try_module_get(cs->driver->owner))
return -ENODEV;
if (mutex_lock_interruptible(&cs->mutex))
@@ -208,6 +207,8 @@
}
mutex_unlock(&cs->mutex);
+
+ module_put(cs->driver->owner);
}
static int if_ioctl(struct tty_struct *tty, struct file *file,
@@ -364,7 +365,7 @@
if (!cs->open_count)
warn("%s: device not opened", __func__);
- else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ else if (cs->mstate != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY;
} else if (!cs->connected) {
@@ -398,9 +399,9 @@
if (!cs->open_count)
warn("%s: device not opened", __func__);
- else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ else if (cs->mstate != MS_LOCKED) {
warn("can't write to unlocked device");
- retval = -EBUSY; //FIXME
+ retval = -EBUSY;
} else if (!cs->connected) {
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
retval = -EBUSY; //FIXME
@@ -430,7 +431,7 @@
if (!cs->open_count)
warn("%s: device not opened", __func__);
- else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+ else if (cs->mstate != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY;
} else if (!cs->connected) {
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index e0505f2..e30a777 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -23,9 +23,9 @@
*/
void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
{
- atomic_set(&iwb->read, 0);
- atomic_set(&iwb->nextread, 0);
- atomic_set(&iwb->write, 0);
+ iwb->read = 0;
+ iwb->nextread = 0;
+ iwb->write = 0;
atomic_set(&iwb->writesem, 1);
iwb->wbits = 0;
iwb->idle = idle;
@@ -39,8 +39,8 @@
{
int read, write, freebytes;
- read = atomic_read(&iwb->read);
- write = atomic_read(&iwb->write);
+ read = iwb->read;
+ write = iwb->write;
if ((freebytes = read - write) > 0) {
/* no wraparound: need padding space within regular area */
return freebytes - BAS_OUTBUFPAD;
@@ -62,7 +62,7 @@
int read;
if (a == b)
return 0;
- read = atomic_read(&iwb->read);
+ read = iwb->read;
if (a < b) {
if (a < read && read <= b)
return +1;
@@ -91,18 +91,18 @@
#ifdef CONFIG_GIGASET_DEBUG
gig_dbg(DEBUG_ISO,
"%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
- __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+ __func__, iwb->data[iwb->write], iwb->wbits);
#endif
return 1;
}
/* finish writing
- * release the write semaphore and update the maximum buffer fill level
+ * release the write semaphore
* returns the current write position
*/
static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
{
- int write = atomic_read(&iwb->write);
+ int write = iwb->write;
atomic_inc(&iwb->writesem);
return write;
}
@@ -116,7 +116,7 @@
*/
static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
{
- int write = atomic_read(&iwb->write);
+ int write = iwb->write;
data <<= iwb->wbits;
data |= iwb->data[write];
nbits += iwb->wbits;
@@ -128,7 +128,7 @@
}
iwb->wbits = nbits;
iwb->data[write] = data & 0xff;
- atomic_set(&iwb->write, write);
+ iwb->write = write;
}
/* put final flag on HDLC bitstream
@@ -142,7 +142,7 @@
/* add two flags, thus reliably covering one byte */
isowbuf_putbits(iwb, 0x7e7e, 8);
/* recover the idle flag byte */
- write = atomic_read(&iwb->write);
+ write = iwb->write;
iwb->idle = iwb->data[write];
gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
/* mask extraneous bits in buffer */
@@ -160,8 +160,8 @@
int read, write, limit, src, dst;
unsigned char pbyte;
- read = atomic_read(&iwb->nextread);
- write = atomic_read(&iwb->write);
+ read = iwb->nextread;
+ write = iwb->write;
if (likely(read == write)) {
/* return idle frame */
return read < BAS_OUTBUFPAD ?
@@ -176,7 +176,7 @@
err("invalid size %d", size);
return -EINVAL;
}
- src = atomic_read(&iwb->read);
+ src = iwb->read;
if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
(read < src && limit >= src))) {
err("isoc write buffer frame reservation violated");
@@ -191,7 +191,8 @@
if (!isowbuf_startwrite(iwb))
return -EBUSY;
/* write position could have changed */
- if (limit >= (write = atomic_read(&iwb->write))) {
+ write = iwb->write;
+ if (limit >= write) {
pbyte = iwb->data[write]; /* save
partial byte */
limit = write + BAS_OUTBUFPAD;
@@ -213,7 +214,7 @@
__func__, pbyte, limit);
iwb->data[limit] = pbyte; /* restore
partial byte */
- atomic_set(&iwb->write, limit);
+ iwb->write = limit;
}
isowbuf_donewrite(iwb);
}
@@ -233,7 +234,7 @@
limit = src;
}
}
- atomic_set(&iwb->nextread, limit);
+ iwb->nextread = limit;
return read;
}
@@ -477,7 +478,7 @@
unsigned char c;
if (unlikely(count <= 0))
- return atomic_read(&iwb->write); /* better ideas? */
+ return iwb->write;
if (isowbuf_freebytes(iwb) < count ||
!isowbuf_startwrite(iwb)) {
@@ -486,13 +487,13 @@
}
gig_dbg(DEBUG_STREAM, "put %d bytes", count);
- write = atomic_read(&iwb->write);
+ write = iwb->write;
do {
c = bitrev8(*in++);
iwb->data[write++] = c;
write %= BAS_OUTBUFSIZE;
} while (--count > 0);
- atomic_set(&iwb->write, write);
+ iwb->write = write;
iwb->idle = c;
return isowbuf_donewrite(iwb);
@@ -947,8 +948,8 @@
unsigned tail, head, numbytes;
unsigned char *src;
- head = atomic_read(&inbuf->head);
- while (head != (tail = atomic_read(&inbuf->tail))) {
+ head = inbuf->head;
+ while (head != (tail = inbuf->tail)) {
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head > tail)
tail = RBUFSIZE;
@@ -956,7 +957,7 @@
numbytes = tail - head;
gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
- if (atomic_read(&cs->mstate) == MS_LOCKED) {
+ if (cs->mstate == MS_LOCKED) {
gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes);
@@ -970,7 +971,7 @@
if (head == RBUFSIZE)
head = 0;
gig_dbg(DEBUG_INTR, "setting head to %u", head);
- atomic_set(&inbuf->head, head);
+ inbuf->head = head;
}
}
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index ea44302..fceeb1d 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/poll.h>
+#include <linux/completion.h>
/* Version Information */
#define DRIVER_AUTHOR "Tilman Schmidt"
@@ -48,7 +49,7 @@
struct platform_device dev;
struct tty_struct *tty;
atomic_t refcnt;
- struct mutex dead_mutex;
+ struct completion dead_cmp;
};
static struct platform_driver device_driver = {
@@ -240,7 +241,7 @@
struct cmdbuf_t *cb;
unsigned long flags;
- gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
@@ -498,7 +499,7 @@
static void cs_put(struct cardstate *cs)
{
if (atomic_dec_and_test(&cs->hw.ser->refcnt))
- mutex_unlock(&cs->hw.ser->dead_mutex);
+ complete(&cs->hw.ser->dead_cmp);
}
/*
@@ -527,8 +528,8 @@
cs->dev = &cs->hw.ser->dev.dev;
cs->hw.ser->tty = tty;
- mutex_init(&cs->hw.ser->dead_mutex);
atomic_set(&cs->hw.ser->refcnt, 1);
+ init_completion(&cs->hw.ser->dead_cmp);
tty->disc_data = cs;
@@ -536,14 +537,13 @@
* startup system and notify the LL that we are ready to run
*/
if (startmode == SM_LOCKED)
- atomic_set(&cs->mstate, MS_LOCKED);
+ cs->mstate = MS_LOCKED;
if (!gigaset_start(cs)) {
tasklet_kill(&cs->write_tasklet);
goto error;
}
gig_dbg(DEBUG_INIT, "Startup of HLL done");
- mutex_lock(&cs->hw.ser->dead_mutex);
return 0;
error:
@@ -577,7 +577,7 @@
else {
/* wait for running methods to finish */
if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
- mutex_lock(&cs->hw.ser->dead_mutex);
+ wait_for_completion(&cs->hw.ser->dead_cmp);
}
/* stop operations */
@@ -714,8 +714,8 @@
return;
}
- tail = atomic_read(&inbuf->tail);
- head = atomic_read(&inbuf->head);
+ tail = inbuf->tail;
+ head = inbuf->head;
gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",
head, tail, count);
@@ -742,7 +742,7 @@
}
gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
- atomic_set(&inbuf->tail, tail);
+ inbuf->tail = tail;
/* Everything was received .. Push data into handler */
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index ca4bee1..77d20ab 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -104,12 +104,17 @@
* flags per packet.
*/
+/* functions called if a device of this driver is connected/disconnected */
static int gigaset_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static void gigaset_disconnect(struct usb_interface *interface);
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+static int gigaset_pre_reset(struct usb_interface *intf);
+
static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = {
@@ -117,12 +122,17 @@
.probe = gigaset_probe,
.disconnect = gigaset_disconnect,
.id_table = gigaset_table,
+ .suspend = gigaset_suspend,
+ .resume = gigaset_resume,
+ .reset_resume = gigaset_resume,
+ .pre_reset = gigaset_pre_reset,
+ .post_reset = gigaset_resume,
};
struct usb_cardstate {
struct usb_device *udev; /* usb device pointer */
struct usb_interface *interface; /* interface for this device */
- atomic_t busy; /* bulk output in progress */
+ int busy; /* bulk output in progress */
/* Output buffer */
unsigned char *bulk_out_buffer;
@@ -314,7 +324,7 @@
gig_dbg(DEBUG_OUTPUT, "modem_fill");
- if (atomic_read(&cs->hw.usb->busy)) {
+ if (cs->hw.usb->busy) {
gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
return;
}
@@ -361,18 +371,13 @@
{
struct inbuf_t *inbuf = urb->context;
struct cardstate *cs = inbuf->cs;
- int resubmit = 0;
+ int status = urb->status;
int r;
unsigned numbytes;
unsigned char *src;
unsigned long flags;
- if (!urb->status) {
- if (!cs->connected) {
- err("%s: disconnected", __func__); /* should never happen */
- return;
- }
-
+ if (!status) {
numbytes = urb->actual_length;
if (numbytes) {
@@ -389,28 +394,26 @@
}
} else
gig_dbg(DEBUG_INTR, "Received zero block length");
- resubmit = 1;
} else {
/* The urb might have been killed. */
- gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
- __func__, urb->status);
- if (urb->status != -ENOENT) { /* not killed */
- if (!cs->connected) {
- err("%s: disconnected", __func__); /* should never happen */
- return;
- }
- resubmit = 1;
- }
+ gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d",
+ __func__, status);
+ if (status == -ENOENT || status == -ESHUTDOWN)
+ /* killed or endpoint shutdown: don't resubmit */
+ return;
}
- if (resubmit) {
- spin_lock_irqsave(&cs->lock, flags);
- r = cs->connected ? usb_submit_urb(urb, GFP_ATOMIC) : -ENODEV;
+ /* resubmit URB */
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!cs->connected) {
spin_unlock_irqrestore(&cs->lock, flags);
- if (r)
- dev_err(cs->dev, "error %d when resubmitting urb.\n",
- -r);
+ err("%s: disconnected", __func__);
+ return;
}
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ if (r)
+ dev_err(cs->dev, "error %d resubmitting URB\n", -r);
}
@@ -418,19 +421,28 @@
static void gigaset_write_bulk_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
+ int status = urb->status;
unsigned long flags;
- if (urb->status)
+ switch (status) {
+ case 0: /* normal completion */
+ break;
+ case -ENOENT: /* killed */
+ gig_dbg(DEBUG_ANY, "%s: killed", __func__);
+ cs->hw.usb->busy = 0;
+ return;
+ default:
dev_err(cs->dev, "bulk transfer failed (status %d)\n",
- -urb->status);
+ -status);
/* That's all we can do. Communication problems
are handled by timeouts or network protocols. */
+ }
spin_lock_irqsave(&cs->lock, flags);
if (!cs->connected) {
err("%s: not connected", __func__);
} else {
- atomic_set(&cs->hw.usb->busy, 0);
+ cs->hw.usb->busy = 0;
tasklet_schedule(&cs->write_tasklet);
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -478,14 +490,14 @@
cb->offset += count;
cb->len -= count;
- atomic_set(&ucs->busy, 1);
+ ucs->busy = 1;
spin_lock_irqsave(&cs->lock, flags);
status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV;
spin_unlock_irqrestore(&cs->lock, flags);
if (status) {
- atomic_set(&ucs->busy, 0);
+ ucs->busy = 0;
err("could not submit urb (error %d)\n",
-status);
cb->len = 0; /* skip urb => remove cb+wakeup
@@ -504,7 +516,7 @@
struct cmdbuf_t *cb;
unsigned long flags;
- gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
"CMD Transmit", len, buf);
@@ -641,7 +653,7 @@
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
skb_pull(bcs->tx_skb, count);
- atomic_set(&ucs->busy, 1);
+ ucs->busy = 1;
gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
spin_lock_irqsave(&cs->lock, flags);
@@ -659,7 +671,7 @@
if (ret) {
err("could not submit urb (error %d)\n", -ret);
- atomic_set(&ucs->busy, 0);
+ ucs->busy = 0;
}
if (!bcs->tx_skb->len) {
@@ -680,53 +692,44 @@
{
int retval;
struct usb_device *udev = interface_to_usbdev(interface);
- unsigned int ifnum;
- struct usb_host_interface *hostif;
+ struct usb_host_interface *hostif = interface->cur_altsetting;
struct cardstate *cs = NULL;
struct usb_cardstate *ucs = NULL;
struct usb_endpoint_descriptor *endpoint;
int buffer_size;
- int alt;
- gig_dbg(DEBUG_ANY,
- "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
- __func__, le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- retval = -ENODEV; //FIXME
+ gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__);
/* See if the device offered us matches what we can accept */
if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) ||
- (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID))
- return -ENODEV;
-
- /* this starts to become ascii art... */
- hostif = interface->cur_altsetting;
- alt = hostif->desc.bAlternateSetting;
- ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
-
- if (alt != 0 || ifnum != 0) {
- dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt);
+ (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) {
+ gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
return -ENODEV;
}
-
- /* Reject application specific intefaces
- *
- */
+ if (hostif->desc.bInterfaceNumber != 0) {
+ gig_dbg(DEBUG_ANY, "interface %d not for me - skip",
+ hostif->desc.bInterfaceNumber);
+ return -ENODEV;
+ }
+ if (hostif->desc.bAlternateSetting != 0) {
+ dev_notice(&udev->dev, "unsupported altsetting %d - skip",
+ hostif->desc.bAlternateSetting);
+ return -ENODEV;
+ }
if (hostif->desc.bInterfaceClass != 255) {
- dev_info(&udev->dev,
- "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n",
- __func__, ifnum, hostif->desc.bInterfaceClass);
+ dev_notice(&udev->dev, "unsupported interface class %d - skip",
+ hostif->desc.bInterfaceClass);
return -ENODEV;
}
dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
- cs = gigaset_getunassignedcs(driver);
- if (!cs) {
- dev_warn(&udev->dev, "no free cardstate\n");
+ /* allocate memory for our device state and intialize it */
+ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+ if (!cs)
return -ENODEV;
- }
ucs = cs->hw.usb;
/* save off device structure ptrs for later use */
@@ -759,7 +762,7 @@
endpoint = &hostif->endpoint[1].desc;
- atomic_set(&ucs->busy, 0);
+ ucs->busy = 0;
ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ucs->read_urb) {
@@ -792,7 +795,7 @@
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
- atomic_set(&cs->mstate, MS_LOCKED);
+ cs->mstate = MS_LOCKED;
if (!gigaset_start(cs)) {
tasklet_kill(&cs->write_tasklet);
@@ -813,7 +816,7 @@
usb_put_dev(ucs->udev);
ucs->udev = NULL;
ucs->interface = NULL;
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
return retval;
}
@@ -824,6 +827,9 @@
cs = usb_get_intfdata(interface);
ucs = cs->hw.usb;
+
+ dev_info(cs->dev, "disconnecting Gigaset USB adapter\n");
+
usb_kill_urb(ucs->read_urb);
gigaset_stop(cs);
@@ -831,7 +837,7 @@
usb_set_intfdata(interface, NULL);
tasklet_kill(&cs->write_tasklet);
- usb_kill_urb(ucs->bulk_out_urb); /* FIXME: only if active? */
+ usb_kill_urb(ucs->bulk_out_urb);
kfree(ucs->bulk_out_buffer);
usb_free_urb(ucs->bulk_out_urb);
@@ -844,7 +850,53 @@
ucs->interface = NULL;
ucs->udev = NULL;
cs->dev = NULL;
- gigaset_unassign(cs);
+ gigaset_freecs(cs);
+}
+
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended or reset.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+
+ /* stop activity */
+ cs->connected = 0; /* prevent rescheduling */
+ usb_kill_urb(cs->hw.usb->read_urb);
+ tasklet_kill(&cs->write_tasklet);
+ usb_kill_urb(cs->hw.usb->bulk_out_urb);
+
+ gig_dbg(DEBUG_SUSPEND, "suspend complete");
+ return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed or reset.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+ struct cardstate *cs = usb_get_intfdata(intf);
+ int rc;
+
+ /* resubmit interrupt URB */
+ cs->connected = 1;
+ rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL);
+ if (rc) {
+ dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc);
+ return rc;
+ }
+
+ gig_dbg(DEBUG_SUSPEND, "resume complete");
+ return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+ /* same as suspend */
+ return gigaset_suspend(intf, PMSG_ON);
}
static const struct gigaset_ops ops = {
@@ -880,11 +932,6 @@
&ops, THIS_MODULE)) == NULL)
goto error;
- /* allocate memory for our device state and intialize it */
- cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
- if (!cardstate)
- goto error;
-
/* register this driver with the USB subsystem */
result = usb_register(&gigaset_usb_driver);
if (result < 0) {
@@ -897,9 +944,7 @@
info(DRIVER_DESC);
return 0;
-error: if (cardstate)
- gigaset_freecs(cardstate);
- cardstate = NULL;
+error:
if (driver)
gigaset_freedriver(driver);
driver = NULL;
@@ -913,11 +958,16 @@
*/
static void __exit usb_gigaset_exit(void)
{
+ int i;
+
gigaset_blockdriver(driver); /* => probe will fail
* => no gigaset_start any more
*/
- gigaset_shutdown(cardstate);
+ /* stop all connected devices */
+ for (i = 0; i < driver->minors; i++)
+ gigaset_shutdown(driver->cs + i);
+
/* from now on, no isdn callback should be possible */
/* deregister this driver with the USB subsystem */
@@ -925,8 +975,6 @@
/* this will call the disconnect-callback */
/* from now on, no disconnect/probe callback should be running */
- gigaset_freecs(cardstate);
- cardstate = NULL;
gigaset_freedriver(driver);
driver = NULL;
}
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
index 0db9cc6..84318ec 100644
--- a/drivers/isdn/hardware/eicon/debug.c
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -1188,7 +1188,7 @@
if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
(features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
- dword rx_dma_magic;
+ dword uninitialized_var(rx_dma_magic);
if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) {
pC->xbuffer[0] = LLI;
pC->xbuffer[1] = 8;
diff --git a/drivers/isdn/hardware/eicon/debuglib.c b/drivers/isdn/hardware/eicon/debuglib.c
index a19b7ff..e39c5c1 100644
--- a/drivers/isdn/hardware/eicon/debuglib.c
+++ b/drivers/isdn/hardware/eicon/debuglib.c
@@ -106,7 +106,7 @@
return (1) ;
}
/*
- * Check if we registered whith an old maint driver (see debuglib.h)
+ * Check if we registered with an old maint driver (see debuglib.h)
*/
if ( myDriverDebugHandle.dbg_end != NULL
/* location of 'dbg_prt' in _OldDbgHandle_ struct */
diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h
index 11b3b9e..016410c 100644
--- a/drivers/isdn/hardware/eicon/debuglib.h
+++ b/drivers/isdn/hardware/eicon/debuglib.h
@@ -177,7 +177,7 @@
} }
#endif
/*
- * For event level debug use a separate define, the paramete are
+ * For event level debug use a separate define, the parameter are
* different and cause compiler errors on some systems.
*/
#define DBG_EVL_ID(args) \
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
index ce8df38..10760b3 100644
--- a/drivers/isdn/hardware/eicon/di.c
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -285,7 +285,7 @@
a->ram_in(a, &RcIn->RcId),
a->ram_in(a, &RcIn->RcCh),
a->ram_inw(a, &RcIn->Reference),
- tmp[0], /* type of extended informtion */
+ tmp[0], /* type of extended information */
tmp[1]); /* extended information */
a->ram_out(a, &RcIn->Rc, 0);
}
diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
index ffa2afa..1403a54 100644
--- a/drivers/isdn/hardware/eicon/diva.c
+++ b/drivers/isdn/hardware/eicon/diva.c
@@ -515,12 +515,11 @@
irqreturn_t diva_os_irq_wrapper(int irq, void *context)
{
- diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
+ diva_os_xdi_adapter_t *a = context;
diva_xdi_clear_interrupts_proc_t clear_int_proc;
- if (!a || !a->xdi_adapter.diva_isr_handler) {
+ if (!a || !a->xdi_adapter.diva_isr_handler)
return IRQ_NONE;
- }
if ((clear_int_proc = a->clear_interrupts_proc)) {
(*clear_int_proc) (a);
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index ccd35d0..1ff98e7 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -4941,7 +4941,7 @@
/* b = IE1 */
/* S = IE1 length + cont. */
/* b = IE2 */
- /* S = IE2 lenght + cont. */
+ /* S = IE2 length + cont. */
sendf(plci->appl,
_MANUFACTURER_I,
Id,
@@ -9027,7 +9027,7 @@
/* facility is a nested structure */
/* FTY can be more than once */
- if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
+ if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f))
{
add_i[0] = (byte *)"\x02\x02\x00"; /* use neither b nor d channel */
}
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 035d158..0f1db1f 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -263,11 +263,7 @@
outl(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
#ifdef __powerpc__
-#ifdef CONFIG_APUS
- *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#else
*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#endif /* CONFIG_APUS */
#else
*ptr++ = inl(cs->hw.avm.isac);
#endif /* __powerpc__ */
@@ -328,11 +324,7 @@
if (cs->subtyp == AVM_FRITZ_PCI) {
while (cnt<count) {
#ifdef __powerpc__
-#ifdef CONFIG_APUS
- out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#else
out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#endif /* CONFIG_APUS */
#else
outl(*ptr++, cs->hw.avm.isac);
#endif /* __powerpc__ */
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index f854501..d3999a8 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -541,7 +541,7 @@
}
ctrl = &cinfo->capi_ctrl;
if(len < CAPI_MSG_BASELEN) {
- printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n",
+ printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, length %d!\n",
card->myid, len);
return;
}
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 9cb6e50..133eb18 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1917,7 +1917,6 @@
info->owner = THIS_MODULE;
#endif
spin_lock_init(&info->readlock);
- init_MUTEX(&info->write_sem);
sprintf(info->last_cause, "0000");
sprintf(info->last_num, "none");
info->last_dir = 0;
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
index a943d07..f93de4a 100644
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ b/drivers/isdn/i4l/isdn_ttyfax.c
@@ -834,7 +834,7 @@
char *rp = &f->resolution;
p[0] += 2;
- if (!info->faxonline & 1) /* not outgoing connection */
+ if (!(info->faxonline & 1)) /* not outgoing connection */
PARSE_ERROR1;
for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 82d957b..bf7997a 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1302,7 +1302,7 @@
}
break;
case ISDN_CMD_DIAL:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1328,7 +1328,7 @@
}
break;
case ISDN_CMD_ACCEPTD:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ICN_BCH) {
a = c->arg + 1;
@@ -1348,7 +1348,7 @@
}
break;
case ISDN_CMD_ACCEPTB:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ICN_BCH) {
a = c->arg + 1;
@@ -1366,7 +1366,7 @@
}
break;
case ISDN_CMD_HANGUP:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ICN_BCH) {
a = c->arg + 1;
@@ -1375,7 +1375,7 @@
}
break;
case ISDN_CMD_SETEAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1391,7 +1391,7 @@
}
break;
case ISDN_CMD_CLREAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1405,7 +1405,7 @@
}
break;
case ISDN_CMD_SETL2:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
if ((c->arg & 255) < ICN_BCH) {
a = c->arg;
@@ -1424,7 +1424,7 @@
}
break;
case ISDN_CMD_SETL3:
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return 0;
default:
@@ -1471,7 +1471,7 @@
icn_card *card = icn_findcard(id);
if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return (icn_writecmd(buf, len, 1, card));
}
@@ -1486,7 +1486,7 @@
icn_card *card = icn_findcard(id);
if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return (icn_readstatus(buf, len, card));
}
@@ -1501,7 +1501,7 @@
icn_card *card = icn_findcard(id);
if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
+ if (!(card->flags & ICN_FLAGS_RUNNING))
return -ENODEV;
return (icn_sendbuf(channel, ack, skb, card));
}
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index bb92e3c..655ef9a 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1184,7 +1184,7 @@
}
break;
case ISDN_CMD_DIAL:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1210,7 +1210,7 @@
}
break;
case ISDN_CMD_ACCEPTD:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ISDNLOOP_BCH) {
a = c->arg + 1;
@@ -1238,7 +1238,7 @@
}
break;
case ISDN_CMD_ACCEPTB:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ISDNLOOP_BCH) {
a = c->arg + 1;
@@ -1264,7 +1264,7 @@
i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
break;
case ISDN_CMD_HANGUP:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (c->arg < ISDNLOOP_BCH) {
a = c->arg + 1;
@@ -1273,7 +1273,7 @@
}
break;
case ISDN_CMD_SETEAZ:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if (card->leased)
break;
@@ -1303,7 +1303,7 @@
}
break;
case ISDN_CMD_SETL2:
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
if ((c->arg & 255) < ISDNLOOP_BCH) {
a = c->arg;
@@ -1395,7 +1395,7 @@
isdnloop_card *card = isdnloop_findcard(id);
if (card) {
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
return (isdnloop_readstatus(buf, len, card));
}
@@ -1410,7 +1410,7 @@
isdnloop_card *card = isdnloop_findcard(id);
if (card) {
- if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+ if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
/* ack request stored in skb scratch area */
*(skb->head) = ack;
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 64c66b3..4a93878 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -137,12 +137,14 @@
EXPORT_SYMBOL_GPL(led_classdev_register);
/**
- * led_classdev_unregister - unregisters a object of led_properties class.
+ * __led_classdev_unregister - unregisters a object of led_properties class.
* @led_cdev: the led device to unregister
+ * @suspended: indicates whether system-wide suspend or resume is in progress
*
* Unregisters a previously registered via led_classdev_register object.
*/
-void led_classdev_unregister(struct led_classdev *led_cdev)
+void __led_classdev_unregister(struct led_classdev *led_cdev,
+ bool suspended)
{
device_remove_file(led_cdev->dev, &dev_attr_brightness);
#ifdef CONFIG_LEDS_TRIGGERS
@@ -153,13 +155,16 @@
up_write(&led_cdev->trigger_lock);
#endif
- device_unregister(led_cdev->dev);
+ if (suspended)
+ device_pm_schedule_removal(led_cdev->dev);
+ else
+ device_unregister(led_cdev->dev);
down_write(&leds_list_lock);
list_del(&led_cdev->node);
up_write(&leds_list_lock);
}
-EXPORT_SYMBOL_GPL(led_classdev_unregister);
+EXPORT_SYMBOL_GPL(__led_classdev_unregister);
static int __init leds_init(void)
{
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index e2eec38..84f85e2 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -52,57 +52,82 @@
/*D:130
* Device configurations
*
- * The configuration information for a device consists of a series of fields.
- * We don't really care what they are: the Launcher set them up, and the driver
- * will look at them during setup.
+ * The configuration information for a device consists of one or more
+ * virtqueues, a feature bitmaks, and some configuration bytes. The
+ * configuration bytes don't really matter to us: the Launcher sets them up, and
+ * the driver will look at them during setup.
*
- * For us these fields come immediately after that device's descriptor in the
- * lguest_devices page.
- *
- * Each field starts with a "type" byte, a "length" byte, then that number of
- * bytes of configuration information. The device descriptor tells us the
- * total configuration length so we know when we've reached the last field. */
+ * A convenient routine to return the device's virtqueue config array:
+ * immediately after the descriptor. */
+static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
+{
+ return (void *)(desc + 1);
+}
-/* type + length bytes */
-#define FHDR_LEN 2
+/* The features come immediately after the virtqueues. */
+static u8 *lg_features(const struct lguest_device_desc *desc)
+{
+ return (void *)(lg_vq(desc) + desc->num_vq);
+}
-/* This finds the first field of a given type for a device's configuration. */
-static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len)
+/* The config space comes after the two feature bitmasks. */
+static u8 *lg_config(const struct lguest_device_desc *desc)
+{
+ return lg_features(desc) + desc->feature_len * 2;
+}
+
+/* The total size of the config page used by this device (incl. desc) */
+static unsigned desc_size(const struct lguest_device_desc *desc)
+{
+ return sizeof(*desc)
+ + desc->num_vq * sizeof(struct lguest_vqconfig)
+ + desc->feature_len * 2
+ + desc->config_len;
+}
+
+/* This tests (and acknowleges) a feature bit. */
+static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
{
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
- int i;
+ u8 *features;
- for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) {
- if (desc->config[i] == type) {
- /* Mark it used, so Host can know we looked at it, and
- * also so we won't find the same one twice. */
- desc->config[i] |= 0x80;
- /* Remember, the second byte is the length. */
- *len = desc->config[i+1];
- /* We return a pointer to the field header. */
- return desc->config + i;
- }
- }
+ /* Obviously if they ask for a feature off the end of our feature
+ * bitmap, it's not set. */
+ if (fbit / 8 > desc->feature_len)
+ return false;
- /* Not found: return NULL for failure. */
- return NULL;
+ /* The feature bitmap comes after the virtqueues. */
+ features = lg_features(desc);
+ if (!(features[fbit / 8] & (1 << (fbit % 8))))
+ return false;
+
+ /* We set the matching bit in the other half of the bitmap to tell the
+ * Host we want to use this feature. We don't use this yet, but we
+ * could in future. */
+ features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
+ return true;
}
/* Once they've found a field, getting a copy of it is easy. */
-static void lg_get(struct virtio_device *vdev, void *token,
+static void lg_get(struct virtio_device *vdev, unsigned int offset,
void *buf, unsigned len)
{
- /* Check they didn't ask for more than the length of the field! */
- BUG_ON(len > ((u8 *)token)[1]);
- memcpy(buf, token + FHDR_LEN, len);
+ struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+
+ /* Check they didn't ask for more than the length of the config! */
+ BUG_ON(offset + len > desc->config_len);
+ memcpy(buf, lg_config(desc) + offset, len);
}
/* Setting the contents is also trivial. */
-static void lg_set(struct virtio_device *vdev, void *token,
+static void lg_set(struct virtio_device *vdev, unsigned int offset,
const void *buf, unsigned len)
{
- BUG_ON(len > ((u8 *)token)[1]);
- memcpy(token + FHDR_LEN, buf, len);
+ struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+
+ /* Check they didn't ask for more than the length of the config! */
+ BUG_ON(offset + len > desc->config_len);
+ memcpy(lg_config(desc) + offset, buf, len);
}
/* The operations to get and set the status word just access the status field
@@ -114,9 +139,20 @@
static void lg_set_status(struct virtio_device *vdev, u8 status)
{
+ BUG_ON(!status);
to_lgdev(vdev)->desc->status = status;
}
+/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
+ * address of the device. The Host will zero the status and all the
+ * features. */
+static void lg_reset(struct virtio_device *vdev)
+{
+ unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
+
+ hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+}
+
/*
* Virtqueues
*
@@ -165,39 +201,29 @@
*
* So we provide devices with a "find virtqueue and set it up" function. */
static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
- bool (*callback)(struct virtqueue *vq))
+ unsigned index,
+ void (*callback)(struct virtqueue *vq))
{
+ struct lguest_device *ldev = to_lgdev(vdev);
struct lguest_vq_info *lvq;
struct virtqueue *vq;
- unsigned int len;
- void *token;
int err;
- /* Look for a field of the correct type to mark a virtqueue. Note that
- * if this succeeds, then the type will be changed so it won't be found
- * again, and future lg_find_vq() calls will find the next
- * virtqueue (if any). */
- token = vdev->config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len);
- if (!token)
+ /* We must have this many virtqueues. */
+ if (index >= ldev->desc->num_vq)
return ERR_PTR(-ENOENT);
lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
if (!lvq)
return ERR_PTR(-ENOMEM);
- /* Note: we could use a configuration space inside here, just like we
- * do for the device. This would allow expansion in future, because
- * our configuration system is designed to be expansible. But this is
- * way easier. */
- if (len != sizeof(lvq->config)) {
- dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len);
- err = -EIO;
- goto free_lvq;
- }
- /* Make a copy of the "struct lguest_vqconfig" field. We need a copy
- * because the config space might not be aligned correctly. */
- vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config));
+ /* Make a copy of the "struct lguest_vqconfig" entry, which sits after
+ * the descriptor. We need a copy because the config space might not
+ * be aligned correctly. */
+ memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
+ printk("Mapping virtqueue %i addr %lx\n", index,
+ (unsigned long)lvq->config.pfn << PAGE_SHIFT);
/* Figure out how many pages the ring will take, and map that memory */
lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
DIV_ROUND_UP(vring_size(lvq->config.num,
@@ -259,11 +285,12 @@
/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
- .find = lg_find,
+ .feature = lg_feature,
.get = lg_get,
.set = lg_set,
.get_status = lg_get_status,
.set_status = lg_set_status,
+ .reset = lg_reset,
.find_vq = lg_find_vq,
.del_vq = lg_del_vq,
};
@@ -329,13 +356,14 @@
struct lguest_device_desc *d;
/* We start at the page beginning, and skip over each entry. */
- for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) {
+ for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
d = lguest_devices + i;
/* Once we hit a zero, stop. */
if (d->type == 0)
break;
+ printk("Device at %i has size %u\n", i, desc_size(d));
add_lguest_device(d);
}
}
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 7ce0ea6..2895810 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -36,6 +36,7 @@
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/kthread.h>
+#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 18dde2a..9367882 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -78,12 +78,14 @@
int cached_gpio;
int sleeping;
struct semaphore lock;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
void __iomem *cd_base;
- int cd_index;
int cd_irq;
int cd_retry;
#endif
+#if defined(CONFIG_BLK_DEV_IDE_PMAC) || defined(CONFIG_MAC_FLOPPY)
+ int cd_index;
+#endif
};
#define MAX_BAYS 2
@@ -91,7 +93,7 @@
static struct media_bay_info media_bays[MAX_BAYS];
int media_bay_count = 0;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
/* check the busy bit in the media-bay ide interface
(assumes the media-bay contains an ide device) */
#define MB_IDE_READY(i) ((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
@@ -401,7 +403,7 @@
set_mb_power(bay, id != MB_NO);
bay->content_id = id;
if (id == MB_NO) {
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
bay->cd_retry = 0;
#endif
printk(KERN_INFO "media bay %d is empty\n", bay->index);
@@ -414,9 +416,9 @@
}
}
+#ifdef CONFIG_MAC_FLOPPY
int check_media_bay(struct device_node *which_bay, int what)
{
-#ifdef CONFIG_BLK_DEV_IDE
int i;
for (i=0; i<media_bay_count; i++)
@@ -426,14 +428,14 @@
media_bays[i].cd_index = -1;
return -EINVAL;
}
-#endif /* CONFIG_BLK_DEV_IDE */
return -ENODEV;
}
EXPORT_SYMBOL(check_media_bay);
+#endif /* CONFIG_MAC_FLOPPY */
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
int check_media_bay_by_base(unsigned long base, int what)
{
-#ifdef CONFIG_BLK_DEV_IDE
int i;
for (i=0; i<media_bay_count; i++)
@@ -443,15 +445,13 @@
media_bays[i].cd_index = -1;
return -EINVAL;
}
-#endif
-
+
return -ENODEV;
}
int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
- int irq, int index)
+ int irq, int index)
{
-#ifdef CONFIG_BLK_DEV_IDE
int i;
for (i=0; i<media_bay_count; i++) {
@@ -483,10 +483,10 @@
return -ENODEV;
}
}
-#endif /* CONFIG_BLK_DEV_IDE */
-
+
return -ENODEV;
}
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
static void media_bay_step(int i)
{
@@ -521,14 +521,13 @@
bay->state = mb_resetting;
MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
break;
-
case mb_resetting:
if (bay->content_id != MB_CD) {
MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
bay->state = mb_up;
break;
}
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
bay->ops->un_reset_ide(bay);
bay->timer = msecs_to_jiffies(MB_IDE_WAIT);
@@ -536,16 +535,14 @@
#else
printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
set_mb_power(bay, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
break;
-
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
case mb_ide_resetting:
bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT);
bay->state = mb_ide_waiting;
MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
break;
-
case mb_ide_waiting:
if (bay->cd_base == NULL) {
bay->timer = 0;
@@ -587,15 +584,14 @@
bay->timer = 0;
}
break;
-#endif /* CONFIG_BLK_DEV_IDE */
-
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
case mb_powering_down:
bay->state = mb_empty;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
if (bay->cd_index >= 0) {
printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
bay->cd_index);
- ide_unregister(bay->cd_index);
+ ide_unregister(bay->cd_index, 1, 1);
bay->cd_index = -1;
}
if (bay->cd_retry) {
@@ -607,7 +603,7 @@
bay->content_id = MB_NO;
}
}
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
MBDBG("mediabay%d: end of power down\n", i);
break;
}
@@ -739,7 +735,7 @@
bay->last_value = bay->content_id;
bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
bay->cd_retry = 0;
#endif
do {
@@ -829,7 +825,7 @@
for (i=0; i<MAX_BAYS; i++) {
memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
media_bays[i].content_id = -1;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
media_bays[i].cd_index = -1;
#endif
}
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index d409f67..8ba4938 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -12,7 +12,7 @@
* - maybe add timeout to commands ?
* - blocking version of time functions
* - polling version of i2c commands (including timer that works with
- * interrutps off)
+ * interrupts off)
* - maybe avoid some data copies with i2c by directly using the smu cmd
* buffer and a lower level internal interface
* - understand SMU -> CPU events and implement reception of them via
@@ -179,7 +179,7 @@
/* CPU might have brought back the cache line, so we need
* to flush again before peeking at the SMU response. We
* flush the entire buffer for now as we haven't read the
- * reply lenght (it's only 2 cache lines anyway)
+ * reply length (it's only 2 cache lines anyway)
*/
faddr = (unsigned long)smu->cmd_buf;
flush_inval_dcache_range(faddr, faddr + 256);
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 01b8eca..6e6dd17 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -111,7 +111,7 @@
static struct adb_request *current_req; /* first request struct in the queue */
static struct adb_request *last_req; /* last request struct in the queue */
static unsigned char reply_buf[16]; /* storage for autopolled replies */
-static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */
+static unsigned char *reply_ptr; /* next byte in reply_buf or req->reply */
static int reading_reply; /* store reply in reply_buf else req->reply */
static int data_index; /* index of the next byte to send from req->data */
static int reply_len; /* number of bytes received in reply_buf or req->reply */
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 1b1ef31..a0585fb 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -237,7 +237,7 @@
if (!page)
return ERR_PTR(-ENOMEM);
- ITERATE_RDEV(mddev, rdev, tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (! test_bit(In_sync, &rdev->flags)
|| test_bit(Faulty, &rdev->flags))
continue;
@@ -261,7 +261,7 @@
struct list_head *tmp;
mddev_t *mddev = bitmap->mddev;
- ITERATE_RDEV(mddev, rdev, tmp)
+ rdev_for_each(rdev, tmp, mddev)
if (test_bit(In_sync, &rdev->flags)
&& !test_bit(Faulty, &rdev->flags)) {
int size = PAGE_SIZE;
@@ -1348,16 +1348,40 @@
*/
sector_t sector = 0;
int blocks;
- if (!bitmap) return;
+ if (!bitmap)
+ return;
while (sector < bitmap->mddev->resync_max_sectors) {
bitmap_end_sync(bitmap, sector, &blocks, 0);
-/*
- if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n",
- (unsigned long long)sector, blocks);
-*/ sector += blocks;
+ sector += blocks;
}
}
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
+{
+ sector_t s = 0;
+ int blocks;
+
+ if (!bitmap)
+ return;
+ if (sector == 0) {
+ bitmap->last_end_sync = jiffies;
+ return;
+ }
+ if (time_before(jiffies, (bitmap->last_end_sync
+ + bitmap->daemon_sleep * HZ)))
+ return;
+ wait_event(bitmap->mddev->recovery_wait,
+ atomic_read(&bitmap->mddev->recovery_active) == 0);
+
+ sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
+ s = 0;
+ while (s < sector && s < bitmap->mddev->resync_max_sectors) {
+ bitmap_end_sync(bitmap, s, &blocks, 0);
+ s += blocks;
+ }
+ bitmap->last_end_sync = jiffies;
+}
+
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
{
/* For each chunk covered by any of these sectors, set the
@@ -1565,3 +1589,4 @@
EXPORT_SYMBOL(bitmap_end_sync);
EXPORT_SYMBOL(bitmap_unplug);
EXPORT_SYMBOL(bitmap_close_sync);
+EXPORT_SYMBOL(bitmap_cond_end_sync);
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index cf2ddce3..d107ddc 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -294,7 +294,7 @@
}
conf->nfaults = 0;
- ITERATE_RDEV(mddev, rdev, tmp)
+ rdev_for_each(rdev, tmp, mddev)
conf->rdev = rdev;
mddev->array_size = mddev->size;
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 3dac1cf..0b85117 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -122,7 +122,7 @@
cnt = 0;
conf->array_size = 0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
int j = rdev->raid_disk;
dev_info_t *disk = conf->disks + j;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index c28a120..5fc326d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -195,7 +195,7 @@
* Any code which breaks out of this loop while own
* a reference to the current mddev and must mddev_put it.
*/
-#define ITERATE_MDDEV(mddev,tmp) \
+#define for_each_mddev(mddev,tmp) \
\
for (({ spin_lock(&all_mddevs_lock); \
tmp = all_mddevs.next; \
@@ -275,6 +275,7 @@
spin_lock_init(&new->write_lock);
init_waitqueue_head(&new->sb_wait);
new->reshape_position = MaxSector;
+ new->resync_max = MaxSector;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
@@ -310,7 +311,7 @@
mdk_rdev_t * rdev;
struct list_head *tmp;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev->desc_nr == nr)
return rdev;
}
@@ -322,7 +323,7 @@
struct list_head *tmp;
mdk_rdev_t *rdev;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev->bdev->bd_dev == dev)
return rdev;
}
@@ -773,12 +774,16 @@
__u64 ev1 = md_event(sb);
rdev->raid_disk = -1;
- rdev->flags = 0;
+ clear_bit(Faulty, &rdev->flags);
+ clear_bit(In_sync, &rdev->flags);
+ clear_bit(WriteMostly, &rdev->flags);
+ clear_bit(BarriersNotsupp, &rdev->flags);
+
if (mddev->raid_disks == 0) {
mddev->major_version = 0;
mddev->minor_version = sb->minor_version;
mddev->patch_version = sb->patch_version;
- mddev->persistent = ! sb->not_persistent;
+ mddev->external = 0;
mddev->chunk_size = sb->chunk_size;
mddev->ctime = sb->ctime;
mddev->utime = sb->utime;
@@ -904,7 +909,7 @@
sb->size = mddev->size;
sb->raid_disks = mddev->raid_disks;
sb->md_minor = mddev->md_minor;
- sb->not_persistent = !mddev->persistent;
+ sb->not_persistent = 0;
sb->utime = mddev->utime;
sb->state = 0;
sb->events_hi = (mddev->events>>32);
@@ -938,7 +943,7 @@
sb->state |= (1<<MD_SB_BITMAP_PRESENT);
sb->disks[0].state = (1<<MD_DISK_REMOVED);
- ITERATE_RDEV(mddev,rdev2,tmp) {
+ rdev_for_each(rdev2, tmp, mddev) {
mdp_disk_t *d;
int desc_nr;
if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
@@ -1153,11 +1158,15 @@
__u64 ev1 = le64_to_cpu(sb->events);
rdev->raid_disk = -1;
- rdev->flags = 0;
+ clear_bit(Faulty, &rdev->flags);
+ clear_bit(In_sync, &rdev->flags);
+ clear_bit(WriteMostly, &rdev->flags);
+ clear_bit(BarriersNotsupp, &rdev->flags);
+
if (mddev->raid_disks == 0) {
mddev->major_version = 1;
mddev->patch_version = 0;
- mddev->persistent = 1;
+ mddev->external = 0;
mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9;
mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
@@ -1286,7 +1295,7 @@
}
max_dev = 0;
- ITERATE_RDEV(mddev,rdev2,tmp)
+ rdev_for_each(rdev2, tmp, mddev)
if (rdev2->desc_nr+1 > max_dev)
max_dev = rdev2->desc_nr+1;
@@ -1295,7 +1304,7 @@
for (i=0; i<max_dev;i++)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
- ITERATE_RDEV(mddev,rdev2,tmp) {
+ rdev_for_each(rdev2, tmp, mddev) {
i = rdev2->desc_nr;
if (test_bit(Faulty, &rdev2->flags))
sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1333,8 +1342,8 @@
struct list_head *tmp, *tmp2;
mdk_rdev_t *rdev, *rdev2;
- ITERATE_RDEV(mddev1,rdev,tmp)
- ITERATE_RDEV(mddev2, rdev2, tmp2)
+ rdev_for_each(rdev, tmp, mddev1)
+ rdev_for_each(rdev2, tmp2, mddev2)
if (rdev->bdev->bd_contains ==
rdev2->bdev->bd_contains)
return 1;
@@ -1401,7 +1410,7 @@
goto fail;
}
list_add(&rdev->same_set, &mddev->disks);
- bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
+ bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
return 0;
fail:
@@ -1410,10 +1419,11 @@
return err;
}
-static void delayed_delete(struct work_struct *ws)
+static void md_delayed_delete(struct work_struct *ws)
{
mdk_rdev_t *rdev = container_of(ws, mdk_rdev_t, del_work);
kobject_del(&rdev->kobj);
+ kobject_put(&rdev->kobj);
}
static void unbind_rdev_from_array(mdk_rdev_t * rdev)
@@ -1432,7 +1442,8 @@
/* We need to delay this, otherwise we can deadlock when
* writing to 'remove' to "dev/state"
*/
- INIT_WORK(&rdev->del_work, delayed_delete);
+ INIT_WORK(&rdev->del_work, md_delayed_delete);
+ kobject_get(&rdev->kobj);
schedule_work(&rdev->del_work);
}
@@ -1441,7 +1452,7 @@
* otherwise reused by a RAID array (or any other kernel
* subsystem), by bd_claiming the device.
*/
-static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
+static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
{
int err = 0;
struct block_device *bdev;
@@ -1453,13 +1464,15 @@
__bdevname(dev, b));
return PTR_ERR(bdev);
}
- err = bd_claim(bdev, rdev);
+ err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
blkdev_put(bdev);
return err;
}
+ if (!shared)
+ set_bit(AllReserved, &rdev->flags);
rdev->bdev = bdev;
return err;
}
@@ -1503,7 +1516,7 @@
struct list_head *tmp;
mdk_rdev_t *rdev;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (!rdev->mddev) {
MD_BUG();
continue;
@@ -1581,17 +1594,17 @@
printk("md: **********************************\n");
printk("md: * <COMPLETE RAID STATE PRINTOUT> *\n");
printk("md: **********************************\n");
- ITERATE_MDDEV(mddev,tmp) {
+ for_each_mddev(mddev, tmp) {
if (mddev->bitmap)
bitmap_print_sb(mddev->bitmap);
else
printk("%s: ", mdname(mddev));
- ITERATE_RDEV(mddev,rdev,tmp2)
+ rdev_for_each(rdev, tmp2, mddev)
printk("<%s>", bdevname(rdev->bdev,b));
printk("\n");
- ITERATE_RDEV(mddev,rdev,tmp2)
+ rdev_for_each(rdev, tmp2, mddev)
print_rdev(rdev);
}
printk("md: **********************************\n");
@@ -1610,7 +1623,7 @@
mdk_rdev_t *rdev;
struct list_head *tmp;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev->sb_events == mddev->events ||
(nospares &&
rdev->raid_disk < 0 &&
@@ -1696,18 +1709,20 @@
MD_BUG();
mddev->events --;
}
- sync_sbs(mddev, nospares);
/*
* do not write anything to disk if using
* nonpersistent superblocks
*/
if (!mddev->persistent) {
- clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+ if (!mddev->external)
+ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+
spin_unlock_irq(&mddev->write_lock);
wake_up(&mddev->sb_wait);
return;
}
+ sync_sbs(mddev, nospares);
spin_unlock_irq(&mddev->write_lock);
dprintk(KERN_INFO
@@ -1715,7 +1730,7 @@
mdname(mddev),mddev->in_sync);
bitmap_update_sb(mddev->bitmap);
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
if (rdev->sb_loaded != 1)
@@ -1785,7 +1800,7 @@
state_show(mdk_rdev_t *rdev, char *page)
{
char *sep = "";
- int len=0;
+ size_t len = 0;
if (test_bit(Faulty, &rdev->flags)) {
len+= sprintf(page+len, "%sfaulty",sep);
@@ -1887,20 +1902,45 @@
slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
{
char *e;
+ int err;
+ char nm[20];
int slot = simple_strtoul(buf, &e, 10);
if (strncmp(buf, "none", 4)==0)
slot = -1;
else if (e==buf || (*e && *e!= '\n'))
return -EINVAL;
- if (rdev->mddev->pers)
- /* Cannot set slot in active array (yet) */
- return -EBUSY;
- if (slot >= rdev->mddev->raid_disks)
- return -ENOSPC;
- rdev->raid_disk = slot;
- /* assume it is working */
- rdev->flags = 0;
- set_bit(In_sync, &rdev->flags);
+ if (rdev->mddev->pers) {
+ /* Setting 'slot' on an active array requires also
+ * updating the 'rd%d' link, and communicating
+ * with the personality with ->hot_*_disk.
+ * For now we only support removing
+ * failed/spare devices. This normally happens automatically,
+ * but not when the metadata is externally managed.
+ */
+ if (slot != -1)
+ return -EBUSY;
+ if (rdev->raid_disk == -1)
+ return -EEXIST;
+ /* personality does all needed checks */
+ if (rdev->mddev->pers->hot_add_disk == NULL)
+ return -EINVAL;
+ err = rdev->mddev->pers->
+ hot_remove_disk(rdev->mddev, rdev->raid_disk);
+ if (err)
+ return err;
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_remove_link(&rdev->mddev->kobj, nm);
+ set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+ md_wakeup_thread(rdev->mddev->thread);
+ } else {
+ if (slot >= rdev->mddev->raid_disks)
+ return -ENOSPC;
+ rdev->raid_disk = slot;
+ /* assume it is working */
+ clear_bit(Faulty, &rdev->flags);
+ clear_bit(WriteMostly, &rdev->flags);
+ set_bit(In_sync, &rdev->flags);
+ }
return len;
}
@@ -1923,6 +1963,10 @@
return -EINVAL;
if (rdev->mddev->pers)
return -EBUSY;
+ if (rdev->size && rdev->mddev->external)
+ /* Must set offset before size, so overlap checks
+ * can be sane */
+ return -EBUSY;
rdev->data_offset = offset;
return len;
}
@@ -1936,16 +1980,69 @@
return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
}
+static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
+{
+ /* check if two start/length pairs overlap */
+ if (s1+l1 <= s2)
+ return 0;
+ if (s2+l2 <= s1)
+ return 0;
+ return 1;
+}
+
static ssize_t
rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
{
char *e;
unsigned long long size = simple_strtoull(buf, &e, 10);
+ unsigned long long oldsize = rdev->size;
if (e==buf || (*e && *e != '\n'))
return -EINVAL;
if (rdev->mddev->pers)
return -EBUSY;
rdev->size = size;
+ if (size > oldsize && rdev->mddev->external) {
+ /* need to check that all other rdevs with the same ->bdev
+ * do not overlap. We need to unlock the mddev to avoid
+ * a deadlock. We have already changed rdev->size, and if
+ * we have to change it back, we will have the lock again.
+ */
+ mddev_t *mddev;
+ int overlap = 0;
+ struct list_head *tmp, *tmp2;
+
+ mddev_unlock(rdev->mddev);
+ for_each_mddev(mddev, tmp) {
+ mdk_rdev_t *rdev2;
+
+ mddev_lock(mddev);
+ rdev_for_each(rdev2, tmp2, mddev)
+ if (test_bit(AllReserved, &rdev2->flags) ||
+ (rdev->bdev == rdev2->bdev &&
+ rdev != rdev2 &&
+ overlaps(rdev->data_offset, rdev->size,
+ rdev2->data_offset, rdev2->size))) {
+ overlap = 1;
+ break;
+ }
+ mddev_unlock(mddev);
+ if (overlap) {
+ mddev_put(mddev);
+ break;
+ }
+ }
+ mddev_lock(rdev->mddev);
+ if (overlap) {
+ /* Someone else could have slipped in a size
+ * change here, but doing so is just silly.
+ * We put oldsize back because we *know* it is
+ * safe, and trust userspace not to race with
+ * itself
+ */
+ rdev->size = oldsize;
+ return -EBUSY;
+ }
+ }
if (size < rdev->mddev->size || rdev->mddev->size == 0)
rdev->mddev->size = size;
return len;
@@ -1980,12 +2077,18 @@
{
struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+ int rv;
if (!entry->store)
return -EIO;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- return entry->store(rdev, page, length);
+ rv = mddev_lock(rdev->mddev);
+ if (!rv) {
+ rv = entry->store(rdev, page, length);
+ mddev_unlock(rdev->mddev);
+ }
+ return rv;
}
static void rdev_free(struct kobject *ko)
@@ -2029,7 +2132,7 @@
if ((err = alloc_disk_sb(rdev)))
goto abort_free;
- err = lock_rdev(rdev, newdev);
+ err = lock_rdev(rdev, newdev, super_format == -2);
if (err)
goto abort_free;
@@ -2099,7 +2202,7 @@
char b[BDEVNAME_SIZE];
freshest = NULL;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
switch (super_types[mddev->major_version].
load_super(rdev, freshest, mddev->minor_version)) {
case 1:
@@ -2120,7 +2223,7 @@
validate_super(mddev, freshest);
i = 0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (rdev != freshest)
if (super_types[mddev->major_version].
validate_super(mddev, rdev)) {
@@ -2215,7 +2318,7 @@
static ssize_t
level_store(mddev_t *mddev, const char *buf, size_t len)
{
- int rv = len;
+ ssize_t rv = len;
if (mddev->pers)
return -EBUSY;
if (len == 0)
@@ -2425,6 +2528,8 @@
case 0:
if (mddev->in_sync)
st = clean;
+ else if (test_bit(MD_CHANGE_CLEAN, &mddev->flags))
+ st = write_pending;
else if (mddev->safemode)
st = active_idle;
else
@@ -2455,11 +2560,9 @@
break;
case clear:
/* stopping an active array */
- if (mddev->pers) {
- if (atomic_read(&mddev->active) > 1)
- return -EBUSY;
- err = do_md_stop(mddev, 0);
- }
+ if (atomic_read(&mddev->active) > 1)
+ return -EBUSY;
+ err = do_md_stop(mddev, 0);
break;
case inactive:
/* stopping an active array */
@@ -2467,7 +2570,8 @@
if (atomic_read(&mddev->active) > 1)
return -EBUSY;
err = do_md_stop(mddev, 2);
- }
+ } else
+ err = 0; /* already inactive */
break;
case suspended:
break; /* not supported yet */
@@ -2495,9 +2599,15 @@
restart_array(mddev);
spin_lock_irq(&mddev->write_lock);
if (atomic_read(&mddev->writes_pending) == 0) {
- mddev->in_sync = 1;
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
- }
+ if (mddev->in_sync == 0) {
+ mddev->in_sync = 1;
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN,
+ &mddev->flags);
+ }
+ err = 0;
+ } else
+ err = -EBUSY;
spin_unlock_irq(&mddev->write_lock);
} else {
mddev->ro = 0;
@@ -2508,7 +2618,8 @@
case active:
if (mddev->pers) {
restart_array(mddev);
- clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (mddev->external)
+ clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
wake_up(&mddev->sb_wait);
err = 0;
} else {
@@ -2574,7 +2685,9 @@
if (err < 0)
goto out;
}
- } else
+ } else if (mddev->external)
+ rdev = md_import_device(dev, -2, -1);
+ else
rdev = md_import_device(dev, -1, -1);
if (IS_ERR(rdev))
@@ -2659,7 +2772,9 @@
/* Metdata version.
- * This is either 'none' for arrays with externally managed metadata,
+ * This is one of
+ * 'none' for arrays with no metadata (good luck...)
+ * 'external' for arrays with externally managed metadata,
* or N.M for internally known formats
*/
static ssize_t
@@ -2668,6 +2783,8 @@
if (mddev->persistent)
return sprintf(page, "%d.%d\n",
mddev->major_version, mddev->minor_version);
+ else if (mddev->external)
+ return sprintf(page, "external:%s\n", mddev->metadata_type);
else
return sprintf(page, "none\n");
}
@@ -2682,6 +2799,21 @@
if (cmd_match(buf, "none")) {
mddev->persistent = 0;
+ mddev->external = 0;
+ mddev->major_version = 0;
+ mddev->minor_version = 90;
+ return len;
+ }
+ if (strncmp(buf, "external:", 9) == 0) {
+ size_t namelen = len-9;
+ if (namelen >= sizeof(mddev->metadata_type))
+ namelen = sizeof(mddev->metadata_type)-1;
+ strncpy(mddev->metadata_type, buf+9, namelen);
+ mddev->metadata_type[namelen] = 0;
+ if (namelen && mddev->metadata_type[namelen-1] == '\n')
+ mddev->metadata_type[--namelen] = 0;
+ mddev->persistent = 0;
+ mddev->external = 1;
mddev->major_version = 0;
mddev->minor_version = 90;
return len;
@@ -2698,6 +2830,7 @@
mddev->major_version = major;
mddev->minor_version = minor;
mddev->persistent = 1;
+ mddev->external = 0;
return len;
}
@@ -2865,6 +2998,43 @@
static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
static ssize_t
+max_sync_show(mddev_t *mddev, char *page)
+{
+ if (mddev->resync_max == MaxSector)
+ return sprintf(page, "max\n");
+ else
+ return sprintf(page, "%llu\n",
+ (unsigned long long)mddev->resync_max);
+}
+static ssize_t
+max_sync_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ if (strncmp(buf, "max", 3) == 0)
+ mddev->resync_max = MaxSector;
+ else {
+ char *ep;
+ unsigned long long max = simple_strtoull(buf, &ep, 10);
+ if (ep == buf || (*ep != 0 && *ep != '\n'))
+ return -EINVAL;
+ if (max < mddev->resync_max &&
+ test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ return -EBUSY;
+
+ /* Must be a multiple of chunk_size */
+ if (mddev->chunk_size) {
+ if (max & (sector_t)((mddev->chunk_size>>9)-1))
+ return -EINVAL;
+ }
+ mddev->resync_max = max;
+ }
+ wake_up(&mddev->recovery_wait);
+ return len;
+}
+
+static struct md_sysfs_entry md_max_sync =
+__ATTR(sync_max, S_IRUGO|S_IWUSR, max_sync_show, max_sync_store);
+
+static ssize_t
suspend_lo_show(mddev_t *mddev, char *page)
{
return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo);
@@ -2974,6 +3144,7 @@
&md_sync_max.attr,
&md_sync_speed.attr,
&md_sync_completed.attr,
+ &md_max_sync.attr,
&md_suspend_lo.attr,
&md_suspend_hi.attr,
&md_bitmap.attr,
@@ -3118,8 +3289,11 @@
/*
* Analyze all RAID superblock(s)
*/
- if (!mddev->raid_disks)
+ if (!mddev->raid_disks) {
+ if (!mddev->persistent)
+ return -EINVAL;
analyze_sbs(mddev);
+ }
chunk_size = mddev->chunk_size;
@@ -3143,7 +3317,7 @@
}
/* devices must have minimum size of one chunk */
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (test_bit(Faulty, &rdev->flags))
continue;
if (rdev->size < chunk_size / 1024) {
@@ -3170,7 +3344,7 @@
* the only valid external interface is through the md
* device.
*/
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
if (test_bit(Faulty, &rdev->flags))
continue;
sync_blockdev(rdev->bdev);
@@ -3236,8 +3410,8 @@
mdk_rdev_t *rdev2;
struct list_head *tmp2;
int warned = 0;
- ITERATE_RDEV(mddev, rdev, tmp) {
- ITERATE_RDEV(mddev, rdev2, tmp2) {
+ rdev_for_each(rdev, tmp, mddev) {
+ rdev_for_each(rdev2, tmp2, mddev) {
if (rdev < rdev2 &&
rdev->bdev->bd_contains ==
rdev2->bdev->bd_contains) {
@@ -3297,7 +3471,7 @@
mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
if (rdev->raid_disk >= 0) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3330,7 +3504,7 @@
if (mddev->degraded && !mddev->sync_thread) {
struct list_head *rtmp;
int spares = 0;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
!test_bit(Faulty, &rdev->flags))
@@ -3507,14 +3681,14 @@
}
mddev->bitmap_offset = 0;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
if (rdev->raid_disk >= 0) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
sysfs_remove_link(&mddev->kobj, nm);
}
- /* make sure all delayed_delete calls have finished */
+ /* make sure all md_delayed_delete calls have finished */
flush_scheduled_work();
export_array(mddev);
@@ -3523,7 +3697,10 @@
mddev->size = 0;
mddev->raid_disks = 0;
mddev->recovery_cp = 0;
+ mddev->resync_max = MaxSector;
mddev->reshape_position = MaxSector;
+ mddev->external = 0;
+ mddev->persistent = 0;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -3546,7 +3723,7 @@
printk(KERN_INFO "md: running: ");
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
char b[BDEVNAME_SIZE];
printk("<%s>", bdevname(rdev->bdev,b));
}
@@ -3589,7 +3766,7 @@
printk(KERN_INFO "md: considering %s ...\n",
bdevname(rdev0->bdev,b));
INIT_LIST_HEAD(&candidates);
- ITERATE_RDEV_PENDING(rdev,tmp)
+ rdev_for_each_list(rdev, tmp, pending_raid_disks)
if (super_90_load(rdev, rdev0, 0) >= 0) {
printk(KERN_INFO "md: adding %s ...\n",
bdevname(rdev->bdev,b));
@@ -3632,7 +3809,8 @@
mddev_unlock(mddev);
} else {
printk(KERN_INFO "md: created %s\n", mdname(mddev));
- ITERATE_RDEV_GENERIC(candidates,rdev,tmp) {
+ mddev->persistent = 1;
+ rdev_for_each_list(rdev, tmp, candidates) {
list_del_init(&rdev->same_set);
if (bind_rdev_to_array(rdev, mddev))
export_rdev(rdev);
@@ -3643,7 +3821,7 @@
/* on success, candidates will be empty, on error
* it won't...
*/
- ITERATE_RDEV_GENERIC(candidates,rdev,tmp)
+ rdev_for_each_list(rdev, tmp, candidates)
export_rdev(rdev);
mddev_put(mddev);
}
@@ -3673,7 +3851,7 @@
struct list_head *tmp;
nr=working=active=failed=spare=0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
nr++;
if (test_bit(Faulty, &rdev->flags))
failed++;
@@ -3919,8 +4097,6 @@
else
rdev->raid_disk = -1;
- rdev->flags = 0;
-
if (rdev->raid_disk < mddev->raid_disks)
if (info->state & (1<<MD_DISK_SYNC))
set_bit(In_sync, &rdev->flags);
@@ -4165,13 +4341,15 @@
else
mddev->recovery_cp = 0;
mddev->persistent = ! info->not_persistent;
+ mddev->external = 0;
mddev->layout = info->layout;
mddev->chunk_size = info->chunk_size;
mddev->max_disks = MD_SB_DISKS;
- mddev->flags = 0;
+ if (mddev->persistent)
+ mddev->flags = 0;
set_bit(MD_CHANGE_DEVS, &mddev->flags);
mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
@@ -4213,7 +4391,7 @@
*/
if (mddev->sync_thread)
return -EBUSY;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
sector_t avail;
avail = rdev->size * 2;
@@ -4471,9 +4649,10 @@
*/
/* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
* RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
- if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
- && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
- && cmd != GET_BITMAP_FILE) {
+ if ((!mddev->raid_disks && !mddev->external)
+ && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
+ && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
+ && cmd != GET_BITMAP_FILE) {
err = -ENODEV;
goto abort_unlock;
}
@@ -4757,7 +4936,7 @@
seq_printf(seq, "unused devices: ");
- ITERATE_RDEV_PENDING(rdev,tmp) {
+ rdev_for_each_list(rdev, tmp, pending_raid_disks) {
char b[BDEVNAME_SIZE];
i++;
seq_printf(seq, "%s ",
@@ -4953,7 +5132,7 @@
}
size = 0;
- ITERATE_RDEV(mddev,rdev,tmp2) {
+ rdev_for_each(rdev, tmp2, mddev) {
char b[BDEVNAME_SIZE];
seq_printf(seq, " %s[%d]",
bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -4982,7 +5161,10 @@
mddev->major_version,
mddev->minor_version);
}
- } else
+ } else if (mddev->external)
+ seq_printf(seq, " super external:%s",
+ mddev->metadata_type);
+ else
seq_printf(seq, " super non-persistent");
if (mddev->pers) {
@@ -5106,7 +5288,7 @@
long curr_events;
idle = 1;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
curr_events = disk_stat_read(disk, sectors[0]) +
disk_stat_read(disk, sectors[1]) -
@@ -5283,7 +5465,7 @@
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
goto skip;
}
- ITERATE_MDDEV(mddev2,tmp) {
+ for_each_mddev(mddev2, tmp) {
if (mddev2 == mddev)
continue;
if (mddev2->curr_resync &&
@@ -5333,7 +5515,7 @@
/* recovery follows the physical size of devices */
max_sectors = mddev->size << 1;
j = MaxSector;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
@@ -5381,8 +5563,16 @@
sector_t sectors;
skipped = 0;
+ if (j >= mddev->resync_max) {
+ sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+ wait_event(mddev->recovery_wait,
+ mddev->resync_max > j
+ || kthread_should_stop());
+ }
+ if (kthread_should_stop())
+ goto interrupted;
sectors = mddev->pers->sync_request(mddev, j, &skipped,
- currspeed < speed_min(mddev));
+ currspeed < speed_min(mddev));
if (sectors == 0) {
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
goto out;
@@ -5424,15 +5614,9 @@
}
- if (kthread_should_stop()) {
- /*
- * got a signal, exit.
- */
- printk(KERN_INFO
- "md: md_do_sync() got signal ... exiting\n");
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- goto out;
- }
+ if (kthread_should_stop())
+ goto interrupted;
+
/*
* this loop exits only if either when we are slower than
@@ -5484,7 +5668,7 @@
} else {
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
mddev->curr_resync = MaxSector;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
@@ -5496,9 +5680,22 @@
skip:
mddev->curr_resync = 0;
+ mddev->resync_max = MaxSector;
+ sysfs_notify(&mddev->kobj, NULL, "sync_completed");
wake_up(&resync_wait);
set_bit(MD_RECOVERY_DONE, &mddev->recovery);
md_wakeup_thread(mddev->thread);
+ return;
+
+ interrupted:
+ /*
+ * got a signal, exit.
+ */
+ printk(KERN_INFO
+ "md: md_do_sync() got signal ... exiting\n");
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ goto out;
+
}
EXPORT_SYMBOL_GPL(md_do_sync);
@@ -5509,8 +5706,9 @@
struct list_head *rtmp;
int spares = 0;
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
+ !mddev->external &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
atomic_read(&rdev->nr_pending)==0) {
@@ -5524,7 +5722,7 @@
}
if (mddev->degraded) {
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk < 0
&& !test_bit(Faulty, &rdev->flags)) {
rdev->recovery_offset = 0;
@@ -5589,7 +5787,7 @@
}
if ( ! (
- mddev->flags ||
+ (mddev->flags && !mddev->external) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
(mddev->safemode == 1) ||
@@ -5605,7 +5803,8 @@
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1;
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
}
if (mddev->safemode == 1)
mddev->safemode = 0;
@@ -5637,7 +5836,7 @@
* information must be scrapped
*/
if (!mddev->degraded)
- ITERATE_RDEV(mddev,rdev,rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
rdev->saved_raid_disk = -1;
mddev->recovery = 0;
@@ -5714,7 +5913,7 @@
printk(KERN_INFO "md: stopping all md devices.\n");
- ITERATE_MDDEV(mddev,tmp)
+ for_each_mddev(mddev, tmp)
if (mddev_trylock(mddev)) {
do_md_stop (mddev, 1);
mddev_unlock(mddev);
@@ -5848,7 +6047,7 @@
unregister_reboot_notifier(&md_notifier);
unregister_sysctl_table(raid_table_header);
remove_proc_entry("mdstat", NULL);
- ITERATE_MDDEV(mddev,tmp) {
+ for_each_mddev(mddev, tmp) {
struct gendisk *disk = mddev->gendisk;
if (!disk)
continue;
diff --git a/drivers/md/mktables.c b/drivers/md/mktables.c
index adef299..b61d576 100644
--- a/drivers/md/mktables.c
+++ b/drivers/md/mktables.c
@@ -1,13 +1,10 @@
-#ident "$Id: mktables.c,v 1.2 2002/12/12 22:41:27 hpa Exp $"
-/* ----------------------------------------------------------------------- *
+/* -*- linux-c -*- ------------------------------------------------------- *
*
- * Copyright 2002 H. Peter Anvin - All Rights Reserved
+ * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- * Bostom MA 02111-1307, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2 or (at your
+ * option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
@@ -26,100 +23,98 @@
static uint8_t gfmul(uint8_t a, uint8_t b)
{
- uint8_t v = 0;
+ uint8_t v = 0;
- while ( b ) {
- if ( b & 1 ) v ^= a;
- a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
- b >>= 1;
- }
- return v;
+ while (b) {
+ if (b & 1)
+ v ^= a;
+ a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
+ b >>= 1;
+ }
+
+ return v;
}
static uint8_t gfpow(uint8_t a, int b)
{
- uint8_t v = 1;
+ uint8_t v = 1;
- b %= 255;
- if ( b < 0 )
- b += 255;
+ b %= 255;
+ if (b < 0)
+ b += 255;
- while ( b ) {
- if ( b & 1 ) v = gfmul(v,a);
- a = gfmul(a,a);
- b >>= 1;
- }
- return v;
+ while (b) {
+ if (b & 1)
+ v = gfmul(v, a);
+ a = gfmul(a, a);
+ b >>= 1;
+ }
+
+ return v;
}
int main(int argc, char *argv[])
{
- int i, j, k;
- uint8_t v;
- uint8_t exptbl[256], invtbl[256];
+ int i, j, k;
+ uint8_t v;
+ uint8_t exptbl[256], invtbl[256];
- printf("#include \"raid6.h\"\n");
+ printf("#include \"raid6.h\"\n");
- /* Compute multiplication table */
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfmul[256][256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i++ ) {
- printf("\t{\n");
- for ( j = 0 ; j < 256 ; j += 8 ) {
- printf("\t\t");
- for ( k = 0 ; k < 8 ; k++ ) {
- printf("0x%02x, ", gfmul(i,j+k));
- }
- printf("\n");
- }
- printf("\t},\n");
- }
- printf("};\n");
+ /* Compute multiplication table */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfmul[256][256] =\n"
+ "{\n");
+ for (i = 0; i < 256; i++) {
+ printf("\t{\n");
+ for (j = 0; j < 256; j += 8) {
+ printf("\t\t");
+ for (k = 0; k < 8; k++)
+ printf("0x%02x,%c", gfmul(i, j + k),
+ (k == 7) ? '\n' : ' ');
+ }
+ printf("\t},\n");
+ }
+ printf("};\n");
- /* Compute power-of-2 table (exponent) */
- v = 1;
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfexp[256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i += 8 ) {
- printf("\t");
- for ( j = 0 ; j < 8 ; j++ ) {
- exptbl[i+j] = v;
- printf("0x%02x, ", v);
- v = gfmul(v,2);
- if ( v == 1 ) v = 0; /* For entry 255, not a real entry */
- }
- printf("\n");
- }
- printf("};\n");
+ /* Compute power-of-2 table (exponent) */
+ v = 1;
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfexp[256] =\n" "{\n");
+ for (i = 0; i < 256; i += 8) {
+ printf("\t");
+ for (j = 0; j < 8; j++) {
+ exptbl[i + j] = v;
+ printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+ v = gfmul(v, 2);
+ if (v == 1)
+ v = 0; /* For entry 255, not a real entry */
+ }
+ }
+ printf("};\n");
- /* Compute inverse table x^-1 == x^254 */
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfinv[256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i += 8 ) {
- printf("\t");
- for ( j = 0 ; j < 8 ; j++ ) {
- invtbl[i+j] = v = gfpow(i+j,254);
- printf("0x%02x, ", v);
- }
- printf("\n");
- }
- printf("};\n");
+ /* Compute inverse table x^-1 == x^254 */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfinv[256] =\n" "{\n");
+ for (i = 0; i < 256; i += 8) {
+ printf("\t");
+ for (j = 0; j < 8; j++) {
+ invtbl[i + j] = v = gfpow(i + j, 254);
+ printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+ }
+ }
+ printf("};\n");
- /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
- printf("\nconst u8 __attribute__((aligned(256)))\n"
- "raid6_gfexi[256] =\n"
- "{\n");
- for ( i = 0 ; i < 256 ; i += 8 ) {
- printf("\t");
- for ( j = 0 ; j < 8 ; j++ ) {
- printf("0x%02x, ", invtbl[exptbl[i+j]^1]);
- }
- printf("\n");
- }
- printf("};\n\n");
+ /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_gfexi[256] =\n" "{\n");
+ for (i = 0; i < 256; i += 8) {
+ printf("\t");
+ for (j = 0; j < 8; j++)
+ printf("0x%02x,%c", invtbl[exptbl[i + j] ^ 1],
+ (j == 7) ? '\n' : ' ');
+ }
+ printf("};\n");
- return 0;
+ return 0;
}
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index eb631eb..3f299d8 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -436,7 +436,7 @@
}
conf->working_disks = 0;
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx < 0 ||
disk_idx >= mddev->raid_disks)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index f8e5917..818b482 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -72,11 +72,11 @@
*/
conf->nr_strip_zones = 0;
- ITERATE_RDEV(mddev,rdev1,tmp1) {
+ rdev_for_each(rdev1, tmp1, mddev) {
printk("raid0: looking at %s\n",
bdevname(rdev1->bdev,b));
c = 0;
- ITERATE_RDEV(mddev,rdev2,tmp2) {
+ rdev_for_each(rdev2, tmp2, mddev) {
printk("raid0: comparing %s(%llu)",
bdevname(rdev1->bdev,b),
(unsigned long long)rdev1->size);
@@ -124,7 +124,7 @@
cnt = 0;
smallest = NULL;
zone->dev = conf->devlist;
- ITERATE_RDEV(mddev, rdev1, tmp1) {
+ rdev_for_each(rdev1, tmp1, mddev) {
int j = rdev1->raid_disk;
if (j < 0 || j >= mddev->raid_disks) {
@@ -293,7 +293,7 @@
/* calculate array device size */
mddev->array_size = 0;
- ITERATE_RDEV(mddev,rdev,tmp)
+ rdev_for_each(rdev, tmp, mddev)
mddev->array_size += rdev->size;
printk("raid0 : md_size is %llu blocks.\n",
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 4a69c41..5c7fef0 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1684,6 +1684,7 @@
if (!go_faster && conf->nr_waiting)
msleep_interruptible(1000);
+ bitmap_cond_end_sync(mddev->bitmap, sector_nr);
raise_barrier(conf);
conf->next_resync = sector_nr;
@@ -1766,6 +1767,8 @@
return rv;
}
+ if (max_sector > mddev->resync_max)
+ max_sector = mddev->resync_max; /* Don't do IO beyond here */
nr_sectors = 0;
sync_blocks = 0;
do {
@@ -1884,7 +1887,7 @@
if (!conf->r1bio_pool)
goto out_no_mem;
- ITERATE_RDEV(mddev, rdev, tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
|| disk_idx < 0)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5cdcc93..017f581 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1657,6 +1657,9 @@
return (max_sector - sector_nr) + sectors_skipped;
}
+ if (max_sector > mddev->resync_max)
+ max_sector = mddev->resync_max; /* Don't do IO beyond here */
+
/* make sure whole request will fit in a chunk - if chunks
* are meaningful
*/
@@ -1670,6 +1673,8 @@
if (!go_faster && conf->nr_waiting)
msleep_interruptible(1000);
+ bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
/* Again, very different code for resync and recovery.
* Both must result in an r10bio with a list of bios that
* have bi_end_io, bi_sector, bi_bdev set,
@@ -2021,7 +2026,7 @@
goto out_free_conf;
}
- ITERATE_RDEV(mddev, rdev, tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
|| disk_idx < 0)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index e8c8157b..2d6f1a5 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3159,7 +3159,8 @@
atomic_inc(&conf->preread_active_stripes);
list_add_tail(&sh->lru, &conf->handle_list);
}
- }
+ } else
+ blk_plug_device(conf->mddev->queue);
}
static void activate_bit_delay(raid5_conf_t *conf)
@@ -3549,7 +3550,8 @@
goto retry;
}
finish_wait(&conf->wait_for_overlap, &w);
- handle_stripe(sh, NULL);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ clear_bit(STRIPE_DELAYED, &sh->state);
release_stripe(sh);
} else {
/* cannot get stripe for read-ahead, just give-up */
@@ -3698,6 +3700,25 @@
release_stripe(sh);
first_sector += STRIPE_SECTORS;
}
+ /* If this takes us to the resync_max point where we have to pause,
+ * then we need to write out the superblock.
+ */
+ sector_nr += conf->chunk_size>>9;
+ if (sector_nr >= mddev->resync_max) {
+ /* Cannot proceed until we've updated the superblock... */
+ wait_event(conf->wait_for_overlap,
+ atomic_read(&conf->reshape_stripes) == 0);
+ mddev->reshape_position = conf->expand_progress;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_CHANGE_DEVS, &mddev->flags)
+ || kthread_should_stop());
+ spin_lock_irq(&conf->device_lock);
+ conf->expand_lo = mddev->reshape_position;
+ spin_unlock_irq(&conf->device_lock);
+ wake_up(&conf->wait_for_overlap);
+ }
return conf->chunk_size>>9;
}
@@ -3734,6 +3755,12 @@
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return reshape_request(mddev, sector_nr, skipped);
+ /* No need to check resync_max as we never do more than one
+ * stripe, and as resync_max will always be on a chunk boundary,
+ * if the check in md_do_sync didn't fire, there is no chance
+ * of overstepping resync_max here
+ */
+
/* if there is too many failed drives and we are trying
* to resync, then assert that we are finished, because there is
* nothing we can do.
@@ -3753,6 +3780,9 @@
return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
}
+
+ bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks);
sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1);
if (sh == NULL) {
@@ -3864,7 +3894,7 @@
* During the scan, completed stripes are saved for us by the interrupt
* handler, so that they will not have to wait for our next wakeup.
*/
-static void raid5d (mddev_t *mddev)
+static void raid5d(mddev_t *mddev)
{
struct stripe_head *sh;
raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3889,12 +3919,6 @@
activate_bit_delay(conf);
}
- if (list_empty(&conf->handle_list) &&
- atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD &&
- !blk_queue_plugged(mddev->queue) &&
- !list_empty(&conf->delayed_list))
- raid5_activate_delayed(conf);
-
while ((bio = remove_bio_from_retry(conf))) {
int ok;
spin_unlock_irq(&conf->device_lock);
@@ -4108,7 +4132,7 @@
pr_debug("raid5: run(%s) called.\n", mdname(mddev));
- ITERATE_RDEV(mddev,rdev,tmp) {
+ rdev_for_each(rdev, tmp, mddev) {
raid_disk = rdev->raid_disk;
if (raid_disk >= conf->raid_disks
|| raid_disk < 0)
@@ -4521,7 +4545,7 @@
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
- ITERATE_RDEV(mddev, rdev, rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags))
spares++;
@@ -4543,7 +4567,7 @@
/* Add some new drives, as many as will fit.
* We know there are enough to make the newly sized array work.
*/
- ITERATE_RDEV(mddev, rdev, rtmp)
+ rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags)) {
if (raid5_add_disk(mddev, rdev)) {
diff --git a/drivers/md/raid6test/test.c b/drivers/md/raid6test/test.c
index 0d5cd57..559cc41 100644
--- a/drivers/md/raid6test/test.c
+++ b/drivers/md/raid6test/test.c
@@ -1,12 +1,10 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
- * Copyright 2002 H. Peter Anvin - All Rights Reserved
+ * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- * Bostom MA 02111-1307, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2 or (at your
+ * option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
@@ -30,67 +28,87 @@
char data[NDISKS][PAGE_SIZE];
char recovi[PAGE_SIZE], recovj[PAGE_SIZE];
-void makedata(void)
+static void makedata(void)
{
int i, j;
- for ( i = 0 ; i < NDISKS ; i++ ) {
- for ( j = 0 ; j < PAGE_SIZE ; j++ ) {
+ for (i = 0; i < NDISKS; i++) {
+ for (j = 0; j < PAGE_SIZE; j++)
data[i][j] = rand();
- }
+
dataptrs[i] = data[i];
}
}
+static char disk_type(int d)
+{
+ switch (d) {
+ case NDISKS-2:
+ return 'P';
+ case NDISKS-1:
+ return 'Q';
+ default:
+ return 'D';
+ }
+}
+
+static int test_disks(int i, int j)
+{
+ int erra, errb;
+
+ memset(recovi, 0xf0, PAGE_SIZE);
+ memset(recovj, 0xba, PAGE_SIZE);
+
+ dataptrs[i] = recovi;
+ dataptrs[j] = recovj;
+
+ raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
+
+ erra = memcmp(data[i], recovi, PAGE_SIZE);
+ errb = memcmp(data[j], recovj, PAGE_SIZE);
+
+ if (i < NDISKS-2 && j == NDISKS-1) {
+ /* We don't implement the DQ failure scenario, since it's
+ equivalent to a RAID-5 failure (XOR, then recompute Q) */
+ erra = errb = 0;
+ } else {
+ printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n",
+ raid6_call.name,
+ i, disk_type(i),
+ j, disk_type(j),
+ (!erra && !errb) ? "OK" :
+ !erra ? "ERRB" :
+ !errb ? "ERRA" : "ERRAB");
+ }
+
+ dataptrs[i] = data[i];
+ dataptrs[j] = data[j];
+
+ return erra || errb;
+}
+
int main(int argc, char *argv[])
{
- const struct raid6_calls * const * algo;
+ const struct raid6_calls *const *algo;
int i, j;
- int erra, errb;
+ int err = 0;
makedata();
- for ( algo = raid6_algos ; *algo ; algo++ ) {
- if ( !(*algo)->valid || (*algo)->valid() ) {
+ for (algo = raid6_algos; *algo; algo++) {
+ if (!(*algo)->valid || (*algo)->valid()) {
raid6_call = **algo;
/* Nuke syndromes */
memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
/* Generate assumed good syndrome */
- raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, (void **)&dataptrs);
+ raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
+ (void **)&dataptrs);
- for ( i = 0 ; i < NDISKS-1 ; i++ ) {
- for ( j = i+1 ; j < NDISKS ; j++ ) {
- memset(recovi, 0xf0, PAGE_SIZE);
- memset(recovj, 0xba, PAGE_SIZE);
-
- dataptrs[i] = recovi;
- dataptrs[j] = recovj;
-
- raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
-
- erra = memcmp(data[i], recovi, PAGE_SIZE);
- errb = memcmp(data[j], recovj, PAGE_SIZE);
-
- if ( i < NDISKS-2 && j == NDISKS-1 ) {
- /* We don't implement the DQ failure scenario, since it's
- equivalent to a RAID-5 failure (XOR, then recompute Q) */
- } else {
- printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n",
- raid6_call.name,
- i, (i==NDISKS-2)?'P':'D',
- j, (j==NDISKS-1)?'Q':(j==NDISKS-2)?'P':'D',
- (!erra && !errb) ? "OK" :
- !erra ? "ERRB" :
- !errb ? "ERRA" :
- "ERRAB");
- }
-
- dataptrs[i] = data[i];
- dataptrs[j] = data[j];
- }
- }
+ for (i = 0; i < NDISKS-1; i++)
+ for (j = i+1; j < NDISKS; j++)
+ err += test_disks(i, j);
}
printf("\n");
}
@@ -99,5 +117,8 @@
/* Pick the best algorithm test */
raid6_select_algo();
- return 0;
+ if (err)
+ printf("\n*** ERRORS FOUND ***\n");
+
+ return err;
}
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 7d04a6f..168a8d3 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -388,7 +388,7 @@
}
dev->revision &= 0xf;
- /* remap the memory from virtual to physical adress */
+ /* remap the memory from virtual to physical address */
err = pci_request_region(pci, 0, "saa7146");
if (err < 0)
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index a33eb59..ed3f826 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -681,7 +681,7 @@
drop = 1;
/* else: destination address matches the MAC address of our receiver device */
}
- /* else: promiscious mode; pass everything up the stack */
+ /* else: promiscuous mode; pass everything up the stack */
if (drop) {
#ifdef ULE_DEBUG
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 28ddd14..850b8c6 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -22,7 +22,6 @@
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 63a47cd..7374c02 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -4344,7 +4344,7 @@
gpio_bits(0x200,0x000);
mdelay(1);
- /* create a new conection */
+ /* create a new connection */
gpio_bits(0x480,0x080);
gpio_bits(0x480,0x480);
mdelay(1);
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
index 5c2c402..84b9e4f 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/video/indycam.c
@@ -326,7 +326,7 @@
// initialize
err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
if (err) {
- printk(KERN_ERR "IndyCam initalization failed\n");
+ printk(KERN_ERR "IndyCam initialization failed\n");
err = -EIO;
goto out_detach_client;
}
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index b630c26..58bab65 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -369,7 +369,7 @@
.get_frequency = microtune_get_frequency,
};
-// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
static int mt2032_init(struct dvb_frontend *fe)
{
struct microtune_priv *priv = fe->tuner_priv;
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h
index 074533e..1a9a4ba 100644
--- a/drivers/media/video/pvrusb2/pvrusb2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2.h
@@ -27,7 +27,7 @@
might want to increase this - however the driver operation will not
be impaired if it is too small. Instead additional units just
won't have an ID assigned and it might not be possible to specify
- module paramters for those extra units. */
+ module parameters for those extra units. */
#define PVR_NUM 20
#endif /* __PVRUSB2_H */
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 7300ace..f991d72 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -542,7 +542,7 @@
}
if (pdev->read_frame != NULL) {
- /* Decompression is a lenghty process, so it's outside of the lock.
+ /* Decompression is a lengthy process, so it's outside of the lock.
This gives the isoc_handler the opportunity to fill more frames
in the mean time.
*/
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index e0ff811..ca05cd6 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -57,7 +57,7 @@
dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g);
- /* check if the paramters are valid */
+ /* check if the parameters are valid */
if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
return -1;
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
deleted file mode 100644
index 9fa5b70..0000000
--- a/drivers/media/video/tvmixer.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-
-#include <asm/semaphore.h>
-#include <asm/uaccess.h>
-
-
-#define DEV_MAX 4
-
-static int devnr = -1;
-module_param(devnr, int, 0644);
-
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-
-struct TVMIXER {
- struct i2c_client *dev;
- int minor;
- int count;
-};
-
-static struct TVMIXER devices[DEV_MAX];
-
-static int tvmixer_adapters(struct i2c_adapter *adap);
-static int tvmixer_clients(struct i2c_client *client);
-
-/* ----------------------------------------------------------------------- */
-
-static int mix_to_v4l(int i)
-{
- int r;
-
- r = ((i & 0xff) * 65536 + 50) / 100;
- if (r > 65535) r = 65535;
- if (r < 0) r = 0;
- return r;
-}
-
-static int v4l_to_mix(int i)
-{
- int r;
-
- r = (i * 100 + 32768) / 65536;
- if (r > 100) r = 100;
- if (r < 0) r = 0;
- return r | (r << 8);
-}
-
-static int v4l_to_mix2(int l, int r)
-{
- r = (r * 100 + 32768) / 65536;
- if (r > 100) r = 100;
- if (r < 0) r = 0;
- l = (l * 100 + 32768) / 65536;
- if (l > 100) l = 100;
- if (l < 0) l = 0;
- return (r << 8) | l;
-}
-
-static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct video_audio va;
- int left,right,ret,val = 0;
- struct TVMIXER *mix = file->private_data;
- struct i2c_client *client = mix->dev;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- if (NULL == client)
- return -ENODEV;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- info.modify_counter = 42 /* FIXME */;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- if (get_user(val, p))
- return -EFAULT;
-
- /* read state */
- memset(&va,0,sizeof(va));
- client->driver->command(client,VIDIOCGAUDIO,&va);
-
- switch (cmd) {
- case MIXER_READ(SOUND_MIXER_RECMASK):
- case MIXER_READ(SOUND_MIXER_CAPS):
- case MIXER_READ(SOUND_MIXER_RECSRC):
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- ret = 0;
- break;
-
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- ret = SOUND_MASK_VOLUME;
- break;
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- ret = SOUND_MASK_VOLUME;
- if (va.flags & VIDEO_AUDIO_BASS)
- ret |= SOUND_MASK_BASS;
- if (va.flags & VIDEO_AUDIO_TREBLE)
- ret |= SOUND_MASK_TREBLE;
- break;
-
- case MIXER_WRITE(SOUND_MIXER_VOLUME):
- left = mix_to_v4l(val);
- right = mix_to_v4l(val >> 8);
- va.volume = max(left,right);
- va.balance = (32768*min(left,right)) / (va.volume ? va.volume : 1);
- va.balance = (left<right) ? (65535-va.balance) : va.balance;
- if (va.volume)
- va.flags &= ~VIDEO_AUDIO_MUTE;
- client->driver->command(client,VIDIOCSAUDIO,&va);
- client->driver->command(client,VIDIOCGAUDIO,&va);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_VOLUME):
- left = (min(65536 - va.balance,32768) *
- va.volume) / 32768;
- right = (min(va.balance,(u16)32768) *
- va.volume) / 32768;
- ret = v4l_to_mix2(left,right);
- break;
-
- case MIXER_WRITE(SOUND_MIXER_BASS):
- va.bass = mix_to_v4l(val);
- client->driver->command(client,VIDIOCSAUDIO,&va);
- client->driver->command(client,VIDIOCGAUDIO,&va);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_BASS):
- ret = v4l_to_mix(va.bass);
- break;
-
- case MIXER_WRITE(SOUND_MIXER_TREBLE):
- va.treble = mix_to_v4l(val);
- client->driver->command(client,VIDIOCSAUDIO,&va);
- client->driver->command(client,VIDIOCGAUDIO,&va);
- /* fall throuth */
- case MIXER_READ(SOUND_MIXER_TREBLE):
- ret = v4l_to_mix(va.treble);
- break;
-
- default:
- return -EINVAL;
- }
- if (put_user(ret, p))
- return -EFAULT;
- return 0;
-}
-
-static int tvmixer_open(struct inode *inode, struct file *file)
-{
- int i, minor = iminor(inode);
- struct TVMIXER *mix = NULL;
- struct i2c_client *client = NULL;
-
- for (i = 0; i < DEV_MAX; i++) {
- if (devices[i].minor == minor) {
- mix = devices+i;
- client = mix->dev;
- break;
- }
- }
-
- if (NULL == client)
- return -ENODEV;
-
- /* lock bttv in memory while the mixer is in use */
- file->private_data = mix;
- if (client->adapter->owner)
- try_module_get(client->adapter->owner);
- return 0;
-}
-
-static int tvmixer_release(struct inode *inode, struct file *file)
-{
- struct TVMIXER *mix = file->private_data;
- struct i2c_client *client;
-
- client = mix->dev;
- if (NULL == client) {
- return -ENODEV;
- }
-
- module_put(client->adapter->owner);
- return 0;
-}
-
-static struct i2c_driver driver = {
- .driver = {
- .name = "tvmixer",
- },
- .id = I2C_DRIVERID_TVMIXER,
- .detach_adapter = tvmixer_adapters,
- .attach_adapter = tvmixer_adapters,
- .detach_client = tvmixer_clients,
-};
-
-static const struct file_operations tvmixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = tvmixer_ioctl,
- .open = tvmixer_open,
- .release = tvmixer_release,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int tvmixer_adapters(struct i2c_adapter *adap)
-{
- struct i2c_client *client;
-
- list_for_each_entry(client, &adap->clients, list)
- tvmixer_clients(client);
- return 0;
-}
-
-static int tvmixer_clients(struct i2c_client *client)
-{
- struct video_audio va;
- int i,minor;
-
- if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
- return -1;
-
- /* unregister ?? */
- for (i = 0; i < DEV_MAX; i++) {
- if (devices[i].dev == client) {
- /* unregister */
- unregister_sound_mixer(devices[i].minor);
- devices[i].dev = NULL;
- devices[i].minor = -1;
- printk("tvmixer: %s unregistered (#1)\n",
- client->name);
- return 0;
- }
- }
-
- /* look for a free slot */
- for (i = 0; i < DEV_MAX; i++)
- if (NULL == devices[i].dev)
- break;
- if (i == DEV_MAX) {
- printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
- return -1;
- }
-
- /* audio chip with mixer ??? */
- if (NULL == client->driver->command)
- return -1;
- memset(&va,0,sizeof(va));
- if (0 != client->driver->command(client,VIDIOCGAUDIO,&va))
- return -1;
- if (0 == (va.flags & VIDEO_AUDIO_VOLUME))
- return -1;
-
- /* everything is fine, register */
- if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
- printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
- return -1;
- }
-
- devices[i].minor = minor;
- devices[i].count = 0;
- devices[i].dev = client;
- printk("tvmixer: %s (%s) registered with minor %d\n",
- client->name,client->adapter->name,minor);
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init tvmixer_init_module(void)
-{
- int i;
-
- for (i = 0; i < DEV_MAX; i++)
- devices[i].minor = -1;
-
- return i2c_add_driver(&driver);
-}
-
-static void __exit tvmixer_cleanup_module(void)
-{
- int i;
-
- i2c_del_driver(&driver);
- for (i = 0; i < DEV_MAX; i++) {
- if (devices[i].minor != -1) {
- unregister_sound_mixer(devices[i].minor);
- printk("tvmixer: %s unregistered (#2)\n",
- devices[i].dev->name);
- }
- }
-}
-
-module_init(tvmixer_init_module);
-module_exit(tvmixer_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index d847273..5e7b795 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -258,7 +258,7 @@
unsigned int p;
/*
- the registers controling gain are 8 bit of which
+ the registers controlling gain are 8 bit of which
we affect only the last 4 bits with our gain.
we know that if saturation is 0, (unsaturated) then
we're grayscale (center axis of the colour cone) so
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index b52b826..df52f8a 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -131,7 +131,7 @@
/* Function prototypes */
static void usbvision_release(struct usb_usbvision *usbvision);
-/* Default initalization of device driver parameters */
+/* Default initialization of device driver parameters */
/* Set the default format for ISOC endpoint */
static int isocMode = ISOC_MODE_COMPRESS;
/* Set the default Debug Mode of the device driver */
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 8ef31ed..a913385 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -566,7 +566,7 @@
}
/* -----------------------------------------------------------------------
- * Client managment code
+ * Client management code
*/
/*
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 6e0ac4c..690281b 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -1270,7 +1270,7 @@
}
/*
- * Scan for a Buz card (actually for the PCI contoler ZR36057),
+ * Scan for a Buz card (actually for the PCI controller ZR36057),
* request the irq and map the io memory
*/
static int __devinit
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index 9f622e0..faae4ec 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -161,7 +161,7 @@
udelay(1);
if (i++ > 200000) { // 200ms, there is for sure something wrong!!!
dprintk(1,
- "%s: timout at wait_end (last status: 0x%02x)\n",
+ "%s: timeout at wait_end (last status: 0x%02x)\n",
ptr->name, ptr->status1);
break;
}
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index 1ef14fe..7849b65 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -163,7 +163,7 @@
udelay(1);
if (i++ > 200000) { // 200ms, there is for sure something wrong!!!
dprintk(1,
- "%s: timout at wait_end (last status: 0x%02x)\n",
+ "%s: timeout at wait_end (last status: 0x%02x)\n",
ptr->name, ptr->status);
break;
}
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index 6be1f6b..af9da03 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -162,7 +162,7 @@
#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */
/* Bit 0 is Status Bit 0: FrameXferErr */
/* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */
- /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */
+ /* Bit 3 is Status Bit 18 WriteDataLengthGTDataLengthErr */
#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500)
#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600)
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 6029509..e630b50 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -1708,7 +1708,7 @@
*
* Outputs: None.
* Return: 0 if successful
- * -EBUSY if previous command timout and IOC reset is not complete.
+ * -EBUSY if previous command timeout and IOC reset is not complete.
* -EFAULT if data unavailable
* -ENODEV if no such device/adapter
* -ETIME if timer expires
@@ -1748,7 +1748,7 @@
*
* Outputs: None.
* Return: 0 if successful
- * -EBUSY if previous command timout and IOC reset is not complete.
+ * -EBUSY if previous command timeout and IOC reset is not complete.
* -EFAULT if data unavailable
* -ENODEV if no such device/adapter
* -ETIME if timer expires
@@ -2316,7 +2316,7 @@
* Outputs: None.
* Return: 0 if successful
* -EFAULT if data unavailable
- * -EBUSY if previous command timout and IOC reset is not complete.
+ * -EBUSY if previous command timeout and IOC reset is not complete.
* -ENODEV if no such device/adapter
* -ETIME if timer expires
* -ENOMEM if memory allocation error
@@ -2553,7 +2553,7 @@
* Outputs: None.
* Return: 0 if successful
* -EFAULT if data unavailable
- * -EBUSY if previous command timout and IOC reset is not complete.
+ * -EBUSY if previous command timeout and IOC reset is not complete.
* -ENODEV if no such device/adapter
* -ETIME if timer expires
* -ENOMEM if memory allocation error
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5c614ec..af1de0c 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -1736,7 +1736,7 @@
fail_out:
/*
- * Free task managment mf, and corresponding tm flags
+ * Free task management mf, and corresponding tm flags
*/
mpt_free_msg_frame(ioc, mf);
hd->tmPending = 0;
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index 7814a06..da715e1 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -916,7 +916,7 @@
* status block. The status block could then be accessed through
* c->status_block.
*
- * Returns 0 on sucess or negative error code on failure.
+ * Returns 0 on success or negative error code on failure.
*/
int i2o_status_get(struct i2o_controller *c)
{
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index d1380a5..f20c30c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -219,6 +219,25 @@
If you are not sure, say Y here.
+config THINKPAD_ACPI_HOTKEY_POLL
+ bool "Suport NVRAM polling for hot keys"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Some thinkpad models benefit from NVRAM polling to detect a few of
+ the hot key press events. If you know your ThinkPad model does not
+ need to do NVRAM polling to support any of the hot keys you use,
+ unselecting this option will save about 1kB of memory.
+
+ ThinkPads T40 and newer, R52 and newer, and X31 and newer are
+ unlikely to need NVRAM polling in their latest BIOS versions.
+
+ NVRAM polling can detect at most the following keys: ThinkPad/Access
+ IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
+ Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
+
+ If you are not sure, say Y here. The driver enables polling only if
+ it is strictly necessary to do so.
config ATMEL_SSC
tristate "Device driver for Atmel SSC peripheral"
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 7dce318..3bd8831 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -33,7 +33,6 @@
* Sam Lin - GPS support
*/
-#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -255,7 +254,7 @@
* method is searched within the scope of the handle, can be NULL. The output
* of the method is written is output, which can also be NULL
*
- * returns 1 if write is successful, 0 else.
+ * returns 0 if write is successful, -1 else.
*/
static int write_acpi_int(acpi_handle handle, const char *method, int val,
struct acpi_buffer *output)
@@ -264,13 +263,19 @@
union acpi_object in_obj; //the only param we use
acpi_status status;
+ if (!handle)
+ return 0;
+
params.count = 1;
params.pointer = &in_obj;
in_obj.type = ACPI_TYPE_INTEGER;
in_obj.integer.value = val;
status = acpi_evaluate_object(handle, (char *)method, ¶ms, output);
- return (status == AE_OK);
+ if (status == AE_OK)
+ return 0;
+ else
+ return -1;
}
static int read_wireless_status(int mask)
@@ -322,7 +327,7 @@
switch (mask) {
case MLED_ON:
- out = !out & 0x1;
+ out = !(out & 0x1);
break;
case GLED_ON:
out = (out & 0x1) + 1;
@@ -336,7 +341,7 @@
break;
}
- if (handle && !write_acpi_int(handle, NULL, out, NULL))
+ if (write_acpi_int(handle, NULL, out, NULL))
printk(ASUS_WARNING " write failed %x\n", mask);
}
@@ -416,7 +421,7 @@
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
/* 0 <= value <= 15 */
- if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+ if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
printk(ASUS_WARNING "Error changing brightness\n");
ret = -EIO;
}
@@ -546,7 +551,7 @@
rv = parse_arg(buf, count, &value);
if (rv > 0) {
- if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+ if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
printk(ASUS_WARNING "LED display write failed\n");
else
hotk->ledd_status = (u32) value;
@@ -591,7 +596,7 @@
static void set_display(int value)
{
/* no sanity check needed for now */
- if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+ if (write_acpi_int(display_set_handle, NULL, value, NULL))
printk(ASUS_WARNING "Error setting display\n");
return;
}
@@ -648,7 +653,7 @@
*/
static void set_light_sens_switch(int value)
{
- if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+ if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
printk(ASUS_WARNING "Error setting light sensor switch\n");
hotk->light_switch = value;
}
@@ -673,7 +678,7 @@
static void set_light_sens_level(int value)
{
- if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+ if (write_acpi_int(ls_level_handle, NULL, value, NULL))
printk(ASUS_WARNING "Error setting light sensor level\n");
hotk->light_level = value;
}
@@ -861,7 +866,7 @@
printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
/* We have to write 0 on init this far for all ASUS models */
- if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+ if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
printk(ASUS_ERR "Hotkey initialization failed\n");
return -ENODEV;
}
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index c8d62c2..1cfd7f3 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -50,7 +50,6 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
-#include <linux/autoconf.h>
#define FUJITSU_DRIVER_VERSION "0.3"
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 552b795..c884730 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -129,27 +129,28 @@
MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
"crash point is to be hit to trigger action");
-unsigned int jp_do_irq(unsigned int irq)
+static unsigned int jp_do_irq(unsigned int irq)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action)
+static irqreturn_t jp_handle_irq_event(unsigned int irq,
+ struct irqaction *action)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-void jp_tasklet_action(struct softirq_action *a)
+static void jp_tasklet_action(struct softirq_action *a)
{
lkdtm_handler();
jprobe_return();
}
-void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
+static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
{
lkdtm_handler();
jprobe_return();
@@ -157,23 +158,24 @@
struct scan_control;
-unsigned long jp_shrink_inactive_list(unsigned long max_scan,
- struct zone *zone, struct scan_control *sc)
+static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
+ struct zone *zone,
+ struct scan_control *sc)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
- const enum hrtimer_mode mode)
+static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
+ const enum hrtimer_mode mode)
{
lkdtm_handler();
jprobe_return();
return 0;
}
-int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
{
lkdtm_handler();
jprobe_return();
@@ -270,7 +272,7 @@
}
}
-int lkdtm_module_init(void)
+static int __init lkdtm_module_init(void)
{
int ret;
@@ -331,7 +333,7 @@
return 0;
}
-void lkdtm_module_exit(void)
+static void __exit lkdtm_module_exit(void)
{
unregister_jprobe(&lkdtm);
printk(KERN_INFO "lkdtm : Crash point unregistered\n");
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 83679c7..de898c6 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -58,7 +58,6 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
-#include <linux/autoconf.h>
#define MSI_DRIVER_VERSION "0.5"
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index cd221fd..7fa61e9 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -25,7 +25,7 @@
#include <asm/atomic.h>
#include <asm/io.h>
-#define PHANTOM_VERSION "n0.9.7"
+#define PHANTOM_VERSION "n0.9.8"
#define PHANTOM_MAX_MINORS 8
@@ -456,8 +456,9 @@
#endif
static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
- .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
+ { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050,
+ .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050,
+ .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index b0f6803..899e3f7 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -73,7 +73,7 @@
if (debug) printk(KERN_WARNING DRV_PFX msg); \
} while (0)
-#define SONY_LAPTOP_DRIVER_VERSION "0.5"
+#define SONY_LAPTOP_DRIVER_VERSION "0.6"
#define SONY_NC_CLASS "sony-nc"
#define SONY_NC_HID "SNY5001"
@@ -146,68 +146,70 @@
* and input layer indexes in the keymap
*/
static int sony_laptop_input_index[] = {
- -1, /* no event */
- -1, /* SONYPI_EVENT_JOGDIAL_DOWN */
- -1, /* SONYPI_EVENT_JOGDIAL_UP */
- -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
- -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
- -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */
- -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */
- 0, /* SONYPI_EVENT_CAPTURE_PRESSED */
- 1, /* SONYPI_EVENT_CAPTURE_RELEASED */
- 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
- 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
- 4, /* SONYPI_EVENT_FNKEY_ESC */
- 5, /* SONYPI_EVENT_FNKEY_F1 */
- 6, /* SONYPI_EVENT_FNKEY_F2 */
- 7, /* SONYPI_EVENT_FNKEY_F3 */
- 8, /* SONYPI_EVENT_FNKEY_F4 */
- 9, /* SONYPI_EVENT_FNKEY_F5 */
- 10, /* SONYPI_EVENT_FNKEY_F6 */
- 11, /* SONYPI_EVENT_FNKEY_F7 */
- 12, /* SONYPI_EVENT_FNKEY_F8 */
- 13, /* SONYPI_EVENT_FNKEY_F9 */
- 14, /* SONYPI_EVENT_FNKEY_F10 */
- 15, /* SONYPI_EVENT_FNKEY_F11 */
- 16, /* SONYPI_EVENT_FNKEY_F12 */
- 17, /* SONYPI_EVENT_FNKEY_1 */
- 18, /* SONYPI_EVENT_FNKEY_2 */
- 19, /* SONYPI_EVENT_FNKEY_D */
- 20, /* SONYPI_EVENT_FNKEY_E */
- 21, /* SONYPI_EVENT_FNKEY_F */
- 22, /* SONYPI_EVENT_FNKEY_S */
- 23, /* SONYPI_EVENT_FNKEY_B */
- 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */
- 25, /* SONYPI_EVENT_PKEY_P1 */
- 26, /* SONYPI_EVENT_PKEY_P2 */
- 27, /* SONYPI_EVENT_PKEY_P3 */
- 28, /* SONYPI_EVENT_BACK_PRESSED */
- -1, /* SONYPI_EVENT_LID_CLOSED */
- -1, /* SONYPI_EVENT_LID_OPENED */
- 29, /* SONYPI_EVENT_BLUETOOTH_ON */
- 30, /* SONYPI_EVENT_BLUETOOTH_OFF */
- 31, /* SONYPI_EVENT_HELP_PRESSED */
- 32, /* SONYPI_EVENT_FNKEY_ONLY */
- 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
- 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */
- 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
- 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
- 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
- 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
- 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
- 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
- 41, /* SONYPI_EVENT_ZOOM_PRESSED */
- 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
- 43, /* SONYPI_EVENT_MEYE_FACE */
- 44, /* SONYPI_EVENT_MEYE_OPPOSITE */
- 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */
- 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */
- -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */
- -1, /* SONYPI_EVENT_BATTERY_INSERT */
- -1, /* SONYPI_EVENT_BATTERY_REMOVE */
- -1, /* SONYPI_EVENT_FNKEY_RELEASED */
- 47, /* SONYPI_EVENT_WIRELESS_ON */
- 48, /* SONYPI_EVENT_WIRELESS_OFF */
+ -1, /* 0 no event */
+ -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */
+ -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */
+ -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+ -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+ -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */
+ -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */
+ 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */
+ 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */
+ 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+ 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+ 4, /* 11 SONYPI_EVENT_FNKEY_ESC */
+ 5, /* 12 SONYPI_EVENT_FNKEY_F1 */
+ 6, /* 13 SONYPI_EVENT_FNKEY_F2 */
+ 7, /* 14 SONYPI_EVENT_FNKEY_F3 */
+ 8, /* 15 SONYPI_EVENT_FNKEY_F4 */
+ 9, /* 16 SONYPI_EVENT_FNKEY_F5 */
+ 10, /* 17 SONYPI_EVENT_FNKEY_F6 */
+ 11, /* 18 SONYPI_EVENT_FNKEY_F7 */
+ 12, /* 19 SONYPI_EVENT_FNKEY_F8 */
+ 13, /* 20 SONYPI_EVENT_FNKEY_F9 */
+ 14, /* 21 SONYPI_EVENT_FNKEY_F10 */
+ 15, /* 22 SONYPI_EVENT_FNKEY_F11 */
+ 16, /* 23 SONYPI_EVENT_FNKEY_F12 */
+ 17, /* 24 SONYPI_EVENT_FNKEY_1 */
+ 18, /* 25 SONYPI_EVENT_FNKEY_2 */
+ 19, /* 26 SONYPI_EVENT_FNKEY_D */
+ 20, /* 27 SONYPI_EVENT_FNKEY_E */
+ 21, /* 28 SONYPI_EVENT_FNKEY_F */
+ 22, /* 29 SONYPI_EVENT_FNKEY_S */
+ 23, /* 30 SONYPI_EVENT_FNKEY_B */
+ 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
+ 25, /* 32 SONYPI_EVENT_PKEY_P1 */
+ 26, /* 33 SONYPI_EVENT_PKEY_P2 */
+ 27, /* 34 SONYPI_EVENT_PKEY_P3 */
+ 28, /* 35 SONYPI_EVENT_BACK_PRESSED */
+ -1, /* 36 SONYPI_EVENT_LID_CLOSED */
+ -1, /* 37 SONYPI_EVENT_LID_OPENED */
+ 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */
+ 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
+ 31, /* 40 SONYPI_EVENT_HELP_PRESSED */
+ 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */
+ 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+ 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
+ 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+ 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+ 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+ 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+ 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+ 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+ 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */
+ 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+ 43, /* 52 SONYPI_EVENT_MEYE_FACE */
+ 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
+ 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
+ 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
+ -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
+ -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */
+ -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */
+ -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */
+ 47, /* 60 SONYPI_EVENT_WIRELESS_ON */
+ 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */
+ 49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
+ 50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
};
static int sony_laptop_input_keycode_map[] = {
@@ -260,6 +262,8 @@
KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
+ KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
+ KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
};
/* release buttons after a short delay if pressed */
@@ -311,7 +315,7 @@
break;
default:
- if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+ if (event > ARRAY_SIZE(sony_laptop_input_index)) {
dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
break;
}
@@ -875,6 +879,15 @@
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
},
},
+ {
+ .ident = "Sony Vaio N Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"),
+ },
+ },
{ }
};
@@ -1169,10 +1182,12 @@
#define SONYPI_DEVICE_TYPE1 0x00000001
#define SONYPI_DEVICE_TYPE2 0x00000002
#define SONYPI_DEVICE_TYPE3 0x00000004
+#define SONYPI_DEVICE_TYPE4 0x00000008
#define SONYPI_TYPE1_OFFSET 0x04
#define SONYPI_TYPE2_OFFSET 0x12
#define SONYPI_TYPE3_OFFSET 0x12
+#define SONYPI_TYPE4_OFFSET 0x12
struct sony_pic_ioport {
struct acpi_resource_io io1;
@@ -1185,18 +1200,33 @@
struct list_head list;
};
+struct sonypi_eventtypes {
+ u8 data;
+ unsigned long mask;
+ struct sonypi_event *events;
+};
+
+struct device_ctrl {
+ int model;
+ int (*handle_irq)(const u8, const u8);
+ u16 evport_offset;
+ u8 has_camera;
+ u8 has_bluetooth;
+ u8 has_wwan;
+ struct sonypi_eventtypes *event_types;
+};
+
struct sony_pic_dev {
- int model;
- u16 evport_offset;
- u8 camera_power;
- u8 bluetooth_power;
- u8 wwan_power;
+ struct device_ctrl *control;
struct acpi_device *acpi_dev;
struct sony_pic_irq *cur_irq;
struct sony_pic_ioport *cur_ioport;
struct list_head interrupts;
struct list_head ioports;
struct mutex lock;
+ u8 camera_power;
+ u8 bluetooth_power;
+ u8 wwan_power;
};
static struct sony_pic_dev spic_dev = {
@@ -1253,6 +1283,7 @@
static struct sonypi_event sonypi_captureev[] = {
{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+ { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
{ 0, 0 }
};
@@ -1289,7 +1320,6 @@
{ 0x01, SONYPI_EVENT_PKEY_P1 },
{ 0x02, SONYPI_EVENT_PKEY_P2 },
{ 0x04, SONYPI_EVENT_PKEY_P3 },
- { 0x5c, SONYPI_EVENT_PKEY_P1 },
{ 0, 0 }
};
@@ -1331,6 +1361,8 @@
/* The set of possible zoom events */
static struct sonypi_event sonypi_zoomev[] = {
{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+ { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
+ { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
{ 0, 0 }
};
@@ -1361,76 +1393,58 @@
{ 0, 0 }
};
-static struct sonypi_eventtypes {
- int model;
- u8 data;
- unsigned long mask;
- struct sonypi_event * events;
-} sony_pic_eventtypes[] = {
- { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
- { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
- { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
- { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
- { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
- { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
- { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
- { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
- { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
- { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
-
- { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
- { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
- { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
- { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
- { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
- { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
- { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
- { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
- { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
- { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
- { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
- { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
- { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
- { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
-
- { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
- { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
- { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
- { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
- { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
- { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
- { 0 }
+static struct sonypi_eventtypes type1_events[] = {
+ { 0, 0xffffffff, sonypi_releaseev },
+ { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+ { 0x30, SONYPI_LID_MASK, sonypi_lidev },
+ { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+ { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+ { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { 0 },
+};
+static struct sonypi_eventtypes type2_events[] = {
+ { 0, 0xffffffff, sonypi_releaseev },
+ { 0x38, SONYPI_LID_MASK, sonypi_lidev },
+ { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
+ { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+ { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0x11, SONYPI_BACK_MASK, sonypi_backev },
+ { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
+ { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
+ { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+ { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0 },
+};
+static struct sonypi_eventtypes type3_events[] = {
+ { 0, 0xffffffff, sonypi_releaseev },
+ { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0 },
+};
+static struct sonypi_eventtypes type4_events[] = {
+ { 0, 0xffffffff, sonypi_releaseev },
+ { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
+ { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { 0 },
};
-static int sony_pic_detect_device_type(void)
-{
- struct pci_dev *pcidev;
- int model = 0;
-
- if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
- model = SONYPI_DEVICE_TYPE1;
-
- else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
- model = SONYPI_DEVICE_TYPE3;
-
- else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
- model = SONYPI_DEVICE_TYPE3;
-
- else
- model = SONYPI_DEVICE_TYPE2;
-
- if (pcidev)
- pci_dev_put(pcidev);
-
- printk(KERN_INFO DRV_PFX "detected Type%d model\n",
- model == SONYPI_DEVICE_TYPE1 ? 1 :
- model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
- return model;
-}
-
+/* low level spic calls */
#define ITERATIONS_LONG 10000
#define ITERATIONS_SHORT 10
#define wait_on_command(command, iterations) { \
@@ -1451,7 +1465,7 @@
outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
- dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
+ dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
return v2;
}
@@ -1466,7 +1480,7 @@
ITERATIONS_LONG);
outb(fn, spic_dev.cur_ioport->io1.minimum);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
- dprintk("sony_pic_call2: 0x%.4x\n", v1);
+ dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
return v1;
}
@@ -1481,10 +1495,105 @@
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
outb(v, spic_dev.cur_ioport->io1.minimum);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
- dprintk("sony_pic_call3: 0x%.4x\n", v1);
+ dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
+ dev, fn, v, v1);
return v1;
}
+/*
+ * minidrivers for SPIC models
+ */
+static int type4_handle_irq(const u8 data_mask, const u8 ev)
+{
+ /*
+ * 0x31 could mean we have to take some extra action and wait for
+ * the next irq for some Type4 models, it will generate a new
+ * irq and we can read new data from the device:
+ * - 0x5c and 0x5f requires 0xA0
+ * - 0x61 requires 0xB3
+ */
+ if (data_mask == 0x31) {
+ if (ev == 0x5c || ev == 0x5f)
+ sony_pic_call1(0xA0);
+ else if (ev == 0x61)
+ sony_pic_call1(0xB3);
+ return 0;
+ }
+ return 1;
+}
+
+static struct device_ctrl spic_types[] = {
+ {
+ .model = SONYPI_DEVICE_TYPE1,
+ .handle_irq = NULL,
+ .evport_offset = SONYPI_TYPE1_OFFSET,
+ .event_types = type1_events,
+ },
+ {
+ .model = SONYPI_DEVICE_TYPE2,
+ .handle_irq = NULL,
+ .evport_offset = SONYPI_TYPE2_OFFSET,
+ .event_types = type2_events,
+ },
+ {
+ .model = SONYPI_DEVICE_TYPE3,
+ .handle_irq = NULL,
+ .evport_offset = SONYPI_TYPE3_OFFSET,
+ .event_types = type3_events,
+ },
+ {
+ .model = SONYPI_DEVICE_TYPE4,
+ .handle_irq = type4_handle_irq,
+ .evport_offset = SONYPI_TYPE4_OFFSET,
+ .event_types = type4_events,
+ },
+};
+
+static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
+{
+ struct pci_dev *pcidev;
+
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ if (pcidev) {
+ dev->control = &spic_types[0];
+ goto out;
+ }
+
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
+ if (pcidev) {
+ dev->control = &spic_types[2];
+ goto out;
+ }
+
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
+ if (pcidev) {
+ dev->control = &spic_types[3];
+ goto out;
+ }
+
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
+ if (pcidev) {
+ dev->control = &spic_types[3];
+ goto out;
+ }
+
+ /* default */
+ dev->control = &spic_types[1];
+
+out:
+ if (pcidev)
+ pci_dev_put(pcidev);
+
+ printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+ dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
+ dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
+ dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
+}
+
/* camera tests and poweron/poweroff */
#define SONYPI_CAMERA_PICTURE 5
#define SONYPI_CAMERA_CONTROL 0x10
@@ -2253,7 +2362,7 @@
buffer.pointer = resource;
/* setup Type 1 resources */
- if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
+ if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
/* setup io resources */
resource->res1.type = ACPI_RESOURCE_TYPE_IO;
@@ -2335,39 +2444,49 @@
if (dev->cur_ioport->io2.minimum)
data_mask = inb_p(dev->cur_ioport->io2.minimum);
else
- data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);
+ data_mask = inb_p(dev->cur_ioport->io1.minimum +
+ dev->control->evport_offset);
dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
- ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);
+ ev, data_mask, dev->cur_ioport->io1.minimum,
+ dev->control->evport_offset);
if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED;
- for (i = 0; sony_pic_eventtypes[i].model; i++) {
+ for (i = 0; dev->control->event_types[i].mask; i++) {
- if (spic_dev.model != sony_pic_eventtypes[i].model)
+ if ((data_mask & dev->control->event_types[i].data) !=
+ dev->control->event_types[i].data)
continue;
- if ((data_mask & sony_pic_eventtypes[i].data) !=
- sony_pic_eventtypes[i].data)
+ if (!(mask & dev->control->event_types[i].mask))
continue;
- if (!(mask & sony_pic_eventtypes[i].mask))
- continue;
-
- for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
- if (ev == sony_pic_eventtypes[i].events[j].data) {
+ for (j = 0; dev->control->event_types[i].events[j].event; j++) {
+ if (ev == dev->control->event_types[i].events[j].data) {
device_event =
- sony_pic_eventtypes[i].events[j].event;
+ dev->control->
+ event_types[i].events[j].event;
goto found;
}
}
}
+ /* Still not able to decode the event try to pass
+ * it over to the minidriver
+ */
+ if (dev->control->handle_irq &&
+ dev->control->handle_irq(data_mask, ev) == 0)
+ return IRQ_HANDLED;
+
+ dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+ ev, data_mask, dev->cur_ioport->io1.minimum,
+ dev->control->evport_offset);
return IRQ_HANDLED;
found:
sony_laptop_report_input_event(device_event);
- acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event);
+ acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
sonypi_compat_report_event(device_event);
return IRQ_HANDLED;
@@ -2429,23 +2548,9 @@
spic_dev.acpi_dev = device;
strcpy(acpi_device_class(device), "sony/hotkey");
- spic_dev.model = sony_pic_detect_device_type();
+ sony_pic_detect_device_type(&spic_dev);
mutex_init(&spic_dev.lock);
- /* model specific characteristics */
- switch(spic_dev.model) {
- case SONYPI_DEVICE_TYPE1:
- spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
- break;
- case SONYPI_DEVICE_TYPE3:
- spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
- break;
- case SONYPI_DEVICE_TYPE2:
- default:
- spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
- break;
- }
-
/* read _PRS resources */
result = sony_pic_possible_resources(device);
if (result) {
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index cf56647..7ba1aca 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3,7 +3,7 @@
*
*
* Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,11 +21,13 @@
* 02110-1301, USA.
*/
-#define IBM_VERSION "0.17"
-#define TPACPI_SYSFS_VERSION 0x020000
+#define TPACPI_VERSION "0.19"
+#define TPACPI_SYSFS_VERSION 0x020200
/*
* Changelog:
+ * 2007-10-20 changelog trimmed down
+ *
* 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
* drivers/misc.
*
@@ -33,89 +35,219 @@
* changelog now lives in git commit history, and will
* not be updated further in-file.
*
- * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
* 2005-03-17 0.11 support for 600e, 770x
* thanks to Jamie Lentin <lentinj@dial.pipex.com>
- * support for 770e, G41
- * G40 and G41 don't have a thinklight
- * temperatures no longer experimental
- * experimental brightness control
- * experimental volume control
- * experimental fan enable/disable
- * 2005-01-16 0.10 fix module loading on R30, R31
- * 2005-01-16 0.9 support for 570, R30, R31
- * ultrabay support on A22p, A3x
- * limit arg for cmos, led, beep, drop experimental status
- * more capable led control on A21e, A22p, T20-22, X20
- * experimental temperatures and fan speed
- * experimental embedded controller register dump
- * mark more functions as __init, drop incorrect __exit
- * use MODULE_VERSION
+ *
+ * 2005-01-16 0.9 use MODULE_VERSION
* thanks to Henrik Brix Andersen <brix@gentoo.org>
* fix parameter passing on module loading
* thanks to Rusty Russell <rusty@rustcorp.com.au>
* thanks to Jim Radford <radford@blackbean.org>
* 2004-11-08 0.8 fix init error case, don't return from a macro
* thanks to Chris Wright <chrisw@osdl.org>
- * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
- * fix led control on A21e
- * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
- * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
- * proc file format changed
- * video_switch command
- * experimental cmos control
- * experimental led control
- * experimental acpi sounds
- * 2004-09-16 0.4 support for module parameters
- * hotkey mask can be prefixed by 0x
- * video output switching
- * video expansion control
- * ultrabay eject support
- * removed lcd brightness/on/off control, didn't work
- * 2004-08-17 0.3 support for R40
- * lcd off, brightness control
- * thinklight on/off
- * 2004-08-14 0.2 support for T series, X20
- * bluetooth enable/disable
- * hotkey events disabled by default
- * removed fan control, currently useless
- * 2004-08-09 0.1 initial release, support for X series
*/
-#include "thinkpad_acpi.h"
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/delay.h>
-MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
-MODULE_DESCRIPTION(IBM_DESC);
-MODULE_VERSION(IBM_VERSION);
-MODULE_LICENSE("GPL");
+#include <linux/nvram.h>
+#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
+#include <asm/uaccess.h>
-/* Please remove this in year 2009 */
-MODULE_ALIAS("ibm_acpi");
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
-/*
- * DMI matching for module autoloading
- *
- * See http://thinkwiki.org/wiki/List_of_DMI_IDs
- * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
- *
- * Only models listed in thinkwiki will be supported, so add yours
- * if it is not there yet.
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+#include <linux/pci_ids.h>
+
+
+/* ThinkPad CMOS commands */
+#define TP_CMOS_VOLUME_DOWN 0
+#define TP_CMOS_VOLUME_UP 1
+#define TP_CMOS_VOLUME_MUTE 2
+#define TP_CMOS_BRIGHTNESS_UP 4
+#define TP_CMOS_BRIGHTNESS_DOWN 5
+
+/* NVRAM Addresses */
+enum tp_nvram_addr {
+ TP_NVRAM_ADDR_HK2 = 0x57,
+ TP_NVRAM_ADDR_THINKLIGHT = 0x58,
+ TP_NVRAM_ADDR_VIDEO = 0x59,
+ TP_NVRAM_ADDR_BRIGHTNESS = 0x5e,
+ TP_NVRAM_ADDR_MIXER = 0x60,
+};
+
+/* NVRAM bit masks */
+enum {
+ TP_NVRAM_MASK_HKT_THINKPAD = 0x08,
+ TP_NVRAM_MASK_HKT_ZOOM = 0x20,
+ TP_NVRAM_MASK_HKT_DISPLAY = 0x40,
+ TP_NVRAM_MASK_HKT_HIBERNATE = 0x80,
+ TP_NVRAM_MASK_THINKLIGHT = 0x10,
+ TP_NVRAM_MASK_HKT_DISPEXPND = 0x30,
+ TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20,
+ TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f,
+ TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0,
+ TP_NVRAM_MASK_MUTE = 0x40,
+ TP_NVRAM_MASK_HKT_VOLUME = 0x80,
+ TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f,
+ TP_NVRAM_POS_LEVEL_VOLUME = 0,
+};
+
+/* ACPI HIDs */
+#define TPACPI_ACPI_HKEY_HID "IBM0068"
+
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION 0x4101
+
+
+/****************************************************************************
+ * Main driver
*/
-#define IBM_BIOS_MODULE_ALIAS(__type) \
- MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
-/* Non-ancient thinkpads */
-MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
-MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+#define TPACPI_NAME "thinkpad"
+#define TPACPI_DESC "ThinkPad ACPI Extras"
+#define TPACPI_FILE TPACPI_NAME "_acpi"
+#define TPACPI_URL "http://ibm-acpi.sf.net/"
+#define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net"
-/* Ancient thinkpad BIOSes have to be identified by
- * BIOS type or model number, and there are far less
- * BIOS types than model numbers... */
-IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
-IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
-IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+#define TPACPI_PROC_DIR "ibm"
+#define TPACPI_ACPI_EVENT_PREFIX "ibm"
+#define TPACPI_DRVR_NAME TPACPI_FILE
+#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
-#define __unused __attribute__ ((unused))
+#define TPACPI_MAX_ACPI_ARGS 3
+
+/* Debugging */
+#define TPACPI_LOG TPACPI_FILE ": "
+#define TPACPI_ERR KERN_ERR TPACPI_LOG
+#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
+#define TPACPI_INFO KERN_INFO TPACPI_LOG
+#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
+
+#define TPACPI_DBG_ALL 0xffff
+#define TPACPI_DBG_ALL 0xffff
+#define TPACPI_DBG_INIT 0x0001
+#define TPACPI_DBG_EXIT 0x0002
+#define dbg_printk(a_dbg_level, format, arg...) \
+ do { if (dbg_level & a_dbg_level) \
+ printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
+ } while (0)
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+ dbg_printk(a_dbg_level, format, ## arg)
+static const char *str_supported(int is_supported);
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
+
+#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a, b) (strncmp((a), (b), strlen(b)))
+
+
+/****************************************************************************
+ * Driver-wide structs and misc. variables
+ */
+
+struct ibm_struct;
+
+struct tp_acpi_drv_struct {
+ const struct acpi_device_id *hid;
+ struct acpi_driver *driver;
+
+ void (*notify) (struct ibm_struct *, u32);
+ acpi_handle *handle;
+ u32 type;
+ struct acpi_device *device;
+};
+
+struct ibm_struct {
+ char *name;
+
+ int (*read) (char *);
+ int (*write) (char *);
+ void (*exit) (void);
+ void (*resume) (void);
+ void (*suspend) (pm_message_t state);
+
+ struct list_head all_drivers;
+
+ struct tp_acpi_drv_struct *acpi;
+
+ struct {
+ u8 acpi_driver_registered:1;
+ u8 acpi_notify_installed:1;
+ u8 proc_created:1;
+ u8 init_called:1;
+ u8 experimental:1;
+ } flags;
+};
+
+struct ibm_init_struct {
+ char param[32];
+
+ int (*init) (struct ibm_init_struct *);
+ struct ibm_struct *data;
+};
+
+static struct {
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+ u32 bay_status:1;
+ u32 bay_eject:1;
+ u32 bay_status2:1;
+ u32 bay_eject2:1;
+#endif
+ u32 bluetooth:1;
+ u32 hotkey:1;
+ u32 hotkey_mask:1;
+ u32 hotkey_wlsw:1;
+ u32 light:1;
+ u32 light_status:1;
+ u32 bright_16levels:1;
+ u32 wan:1;
+ u32 fan_ctrl_status_undef:1;
+ u32 input_device_registered:1;
+ u32 platform_drv_registered:1;
+ u32 platform_drv_attrs_registered:1;
+ u32 sensors_pdrv_registered:1;
+ u32 sensors_pdrv_attrs_registered:1;
+ u32 sensors_pdev_attrs_registered:1;
+ u32 hotkey_poll_active:1;
+} tp_features;
+
+struct thinkpad_id_data {
+ unsigned int vendor; /* ThinkPad vendor:
+ * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+ char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
+ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
+
+ u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+ u16 ec_model;
+
+ char *model_str;
+};
+static struct thinkpad_id_data thinkpad_id;
static enum {
TPACPI_LIFE_INIT = 0,
@@ -123,6 +255,9 @@
TPACPI_LIFE_EXITING,
} tpacpi_lifecycle;
+static int experimental;
+static u32 dbg_level;
+
/****************************************************************************
****************************************************************************
*
@@ -137,13 +272,13 @@
static acpi_handle root_handle;
-#define IBM_HANDLE(object, parent, paths...) \
+#define TPACPI_HANDLE(object, parent, paths...) \
static acpi_handle object##_handle; \
static acpi_handle *object##_parent = &parent##_handle; \
static char *object##_path; \
static char *object##_paths[] = { paths }
-IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
+TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
"\\_SB.PCI.ISA.EC", /* 570 */
"\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
"\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
@@ -152,20 +287,16 @@
"\\_SB.PCI0.LPC.EC", /* all others */
);
-IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
-IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
+TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */
+TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */
-
-/*************************************************************************
- * Misc ACPI handles
- */
-
-IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
+TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, */
+ /* T4x, X31, X40 */
"\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
"\\CMS", /* R40, R40e */
); /* all others */
-IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
+TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
"^HKEY", /* R30, R31 */
"HKEY", /* all others */
); /* 570 */
@@ -180,7 +311,7 @@
{
char *fmt0 = fmt;
struct acpi_object_list params;
- union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+ union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS];
struct acpi_buffer result, *resultp;
union acpi_object out_obj;
acpi_status status;
@@ -190,7 +321,7 @@
int quiet;
if (!*fmt) {
- printk(IBM_ERR "acpi_evalf() called with empty format\n");
+ printk(TPACPI_ERR "acpi_evalf() called with empty format\n");
return 0;
}
@@ -215,7 +346,7 @@
break;
/* add more types as needed */
default:
- printk(IBM_ERR "acpi_evalf() called "
+ printk(TPACPI_ERR "acpi_evalf() called "
"with invalid format character '%c'\n", c);
return 0;
}
@@ -242,29 +373,19 @@
break;
/* add more types as needed */
default:
- printk(IBM_ERR "acpi_evalf() called "
+ printk(TPACPI_ERR "acpi_evalf() called "
"with invalid format character '%c'\n", res_type);
return 0;
}
if (!success && !quiet)
- printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+ printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
method, fmt0, status);
return success;
}
-static void __unused acpi_print_int(acpi_handle handle, char *method)
-{
- int i;
-
- if (acpi_evalf(handle, &i, method, "d"))
- printk(IBM_INFO "%s = 0x%x\n", method, i);
- else
- printk(IBM_ERR "error calling %s\n", method);
-}
-
-static int acpi_ec_read(int i, u8 * p)
+static int acpi_ec_read(int i, u8 *p)
{
int v;
@@ -293,6 +414,7 @@
return 1;
}
+#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY)
static int _sta(acpi_handle handle)
{
int status;
@@ -302,6 +424,7 @@
return status;
}
+#endif
static int issue_thinkpad_cmos_command(int cmos_cmd)
{
@@ -318,6 +441,10 @@
* ACPI device model
*/
+#define TPACPI_ACPIHANDLE_INIT(object) \
+ drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
+ object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+
static void drv_acpi_handle_init(char *name,
acpi_handle *handle, acpi_handle parent,
char **paths, int num_paths, char **path)
@@ -372,25 +499,27 @@
rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
if (rc < 0) {
- printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
+ printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n",
ibm->name, rc);
return -ENODEV;
}
acpi_driver_data(ibm->acpi->device) = ibm;
sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
- IBM_ACPI_EVENT_PREFIX,
+ TPACPI_ACPI_EVENT_PREFIX,
ibm->name);
status = acpi_install_notify_handler(*ibm->acpi->handle,
ibm->acpi->type, dispatch_acpi_notify, ibm);
if (ACPI_FAILURE(status)) {
if (status == AE_ALREADY_EXISTS) {
- printk(IBM_NOTICE "another device driver is already handling %s events\n",
- ibm->name);
+ printk(TPACPI_NOTICE
+ "another device driver is already "
+ "handling %s events\n", ibm->name);
} else {
- printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
- ibm->name, status);
+ printk(TPACPI_ERR
+ "acpi_install_notify_handler(%s) failed: %d\n",
+ ibm->name, status);
}
return -ENODEV;
}
@@ -414,18 +543,18 @@
ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
if (!ibm->acpi->driver) {
- printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
+ printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n");
return -ENOMEM;
}
- sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
+ sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name);
ibm->acpi->driver->ids = ibm->acpi->hid;
ibm->acpi->driver->ops.add = &tpacpi_device_add;
rc = acpi_bus_register_driver(ibm->acpi->driver);
if (rc < 0) {
- printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+ printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n",
ibm->name, rc);
kfree(ibm->acpi->driver);
ibm->acpi->driver = NULL;
@@ -470,7 +599,7 @@
}
static int dispatch_procfs_write(struct file *file,
- const char __user * userbuf,
+ const char __user *userbuf,
unsigned long count, void *data)
{
struct ibm_struct *ibm = data;
@@ -530,7 +659,22 @@
static struct device *tpacpi_hwmon;
static struct input_dev *tpacpi_inputdev;
static struct mutex tpacpi_inputdev_send_mutex;
+static LIST_HEAD(tpacpi_all_drivers);
+static int tpacpi_suspend_handler(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct ibm_struct *ibm, *itmp;
+
+ list_for_each_entry_safe(ibm, itmp,
+ &tpacpi_all_drivers,
+ all_drivers) {
+ if (ibm->suspend)
+ (ibm->suspend)(state);
+ }
+
+ return 0;
+}
static int tpacpi_resume_handler(struct platform_device *pdev)
{
@@ -548,20 +692,114 @@
static struct platform_driver tpacpi_pdriver = {
.driver = {
- .name = IBM_DRVR_NAME,
+ .name = TPACPI_DRVR_NAME,
.owner = THIS_MODULE,
},
+ .suspend = tpacpi_suspend_handler,
.resume = tpacpi_resume_handler,
};
static struct platform_driver tpacpi_hwmon_pdriver = {
.driver = {
- .name = IBM_HWMON_DRVR_NAME,
+ .name = TPACPI_HWMON_DRVR_NAME,
.owner = THIS_MODULE,
},
};
/*************************************************************************
+ * sysfs support helpers
+ */
+
+struct attribute_set {
+ unsigned int members, max_members;
+ struct attribute_group group;
+};
+
+struct attribute_set_obj {
+ struct attribute_set s;
+ struct attribute *a;
+} __attribute__((packed));
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+ const char *name)
+{
+ struct attribute_set_obj *sobj;
+
+ if (max_members == 0)
+ return NULL;
+
+ /* Allocates space for implicit NULL at the end too */
+ sobj = kzalloc(sizeof(struct attribute_set_obj) +
+ max_members * sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!sobj)
+ return NULL;
+ sobj->s.max_members = max_members;
+ sobj->s.group.attrs = &sobj->a;
+ sobj->s.group.name = name;
+
+ return &sobj->s;
+}
+
+#define destroy_attr_set(_set) \
+ kfree(_set);
+
+/* not multi-threaded safe, use it in a single thread per set */
+static int add_to_attr_set(struct attribute_set *s, struct attribute *attr)
+{
+ if (!s || !attr)
+ return -EINVAL;
+
+ if (s->members >= s->max_members)
+ return -ENOMEM;
+
+ s->group.attrs[s->members] = attr;
+ s->members++;
+
+ return 0;
+}
+
+static int add_many_to_attr_set(struct attribute_set *s,
+ struct attribute **attr,
+ unsigned int count)
+{
+ int i, res;
+
+ for (i = 0; i < count; i++) {
+ res = add_to_attr_set(s, attr[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static void delete_attr_set(struct attribute_set *s, struct kobject *kobj)
+{
+ sysfs_remove_group(kobj, &s->group);
+ destroy_attr_set(s);
+}
+
+#define register_attr_set_with_sysfs(_attr_set, _kobj) \
+ sysfs_create_group(_kobj, &_attr_set->group)
+
+static int parse_strtoul(const char *buf,
+ unsigned long max, unsigned long *value)
+{
+ char *endp;
+
+ while (*buf && isspace(*buf))
+ buf++;
+ *value = simple_strtoul(buf, &endp, 0);
+ while (*endp && isspace(*endp))
+ endp++;
+ if (*endp || *value > max)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*************************************************************************
* thinkpad-acpi driver attributes
*/
@@ -603,7 +841,8 @@
static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
+ return snprintf(buf, PAGE_SIZE, "%s v%s\n",
+ TPACPI_DESC, TPACPI_VERSION);
}
static DRIVER_ATTR(version, S_IRUGO,
@@ -611,7 +850,7 @@
/* --------------------------------------------------------------------- */
-static struct driver_attribute* tpacpi_driver_attributes[] = {
+static struct driver_attribute *tpacpi_driver_attributes[] = {
&driver_attr_debug_level, &driver_attr_version,
&driver_attr_interface_version,
};
@@ -634,92 +873,10 @@
{
int i;
- for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
+ for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
driver_remove_file(drv, tpacpi_driver_attributes[i]);
}
-/*************************************************************************
- * sysfs support helpers
- */
-
-struct attribute_set_obj {
- struct attribute_set s;
- struct attribute *a;
-} __attribute__((packed));
-
-static struct attribute_set *create_attr_set(unsigned int max_members,
- const char* name)
-{
- struct attribute_set_obj *sobj;
-
- if (max_members == 0)
- return NULL;
-
- /* Allocates space for implicit NULL at the end too */
- sobj = kzalloc(sizeof(struct attribute_set_obj) +
- max_members * sizeof(struct attribute *),
- GFP_KERNEL);
- if (!sobj)
- return NULL;
- sobj->s.max_members = max_members;
- sobj->s.group.attrs = &sobj->a;
- sobj->s.group.name = name;
-
- return &sobj->s;
-}
-
-/* not multi-threaded safe, use it in a single thread per set */
-static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
-{
- if (!s || !attr)
- return -EINVAL;
-
- if (s->members >= s->max_members)
- return -ENOMEM;
-
- s->group.attrs[s->members] = attr;
- s->members++;
-
- return 0;
-}
-
-static int add_many_to_attr_set(struct attribute_set* s,
- struct attribute **attr,
- unsigned int count)
-{
- int i, res;
-
- for (i = 0; i < count; i++) {
- res = add_to_attr_set(s, attr[i]);
- if (res)
- return res;
- }
-
- return 0;
-}
-
-static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
-{
- sysfs_remove_group(kobj, &s->group);
- destroy_attr_set(s);
-}
-
-static int parse_strtoul(const char *buf,
- unsigned long max, unsigned long *value)
-{
- char *endp;
-
- while (*buf && isspace(*buf))
- buf++;
- *value = simple_strtoul(buf, &endp, 0);
- while (*endp && isspace(*endp))
- endp++;
- if (*endp || *value > max)
- return -EINVAL;
-
- return 0;
-}
-
/****************************************************************************
****************************************************************************
*
@@ -734,17 +891,17 @@
static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
{
- printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
- printk(IBM_INFO "%s\n", IBM_URL);
+ printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
+ printk(TPACPI_INFO "%s\n", TPACPI_URL);
- printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+ printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
(thinkpad_id.bios_version_str) ?
thinkpad_id.bios_version_str : "unknown",
(thinkpad_id.ec_version_str) ?
thinkpad_id.ec_version_str : "unknown");
if (thinkpad_id.vendor && thinkpad_id.model_str)
- printk(IBM_INFO "%s %s\n",
+ printk(TPACPI_INFO "%s %s\n",
(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
"IBM" : ((thinkpad_id.vendor ==
PCI_VENDOR_ID_LENOVO) ?
@@ -758,8 +915,8 @@
{
int len = 0;
- len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
- len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+ len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC);
+ len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
return len;
}
@@ -773,15 +930,129 @@
* Hotkey subdriver
*/
+enum { /* hot key scan codes (derived from ACPI DSDT) */
+ TP_ACPI_HOTKEYSCAN_FNF1 = 0,
+ TP_ACPI_HOTKEYSCAN_FNF2,
+ TP_ACPI_HOTKEYSCAN_FNF3,
+ TP_ACPI_HOTKEYSCAN_FNF4,
+ TP_ACPI_HOTKEYSCAN_FNF5,
+ TP_ACPI_HOTKEYSCAN_FNF6,
+ TP_ACPI_HOTKEYSCAN_FNF7,
+ TP_ACPI_HOTKEYSCAN_FNF8,
+ TP_ACPI_HOTKEYSCAN_FNF9,
+ TP_ACPI_HOTKEYSCAN_FNF10,
+ TP_ACPI_HOTKEYSCAN_FNF11,
+ TP_ACPI_HOTKEYSCAN_FNF12,
+ TP_ACPI_HOTKEYSCAN_FNBACKSPACE,
+ TP_ACPI_HOTKEYSCAN_FNINSERT,
+ TP_ACPI_HOTKEYSCAN_FNDELETE,
+ TP_ACPI_HOTKEYSCAN_FNHOME,
+ TP_ACPI_HOTKEYSCAN_FNEND,
+ TP_ACPI_HOTKEYSCAN_FNPAGEUP,
+ TP_ACPI_HOTKEYSCAN_FNPAGEDOWN,
+ TP_ACPI_HOTKEYSCAN_FNSPACE,
+ TP_ACPI_HOTKEYSCAN_VOLUMEUP,
+ TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
+ TP_ACPI_HOTKEYSCAN_MUTE,
+ TP_ACPI_HOTKEYSCAN_THINKPAD,
+};
+
+enum { /* Keys available through NVRAM polling */
+ TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U,
+ TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U,
+};
+
+enum { /* Positions of some of the keys in hotkey masks */
+ TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7,
+ TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8,
+ TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12,
+ TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME,
+ TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND,
+ TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP,
+ TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE,
+ TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP,
+ TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
+ TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE,
+ TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD,
+};
+
+enum { /* NVRAM to ACPI HKEY group map */
+ TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK |
+ TP_ACPI_HKEY_ZOOM_MASK |
+ TP_ACPI_HKEY_DISPSWTCH_MASK |
+ TP_ACPI_HKEY_HIBERNATE_MASK,
+ TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK |
+ TP_ACPI_HKEY_BRGHTDWN_MASK,
+ TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK |
+ TP_ACPI_HKEY_VOLDWN_MASK |
+ TP_ACPI_HKEY_MUTE_MASK,
+};
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+struct tp_nvram_state {
+ u16 thinkpad_toggle:1;
+ u16 zoom_toggle:1;
+ u16 display_toggle:1;
+ u16 thinklight_toggle:1;
+ u16 hibernate_toggle:1;
+ u16 displayexp_toggle:1;
+ u16 display_state:1;
+ u16 brightness_toggle:1;
+ u16 volume_toggle:1;
+ u16 mute:1;
+
+ u8 brightness_level;
+ u8 volume_level;
+};
+
+static struct task_struct *tpacpi_hotkey_task;
+static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
+static int hotkey_poll_freq = 10; /* Hz */
+static struct mutex hotkey_thread_mutex;
+static struct mutex hotkey_thread_data_mutex;
+static unsigned int hotkey_config_change;
+
+#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+#define hotkey_source_mask 0U
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+static struct mutex hotkey_mutex;
+
+static enum { /* Reasons for waking up */
+ TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */
+ TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */
+ TP_ACPI_WAKEUP_UNDOCK, /* Undock request */
+} hotkey_wakeup_reason;
+
+static int hotkey_autosleep_ack;
+
static int hotkey_orig_status;
static u32 hotkey_orig_mask;
static u32 hotkey_all_mask;
static u32 hotkey_reserved_mask;
+static u32 hotkey_mask;
+
+static unsigned int hotkey_report_mode;
static u16 *hotkey_keycode_map;
static struct attribute_set *hotkey_dev_attributes;
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+#define HOTKEY_CONFIG_CRITICAL_START \
+ do { \
+ mutex_lock(&hotkey_thread_data_mutex); \
+ hotkey_config_change++; \
+ } while (0);
+#define HOTKEY_CONFIG_CRITICAL_END \
+ mutex_unlock(&hotkey_thread_data_mutex);
+#else
+#define HOTKEY_CONFIG_CRITICAL_START
+#define HOTKEY_CONFIG_CRITICAL_END
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
static int hotkey_get_wlsw(int *status)
{
if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -789,15 +1060,400 @@
return 0;
}
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_mask_get(void)
+{
+ u32 m = 0;
+
+ if (tp_features.hotkey_mask) {
+ if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
+ return -EIO;
+ }
+ hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
+
+ return 0;
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_mask_set(u32 mask)
+{
+ int i;
+ int rc = 0;
+
+ if (tp_features.hotkey_mask) {
+ HOTKEY_CONFIG_CRITICAL_START
+ for (i = 0; i < 32; i++) {
+ u32 m = 1 << i;
+ /* enable in firmware mask only keys not in NVRAM
+ * mode, but enable the key in the cached hotkey_mask
+ * regardless of mode, or the key will end up
+ * disabled by hotkey_mask_get() */
+ if (!acpi_evalf(hkey_handle,
+ NULL, "MHKM", "vdd", i + 1,
+ !!((mask & ~hotkey_source_mask) & m))) {
+ rc = -EIO;
+ break;
+ } else {
+ hotkey_mask = (hotkey_mask & ~m) | (mask & m);
+ }
+ }
+ HOTKEY_CONFIG_CRITICAL_END
+
+ /* hotkey_mask_get must be called unconditionally below */
+ if (!hotkey_mask_get() && !rc &&
+ (hotkey_mask & ~hotkey_source_mask) !=
+ (mask & ~hotkey_source_mask)) {
+ printk(TPACPI_NOTICE
+ "requested hot key mask 0x%08x, but "
+ "firmware forced it to 0x%08x\n",
+ mask, hotkey_mask);
+ }
+ } else {
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ HOTKEY_CONFIG_CRITICAL_START
+ hotkey_mask = mask & hotkey_source_mask;
+ HOTKEY_CONFIG_CRITICAL_END
+ hotkey_mask_get();
+ if (hotkey_mask != mask) {
+ printk(TPACPI_NOTICE
+ "requested hot key mask 0x%08x, "
+ "forced to 0x%08x (NVRAM poll mask is "
+ "0x%08x): no firmware mask support\n",
+ mask, hotkey_mask, hotkey_source_mask);
+ }
+#else
+ hotkey_mask_get();
+ rc = -ENXIO;
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+ }
+
+ return rc;
+}
+
+static int hotkey_status_get(int *status)
+{
+ if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+ return -EIO;
+
+ return 0;
+}
+
+static int hotkey_status_set(int status)
+{
+ if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+ int wlsw;
+
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
+ input_report_switch(tpacpi_inputdev,
+ SW_RADIO, !!wlsw);
+ input_sync(tpacpi_inputdev);
+ }
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
+}
+
+static void tpacpi_input_send_key(unsigned int scancode)
+{
+ unsigned int keycode;
+
+ keycode = hotkey_keycode_map[scancode];
+
+ if (keycode != KEY_RESERVED) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
+ input_report_key(tpacpi_inputdev, keycode, 1);
+ if (keycode == KEY_UNKNOWN)
+ input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+ scancode);
+ input_sync(tpacpi_inputdev);
+
+ input_report_key(tpacpi_inputdev, keycode, 0);
+ if (keycode == KEY_UNKNOWN)
+ input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+ scancode);
+ input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
+ }
+}
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
+
+static void tpacpi_hotkey_send_key(unsigned int scancode)
+{
+ tpacpi_input_send_key(scancode);
+ if (hotkey_report_mode < 2) {
+ acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
+ 0x80, 0x1001 + scancode);
+ }
+}
+
+static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m)
+{
+ u8 d;
+
+ if (m & TP_NVRAM_HKEY_GROUP_HK2) {
+ d = nvram_read_byte(TP_NVRAM_ADDR_HK2);
+ n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD);
+ n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM);
+ n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY);
+ n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE);
+ }
+ if (m & TP_ACPI_HKEY_THNKLGHT_MASK) {
+ d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT);
+ n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT);
+ }
+ if (m & TP_ACPI_HKEY_DISPXPAND_MASK) {
+ d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO);
+ n->displayexp_toggle =
+ !!(d & TP_NVRAM_MASK_HKT_DISPEXPND);
+ }
+ if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) {
+ d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
+ n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+ >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+ n->brightness_toggle =
+ !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS);
+ }
+ if (m & TP_NVRAM_HKEY_GROUP_VOLUME) {
+ d = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
+ n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME)
+ >> TP_NVRAM_POS_LEVEL_VOLUME;
+ n->mute = !!(d & TP_NVRAM_MASK_MUTE);
+ n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME);
+ }
+}
+
+#define TPACPI_COMPARE_KEY(__scancode, __member) \
+ do { \
+ if ((mask & (1 << __scancode)) && \
+ oldn->__member != newn->__member) \
+ tpacpi_hotkey_send_key(__scancode); \
+ } while (0)
+
+#define TPACPI_MAY_SEND_KEY(__scancode) \
+ do { if (mask & (1 << __scancode)) \
+ tpacpi_hotkey_send_key(__scancode); } while (0)
+
+static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
+ struct tp_nvram_state *newn,
+ u32 mask)
+{
+ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
+ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
+ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle);
+ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle);
+
+ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle);
+
+ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle);
+
+ /* handle volume */
+ if (oldn->volume_toggle != newn->volume_toggle) {
+ if (oldn->mute != newn->mute) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
+ }
+ if (oldn->volume_level > newn->volume_level) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
+ } else if (oldn->volume_level < newn->volume_level) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
+ } else if (oldn->mute == newn->mute) {
+ /* repeated key presses that didn't change state */
+ if (newn->mute) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
+ } else if (newn->volume_level != 0) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
+ } else {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
+ }
+ }
+ }
+
+ /* handle brightness */
+ if (oldn->brightness_toggle != newn->brightness_toggle) {
+ if (oldn->brightness_level < newn->brightness_level) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
+ } else if (oldn->brightness_level > newn->brightness_level) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
+ } else {
+ /* repeated key presses that didn't change state */
+ if (newn->brightness_level != 0) {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
+ } else {
+ TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
+ }
+ }
+ }
+}
+
+#undef TPACPI_COMPARE_KEY
+#undef TPACPI_MAY_SEND_KEY
+
+static int hotkey_kthread(void *data)
+{
+ struct tp_nvram_state s[2];
+ u32 mask;
+ unsigned int si, so;
+ unsigned long t;
+ unsigned int change_detector, must_reset;
+
+ mutex_lock(&hotkey_thread_mutex);
+
+ if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
+ goto exit;
+
+ set_freezable();
+
+ so = 0;
+ si = 1;
+ t = 0;
+
+ /* Initial state for compares */
+ mutex_lock(&hotkey_thread_data_mutex);
+ change_detector = hotkey_config_change;
+ mask = hotkey_source_mask & hotkey_mask;
+ mutex_unlock(&hotkey_thread_data_mutex);
+ hotkey_read_nvram(&s[so], mask);
+
+ while (!kthread_should_stop() && hotkey_poll_freq) {
+ if (t == 0)
+ t = 1000/hotkey_poll_freq;
+ t = msleep_interruptible(t);
+ if (unlikely(kthread_should_stop()))
+ break;
+ must_reset = try_to_freeze();
+ if (t > 0 && !must_reset)
+ continue;
+
+ mutex_lock(&hotkey_thread_data_mutex);
+ if (must_reset || hotkey_config_change != change_detector) {
+ /* forget old state on thaw or config change */
+ si = so;
+ t = 0;
+ change_detector = hotkey_config_change;
+ }
+ mask = hotkey_source_mask & hotkey_mask;
+ mutex_unlock(&hotkey_thread_data_mutex);
+
+ if (likely(mask)) {
+ hotkey_read_nvram(&s[si], mask);
+ if (likely(si != so)) {
+ hotkey_compare_and_issue_event(&s[so], &s[si],
+ mask);
+ }
+ }
+
+ so = si;
+ si ^= 1;
+ }
+
+exit:
+ mutex_unlock(&hotkey_thread_mutex);
+ return 0;
+}
+
+static void hotkey_poll_stop_sync(void)
+{
+ if (tpacpi_hotkey_task) {
+ if (frozen(tpacpi_hotkey_task) ||
+ freezing(tpacpi_hotkey_task))
+ thaw_process(tpacpi_hotkey_task);
+
+ kthread_stop(tpacpi_hotkey_task);
+ tpacpi_hotkey_task = NULL;
+ mutex_lock(&hotkey_thread_mutex);
+ /* at this point, the thread did exit */
+ mutex_unlock(&hotkey_thread_mutex);
+ }
+}
+
+/* call with hotkey_mutex held */
+static void hotkey_poll_setup(int may_warn)
+{
+ if ((hotkey_source_mask & hotkey_mask) != 0 &&
+ hotkey_poll_freq > 0 &&
+ (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
+ if (!tpacpi_hotkey_task) {
+ tpacpi_hotkey_task = kthread_run(hotkey_kthread,
+ NULL,
+ TPACPI_FILE "d");
+ if (IS_ERR(tpacpi_hotkey_task)) {
+ tpacpi_hotkey_task = NULL;
+ printk(TPACPI_ERR
+ "could not create kernel thread "
+ "for hotkey polling\n");
+ }
+ }
+ } else {
+ hotkey_poll_stop_sync();
+ if (may_warn &&
+ hotkey_source_mask != 0 && hotkey_poll_freq == 0) {
+ printk(TPACPI_NOTICE
+ "hot keys 0x%08x require polling, "
+ "which is currently disabled\n",
+ hotkey_source_mask);
+ }
+ }
+}
+
+static void hotkey_poll_setup_safe(int may_warn)
+{
+ mutex_lock(&hotkey_mutex);
+ hotkey_poll_setup(may_warn);
+ mutex_unlock(&hotkey_mutex);
+}
+
+static int hotkey_inputdev_open(struct input_dev *dev)
+{
+ switch (tpacpi_lifecycle) {
+ case TPACPI_LIFE_INIT:
+ /*
+ * hotkey_init will call hotkey_poll_setup_safe
+ * at the appropriate moment
+ */
+ return 0;
+ case TPACPI_LIFE_EXITING:
+ return -EBUSY;
+ case TPACPI_LIFE_RUNNING:
+ hotkey_poll_setup_safe(0);
+ return 0;
+ }
+
+ /* Should only happen if tpacpi_lifecycle is corrupt */
+ BUG();
+ return -EBUSY;
+}
+
+static void hotkey_inputdev_close(struct input_dev *dev)
+{
+ /* disable hotkey polling when possible */
+ if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
+ hotkey_poll_setup_safe(0);
+}
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
/* sysfs hotkey enable ------------------------------------------------- */
static ssize_t hotkey_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int res, status;
- u32 mask;
- res = hotkey_get(&status, &mask);
+ res = hotkey_status_get(&status);
if (res)
return res;
@@ -809,15 +1465,12 @@
const char *buf, size_t count)
{
unsigned long t;
- int res, status;
- u32 mask;
+ int res;
if (parse_strtoul(buf, 1, &t))
return -EINVAL;
- res = hotkey_get(&status, &mask);
- if (!res)
- res = hotkey_set(t, mask);
+ res = hotkey_status_set(t);
return (res) ? res : count;
}
@@ -831,14 +1484,15 @@
struct device_attribute *attr,
char *buf)
{
- int res, status;
- u32 mask;
+ int res;
- res = hotkey_get(&status, &mask);
- if (res)
- return res;
+ if (mutex_lock_interruptible(&hotkey_mutex))
+ return -ERESTARTSYS;
+ res = hotkey_mask_get();
+ mutex_unlock(&hotkey_mutex);
- return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
+ return (res)?
+ res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask);
}
static ssize_t hotkey_mask_store(struct device *dev,
@@ -846,15 +1500,21 @@
const char *buf, size_t count)
{
unsigned long t;
- int res, status;
- u32 mask;
+ int res;
if (parse_strtoul(buf, 0xffffffffUL, &t))
return -EINVAL;
- res = hotkey_get(&status, &mask);
- if (!res)
- hotkey_set(status, t);
+ if (mutex_lock_interruptible(&hotkey_mutex))
+ return -ERESTARTSYS;
+
+ res = hotkey_mask_set(t);
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ hotkey_poll_setup(1);
+#endif
+
+ mutex_unlock(&hotkey_mutex);
return (res) ? res : count;
}
@@ -890,7 +1550,8 @@
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+ hotkey_all_mask | hotkey_source_mask);
}
static struct device_attribute dev_attr_hotkey_all_mask =
@@ -902,14 +1563,87 @@
char *buf)
{
return snprintf(buf, PAGE_SIZE, "0x%08x\n",
- hotkey_all_mask & ~hotkey_reserved_mask);
+ (hotkey_all_mask | hotkey_source_mask)
+ & ~hotkey_reserved_mask);
}
static struct device_attribute dev_attr_hotkey_recommended_mask =
__ATTR(hotkey_recommended_mask, S_IRUGO,
hotkey_recommended_mask_show, NULL);
-/* sysfs hotkey radio_sw ----------------------------------------------- */
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+
+/* sysfs hotkey hotkey_source_mask ------------------------------------- */
+static ssize_t hotkey_source_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask);
+}
+
+static ssize_t hotkey_source_mask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 0xffffffffUL, &t) ||
+ ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&hotkey_mutex))
+ return -ERESTARTSYS;
+
+ HOTKEY_CONFIG_CRITICAL_START
+ hotkey_source_mask = t;
+ HOTKEY_CONFIG_CRITICAL_END
+
+ hotkey_poll_setup(1);
+
+ mutex_unlock(&hotkey_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_hotkey_source_mask =
+ __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO,
+ hotkey_source_mask_show, hotkey_source_mask_store);
+
+/* sysfs hotkey hotkey_poll_freq --------------------------------------- */
+static ssize_t hotkey_poll_freq_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq);
+}
+
+static ssize_t hotkey_poll_freq_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 25, &t))
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&hotkey_mutex))
+ return -ERESTARTSYS;
+
+ hotkey_poll_freq = t;
+
+ hotkey_poll_setup(1);
+ mutex_unlock(&hotkey_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_hotkey_poll_freq =
+ __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO,
+ hotkey_poll_freq_show, hotkey_poll_freq_store);
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+/* sysfs hotkey radio_sw (pollable) ------------------------------------ */
static ssize_t hotkey_radio_sw_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -925,6 +1659,13 @@
static struct device_attribute dev_attr_hotkey_radio_sw =
__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+static void hotkey_radio_sw_notify_change(void)
+{
+ if (tp_features.hotkey_wlsw)
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+ "hotkey_radio_sw");
+}
+
/* sysfs hotkey report_mode -------------------------------------------- */
static ssize_t hotkey_report_mode_show(struct device *dev,
struct device_attribute *attr,
@@ -937,43 +1678,132 @@
static struct device_attribute dev_attr_hotkey_report_mode =
__ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
+/* sysfs wakeup reason (pollable) -------------------------------------- */
+static ssize_t hotkey_wakeup_reason_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
+}
+
+static struct device_attribute dev_attr_hotkey_wakeup_reason =
+ __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
+
+void hotkey_wakeup_reason_notify_change(void)
+{
+ if (tp_features.hotkey_mask)
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+ "wakeup_reason");
+}
+
+/* sysfs wakeup hotunplug_complete (pollable) -------------------------- */
+static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
+}
+
+static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
+ __ATTR(wakeup_hotunplug_complete, S_IRUGO,
+ hotkey_wakeup_hotunplug_complete_show, NULL);
+
+void hotkey_wakeup_hotunplug_complete_notify_change(void)
+{
+ if (tp_features.hotkey_mask)
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+ "wakeup_hotunplug_complete");
+}
+
/* --------------------------------------------------------------------- */
static struct attribute *hotkey_attributes[] __initdata = {
&dev_attr_hotkey_enable.attr,
+ &dev_attr_hotkey_bios_enabled.attr,
&dev_attr_hotkey_report_mode.attr,
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ &dev_attr_hotkey_mask.attr,
+ &dev_attr_hotkey_all_mask.attr,
+ &dev_attr_hotkey_recommended_mask.attr,
+ &dev_attr_hotkey_source_mask.attr,
+ &dev_attr_hotkey_poll_freq.attr,
+#endif
};
static struct attribute *hotkey_mask_attributes[] __initdata = {
- &dev_attr_hotkey_mask.attr,
- &dev_attr_hotkey_bios_enabled.attr,
&dev_attr_hotkey_bios_mask.attr,
+#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ &dev_attr_hotkey_mask.attr,
&dev_attr_hotkey_all_mask.attr,
&dev_attr_hotkey_recommended_mask.attr,
+#endif
+ &dev_attr_hotkey_wakeup_reason.attr,
+ &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
};
static int __init hotkey_init(struct ibm_init_struct *iibm)
{
-
+ /* Requirements for changing the default keymaps:
+ *
+ * 1. Many of the keys are mapped to KEY_RESERVED for very
+ * good reasons. Do not change them unless you have deep
+ * knowledge on the IBM and Lenovo ThinkPad firmware for
+ * the various ThinkPad models. The driver behaves
+ * differently for KEY_RESERVED: such keys have their
+ * hot key mask *unset* in mask_recommended, and also
+ * in the initial hot key mask programmed into the
+ * firmware at driver load time, which means the firm-
+ * ware may react very differently if you change them to
+ * something else;
+ *
+ * 2. You must be subscribed to the linux-thinkpad and
+ * ibm-acpi-devel mailing lists, and you should read the
+ * list archives since 2007 if you want to change the
+ * keymaps. This requirement exists so that you will
+ * know the past history of problems with the thinkpad-
+ * acpi driver keymaps, and also that you will be
+ * listening to any bug reports;
+ *
+ * 3. Do not send thinkpad-acpi specific patches directly to
+ * for merging, *ever*. Send them to the linux-acpi
+ * mailinglist for comments. Merging is to be done only
+ * through acpi-test and the ACPI maintainer.
+ *
+ * If the above is too much to ask, don't change the keymap.
+ * Ask the thinkpad-acpi maintainer to do it, instead.
+ */
static u16 ibm_keycode_map[] __initdata = {
/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
- /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+
+ /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+
+ /* brightness: firmware always reacts to them, unless
+ * X.org did some tricks in the radeon BIOS scratch
+ * registers of *some* models */
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
- /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+
+ /* Thinklight: firmware always react to it */
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
+
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
+
+ /* Volume: firmware always react to it and reprograms
+ * the built-in *extra* mixer. Never map it to control
+ * another mixer by default. */
KEY_RESERVED, /* 0x14: VOLUME UP */
KEY_RESERVED, /* 0x15: VOLUME DOWN */
KEY_RESERVED, /* 0x16: MUTE */
+
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
+
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -983,20 +1813,37 @@
KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
- /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+
+ /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
- /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
+
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
+
+ /* Volume: z60/z61, T60 (BIOS version?): firmware always
+ * react to it and reprograms the built-in *extra* mixer.
+ * Never map it to control another mixer by default.
+ *
+ * T60?, T61, R60?, R61: firmware and EC tries to send
+ * these over the regular keyboard, so these are no-ops,
+ * but there are still weird bugs re. MUTE, so do not
+ * change unless you get test reports from all Lenovo
+ * models. May cause the BIOS to interfere with the
+ * HDA mixer.
+ */
KEY_RESERVED, /* 0x14: VOLUME UP */
KEY_RESERVED, /* 0x15: VOLUME DOWN */
KEY_RESERVED, /* 0x16: MUTE */
+
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
+
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -1013,10 +1860,17 @@
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
BUG_ON(!tpacpi_inputdev);
+ BUG_ON(tpacpi_inputdev->open != NULL ||
+ tpacpi_inputdev->close != NULL);
- IBM_ACPIHANDLE_INIT(hkey);
+ TPACPI_ACPIHANDLE_INIT(hkey);
mutex_init(&hotkey_mutex);
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ mutex_init(&hotkey_thread_mutex);
+ mutex_init(&hotkey_thread_data_mutex);
+#endif
+
/* hotkey not supported on 570 */
tp_features.hotkey = hkey_handle != NULL;
@@ -1024,7 +1878,7 @@
str_supported(tp_features.hotkey));
if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(8, NULL);
+ hotkey_dev_attributes = create_attr_set(12, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1038,15 +1892,15 @@
for HKEY interface version 0x100 */
if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
if ((hkeyv >> 8) != 1) {
- printk(IBM_ERR "unknown version of the "
+ printk(TPACPI_ERR "unknown version of the "
"HKEY interface: 0x%x\n", hkeyv);
- printk(IBM_ERR "please report this to %s\n",
- IBM_MAIL);
+ printk(TPACPI_ERR "please report this to %s\n",
+ TPACPI_MAIL);
} else {
/*
* MHKV 0x100 in A31, R40, R40e,
* T4x, X31, and later
- * */
+ */
tp_features.hotkey_mask = 1;
}
}
@@ -1057,25 +1911,46 @@
if (tp_features.hotkey_mask) {
if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
"MHKA", "qd")) {
- printk(IBM_ERR
+ printk(TPACPI_ERR
"missing MHKA handler, "
"please report this to %s\n",
- IBM_MAIL);
- hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+ TPACPI_MAIL);
+ /* FN+F12, FN+F4, FN+F3 */
+ hotkey_all_mask = 0x080cU;
}
}
- res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
+ /* hotkey_source_mask *must* be zero for
+ * the first hotkey_mask_get */
+ res = hotkey_status_get(&hotkey_orig_status);
if (!res && tp_features.hotkey_mask) {
- res = add_many_to_attr_set(hotkey_dev_attributes,
- hotkey_mask_attributes,
- ARRAY_SIZE(hotkey_mask_attributes));
+ res = hotkey_mask_get();
+ hotkey_orig_mask = hotkey_mask;
+ if (!res) {
+ res = add_many_to_attr_set(
+ hotkey_dev_attributes,
+ hotkey_mask_attributes,
+ ARRAY_SIZE(hotkey_mask_attributes));
+ }
}
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ if (tp_features.hotkey_mask) {
+ hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
+ & ~hotkey_all_mask;
+ } else {
+ hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "hotkey source mask 0x%08x, polling freq %d\n",
+ hotkey_source_mask, hotkey_poll_freq);
+#endif
+
/* Not all thinkpads have a hardware radio switch */
if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
tp_features.hotkey_wlsw = 1;
- printk(IBM_INFO
+ printk(TPACPI_INFO
"radio switch found; radios are %s\n",
enabled(status, 0));
res = add_to_attr_set(hotkey_dev_attributes,
@@ -1094,7 +1969,8 @@
hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
GFP_KERNEL);
if (!hotkey_keycode_map) {
- printk(IBM_ERR "failed to allocate memory for key map\n");
+ printk(TPACPI_ERR
+ "failed to allocate memory for key map\n");
return -ENOMEM;
}
@@ -1133,15 +2009,26 @@
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
- res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
- | hotkey_orig_mask);
+ res = hotkey_status_set(1);
if (res)
return res;
+ res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
+ & ~hotkey_reserved_mask)
+ | hotkey_orig_mask);
+ if (res < 0 && res != -ENXIO)
+ return res;
dbg_printk(TPACPI_DBG_INIT,
"legacy hot key reporting over procfs %s\n",
(hotkey_report_mode < 2) ?
"enabled" : "disabled");
+
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ tpacpi_inputdev->open = &hotkey_inputdev_open;
+ tpacpi_inputdev->close = &hotkey_inputdev_close;
+
+ hotkey_poll_setup_safe(1);
+#endif
}
return (tp_features.hotkey)? 0 : 1;
@@ -1149,13 +2036,19 @@
static void hotkey_exit(void)
{
- int res;
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ hotkey_poll_stop_sync();
+#endif
if (tp_features.hotkey) {
- dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
- res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
- if (res)
- printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
+ dbg_printk(TPACPI_DBG_EXIT,
+ "restoring original hot key mask\n");
+ /* no short-circuit boolean operator below! */
+ if ((hotkey_mask_set(hotkey_orig_mask) |
+ hotkey_status_set(hotkey_orig_status)) != 0)
+ printk(TPACPI_ERR
+ "failed to restore hot key mask "
+ "to BIOS defaults\n");
}
if (hotkey_dev_attributes) {
@@ -1164,62 +2057,28 @@
}
}
-static void tpacpi_input_send_key(unsigned int scancode,
- unsigned int keycode)
-{
- if (keycode != KEY_RESERVED) {
- mutex_lock(&tpacpi_inputdev_send_mutex);
-
- input_report_key(tpacpi_inputdev, keycode, 1);
- if (keycode == KEY_UNKNOWN)
- input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
- scancode);
- input_sync(tpacpi_inputdev);
-
- input_report_key(tpacpi_inputdev, keycode, 0);
- if (keycode == KEY_UNKNOWN)
- input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
- scancode);
- input_sync(tpacpi_inputdev);
-
- mutex_unlock(&tpacpi_inputdev_send_mutex);
- }
-}
-
-static void tpacpi_input_send_radiosw(void)
-{
- int wlsw;
-
- mutex_lock(&tpacpi_inputdev_send_mutex);
-
- if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
- input_report_switch(tpacpi_inputdev,
- SW_RADIO, !!wlsw);
- input_sync(tpacpi_inputdev);
- }
-
- mutex_unlock(&tpacpi_inputdev_send_mutex);
-}
-
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
u32 hkey;
- unsigned int keycode, scancode;
+ unsigned int scancode;
int send_acpi_ev;
int ignore_acpi_ev;
+ int unk_ev;
if (event != 0x80) {
- printk(IBM_ERR "unknown HKEY notification event %d\n", event);
+ printk(TPACPI_ERR
+ "unknown HKEY notification event %d\n", event);
/* forward it to userspace, maybe it knows how to handle it */
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
- event, 0);
+ acpi_bus_generate_netlink_event(
+ ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, 0);
return;
}
while (1) {
if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
- printk(IBM_ERR "failed to retrieve HKEY event\n");
+ printk(TPACPI_ERR "failed to retrieve HKEY event\n");
return;
}
@@ -1228,8 +2087,9 @@
return;
}
- send_acpi_ev = 0;
+ send_acpi_ev = 1;
ignore_acpi_ev = 0;
+ unk_ev = 0;
switch (hkey >> 12) {
case 1:
@@ -1237,104 +2097,139 @@
scancode = hkey & 0xfff;
if (scancode > 0 && scancode < 0x21) {
scancode--;
- keycode = hotkey_keycode_map[scancode];
- tpacpi_input_send_key(scancode, keycode);
+ if (!(hotkey_source_mask & (1 << scancode))) {
+ tpacpi_input_send_key(scancode);
+ send_acpi_ev = 0;
+ } else {
+ ignore_acpi_ev = 1;
+ }
} else {
- printk(IBM_ERR
- "hotkey 0x%04x out of range for keyboard map\n",
- hkey);
- send_acpi_ev = 1;
+ unk_ev = 1;
+ }
+ break;
+ case 2:
+ /* Wakeup reason */
+ switch (hkey) {
+ case 0x2304: /* suspend, undock */
+ case 0x2404: /* hibernation, undock */
+ hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
+ ignore_acpi_ev = 1;
+ break;
+ case 0x2305: /* suspend, bay eject */
+ case 0x2405: /* hibernation, bay eject */
+ hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
+ ignore_acpi_ev = 1;
+ break;
+ default:
+ unk_ev = 1;
+ }
+ if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
+ printk(TPACPI_INFO
+ "woke up due to a hot-unplug "
+ "request...\n");
+ hotkey_wakeup_reason_notify_change();
+ }
+ break;
+ case 3:
+ /* bay-related wakeups */
+ if (hkey == 0x3003) {
+ hotkey_autosleep_ack = 1;
+ printk(TPACPI_INFO
+ "bay ejected\n");
+ hotkey_wakeup_hotunplug_complete_notify_change();
+ } else {
+ unk_ev = 1;
+ }
+ break;
+ case 4:
+ /* dock-related wakeups */
+ if (hkey == 0x4003) {
+ hotkey_autosleep_ack = 1;
+ printk(TPACPI_INFO
+ "undocked\n");
+ hotkey_wakeup_hotunplug_complete_notify_change();
+ } else {
+ unk_ev = 1;
}
break;
case 5:
- /* 0x5000-0x5FFF: LID */
- /* we don't handle it through this path, just
- * eat up known LID events */
- if (hkey != 0x5001 && hkey != 0x5002) {
- printk(IBM_ERR
- "unknown LID-related HKEY event: 0x%04x\n",
- hkey);
- send_acpi_ev = 1;
- } else {
+ /* 0x5000-0x5FFF: human interface helpers */
+ switch (hkey) {
+ case 0x5010: /* Lenovo new BIOS: brightness changed */
+ case 0x5009: /* X61t: swivel up (tablet mode) */
+ case 0x500a: /* X61t: swivel down (normal mode) */
+ case 0x500b: /* X61t: tablet pen inserted into bay */
+ case 0x500c: /* X61t: tablet pen removed from bay */
+ break;
+ case 0x5001:
+ case 0x5002:
+ /* LID switch events. Do not propagate */
ignore_acpi_ev = 1;
+ break;
+ default:
+ unk_ev = 1;
}
break;
case 7:
/* 0x7000-0x7FFF: misc */
if (tp_features.hotkey_wlsw && hkey == 0x7000) {
tpacpi_input_send_radiosw();
+ hotkey_radio_sw_notify_change();
+ send_acpi_ev = 0;
break;
}
/* fallthrough to default */
default:
- /* case 2: dock-related */
- /* 0x2305 - T43 waking up due to bay lever eject while aslept */
- /* case 3: ultra-bay related. maybe bay in dock? */
- /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
- printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
- send_acpi_ev = 1;
+ unk_ev = 1;
+ }
+ if (unk_ev) {
+ printk(TPACPI_NOTICE
+ "unhandled HKEY event 0x%04x\n", hkey);
}
/* Legacy events */
- if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) {
- acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+ if (!ignore_acpi_ev &&
+ (send_acpi_ev || hotkey_report_mode < 2)) {
+ acpi_bus_generate_proc_event(ibm->acpi->device,
+ event, hkey);
}
/* netlink events */
if (!ignore_acpi_ev && send_acpi_ev) {
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
- event, hkey);
+ acpi_bus_generate_netlink_event(
+ ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, hkey);
}
}
}
+static void hotkey_suspend(pm_message_t state)
+{
+ /* Do these on suspend, we get the events on early resume! */
+ hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
+ hotkey_autosleep_ack = 0;
+}
+
static void hotkey_resume(void)
{
+ if (hotkey_mask_get())
+ printk(TPACPI_ERR
+ "error while trying to read hot key mask "
+ "from firmware\n");
tpacpi_input_send_radiosw();
-}
-
-/*
- * Call with hotkey_mutex held
- */
-static int hotkey_get(int *status, u32 *mask)
-{
- if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
- return -EIO;
-
- if (tp_features.hotkey_mask)
- if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
- return -EIO;
-
- return 0;
-}
-
-/*
- * Call with hotkey_mutex held
- */
-static int hotkey_set(int status, u32 mask)
-{
- int i;
-
- if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
- return -EIO;
-
- if (tp_features.hotkey_mask)
- for (i = 0; i < 32; i++) {
- int bit = ((1 << i) & mask) != 0;
- if (!acpi_evalf(hkey_handle,
- NULL, "MHKM", "vdd", i + 1, bit))
- return -EIO;
- }
-
- return 0;
+ hotkey_radio_sw_notify_change();
+ hotkey_wakeup_reason_notify_change();
+ hotkey_wakeup_hotunplug_complete_notify_change();
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ hotkey_poll_setup_safe(0);
+#endif
}
/* procfs -------------------------------------------------------------- */
static int hotkey_read(char *p)
{
int res, status;
- u32 mask;
int len = 0;
if (!tp_features.hotkey) {
@@ -1344,14 +2239,16 @@
if (mutex_lock_interruptible(&hotkey_mutex))
return -ERESTARTSYS;
- res = hotkey_get(&status, &mask);
+ res = hotkey_status_get(&status);
+ if (!res)
+ res = hotkey_mask_get();
mutex_unlock(&hotkey_mutex);
if (res)
return res;
len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
if (tp_features.hotkey_mask) {
- len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
+ len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask);
len += sprintf(p + len,
"commands:\tenable, disable, reset, <mask>\n");
} else {
@@ -1367,7 +2264,6 @@
int res, status;
u32 mask;
char *cmd;
- int do_cmd = 0;
if (!tp_features.hotkey)
return -ENODEV;
@@ -1375,9 +2271,8 @@
if (mutex_lock_interruptible(&hotkey_mutex))
return -ERESTARTSYS;
- res = hotkey_get(&status, &mask);
- if (res)
- goto errexit;
+ status = -1;
+ mask = hotkey_mask;
res = 0;
while ((cmd = next_cmd(&buf))) {
@@ -1396,11 +2291,12 @@
res = -EINVAL;
goto errexit;
}
- do_cmd = 1;
}
+ if (status != -1)
+ res = hotkey_status_set(status);
- if (do_cmd)
- res = hotkey_set(status, mask);
+ if (!res && mask != hotkey_mask)
+ res = hotkey_mask_set(mask);
errexit:
mutex_unlock(&hotkey_mutex);
@@ -1408,7 +2304,7 @@
}
static const struct acpi_device_id ibm_htk_device_ids[] = {
- {IBM_HKEY_HID, 0},
+ {TPACPI_ACPI_HKEY_HID, 0},
{"", 0},
};
@@ -1425,6 +2321,7 @@
.write = hotkey_write,
.exit = hotkey_exit,
.resume = hotkey_resume,
+ .suspend = hotkey_suspend,
.acpi = &ibm_hotkey_acpidriver,
};
@@ -1432,6 +2329,16 @@
* Bluetooth subdriver
*/
+enum {
+ /* ACPI GBDC/SBDC bits */
+ TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
+ TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
+ TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
+};
+
+static int bluetooth_get_radiosw(void);
+static int bluetooth_set_radiosw(int radio_on);
+
/* sysfs bluetooth enable ---------------------------------------------- */
static ssize_t bluetooth_enable_show(struct device *dev,
struct device_attribute *attr,
@@ -1483,7 +2390,7 @@
vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
- IBM_ACPIHANDLE_INIT(hkey);
+ TPACPI_ACPIHANDLE_INIT(hkey);
/* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
@@ -1596,6 +2503,16 @@
* Wan subdriver
*/
+enum {
+ /* ACPI GWAN/SWAN bits */
+ TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
+ TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
+ TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
+};
+
+static int wan_get_radiosw(void);
+static int wan_set_radiosw(int radio_on);
+
/* sysfs wan enable ---------------------------------------------------- */
static ssize_t wan_enable_show(struct device *dev,
struct device_attribute *attr,
@@ -1647,7 +2564,7 @@
vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
- IBM_ACPIHANDLE_INIT(hkey);
+ TPACPI_ACPIHANDLE_INIT(hkey);
tp_features.wan = hkey_handle &&
acpi_evalf(hkey_handle, &status, "GWAN", "qd");
@@ -1759,17 +2676,41 @@
* Video subdriver
*/
+enum video_access_mode {
+ TPACPI_VIDEO_NONE = 0,
+ TPACPI_VIDEO_570, /* 570 */
+ TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
+ TPACPI_VIDEO_NEW, /* all others */
+};
+
+enum { /* video status flags, based on VIDEO_570 */
+ TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
+ TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
+ TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
+};
+
+enum { /* TPACPI_VIDEO_570 constants */
+ TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
+ TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
+ * video_status_flags */
+ TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
+ TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
+};
+
static enum video_access_mode video_supported;
static int video_orig_autosw;
-IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
+static int video_autosw_get(void);
+static int video_autosw_set(int enable);
+
+TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
"\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
"\\_SB.PCI0.VID0", /* 770e */
"\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
"\\_SB.PCI0.AGP.VID", /* all others */
); /* R30, R31 */
-IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
+TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
static int __init video_init(struct ibm_init_struct *iibm)
{
@@ -1777,8 +2718,8 @@
vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
- IBM_ACPIHANDLE_INIT(vid);
- IBM_ACPIHANDLE_INIT(vid2);
+ TPACPI_ACPIHANDLE_INIT(vid);
+ TPACPI_ACPIHANDLE_INIT(vid2);
if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
/* G41, assume IVGA doesn't change */
@@ -1809,7 +2750,7 @@
dbg_printk(TPACPI_DBG_EXIT,
"restoring original video autoswitch mode\n");
if (video_autosw_set(video_orig_autosw))
- printk(IBM_ERR "error while trying to restore original "
+ printk(TPACPI_ERR "error while trying to restore original "
"video autoswitch mode\n");
}
@@ -1882,13 +2823,14 @@
res = acpi_evalf(vid_handle, NULL,
"ASWT", "vdd", status * 0x100, 0);
if (!autosw && video_autosw_set(autosw)) {
- printk(IBM_ERR "video auto-switch left enabled due to error\n");
+ printk(TPACPI_ERR
+ "video auto-switch left enabled due to error\n");
return -EIO;
}
break;
case TPACPI_VIDEO_NEW:
res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
- acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
+ acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
break;
default:
return -ENOSYS;
@@ -1951,7 +2893,8 @@
return -ENOSYS;
}
if (!autosw && video_autosw_set(autosw)) {
- printk(IBM_ERR "video auto-switch left enabled due to error\n");
+ printk(TPACPI_ERR
+ "video auto-switch left enabled due to error\n");
return -EIO;
}
@@ -2080,16 +3023,16 @@
* Light (thinklight) subdriver
*/
-IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
-IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
+TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
+TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
static int __init light_init(struct ibm_init_struct *iibm)
{
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
- IBM_ACPIHANDLE_INIT(ledb);
- IBM_ACPIHANDLE_INIT(lght);
- IBM_ACPIHANDLE_INIT(cmos);
+ TPACPI_ACPIHANDLE_INIT(ledb);
+ TPACPI_ACPIHANDLE_INIT(lght);
+ TPACPI_ACPIHANDLE_INIT(cmos);
/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -2167,14 +3110,18 @@
#ifdef CONFIG_THINKPAD_ACPI_DOCK
-IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
+static void dock_notify(struct ibm_struct *ibm, u32 event);
+static int dock_read(char *p);
+static int dock_write(char *buf);
+
+TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
"\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
"\\_SB.PCI0.PCI1.DOCK", /* all others */
"\\_SB.PCI.ISA.SLCE", /* 570 */
); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
/* don't list other alternatives as we install a notify handler on the 570 */
-IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
+TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
static const struct acpi_device_id ibm_pci_device_ids[] = {
{PCI_ROOT_HID_STRING, 0},
@@ -2217,7 +3164,7 @@
{
vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
- IBM_ACPIHANDLE_INIT(dock);
+ TPACPI_ACPIHANDLE_INIT(dock);
vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
str_supported(dock_handle != NULL));
@@ -2233,7 +3180,7 @@
if (dock_driver_data[0].flags.acpi_driver_registered &&
dock_driver_data[0].flags.acpi_notify_installed) {
- IBM_ACPIHANDLE_INIT(pci);
+ TPACPI_ACPIHANDLE_INIT(pci);
dock2_needed = (pci_handle != NULL);
vdbg_printk(TPACPI_DBG_INIT,
"dock PCI handler for the TP 570 is %s\n",
@@ -2265,7 +3212,7 @@
else if (event == 0 && docked)
data = 3; /* dock */
else {
- printk(IBM_ERR "unknown dock event %d, status %d\n",
+ printk(TPACPI_ERR "unknown dock event %d, status %d\n",
event, _sta(dock_handle));
data = 0; /* unknown */
}
@@ -2321,18 +3268,19 @@
*/
#ifdef CONFIG_THINKPAD_ACPI_BAY
-IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
+
+TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
"\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
"\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
"\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
); /* A21e, R30, R31 */
-IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
+TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
"_EJ0", /* all others */
); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
+TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
"\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
); /* all others */
-IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
+TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
"_EJ0", /* 770x */
); /* all others */
@@ -2340,12 +3288,12 @@
{
vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
- IBM_ACPIHANDLE_INIT(bay);
+ TPACPI_ACPIHANDLE_INIT(bay);
if (bay_handle)
- IBM_ACPIHANDLE_INIT(bay_ej);
- IBM_ACPIHANDLE_INIT(bay2);
+ TPACPI_ACPIHANDLE_INIT(bay_ej);
+ TPACPI_ACPIHANDLE_INIT(bay2);
if (bay2_handle)
- IBM_ACPIHANDLE_INIT(bay2_ej);
+ TPACPI_ACPIHANDLE_INIT(bay2_ej);
tp_features.bay_status = bay_handle &&
acpi_evalf(bay_handle, NULL, "_STA", "qv");
@@ -2474,7 +3422,7 @@
vdbg_printk(TPACPI_DBG_INIT,
"initializing cmos commands subdriver\n");
- IBM_ACPIHANDLE_INIT(cmos);
+ TPACPI_ACPIHANDLE_INIT(cmos);
vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
str_supported(cmos_handle != NULL));
@@ -2538,10 +3486,24 @@
* LED subdriver
*/
+enum led_access_mode {
+ TPACPI_LED_NONE = 0,
+ TPACPI_LED_570, /* 570 */
+ TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ TPACPI_LED_NEW, /* all others */
+};
+
+enum { /* For TPACPI_LED_OLD */
+ TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
+ TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
+ TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
+};
+
static enum led_access_mode led_supported;
-IBM_HANDLE(led, ec, "SLED", /* 570 */
- "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+TPACPI_HANDLE(led, ec, "SLED", /* 570 */
+ "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */
+ /* T20-22, X20-21 */
"LED", /* all others */
); /* R30, R31 */
@@ -2549,7 +3511,7 @@
{
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
- IBM_ACPIHANDLE_INIT(led);
+ TPACPI_ACPIHANDLE_INIT(led);
if (!led_handle)
/* led not supported on R30, R31 */
@@ -2638,13 +3600,11 @@
led = 1 << led;
ret = ec_write(TPACPI_LED_EC_HLMS, led);
if (ret >= 0)
- ret =
- ec_write(TPACPI_LED_EC_HLBL,
- led * led_exp_hlbl[ind]);
+ ret = ec_write(TPACPI_LED_EC_HLBL,
+ led * led_exp_hlbl[ind]);
if (ret >= 0)
- ret =
- ec_write(TPACPI_LED_EC_HLCL,
- led * led_exp_hlcl[ind]);
+ ret = ec_write(TPACPI_LED_EC_HLCL,
+ led * led_exp_hlcl[ind]);
if (ret < 0)
return ret;
} else {
@@ -2668,13 +3628,13 @@
* Beep subdriver
*/
-IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
+TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
static int __init beep_init(struct ibm_init_struct *iibm)
{
vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
- IBM_ACPIHANDLE_INIT(beep);
+ TPACPI_ACPIHANDLE_INIT(beep);
vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
str_supported(beep_handle != NULL));
@@ -2727,8 +3687,109 @@
* Thermal subdriver
*/
+enum thermal_access_mode {
+ TPACPI_THERMAL_NONE = 0, /* No thermal support */
+ TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
+ TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
+ TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
+ TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
+};
+
+enum { /* TPACPI_THERMAL_TPEC_* */
+ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
+ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
+ TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
+};
+
+#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+ s32 temp[TPACPI_MAX_THERMAL_SENSORS];
+};
+
static enum thermal_access_mode thermal_read_mode;
+/* idx is zero-based */
+static int thermal_get_sensor(int idx, s32 *value)
+{
+ int t;
+ s8 tmp;
+ char tmpi[5];
+
+ t = TP_EC_THERMAL_TMP0;
+
+ switch (thermal_read_mode) {
+#if TPACPI_MAX_THERMAL_SENSORS >= 16
+ case TPACPI_THERMAL_TPEC_16:
+ if (idx >= 8 && idx <= 15) {
+ t = TP_EC_THERMAL_TMP8;
+ idx -= 8;
+ }
+ /* fallthrough */
+#endif
+ case TPACPI_THERMAL_TPEC_8:
+ if (idx <= 7) {
+ if (!acpi_ec_read(t + idx, &tmp))
+ return -EIO;
+ *value = tmp * 1000;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_ACPI_UPDT:
+ if (idx <= 7) {
+ snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+ if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ return -EIO;
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ *value = (t - 2732) * 100;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_ACPI_TMP07:
+ if (idx <= 7) {
+ snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ if (t > 127 || t < -127)
+ t = TP_EC_THERMAL_TMP_NA;
+ *value = t * 1000;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_NONE:
+ default:
+ return -ENOSYS;
+ }
+
+ return -EINVAL;
+}
+
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+ int res, i;
+ int n;
+
+ n = 8;
+ i = 0;
+
+ if (!s)
+ return -EINVAL;
+
+ if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
+ n = 16;
+
+ for (i = 0 ; i < n; i++) {
+ res = thermal_get_sensor(i, &s->temp[i]);
+ if (res)
+ return res;
+ }
+
+ return n;
+}
+
/* sysfs temp##_input -------------------------------------------------- */
static ssize_t thermal_temp_input_show(struct device *dev,
@@ -2751,7 +3812,8 @@
}
#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
- SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
+ SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \
+ thermal_temp_input_show, NULL, _idxB)
static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
THERMAL_SENSOR_ATTR_TEMP(1, 0),
@@ -2845,12 +3907,13 @@
if (ta1 == 0) {
/* This is sheer paranoia, but we handle it anyway */
if (acpi_tmp7) {
- printk(IBM_ERR
+ printk(TPACPI_ERR
"ThinkPad ACPI EC access misbehaving, "
- "falling back to ACPI TMPx access mode\n");
+ "falling back to ACPI TMPx access "
+ "mode\n");
thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
} else {
- printk(IBM_ERR
+ printk(TPACPI_ERR
"ThinkPad ACPI EC access misbehaving, "
"disabling thermal sensors access\n");
thermal_read_mode = TPACPI_THERMAL_NONE;
@@ -2877,7 +3940,7 @@
str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
thermal_read_mode);
- switch(thermal_read_mode) {
+ switch (thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16:
res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
@@ -2902,103 +3965,21 @@
static void thermal_exit(void)
{
- switch(thermal_read_mode) {
- case TPACPI_THERMAL_TPEC_16:
- sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
- &thermal_temp_input16_group);
- break;
- case TPACPI_THERMAL_TPEC_8:
- case TPACPI_THERMAL_ACPI_TMP07:
- case TPACPI_THERMAL_ACPI_UPDT:
- sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
- &thermal_temp_input16_group);
- break;
- case TPACPI_THERMAL_NONE:
- default:
- break;
- }
-}
-
-/* idx is zero-based */
-static int thermal_get_sensor(int idx, s32 *value)
-{
- int t;
- s8 tmp;
- char tmpi[5];
-
- t = TP_EC_THERMAL_TMP0;
-
switch (thermal_read_mode) {
-#if TPACPI_MAX_THERMAL_SENSORS >= 16
case TPACPI_THERMAL_TPEC_16:
- if (idx >= 8 && idx <= 15) {
- t = TP_EC_THERMAL_TMP8;
- idx -= 8;
- }
- /* fallthrough */
-#endif
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ break;
case TPACPI_THERMAL_TPEC_8:
- if (idx <= 7) {
- if (!acpi_ec_read(t + idx, &tmp))
- return -EIO;
- *value = tmp * 1000;
- return 0;
- }
- break;
-
- case TPACPI_THERMAL_ACPI_UPDT:
- if (idx <= 7) {
- snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
- if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
- return -EIO;
- if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
- return -EIO;
- *value = (t - 2732) * 100;
- return 0;
- }
- break;
-
case TPACPI_THERMAL_ACPI_TMP07:
- if (idx <= 7) {
- snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
- if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
- return -EIO;
- if (t > 127 || t < -127)
- t = TP_EC_THERMAL_TMP_NA;
- *value = t * 1000;
- return 0;
- }
+ case TPACPI_THERMAL_ACPI_UPDT:
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
+ &thermal_temp_input16_group);
break;
-
case TPACPI_THERMAL_NONE:
default:
- return -ENOSYS;
+ break;
}
-
- return -EINVAL;
-}
-
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
-{
- int res, i;
- int n;
-
- n = 8;
- i = 0;
-
- if (!s)
- return -EINVAL;
-
- if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
- n = 16;
-
- for(i = 0 ; i < n; i++) {
- res = thermal_get_sensor(i, &s->temp[i]);
- if (res)
- return res;
- }
-
- return n;
}
static int thermal_read(char *p)
@@ -3103,189 +4084,15 @@
* Backlight/brightness subdriver
*/
-static struct backlight_device *ibm_backlight_device;
+#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
-static struct backlight_ops ibm_backlight_data = {
- .get_brightness = brightness_get,
- .update_status = brightness_update_status,
-};
+static struct backlight_device *ibm_backlight_device;
+static int brightness_offset = 0x31;
+static int brightness_mode;
+static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
static struct mutex brightness_mutex;
-static int __init tpacpi_query_bcll_levels(acpi_handle handle)
-{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- int rc;
-
- if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
- obj = (union acpi_object *)buffer.pointer;
- if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
- printk(IBM_ERR "Unknown BCLL data, "
- "please report this to %s\n", IBM_MAIL);
- rc = 0;
- } else {
- rc = obj->package.count;
- }
- } else {
- return 0;
- }
-
- kfree(buffer.pointer);
- return rc;
-}
-
-static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
-
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("BCLL", name, sizeof(name) - 1)) {
- if (tpacpi_query_bcll_levels(handle) == 16) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
- } else {
- return AE_OK;
- }
-}
-
-static int __init brightness_check_levels(void)
-{
- int status;
- void *found_node = NULL;
-
- if (!vid_handle) {
- IBM_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a BCLL package with 16 levels */
- status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
- brightness_find_bcll, NULL, &found_node);
-
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
-static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
-
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("_BCL", name, sizeof(name) - 1)) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
-}
-
-static int __init brightness_check_std_acpi_support(void)
-{
- int status;
- void *found_node = NULL;
-
- if (!vid_handle) {
- IBM_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a _BCL method, but don't execute it */
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
- brightness_find_bcl, NULL, &found_node);
-
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
-static int __init brightness_init(struct ibm_init_struct *iibm)
-{
- int b;
-
- vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
-
- mutex_init(&brightness_mutex);
-
- if (!brightness_enable) {
- dbg_printk(TPACPI_DBG_INIT,
- "brightness support disabled by module parameter\n");
- return 1;
- } else if (brightness_enable > 1) {
- if (brightness_check_std_acpi_support()) {
- printk(IBM_NOTICE
- "standard ACPI backlight interface available, not loading native one...\n");
- return 1;
- }
- }
-
- if (!brightness_mode) {
- if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
- brightness_mode = 2;
- else
- brightness_mode = 3;
-
- dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
- brightness_mode);
- }
-
- if (brightness_mode > 3)
- return -EINVAL;
-
- tp_features.bright_16levels =
- thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
- brightness_check_levels();
-
- b = brightness_get(NULL);
- if (b < 0)
- return 1;
-
- if (tp_features.bright_16levels)
- printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
-
- ibm_backlight_device = backlight_device_register(
- TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
- &ibm_backlight_data);
- if (IS_ERR(ibm_backlight_device)) {
- printk(IBM_ERR "Could not register backlight device\n");
- return PTR_ERR(ibm_backlight_device);
- }
- vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
-
- ibm_backlight_device->props.max_brightness =
- (tp_features.bright_16levels)? 15 : 7;
- ibm_backlight_device->props.brightness = b;
- backlight_update_status(ibm_backlight_device);
-
- return 0;
-}
-
-static void brightness_exit(void)
-{
- if (ibm_backlight_device) {
- vdbg_printk(TPACPI_DBG_EXIT,
- "calling backlight_device_unregister()\n");
- backlight_device_unregister(ibm_backlight_device);
- ibm_backlight_device = NULL;
- }
-}
-
-static int brightness_update_status(struct backlight_device *bd)
-{
- /* it is the backlight class's job (caller) to handle
- * EINTR and other errors properly */
- return brightness_set(
- (bd->props.fb_blank == FB_BLANK_UNBLANK &&
- bd->props.power == FB_BLANK_UNBLANK) ?
- bd->props.brightness : 0);
-}
-
/*
* ThinkPads can read brightness from two places: EC 0x31, or
* CMOS NVRAM byte 0x5E, bits 0-3.
@@ -3309,7 +4116,7 @@
}
if (brightness_mode == 3 && lec != lcmos) {
- printk(IBM_ERR
+ printk(TPACPI_ERR
"CMOS NVRAM (%u) and EC (%u) do not agree "
"on display brightness level\n",
(unsigned int) lcmos,
@@ -3363,12 +4170,200 @@
return res;
}
+/* sysfs backlight class ----------------------------------------------- */
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+ /* it is the backlight class's job (caller) to handle
+ * EINTR and other errors properly */
+ return brightness_set(
+ (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+ bd->props.power == FB_BLANK_UNBLANK) ?
+ bd->props.brightness : 0);
+}
+
+static struct backlight_ops ibm_backlight_data = {
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int __init tpacpi_query_bcll_levels(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ int rc;
+
+ if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+ obj = (union acpi_object *)buffer.pointer;
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+ printk(TPACPI_ERR "Unknown BCLL data, "
+ "please report this to %s\n", TPACPI_MAIL);
+ rc = 0;
+ } else {
+ rc = obj->package.count;
+ }
+ } else {
+ return 0;
+ }
+
+ kfree(buffer.pointer);
+ return rc;
+}
+
+static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("BCLL", name, sizeof(name) - 1)) {
+ if (tpacpi_query_bcll_levels(handle) == 16) {
+ *rv = handle;
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+ } else {
+ return AE_OK;
+ }
+}
+
+static int __init brightness_check_levels(void)
+{
+ int status;
+ void *found_node = NULL;
+
+ if (!vid_handle) {
+ TPACPI_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /* Search for a BCLL package with 16 levels */
+ status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
+ brightness_find_bcll, NULL,
+ &found_node);
+
+ return (ACPI_SUCCESS(status) && found_node != NULL);
+}
+
+static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("_BCL", name, sizeof(name) - 1)) {
+ *rv = handle;
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+}
+
+static int __init brightness_check_std_acpi_support(void)
+{
+ int status;
+ void *found_node = NULL;
+
+ if (!vid_handle) {
+ TPACPI_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /* Search for a _BCL method, but don't execute it */
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+ brightness_find_bcl, NULL, &found_node);
+
+ return (ACPI_SUCCESS(status) && found_node != NULL);
+}
+
+static int __init brightness_init(struct ibm_init_struct *iibm)
+{
+ int b;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+
+ mutex_init(&brightness_mutex);
+
+ if (!brightness_enable) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "brightness support disabled by "
+ "module parameter\n");
+ return 1;
+ } else if (brightness_enable > 1) {
+ if (brightness_check_std_acpi_support()) {
+ printk(TPACPI_NOTICE
+ "standard ACPI backlight interface "
+ "available, not loading native one...\n");
+ return 1;
+ }
+ }
+
+ if (!brightness_mode) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+ brightness_mode = 2;
+ else
+ brightness_mode = 3;
+
+ dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+ brightness_mode);
+ }
+
+ if (brightness_mode > 3)
+ return -EINVAL;
+
+ tp_features.bright_16levels =
+ thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
+ brightness_check_levels();
+
+ b = brightness_get(NULL);
+ if (b < 0)
+ return 1;
+
+ if (tp_features.bright_16levels)
+ printk(TPACPI_INFO
+ "detected a 16-level brightness capable ThinkPad\n");
+
+ ibm_backlight_device = backlight_device_register(
+ TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
+ &ibm_backlight_data);
+ if (IS_ERR(ibm_backlight_device)) {
+ printk(TPACPI_ERR "Could not register backlight device\n");
+ return PTR_ERR(ibm_backlight_device);
+ }
+ vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
+
+ ibm_backlight_device->props.max_brightness =
+ (tp_features.bright_16levels)? 15 : 7;
+ ibm_backlight_device->props.brightness = b;
+ backlight_update_status(ibm_backlight_device);
+
+ return 0;
+}
+
+static void brightness_exit(void)
+{
+ if (ibm_backlight_device) {
+ vdbg_printk(TPACPI_DBG_EXIT,
+ "calling backlight_device_unregister()\n");
+ backlight_device_unregister(ibm_backlight_device);
+ ibm_backlight_device = NULL;
+ }
+}
+
static int brightness_read(char *p)
{
int len = 0;
int level;
- if ((level = brightness_get(NULL)) < 0) {
+ level = brightness_get(NULL);
+ if (level < 0) {
len += sprintf(p + len, "level:\t\tunreadable\n");
} else {
len += sprintf(p + len, "level:\t\t%d\n", level);
@@ -3425,6 +4420,8 @@
* Volume subdriver
*/
+static int volume_offset = 0x30;
+
static int volume_read(char *p)
{
int len = 0;
@@ -3474,8 +4471,11 @@
} else
return -EINVAL;
- if (new_level != level) { /* mute doesn't change */
- cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
+ if (new_level != level) {
+ /* mute doesn't change */
+
+ cmos_cmd = (new_level > level) ?
+ TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
inc = new_level > level ? 1 : -1;
if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
@@ -3487,14 +4487,18 @@
!acpi_ec_write(volume_offset, i + inc))
return -EIO;
- if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
- !acpi_ec_write(volume_offset,
- new_level + mute)))
+ if (mute &&
+ (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
+ !acpi_ec_write(volume_offset, new_level + mute))) {
return -EIO;
+ }
}
- if (new_mute != mute) { /* level doesn't change */
- cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
+ if (new_mute != mute) {
+ /* level doesn't change */
+
+ cmos_cmd = (new_mute) ?
+ TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
if (issue_thinkpad_cmos_command(cmos_cmd) ||
!acpi_ec_write(volume_offset, level + new_mute))
@@ -3616,26 +4620,377 @@
* but the ACPI tables just mention level 7.
*/
+enum { /* Fan control constants */
+ fan_status_offset = 0x2f, /* EC register 0x2f */
+ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
+ * 0x84 must be read before 0x85 */
+
+ TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
+ TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
+
+ TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
+};
+
+enum fan_status_access_mode {
+ TPACPI_FAN_NONE = 0, /* No fan status or control */
+ TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
+ TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+ TPACPI_FAN_WR_NONE = 0, /* No fan control */
+ TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
+ TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
+ TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+ TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
+ TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
+ TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
+ * and also watchdog cmd */
+};
+
+static int fan_control_allowed;
+
static enum fan_status_access_mode fan_status_access_mode;
static enum fan_control_access_mode fan_control_access_mode;
static enum fan_control_commands fan_control_commands;
static u8 fan_control_initial_status;
static u8 fan_control_desired_level;
+static int fan_watchdog_maxinterval;
+
+static struct mutex fan_mutex;
static void fan_watchdog_fire(struct work_struct *ignored);
-static int fan_watchdog_maxinterval;
static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
-IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
-IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
+TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
+TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */
"\\FSPD", /* 600e/x, 770e, 770x */
); /* all others */
-IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
+TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
"JFNS", /* 770x-JL */
); /* all others */
/*
+ * Call with fan_mutex held
+ */
+static void fan_update_desired_level(u8 status)
+{
+ if ((status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+ if (status > 7)
+ fan_control_desired_level = 7;
+ else
+ fan_control_desired_level = status;
+ }
+}
+
+static int fan_get_status(u8 *status)
+{
+ u8 s;
+
+ /* TODO:
+ * Add TPACPI_FAN_RD_ACPI_FANS ? */
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+
+ if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+ return -EIO;
+
+ if (likely(status))
+ *status = s & 0x07;
+
+ break;
+
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+ return -EIO;
+
+ if (likely(status))
+ *status = s;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int fan_get_status_safe(u8 *status)
+{
+ int rc;
+ u8 s;
+
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
+ rc = fan_get_status(&s);
+ if (!rc)
+ fan_update_desired_level(s);
+ mutex_unlock(&fan_mutex);
+
+ if (status)
+ *status = s;
+
+ return rc;
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+ u8 hi, lo;
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+ !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+ return -EIO;
+
+ if (likely(speed))
+ *speed = (hi << 8) | lo;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int fan_set_level(int level)
+{
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ if (level >= 0 && level <= 7) {
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+ return -EIO;
+ } else
+ return -EINVAL;
+ break;
+
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ if ((level != TP_EC_FAN_AUTO) &&
+ (level != TP_EC_FAN_FULLSPEED) &&
+ ((level < 0) || (level > 7)))
+ return -EINVAL;
+
+ /* safety net should the EC not support AUTO
+ * or FULLSPEED mode bits and just ignore them */
+ if (level & TP_EC_FAN_FULLSPEED)
+ level |= 7; /* safety min speed 7 */
+ else if (level & TP_EC_FAN_AUTO)
+ level |= 4; /* safety min speed 4 */
+
+ if (!acpi_ec_write(fan_status_offset, level))
+ return -EIO;
+ else
+ tp_features.fan_ctrl_status_undef = 0;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_level_safe(int level)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
+
+ if (level == TPACPI_FAN_LAST_LEVEL)
+ level = fan_control_desired_level;
+
+ rc = fan_set_level(level);
+ if (!rc)
+ fan_update_desired_level(level);
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_enable(void)
+{
+ u8 s;
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
+
+ /* Don't go out of emergency fan mode */
+ if (s != 7) {
+ s &= 0x07;
+ s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+ }
+
+ if (!acpi_ec_write(fan_status_offset, s))
+ rc = -EIO;
+ else {
+ tp_features.fan_ctrl_status_undef = 0;
+ rc = 0;
+ }
+ break;
+
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
+
+ s &= 0x07;
+
+ /* Set fan to at least level 4 */
+ s |= 4;
+
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+ rc = -EIO;
+ else
+ rc = 0;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_disable(void)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
+
+ rc = 0;
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ if (!acpi_ec_write(fan_status_offset, 0x00))
+ rc = -EIO;
+ else {
+ fan_control_desired_level = 0;
+ tp_features.fan_ctrl_status_undef = 0;
+ }
+ break;
+
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+ rc = -EIO;
+ else
+ fan_control_desired_level = 0;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_speed(int speed)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
+
+ rc = 0;
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ if (speed >= 0 && speed <= 65535) {
+ if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
+ speed, speed, speed))
+ rc = -EIO;
+ } else
+ rc = -EINVAL;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static void fan_watchdog_reset(void)
+{
+ static int fan_watchdog_active;
+
+ if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
+ return;
+
+ if (fan_watchdog_active)
+ cancel_delayed_work(&fan_watchdog_task);
+
+ if (fan_watchdog_maxinterval > 0 &&
+ tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
+ fan_watchdog_active = 1;
+ if (!schedule_delayed_work(&fan_watchdog_task,
+ msecs_to_jiffies(fan_watchdog_maxinterval
+ * 1000))) {
+ printk(TPACPI_ERR
+ "failed to schedule the fan watchdog, "
+ "watchdog will not trigger\n");
+ }
+ } else
+ fan_watchdog_active = 0;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+ int rc;
+
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
+ printk(TPACPI_NOTICE "fan watchdog: enabling fan\n");
+ rc = fan_set_enable();
+ if (rc < 0) {
+ printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, "
+ "will try again later...\n", -rc);
+ /* reschedule for later */
+ fan_watchdog_reset();
+ }
+}
+
+/*
* SYSFS fan layout: hwmon compatible (device)
*
* pwm*_enable:
@@ -3868,9 +5223,9 @@
tp_features.fan_ctrl_status_undef = 0;
fan_control_desired_level = 7;
- IBM_ACPIHANDLE_INIT(fans);
- IBM_ACPIHANDLE_INIT(gfan);
- IBM_ACPIHANDLE_INIT(sfan);
+ TPACPI_ACPIHANDLE_INIT(fans);
+ TPACPI_ACPIHANDLE_INIT(gfan);
+ TPACPI_ACPIHANDLE_INIT(sfan);
if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */
@@ -3896,16 +5251,16 @@
case 0x3837: /* TP-78 */
case 0x3637: /* TP-76 */
case 0x3037: /* TP-70 */
- printk(IBM_NOTICE
- "fan_init: initial fan status is "
- "unknown, assuming it is in auto "
- "mode\n");
+ printk(TPACPI_NOTICE
+ "fan_init: initial fan status "
+ "is unknown, assuming it is "
+ "in auto mode\n");
tp_features.fan_ctrl_status_undef = 1;
;;
}
}
} else {
- printk(IBM_ERR
+ printk(TPACPI_ERR
"ThinkPad ACPI EC access misbehaving, "
"fan status and control unavailable\n");
return 1;
@@ -3970,333 +5325,20 @@
return 1;
}
-/*
- * Call with fan_mutex held
- */
-static void fan_update_desired_level(u8 status)
-{
- if ((status &
- (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
- if (status > 7)
- fan_control_desired_level = 7;
- else
- fan_control_desired_level = status;
- }
-}
-
-static int fan_get_status(u8 *status)
-{
- u8 s;
-
- /* TODO:
- * Add TPACPI_FAN_RD_ACPI_FANS ? */
-
- switch (fan_status_access_mode) {
- case TPACPI_FAN_RD_ACPI_GFAN:
- /* 570, 600e/x, 770e, 770x */
-
- if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
- return -EIO;
-
- if (likely(status))
- *status = s & 0x07;
-
- break;
-
- case TPACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
- return -EIO;
-
- if (likely(status))
- *status = s;
-
- break;
-
- default:
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int fan_get_status_safe(u8 *status)
-{
- int rc;
- u8 s;
-
- if (mutex_lock_interruptible(&fan_mutex))
- return -ERESTARTSYS;
- rc = fan_get_status(&s);
- if (!rc)
- fan_update_desired_level(s);
- mutex_unlock(&fan_mutex);
-
- if (status)
- *status = s;
-
- return rc;
-}
-
static void fan_exit(void)
{
- vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
+ vdbg_printk(TPACPI_DBG_EXIT,
+ "cancelling any pending fan watchdog tasks\n");
/* FIXME: can we really do this unconditionally? */
sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
- driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog);
+ driver_remove_file(&tpacpi_hwmon_pdriver.driver,
+ &driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task);
flush_scheduled_work();
}
-static int fan_get_speed(unsigned int *speed)
-{
- u8 hi, lo;
-
- switch (fan_status_access_mode) {
- case TPACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
- !acpi_ec_read(fan_rpm_offset + 1, &hi)))
- return -EIO;
-
- if (likely(speed))
- *speed = (hi << 8) | lo;
-
- break;
-
- default:
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void fan_watchdog_fire(struct work_struct *ignored)
-{
- int rc;
-
- if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
- return;
-
- printk(IBM_NOTICE "fan watchdog: enabling fan\n");
- rc = fan_set_enable();
- if (rc < 0) {
- printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
- "will try again later...\n", -rc);
- /* reschedule for later */
- fan_watchdog_reset();
- }
-}
-
-static void fan_watchdog_reset(void)
-{
- static int fan_watchdog_active;
-
- if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
- return;
-
- if (fan_watchdog_active)
- cancel_delayed_work(&fan_watchdog_task);
-
- if (fan_watchdog_maxinterval > 0 &&
- tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
- fan_watchdog_active = 1;
- if (!schedule_delayed_work(&fan_watchdog_task,
- msecs_to_jiffies(fan_watchdog_maxinterval
- * 1000))) {
- printk(IBM_ERR "failed to schedule the fan watchdog, "
- "watchdog will not trigger\n");
- }
- } else
- fan_watchdog_active = 0;
-}
-
-static int fan_set_level(int level)
-{
- if (!fan_control_allowed)
- return -EPERM;
-
- switch (fan_control_access_mode) {
- case TPACPI_FAN_WR_ACPI_SFAN:
- if (level >= 0 && level <= 7) {
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
- return -EIO;
- } else
- return -EINVAL;
- break;
-
- case TPACPI_FAN_WR_ACPI_FANS:
- case TPACPI_FAN_WR_TPEC:
- if ((level != TP_EC_FAN_AUTO) &&
- (level != TP_EC_FAN_FULLSPEED) &&
- ((level < 0) || (level > 7)))
- return -EINVAL;
-
- /* safety net should the EC not support AUTO
- * or FULLSPEED mode bits and just ignore them */
- if (level & TP_EC_FAN_FULLSPEED)
- level |= 7; /* safety min speed 7 */
- else if (level & TP_EC_FAN_FULLSPEED)
- level |= 4; /* safety min speed 4 */
-
- if (!acpi_ec_write(fan_status_offset, level))
- return -EIO;
- else
- tp_features.fan_ctrl_status_undef = 0;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_level_safe(int level)
-{
- int rc;
-
- if (!fan_control_allowed)
- return -EPERM;
-
- if (mutex_lock_interruptible(&fan_mutex))
- return -ERESTARTSYS;
-
- if (level == TPACPI_FAN_LAST_LEVEL)
- level = fan_control_desired_level;
-
- rc = fan_set_level(level);
- if (!rc)
- fan_update_desired_level(level);
-
- mutex_unlock(&fan_mutex);
- return rc;
-}
-
-static int fan_set_enable(void)
-{
- u8 s;
- int rc;
-
- if (!fan_control_allowed)
- return -EPERM;
-
- if (mutex_lock_interruptible(&fan_mutex))
- return -ERESTARTSYS;
-
- switch (fan_control_access_mode) {
- case TPACPI_FAN_WR_ACPI_FANS:
- case TPACPI_FAN_WR_TPEC:
- rc = fan_get_status(&s);
- if (rc < 0)
- break;
-
- /* Don't go out of emergency fan mode */
- if (s != 7) {
- s &= 0x07;
- s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
- }
-
- if (!acpi_ec_write(fan_status_offset, s))
- rc = -EIO;
- else {
- tp_features.fan_ctrl_status_undef = 0;
- rc = 0;
- }
- break;
-
- case TPACPI_FAN_WR_ACPI_SFAN:
- rc = fan_get_status(&s);
- if (rc < 0)
- break;
-
- s &= 0x07;
-
- /* Set fan to at least level 4 */
- s |= 4;
-
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
- rc= -EIO;
- else
- rc = 0;
- break;
-
- default:
- rc = -ENXIO;
- }
-
- mutex_unlock(&fan_mutex);
- return rc;
-}
-
-static int fan_set_disable(void)
-{
- int rc;
-
- if (!fan_control_allowed)
- return -EPERM;
-
- if (mutex_lock_interruptible(&fan_mutex))
- return -ERESTARTSYS;
-
- rc = 0;
- switch (fan_control_access_mode) {
- case TPACPI_FAN_WR_ACPI_FANS:
- case TPACPI_FAN_WR_TPEC:
- if (!acpi_ec_write(fan_status_offset, 0x00))
- rc = -EIO;
- else {
- fan_control_desired_level = 0;
- tp_features.fan_ctrl_status_undef = 0;
- }
- break;
-
- case TPACPI_FAN_WR_ACPI_SFAN:
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
- rc = -EIO;
- else
- fan_control_desired_level = 0;
- break;
-
- default:
- rc = -ENXIO;
- }
-
-
- mutex_unlock(&fan_mutex);
- return rc;
-}
-
-static int fan_set_speed(int speed)
-{
- int rc;
-
- if (!fan_control_allowed)
- return -EPERM;
-
- if (mutex_lock_interruptible(&fan_mutex))
- return -ERESTARTSYS;
-
- rc = 0;
- switch (fan_control_access_mode) {
- case TPACPI_FAN_WR_ACPI_FANS:
- if (speed >= 0 && speed <= 65535) {
- if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
- speed, speed, speed))
- rc = -EIO;
- } else
- rc = -EINVAL;
- break;
-
- default:
- rc = -ENXIO;
- }
-
- mutex_unlock(&fan_mutex);
- return rc;
-}
-
static int fan_read(char *p)
{
int len = 0;
@@ -4307,7 +5349,8 @@
switch (fan_status_access_mode) {
case TPACPI_FAN_RD_ACPI_GFAN:
/* 570, 600e/x, 770e, 770x */
- if ((rc = fan_get_status_safe(&status)) < 0)
+ rc = fan_get_status_safe(&status);
+ if (rc < 0)
return rc;
len += sprintf(p + len, "status:\t\t%s\n"
@@ -4317,7 +5360,8 @@
case TPACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
- if ((rc = fan_get_status_safe(&status)) < 0)
+ rc = fan_get_status_safe(&status);
+ if (rc < 0)
return rc;
if (unlikely(tp_features.fan_ctrl_status_undef)) {
@@ -4332,7 +5376,8 @@
len += sprintf(p + len, "status:\t\t%s\n",
(status != 0) ? "enabled" : "disabled");
- if ((rc = fan_get_speed(&speed)) < 0)
+ rc = fan_get_speed(&speed);
+ if (rc < 0)
return rc;
len += sprintf(p + len, "speed:\t\t%d\n", speed);
@@ -4368,8 +5413,8 @@
if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
len += sprintf(p + len, "commands:\tenable, disable\n"
- "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
- "1-120 (seconds))\n");
+ "commands:\twatchdog <timeout> (<timeout> "
+ "is 0 (off), 1-120 (seconds))\n");
if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
len += sprintf(p + len, "commands:\tspeed <speed>"
@@ -4385,13 +5430,14 @@
if (strlencmp(cmd, "level auto") == 0)
level = TP_EC_FAN_AUTO;
else if ((strlencmp(cmd, "level disengaged") == 0) |
- (strlencmp(cmd, "level full-speed") == 0))
+ (strlencmp(cmd, "level full-speed") == 0))
level = TP_EC_FAN_FULLSPEED;
else if (sscanf(cmd, "level %d", &level) != 1)
return 0;
- if ((*rc = fan_set_level_safe(level)) == -ENXIO)
- printk(IBM_ERR "level command accepted for unsupported "
+ *rc = fan_set_level_safe(level);
+ if (*rc == -ENXIO)
+ printk(TPACPI_ERR "level command accepted for unsupported "
"access mode %d", fan_control_access_mode);
return 1;
@@ -4402,8 +5448,9 @@
if (strlencmp(cmd, "enable") != 0)
return 0;
- if ((*rc = fan_set_enable()) == -ENXIO)
- printk(IBM_ERR "enable command accepted for unsupported "
+ *rc = fan_set_enable();
+ if (*rc == -ENXIO)
+ printk(TPACPI_ERR "enable command accepted for unsupported "
"access mode %d", fan_control_access_mode);
return 1;
@@ -4414,8 +5461,9 @@
if (strlencmp(cmd, "disable") != 0)
return 0;
- if ((*rc = fan_set_disable()) == -ENXIO)
- printk(IBM_ERR "disable command accepted for unsupported "
+ *rc = fan_set_disable();
+ if (*rc == -ENXIO)
+ printk(TPACPI_ERR "disable command accepted for unsupported "
"access mode %d", fan_control_access_mode);
return 1;
@@ -4431,8 +5479,9 @@
if (sscanf(cmd, "speed %d", &speed) != 1)
return 0;
- if ((*rc = fan_set_speed(speed)) == -ENXIO)
- printk(IBM_ERR "speed command accepted for unsupported "
+ *rc = fan_set_speed(speed);
+ if (*rc == -ENXIO)
+ printk(TPACPI_ERR "speed command accepted for unsupported "
"access mode %d", fan_control_access_mode);
return 1;
@@ -4496,7 +5545,7 @@
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME);
+ return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME);
}
static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
@@ -4507,14 +5556,12 @@
/* /proc support */
static struct proc_dir_entry *proc_dir;
-/* Subdriver registry */
-static LIST_HEAD(tpacpi_all_drivers);
-
-
/*
* Module and infrastructure proble, init and exit handling
*/
+static int force_load;
+
#ifdef CONFIG_THINKPAD_ACPI_DEBUG
static const char * __init str_supported(int is_supported)
{
@@ -4524,86 +5571,6 @@
}
#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
-static int __init ibm_init(struct ibm_init_struct *iibm)
-{
- int ret;
- struct ibm_struct *ibm = iibm->data;
- struct proc_dir_entry *entry;
-
- BUG_ON(ibm == NULL);
-
- INIT_LIST_HEAD(&ibm->all_drivers);
-
- if (ibm->flags.experimental && !experimental)
- return 0;
-
- dbg_printk(TPACPI_DBG_INIT,
- "probing for %s\n", ibm->name);
-
- if (iibm->init) {
- ret = iibm->init(iibm);
- if (ret > 0)
- return 0; /* probe failed */
- if (ret)
- return ret;
-
- ibm->flags.init_called = 1;
- }
-
- if (ibm->acpi) {
- if (ibm->acpi->hid) {
- ret = register_tpacpi_subdriver(ibm);
- if (ret)
- goto err_out;
- }
-
- if (ibm->acpi->notify) {
- ret = setup_acpi_notify(ibm);
- if (ret == -ENODEV) {
- printk(IBM_NOTICE "disabling subdriver %s\n",
- ibm->name);
- ret = 0;
- goto err_out;
- }
- if (ret < 0)
- goto err_out;
- }
- }
-
- dbg_printk(TPACPI_DBG_INIT,
- "%s installed\n", ibm->name);
-
- if (ibm->read) {
- entry = create_proc_entry(ibm->name,
- S_IFREG | S_IRUGO | S_IWUSR,
- proc_dir);
- if (!entry) {
- printk(IBM_ERR "unable to create proc entry %s\n",
- ibm->name);
- ret = -ENODEV;
- goto err_out;
- }
- entry->owner = THIS_MODULE;
- entry->data = ibm;
- entry->read_proc = &dispatch_procfs_read;
- if (ibm->write)
- entry->write_proc = &dispatch_procfs_write;
- ibm->flags.proc_created = 1;
- }
-
- list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
-
- return 0;
-
-err_out:
- dbg_printk(TPACPI_DBG_INIT,
- "%s: at error exit path with result %d\n",
- ibm->name, ret);
-
- ibm_exit(ibm);
- return (ret < 0)? ret : 0;
-}
-
static void ibm_exit(struct ibm_struct *ibm)
{
dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
@@ -4646,6 +5613,86 @@
dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
}
+static int __init ibm_init(struct ibm_init_struct *iibm)
+{
+ int ret;
+ struct ibm_struct *ibm = iibm->data;
+ struct proc_dir_entry *entry;
+
+ BUG_ON(ibm == NULL);
+
+ INIT_LIST_HEAD(&ibm->all_drivers);
+
+ if (ibm->flags.experimental && !experimental)
+ return 0;
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "probing for %s\n", ibm->name);
+
+ if (iibm->init) {
+ ret = iibm->init(iibm);
+ if (ret > 0)
+ return 0; /* probe failed */
+ if (ret)
+ return ret;
+
+ ibm->flags.init_called = 1;
+ }
+
+ if (ibm->acpi) {
+ if (ibm->acpi->hid) {
+ ret = register_tpacpi_subdriver(ibm);
+ if (ret)
+ goto err_out;
+ }
+
+ if (ibm->acpi->notify) {
+ ret = setup_acpi_notify(ibm);
+ if (ret == -ENODEV) {
+ printk(TPACPI_NOTICE "disabling subdriver %s\n",
+ ibm->name);
+ ret = 0;
+ goto err_out;
+ }
+ if (ret < 0)
+ goto err_out;
+ }
+ }
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "%s installed\n", ibm->name);
+
+ if (ibm->read) {
+ entry = create_proc_entry(ibm->name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ proc_dir);
+ if (!entry) {
+ printk(TPACPI_ERR "unable to create proc entry %s\n",
+ ibm->name);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ entry->owner = THIS_MODULE;
+ entry->data = ibm;
+ entry->read_proc = &dispatch_procfs_read;
+ if (ibm->write)
+ entry->write_proc = &dispatch_procfs_write;
+ ibm->flags.proc_created = 1;
+ }
+
+ list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
+
+ return 0;
+
+err_out:
+ dbg_printk(TPACPI_DBG_INIT,
+ "%s: at error exit path with result %d\n",
+ ibm->name, ret);
+
+ ibm_exit(ibm);
+ return (ret < 0)? ret : 0;
+}
+
/* Probing */
static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
@@ -4715,10 +5762,10 @@
is_thinkpad = (thinkpad_id.model_str != NULL);
/* ec is required because many other handles are relative to it */
- IBM_ACPIHANDLE_INIT(ec);
+ TPACPI_ACPIHANDLE_INIT(ec);
if (!ec_handle) {
if (is_thinkpad)
- printk(IBM_ERR
+ printk(TPACPI_ERR
"Not yet supported ThinkPad detected!\n");
return -ENODEV;
}
@@ -4839,184 +5886,58 @@
return -EINVAL;
}
-static int experimental;
module_param(experimental, int, 0);
+MODULE_PARM_DESC(experimental,
+ "Enables experimental features when non-zero");
-static u32 dbg_level;
module_param_named(debug, dbg_level, uint, 0);
+MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
-static int force_load;
module_param(force_load, bool, 0);
+MODULE_PARM_DESC(force_load,
+ "Attempts to load the driver even on a "
+ "mis-identified ThinkPad when true");
-static int fan_control_allowed;
module_param_named(fan_control, fan_control_allowed, bool, 0);
+MODULE_PARM_DESC(fan_control,
+ "Enables setting fan parameters features when true");
-static int brightness_mode;
module_param_named(brightness_mode, brightness_mode, int, 0);
+MODULE_PARM_DESC(brightness_mode,
+ "Selects brightness control strategy: "
+ "0=auto, 1=EC, 2=CMOS, 3=both");
-static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
module_param(brightness_enable, uint, 0);
+MODULE_PARM_DESC(brightness_enable,
+ "Enables backlight control when 1, disables when 0");
-static unsigned int hotkey_report_mode;
module_param(hotkey_report_mode, uint, 0);
+MODULE_PARM_DESC(hotkey_report_mode,
+ "used for backwards compatibility with userspace, "
+ "see documentation");
-#define IBM_PARAM(feature) \
- module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+#define TPACPI_PARAM(feature) \
+ module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
+ MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
+ "at module load, see documentation")
-IBM_PARAM(hotkey);
-IBM_PARAM(bluetooth);
-IBM_PARAM(video);
-IBM_PARAM(light);
+TPACPI_PARAM(hotkey);
+TPACPI_PARAM(bluetooth);
+TPACPI_PARAM(video);
+TPACPI_PARAM(light);
#ifdef CONFIG_THINKPAD_ACPI_DOCK
-IBM_PARAM(dock);
+TPACPI_PARAM(dock);
#endif
#ifdef CONFIG_THINKPAD_ACPI_BAY
-IBM_PARAM(bay);
+TPACPI_PARAM(bay);
#endif /* CONFIG_THINKPAD_ACPI_BAY */
-IBM_PARAM(cmos);
-IBM_PARAM(led);
-IBM_PARAM(beep);
-IBM_PARAM(ecdump);
-IBM_PARAM(brightness);
-IBM_PARAM(volume);
-IBM_PARAM(fan);
-
-static int __init thinkpad_acpi_module_init(void)
-{
- int ret, i;
-
- tpacpi_lifecycle = TPACPI_LIFE_INIT;
-
- /* Parameter checking */
- if (hotkey_report_mode > 2)
- return -EINVAL;
-
- /* Driver-level probe */
-
- get_thinkpad_model_data(&thinkpad_id);
- ret = probe_for_thinkpad();
- if (ret) {
- thinkpad_acpi_module_exit();
- return ret;
- }
-
- /* Driver initialization */
-
- IBM_ACPIHANDLE_INIT(ecrd);
- IBM_ACPIHANDLE_INIT(ecwr);
-
- proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
- if (!proc_dir) {
- printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
- thinkpad_acpi_module_exit();
- return -ENODEV;
- }
- proc_dir->owner = THIS_MODULE;
-
- ret = platform_driver_register(&tpacpi_pdriver);
- if (ret) {
- printk(IBM_ERR "unable to register main platform driver\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- tp_features.platform_drv_registered = 1;
-
- ret = platform_driver_register(&tpacpi_hwmon_pdriver);
- if (ret) {
- printk(IBM_ERR "unable to register hwmon platform driver\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- tp_features.sensors_pdrv_registered = 1;
-
- ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
- if (!ret) {
- tp_features.platform_drv_attrs_registered = 1;
- ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver);
- }
- if (ret) {
- printk(IBM_ERR "unable to create sysfs driver attributes\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- tp_features.sensors_pdrv_attrs_registered = 1;
-
-
- /* Device initialization */
- tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
- NULL, 0);
- if (IS_ERR(tpacpi_pdev)) {
- ret = PTR_ERR(tpacpi_pdev);
- tpacpi_pdev = NULL;
- printk(IBM_ERR "unable to register platform device\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- tpacpi_sensors_pdev = platform_device_register_simple(
- IBM_HWMON_DRVR_NAME,
- -1, NULL, 0);
- if (IS_ERR(tpacpi_sensors_pdev)) {
- ret = PTR_ERR(tpacpi_sensors_pdev);
- tpacpi_sensors_pdev = NULL;
- printk(IBM_ERR "unable to register hwmon platform device\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- ret = device_create_file(&tpacpi_sensors_pdev->dev,
- &dev_attr_thinkpad_acpi_pdev_name);
- if (ret) {
- printk(IBM_ERR
- "unable to create sysfs hwmon device attributes\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- tp_features.sensors_pdev_attrs_registered = 1;
- tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev);
- if (IS_ERR(tpacpi_hwmon)) {
- ret = PTR_ERR(tpacpi_hwmon);
- tpacpi_hwmon = NULL;
- printk(IBM_ERR "unable to register hwmon device\n");
- thinkpad_acpi_module_exit();
- return ret;
- }
- mutex_init(&tpacpi_inputdev_send_mutex);
- tpacpi_inputdev = input_allocate_device();
- if (!tpacpi_inputdev) {
- printk(IBM_ERR "unable to allocate input device\n");
- thinkpad_acpi_module_exit();
- return -ENOMEM;
- } else {
- /* Prepare input device, but don't register */
- tpacpi_inputdev->name = "ThinkPad Extra Buttons";
- tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
- tpacpi_inputdev->id.bustype = BUS_HOST;
- tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
- thinkpad_id.vendor :
- PCI_VENDOR_ID_IBM;
- tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
- tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
- }
- for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
- ret = ibm_init(&ibms_init[i]);
- if (ret >= 0 && *ibms_init[i].param)
- ret = ibms_init[i].data->write(ibms_init[i].param);
- if (ret < 0) {
- thinkpad_acpi_module_exit();
- return ret;
- }
- }
- ret = input_register_device(tpacpi_inputdev);
- if (ret < 0) {
- printk(IBM_ERR "unable to register input device\n");
- thinkpad_acpi_module_exit();
- return ret;
- } else {
- tp_features.input_device_registered = 1;
- }
-
- tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
- return 0;
-}
+TPACPI_PARAM(cmos);
+TPACPI_PARAM(led);
+TPACPI_PARAM(beep);
+TPACPI_PARAM(ecdump);
+TPACPI_PARAM(brightness);
+TPACPI_PARAM(volume);
+TPACPI_PARAM(fan);
static void thinkpad_acpi_module_exit(void)
{
@@ -5062,12 +5983,187 @@
platform_driver_unregister(&tpacpi_pdriver);
if (proc_dir)
- remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
+ remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
kfree(thinkpad_id.bios_version_str);
kfree(thinkpad_id.ec_version_str);
kfree(thinkpad_id.model_str);
}
+
+static int __init thinkpad_acpi_module_init(void)
+{
+ int ret, i;
+
+ tpacpi_lifecycle = TPACPI_LIFE_INIT;
+
+ /* Parameter checking */
+ if (hotkey_report_mode > 2)
+ return -EINVAL;
+
+ /* Driver-level probe */
+
+ get_thinkpad_model_data(&thinkpad_id);
+ ret = probe_for_thinkpad();
+ if (ret) {
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+
+ /* Driver initialization */
+
+ TPACPI_ACPIHANDLE_INIT(ecrd);
+ TPACPI_ACPIHANDLE_INIT(ecwr);
+
+ proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
+ if (!proc_dir) {
+ printk(TPACPI_ERR
+ "unable to create proc dir " TPACPI_PROC_DIR);
+ thinkpad_acpi_module_exit();
+ return -ENODEV;
+ }
+ proc_dir->owner = THIS_MODULE;
+
+ ret = platform_driver_register(&tpacpi_pdriver);
+ if (ret) {
+ printk(TPACPI_ERR
+ "unable to register main platform driver\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.platform_drv_registered = 1;
+
+ ret = platform_driver_register(&tpacpi_hwmon_pdriver);
+ if (ret) {
+ printk(TPACPI_ERR
+ "unable to register hwmon platform driver\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdrv_registered = 1;
+
+ ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+ if (!ret) {
+ tp_features.platform_drv_attrs_registered = 1;
+ ret = tpacpi_create_driver_attributes(
+ &tpacpi_hwmon_pdriver.driver);
+ }
+ if (ret) {
+ printk(TPACPI_ERR
+ "unable to create sysfs driver attributes\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdrv_attrs_registered = 1;
+
+
+ /* Device initialization */
+ tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1,
+ NULL, 0);
+ if (IS_ERR(tpacpi_pdev)) {
+ ret = PTR_ERR(tpacpi_pdev);
+ tpacpi_pdev = NULL;
+ printk(TPACPI_ERR "unable to register platform device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tpacpi_sensors_pdev = platform_device_register_simple(
+ TPACPI_HWMON_DRVR_NAME,
+ -1, NULL, 0);
+ if (IS_ERR(tpacpi_sensors_pdev)) {
+ ret = PTR_ERR(tpacpi_sensors_pdev);
+ tpacpi_sensors_pdev = NULL;
+ printk(TPACPI_ERR
+ "unable to register hwmon platform device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ ret = device_create_file(&tpacpi_sensors_pdev->dev,
+ &dev_attr_thinkpad_acpi_pdev_name);
+ if (ret) {
+ printk(TPACPI_ERR
+ "unable to create sysfs hwmon device attributes\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdev_attrs_registered = 1;
+ tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev);
+ if (IS_ERR(tpacpi_hwmon)) {
+ ret = PTR_ERR(tpacpi_hwmon);
+ tpacpi_hwmon = NULL;
+ printk(TPACPI_ERR "unable to register hwmon device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ mutex_init(&tpacpi_inputdev_send_mutex);
+ tpacpi_inputdev = input_allocate_device();
+ if (!tpacpi_inputdev) {
+ printk(TPACPI_ERR "unable to allocate input device\n");
+ thinkpad_acpi_module_exit();
+ return -ENOMEM;
+ } else {
+ /* Prepare input device, but don't register */
+ tpacpi_inputdev->name = "ThinkPad Extra Buttons";
+ tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
+ tpacpi_inputdev->id.bustype = BUS_HOST;
+ tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+ thinkpad_id.vendor :
+ PCI_VENDOR_ID_IBM;
+ tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+ tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
+ }
+ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+ ret = ibm_init(&ibms_init[i]);
+ if (ret >= 0 && *ibms_init[i].param)
+ ret = ibms_init[i].data->write(ibms_init[i].param);
+ if (ret < 0) {
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ }
+ ret = input_register_device(tpacpi_inputdev);
+ if (ret < 0) {
+ printk(TPACPI_ERR "unable to register input device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ } else {
+ tp_features.input_device_registered = 1;
+ }
+
+ tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
+ return 0;
+}
+
+/* Please remove this in year 2009 */
+MODULE_ALIAS("ibm_acpi");
+
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+ MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
+
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
+MODULE_DESCRIPTION(TPACPI_DESC);
+MODULE_VERSION(TPACPI_VERSION);
+MODULE_LICENSE("GPL");
+
module_init(thinkpad_acpi_module_init);
module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
deleted file mode 100644
index 8fba2bb..0000000
--- a/drivers/misc/thinkpad_acpi.h
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * thinkpad_acpi.h - ThinkPad ACPI Extras
- *
- *
- * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#ifndef __THINKPAD_ACPI_H__
-#define __THINKPAD_ACPI_H__
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-
-#include <linux/nvram.h>
-#include <linux/proc_fs.h>
-#include <linux/sysfs.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <linux/platform_device.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/input.h>
-#include <asm/uaccess.h>
-
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
-
-#include <linux/pci_ids.h>
-
-/****************************************************************************
- * Main driver
- */
-
-#define IBM_NAME "thinkpad"
-#define IBM_DESC "ThinkPad ACPI Extras"
-#define IBM_FILE IBM_NAME "_acpi"
-#define IBM_URL "http://ibm-acpi.sf.net/"
-#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
-
-#define IBM_PROC_DIR "ibm"
-#define IBM_ACPI_EVENT_PREFIX "ibm"
-#define IBM_DRVR_NAME IBM_FILE
-#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
-
-#define IBM_LOG IBM_FILE ": "
-#define IBM_ERR KERN_ERR IBM_LOG
-#define IBM_NOTICE KERN_NOTICE IBM_LOG
-#define IBM_INFO KERN_INFO IBM_LOG
-#define IBM_DEBUG KERN_DEBUG IBM_LOG
-
-#define IBM_MAX_ACPI_ARGS 3
-
-/* ThinkPad CMOS commands */
-#define TP_CMOS_VOLUME_DOWN 0
-#define TP_CMOS_VOLUME_UP 1
-#define TP_CMOS_VOLUME_MUTE 2
-#define TP_CMOS_BRIGHTNESS_UP 4
-#define TP_CMOS_BRIGHTNESS_DOWN 5
-
-/* ThinkPad CMOS NVRAM constants */
-#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
-#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
-#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
-
-#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
-#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
-#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
-
-/* Debugging */
-#define TPACPI_DBG_ALL 0xffff
-#define TPACPI_DBG_ALL 0xffff
-#define TPACPI_DBG_INIT 0x0001
-#define TPACPI_DBG_EXIT 0x0002
-#define dbg_printk(a_dbg_level, format, arg...) \
- do { if (dbg_level & a_dbg_level) \
- printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
-#ifdef CONFIG_THINKPAD_ACPI_DEBUG
-#define vdbg_printk(a_dbg_level, format, arg...) \
- dbg_printk(a_dbg_level, format, ## arg)
-static const char *str_supported(int is_supported);
-#else
-#define vdbg_printk(a_dbg_level, format, arg...)
-#endif
-
-/* Input IDs */
-#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
-#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
-#define TPACPI_HKEY_INPUT_VERSION 0x4101
-
-/* ACPI HIDs */
-#define IBM_HKEY_HID "IBM0068"
-
-/* ACPI helpers */
-static int __must_check acpi_evalf(acpi_handle handle,
- void *res, char *method, char *fmt, ...);
-static int __must_check acpi_ec_read(int i, u8 * p);
-static int __must_check acpi_ec_write(int i, u8 v);
-static int __must_check _sta(acpi_handle handle);
-
-/* ACPI handles */
-static acpi_handle root_handle; /* root namespace */
-static acpi_handle ec_handle; /* EC */
-static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
-static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
-
-static void drv_acpi_handle_init(char *name,
- acpi_handle *handle, acpi_handle parent,
- char **paths, int num_paths, char **path);
-#define IBM_ACPIHANDLE_INIT(object) \
- drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
- object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-
-/* ThinkPad ACPI helpers */
-static int issue_thinkpad_cmos_command(int cmos_cmd);
-
-/* procfs support */
-static struct proc_dir_entry *proc_dir;
-
-/* procfs helpers */
-static int dispatch_procfs_read(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-static int dispatch_procfs_write(struct file *file,
- const char __user * userbuf,
- unsigned long count, void *data);
-static char *next_cmd(char **cmds);
-
-/* sysfs support */
-struct attribute_set {
- unsigned int members, max_members;
- struct attribute_group group;
-};
-
-static struct attribute_set *create_attr_set(unsigned int max_members,
- const char* name);
-#define destroy_attr_set(_set) \
- kfree(_set);
-static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
-static int add_many_to_attr_set(struct attribute_set* s,
- struct attribute **attr,
- unsigned int count);
-#define register_attr_set_with_sysfs(_attr_set, _kobj) \
- sysfs_create_group(_kobj, &_attr_set->group)
-static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
-
-static int parse_strtoul(const char *buf, unsigned long max,
- unsigned long *value);
-
-/* Device model */
-static struct platform_device *tpacpi_pdev;
-static struct platform_device *tpacpi_sensors_pdev;
-static struct device *tpacpi_hwmon;
-static struct platform_driver tpacpi_pdriver;
-static struct input_dev *tpacpi_inputdev;
-static int tpacpi_create_driver_attributes(struct device_driver *drv);
-static void tpacpi_remove_driver_attributes(struct device_driver *drv);
-
-/* Module */
-static int experimental;
-static u32 dbg_level;
-static int force_load;
-static unsigned int hotkey_report_mode;
-
-static int thinkpad_acpi_module_init(void);
-static void thinkpad_acpi_module_exit(void);
-
-
-/****************************************************************************
- * Subdrivers
- */
-
-struct ibm_struct;
-
-struct tp_acpi_drv_struct {
- const struct acpi_device_id *hid;
- struct acpi_driver *driver;
-
- void (*notify) (struct ibm_struct *, u32);
- acpi_handle *handle;
- u32 type;
- struct acpi_device *device;
-};
-
-struct ibm_struct {
- char *name;
-
- int (*read) (char *);
- int (*write) (char *);
- void (*exit) (void);
- void (*resume) (void);
-
- struct list_head all_drivers;
-
- struct tp_acpi_drv_struct *acpi;
-
- struct {
- u8 acpi_driver_registered:1;
- u8 acpi_notify_installed:1;
- u8 proc_created:1;
- u8 init_called:1;
- u8 experimental:1;
- } flags;
-};
-
-struct ibm_init_struct {
- char param[32];
-
- int (*init) (struct ibm_init_struct *);
- struct ibm_struct *data;
-};
-
-static struct {
-#ifdef CONFIG_THINKPAD_ACPI_BAY
- u32 bay_status:1;
- u32 bay_eject:1;
- u32 bay_status2:1;
- u32 bay_eject2:1;
-#endif
- u32 bluetooth:1;
- u32 hotkey:1;
- u32 hotkey_mask:1;
- u32 hotkey_wlsw:1;
- u32 light:1;
- u32 light_status:1;
- u32 bright_16levels:1;
- u32 wan:1;
- u32 fan_ctrl_status_undef:1;
- u32 input_device_registered:1;
- u32 platform_drv_registered:1;
- u32 platform_drv_attrs_registered:1;
- u32 sensors_pdrv_registered:1;
- u32 sensors_pdrv_attrs_registered:1;
- u32 sensors_pdev_attrs_registered:1;
-} tp_features;
-
-struct thinkpad_id_data {
- unsigned int vendor; /* ThinkPad vendor:
- * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
-
- char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
- char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
-
- u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
- u16 ec_model;
-
- char *model_str;
-};
-
-static struct thinkpad_id_data thinkpad_id;
-
-static struct list_head tpacpi_all_drivers;
-
-static struct ibm_init_struct ibms_init[];
-static int set_ibm_param(const char *val, struct kernel_param *kp);
-static int ibm_init(struct ibm_init_struct *iibm);
-static void ibm_exit(struct ibm_struct *ibm);
-
-
-/*
- * procfs master subdriver
- */
-static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
-static int thinkpad_acpi_driver_read(char *p);
-
-
-/*
- * Bay subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_BAY
-static acpi_handle bay_handle, bay_ej_handle;
-static acpi_handle bay2_handle, bay2_ej_handle;
-
-static int bay_init(struct ibm_init_struct *iibm);
-static void bay_notify(struct ibm_struct *ibm, u32 event);
-static int bay_read(char *p);
-static int bay_write(char *buf);
-#endif /* CONFIG_THINKPAD_ACPI_BAY */
-
-
-/*
- * Beep subdriver
- */
-
-static acpi_handle beep_handle;
-
-static int beep_read(char *p);
-static int beep_write(char *buf);
-
-
-/*
- * Bluetooth subdriver
- */
-
-enum {
- /* ACPI GBDC/SBDC bits */
- TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
- TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
- TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
-};
-
-static int bluetooth_init(struct ibm_init_struct *iibm);
-static int bluetooth_get_radiosw(void);
-static int bluetooth_set_radiosw(int radio_on);
-static int bluetooth_read(char *p);
-static int bluetooth_write(char *buf);
-
-
-/*
- * Brightness (backlight) subdriver
- */
-
-#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
-
-static struct backlight_device *ibm_backlight_device;
-static int brightness_offset = 0x31;
-static int brightness_mode;
-static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
-
-static int brightness_init(struct ibm_init_struct *iibm);
-static void brightness_exit(void);
-static int brightness_get(struct backlight_device *bd);
-static int brightness_set(int value);
-static int brightness_update_status(struct backlight_device *bd);
-static int brightness_read(char *p);
-static int brightness_write(char *buf);
-
-
-/*
- * CMOS subdriver
- */
-
-static int cmos_read(char *p);
-static int cmos_write(char *buf);
-
-
-/*
- * Dock subdriver
- */
-
-#ifdef CONFIG_THINKPAD_ACPI_DOCK
-static acpi_handle pci_handle;
-static acpi_handle dock_handle;
-
-static void dock_notify(struct ibm_struct *ibm, u32 event);
-static int dock_read(char *p);
-static int dock_write(char *buf);
-#endif /* CONFIG_THINKPAD_ACPI_DOCK */
-
-
-/*
- * EC dump subdriver
- */
-
-static int ecdump_read(char *p) ;
-static int ecdump_write(char *buf);
-
-
-/*
- * Fan subdriver
- */
-
-enum { /* Fan control constants */
- fan_status_offset = 0x2f, /* EC register 0x2f */
- fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
- * 0x84 must be read before 0x85 */
-
- TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
- TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
-
- TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
-};
-
-enum fan_status_access_mode {
- TPACPI_FAN_NONE = 0, /* No fan status or control */
- TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
- TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
-};
-
-enum fan_control_access_mode {
- TPACPI_FAN_WR_NONE = 0, /* No fan control */
- TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
- TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
- TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
-};
-
-enum fan_control_commands {
- TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
- TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
- TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
- * and also watchdog cmd */
-};
-
-static int fan_control_allowed;
-
-static enum fan_status_access_mode fan_status_access_mode;
-static enum fan_control_access_mode fan_control_access_mode;
-static enum fan_control_commands fan_control_commands;
-static u8 fan_control_initial_status;
-static u8 fan_control_desired_level;
-static int fan_watchdog_maxinterval;
-
-static struct mutex fan_mutex;
-
-static acpi_handle fans_handle, gfan_handle, sfan_handle;
-
-static int fan_init(struct ibm_init_struct *iibm);
-static void fan_exit(void);
-static int fan_get_status(u8 *status);
-static int fan_get_status_safe(u8 *status);
-static int fan_get_speed(unsigned int *speed);
-static void fan_update_desired_level(u8 status);
-static void fan_watchdog_fire(struct work_struct *ignored);
-static void fan_watchdog_reset(void);
-static int fan_set_level(int level);
-static int fan_set_level_safe(int level);
-static int fan_set_enable(void);
-static int fan_set_disable(void);
-static int fan_set_speed(int speed);
-static int fan_read(char *p);
-static int fan_write(char *buf);
-static int fan_write_cmd_level(const char *cmd, int *rc);
-static int fan_write_cmd_enable(const char *cmd, int *rc);
-static int fan_write_cmd_disable(const char *cmd, int *rc);
-static int fan_write_cmd_speed(const char *cmd, int *rc);
-static int fan_write_cmd_watchdog(const char *cmd, int *rc);
-
-
-/*
- * Hotkey subdriver
- */
-
-static int hotkey_orig_status;
-static u32 hotkey_orig_mask;
-
-static struct mutex hotkey_mutex;
-
-static int hotkey_init(struct ibm_init_struct *iibm);
-static void hotkey_exit(void);
-static int hotkey_get(int *status, u32 *mask);
-static int hotkey_set(int status, u32 mask);
-static void hotkey_notify(struct ibm_struct *ibm, u32 event);
-static int hotkey_read(char *p);
-static int hotkey_write(char *buf);
-
-
-/*
- * LED subdriver
- */
-
-enum led_access_mode {
- TPACPI_LED_NONE = 0,
- TPACPI_LED_570, /* 570 */
- TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- TPACPI_LED_NEW, /* all others */
-};
-
-enum { /* For TPACPI_LED_OLD */
- TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
- TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
- TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
-};
-
-static enum led_access_mode led_supported;
-static acpi_handle led_handle;
-
-static int led_init(struct ibm_init_struct *iibm);
-static int led_read(char *p);
-static int led_write(char *buf);
-
-/*
- * Light (thinklight) subdriver
- */
-
-static acpi_handle lght_handle, ledb_handle;
-
-static int light_init(struct ibm_init_struct *iibm);
-static int light_read(char *p);
-static int light_write(char *buf);
-
-
-/*
- * Thermal subdriver
- */
-
-enum thermal_access_mode {
- TPACPI_THERMAL_NONE = 0, /* No thermal support */
- TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
- TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
- TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
- TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
-};
-
-enum { /* TPACPI_THERMAL_TPEC_* */
- TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
- TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
- TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
-};
-
-#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
-struct ibm_thermal_sensors_struct {
- s32 temp[TPACPI_MAX_THERMAL_SENSORS];
-};
-
-static enum thermal_access_mode thermal_read_mode;
-
-static int thermal_init(struct ibm_init_struct *iibm);
-static int thermal_get_sensor(int idx, s32 *value);
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
-static int thermal_read(char *p);
-
-
-/*
- * Video subdriver
- */
-
-enum video_access_mode {
- TPACPI_VIDEO_NONE = 0,
- TPACPI_VIDEO_570, /* 570 */
- TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
- TPACPI_VIDEO_NEW, /* all others */
-};
-
-enum { /* video status flags, based on VIDEO_570 */
- TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
- TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
- TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
-};
-
-enum { /* TPACPI_VIDEO_570 constants */
- TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
- TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
- * video_status_flags */
- TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
- TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
-};
-
-static enum video_access_mode video_supported;
-static int video_orig_autosw;
-static acpi_handle vid_handle, vid2_handle;
-
-static int video_init(struct ibm_init_struct *iibm);
-static void video_exit(void);
-static int video_outputsw_get(void);
-static int video_outputsw_set(int status);
-static int video_autosw_get(void);
-static int video_autosw_set(int enable);
-static int video_outputsw_cycle(void);
-static int video_expand_toggle(void);
-static int video_read(char *p);
-static int video_write(char *buf);
-
-
-/*
- * Volume subdriver
- */
-
-static int volume_offset = 0x30;
-
-static int volume_read(char *p);
-static int volume_write(char *buf);
-
-
-/*
- * Wan subdriver
- */
-
-enum {
- /* ACPI GWAN/SWAN bits */
- TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
- TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
- TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
-};
-
-static int wan_init(struct ibm_init_struct *iibm);
-static int wan_get_radiosw(void);
-static int wan_set_radiosw(int radio_on);
-static int wan_read(char *p);
-static int wan_write(char *buf);
-
-
-#endif /* __THINKPAD_ACPI_H */
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index be4b994..eeaaa9d 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -4,7 +4,7 @@
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004-2006 Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (C) 2004-2006 Joern Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
*/
@@ -485,5 +485,5 @@
module_exit(block2mtd_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others");
+MODULE_AUTHOR("Joern Engel <joern@lazybastard.org>");
MODULE_DESCRIPTION("Emulate an MTD using a block device");
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index c73e96b..90acf57 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -376,7 +376,7 @@
* hardware restriction. */
if (doc->mfr) {
if (doc->mfr == mfr && doc->id == id)
- return 1; /* This is another the same the first */
+ return 1; /* This is the same as the first */
else
printk(KERN_WARNING
"Flash chip at floor %d, chip %d is different:\n",
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 56cc1ca..180298b 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -2,7 +2,7 @@
* $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
*
* Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
- * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de>
*
* Usage:
*
@@ -299,5 +299,5 @@
module_exit(cleanup_phram);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>");
MODULE_DESCRIPTION("MTD driver for physical RAM");
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c
index d884f2b..2a8fde9 100644
--- a/drivers/mtd/maps/mtx-1_flash.c
+++ b/drivers/mtd/maps/mtx-1_flash.c
@@ -4,7 +4,7 @@
* $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
*
* (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
- * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
+ * (C) 2005 Joern Engel <joern@wohnheim.fh-wedel.de>
*
*/
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index e3744eb..dd38011 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -20,7 +20,7 @@
*
* 02-12-2002 TG Cleanup of module params
*
- * 02-20-2002 TG adjusted for different rd/wr adress support
+ * 02-20-2002 TG adjusted for different rd/wr address support
* added support for read device ready/busy line
* added page_cache
*
@@ -144,7 +144,7 @@
goto out;
}
- /* map physical adress */
+ /* map physical address */
autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
if (!autcpu12_fio_base) {
printk("Ioremap autcpu12 SmartMedia Card failed\n");
@@ -227,7 +227,7 @@
/* Release resources, unregister device */
nand_release(autcpu12_mtd);
- /* unmap physical adress */
+ /* unmap physical address */
iounmap(autcpu12_fio_base);
/* Free the MTD device structure */
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 1657ecd..a52f3a7 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -4,7 +4,7 @@
* http://blackfin.uclinux.org/
* Bryan Wu <bryan.wu@analog.com>
*
- * Blackfin BF5xx on-chip NAND flash controler driver
+ * Blackfin BF5xx on-chip NAND flash controller driver
*
* Derived from drivers/mtd/nand/s3c2410.c
* Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 89deff0..19e1594 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -337,7 +337,7 @@
nand_release(cs553x_mtd[i]);
cs553x_mtd[i] = NULL;
- /* unmap physical adress */
+ /* unmap physical address */
iounmap(mmio_base);
/* Free the MTD device structure */
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
index 0146cdc..ba67bbec 100644
--- a/drivers/mtd/nand/edb7312.c
+++ b/drivers/mtd/nand/edb7312.c
@@ -125,7 +125,7 @@
return -ENOMEM;
}
- /* map physical adress */
+ /* map physical address */
ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
if (!ep7312_fio_base) {
printk("ioremap EDB7312 NAND flash failed\n");
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e29c1da..ddd4fc0 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -89,7 +89,7 @@
struct mtd_oob_ops *ops);
/*
- * For devices which display every fart in the system on a seperate LED. Is
+ * For devices which display every fart in the system on a separate LED. Is
* compiled away when LED support is disabled.
*/
DEFINE_LED_TRIGGER(nand_led_trigger);
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 10490b4..bb885d1 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -210,7 +210,7 @@
#define STATE_CMD_RESET 0x0000000C /* reset */
#define STATE_CMD_MASK 0x0000000F /* command states mask */
-/* After an addres is input, the simulator goes to one of these states */
+/* After an address is input, the simulator goes to one of these states */
#define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */
#define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */
#define STATE_ADDR_ZERO 0x00000030 /* one byte zero address was accepted */
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 66f76e9..2bd0737 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -8,7 +8,7 @@
*
* Changelog:
* 21-Sep-2004 BJD Initial version
- * 23-Sep-2004 BJD Mulitple device support
+ * 23-Sep-2004 BJD Multiple device support
* 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
* 12-Oct-2004 BJD Fixed errors in use of platform data
* 18-Feb-2005 BJD Fix sparse errors
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 51c7288..033f880 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -165,7 +165,7 @@
return -ENOMEM;
}
- /* map physical adress */
+ /* map physical address */
sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
if (!sharpsl_io_base) {
printk("ioremap to access Sharp SL NAND chip failed\n");
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 067262ee..0513cbc 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -429,7 +429,7 @@
}
}
-/* calc_chain_lenght: Walk through a Virtual Unit Chain and estimate chain length */
+/* calc_chain_length: Walk through a Virtual Unit Chain and estimate chain length */
static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
{
unsigned int length = 0, block = first_block;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 389980f..7d170cd 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -814,8 +814,8 @@
will be called smc-ultra32.
config BFIN_MAC
- tristate "Blackfin 536/537 on-chip mac support"
- depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+ tristate "Blackfin 527/536/537 on-chip mac support"
+ depends on NET_ETHERNET && (BF527 || BF537 || BF536) && (!BF537_PORT_H)
select CRC32
select MII
select PHYLIB
@@ -828,7 +828,7 @@
config BFIN_MAC_USE_L1
bool "Use L1 memory for rx/tx packets"
- depends on BFIN_MAC && BF537
+ depends on BFIN_MAC && (BF527 || BF537)
default y
help
To get maximum network performance, you should use L1 memory as rx/tx buffers.
@@ -855,7 +855,8 @@
config BFIN_MAC_RMII
bool "RMII PHY Interface (EXPERIMENTAL)"
depends on BFIN_MAC && EXPERIMENTAL
- default n
+ default y if BFIN527_EZKIT
+ default n if BFIN537_STAMP
help
Use Reduced PHY MII Interface
@@ -919,8 +920,7 @@
---help---
Support for the Microchip EN28J60 ethernet chip.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
+ To compile this driver as a module, choose M here. The module will be
called enc28j60.
config ENC28J60_WRITEVERIFY
@@ -1199,7 +1199,7 @@
config IBMLANA
tristate "IBM LAN Adapter/A support"
- depends on MCA && MCA_LEGACY
+ depends on MCA
---help---
This is a Micro Channel Ethernet adapter. You need to set
CONFIG_MCA to use this driver. It is both available as an in-kernel
@@ -2040,8 +2040,7 @@
More specific information on configuring the driver is in
<file:Documentation/networking/e1000.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called igb.
source "drivers/net/ixp2000/Kconfig"
@@ -3113,6 +3112,7 @@
tristate "Virtio network driver (EXPERIMENTAL)"
depends on EXPERIMENTAL && VIRTIO
---help---
- This is the virtual network driver for lguest. Say Y or M.
+ This is the virtual network driver for virtio. It can be used with
+ lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
endif # NETDEVICES
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 25b114a..0ae0d83 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -384,7 +384,7 @@
/* Wait until PHY reset is complete */
do {
read_phy(lp->phy_address, MII_BMCR, &bmcr);
- } while (!(bmcr && BMCR_RESET));
+ } while (!(bmcr & BMCR_RESET));
disable_mdi();
spin_unlock_irq(&lp->lock);
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 7495a9e..194949a 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -137,11 +137,12 @@
static void ax_reset_8390(struct net_device *dev)
{
struct ei_device *ei_local = netdev_priv(dev);
+ struct ax_device *ax = to_ax_dev(dev);
unsigned long reset_start_time = jiffies;
void __iomem *addr = (void __iomem *)dev->base_addr;
if (ei_debug > 1)
- printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+ dev_dbg(&ax->dev->dev, "resetting the 8390 t=%ld\n", jiffies);
ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET);
@@ -151,7 +152,7 @@
/* This check _should_not_ be necessary, omit eventually. */
while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) {
if (jiffies - reset_start_time > 2*HZ/100) {
- printk(KERN_WARNING "%s: %s did not complete.\n",
+ dev_warn(&ax->dev->dev, "%s: %s did not complete.\n",
__FUNCTION__, dev->name);
break;
}
@@ -165,13 +166,15 @@
int ring_page)
{
struct ei_device *ei_local = netdev_priv(dev);
+ struct ax_device *ax = to_ax_dev(dev);
void __iomem *nic_base = ei_local->mem;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
- printk(KERN_EMERG "%s: DMAing conflict in %s [DMAstat:%d][irqlock:%d].\n",
+ dev_err(&ax->dev->dev, "%s: DMAing conflict in %s "
+ "[DMAstat:%d][irqlock:%d].\n",
dev->name, __FUNCTION__,
- ei_status.dmaing, ei_status.irqlock);
+ ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -204,13 +207,16 @@
struct sk_buff *skb, int ring_offset)
{
struct ei_device *ei_local = netdev_priv(dev);
+ struct ax_device *ax = to_ax_dev(dev);
void __iomem *nic_base = ei_local->mem;
char *buf = skb->data;
if (ei_status.dmaing) {
- printk(KERN_EMERG "%s: DMAing conflict in ax_block_input "
+ dev_err(&ax->dev->dev,
+ "%s: DMAing conflict in %s "
"[DMAstat:%d][irqlock:%d].\n",
- dev->name, ei_status.dmaing, ei_status.irqlock);
+ dev->name, __FUNCTION__,
+ ei_status.dmaing, ei_status.irqlock);
return;
}
@@ -239,6 +245,7 @@
const unsigned char *buf, const int start_page)
{
struct ei_device *ei_local = netdev_priv(dev);
+ struct ax_device *ax = to_ax_dev(dev);
void __iomem *nic_base = ei_local->mem;
unsigned long dma_start;
@@ -251,7 +258,7 @@
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
- printk(KERN_EMERG "%s: DMAing conflict in %s."
+ dev_err(&ax->dev->dev, "%s: DMAing conflict in %s."
"[DMAstat:%d][irqlock:%d]\n",
dev->name, __FUNCTION__,
ei_status.dmaing, ei_status.irqlock);
@@ -281,7 +288,8 @@
while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) {
if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
- printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+ dev_warn(&ax->dev->dev,
+ "%s: timeout waiting for Tx RDC.\n", dev->name);
ax_reset_8390(dev);
ax_NS8390_init(dev,1);
break;
@@ -424,10 +432,11 @@
ax_phy_write(struct net_device *dev, int phy_addr, int reg, int value)
{
struct ei_device *ei = (struct ei_device *) netdev_priv(dev);
+ struct ax_device *ax = to_ax_dev(dev);
unsigned long flags;
- printk(KERN_DEBUG "%s: %p, %04x, %04x %04x\n",
- __FUNCTION__, dev, phy_addr, reg, value);
+ dev_dbg(&ax->dev->dev, "%s: %p, %04x, %04x %04x\n",
+ __FUNCTION__, dev, phy_addr, reg, value);
spin_lock_irqsave(&ei->page_lock, flags);
@@ -750,14 +759,11 @@
ax_NS8390_init(dev, 0);
if (first_init) {
- printk("AX88796: %dbit, irq %d, %lx, MAC: ",
- ei_status.word16 ? 16:8, dev->irq, dev->base_addr);
+ DECLARE_MAC_BUF(mac);
- for (i = 0; i < ETHER_ADDR_LEN; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- (i < (ETHER_ADDR_LEN-1) ? ':' : ' '));
-
- printk("\n");
+ dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %s\n",
+ ei_status.word16 ? 16:8, dev->irq, dev->base_addr,
+ print_mac(mac, dev->dev_addr));
}
ret = register_netdev(dev);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index eb97175..c993a32 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -1,34 +1,11 @@
/*
- * File: drivers/net/bfin_mac.c
- * Based on:
- * Maintainer:
- * Bryan Wu <bryan.wu@analog.com>
+ * Blackfin On-Chip MAC Driver
*
- * Original author:
- * Luke Yang <luke.yang@analog.com>
+ * Copyright 2004-2007 Analog Devices Inc.
*
- * Created:
- * Description:
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program ; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/init.h>
@@ -65,7 +42,7 @@
#define DRV_NAME "bfin_mac"
#define DRV_VERSION "1.1"
#define DRV_AUTHOR "Bryan Wu, Luke Yang"
-#define DRV_DESC "Blackfin BF53[67] on-chip Ethernet MAC driver"
+#define DRV_DESC "Blackfin BF53[67] BF527 on-chip Ethernet MAC driver"
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -296,7 +273,7 @@
/* poll the STABUSY bit */
while ((bfin_read_EMAC_STAADD()) & STABUSY) {
- mdelay(10);
+ udelay(1);
if (timeout_cnt-- < 0) {
printk(KERN_ERR DRV_NAME
": wait MDC/MDIO transaction to complete timeout\n");
@@ -412,20 +389,26 @@
spin_unlock_irqrestore(&lp->lock, flags);
}
+/* MDC = 2.5 MHz */
+#define MDC_CLK 2500000
+
static int mii_probe(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = NULL;
unsigned short sysctl;
int i;
+ u32 sclk, mdc_div;
/* Enable PHY output early */
if (!(bfin_read_VR_CTL() & PHYCLKOE))
bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
- /* MDC = 2.5 MHz */
+ sclk = get_sclk();
+ mdc_div = ((sclk / MDC_CLK) / 2) - 1;
+
sysctl = bfin_read_EMAC_SYSCTL();
- sysctl |= SET_MDCDIV(24);
+ sysctl = (sysctl & ~MDCDIV) | SET_MDCDIV(mdc_div);
bfin_write_EMAC_SYSCTL(sysctl);
/* search for connect PHY device */
@@ -477,8 +460,10 @@
lp->phydev = phydev;
printk(KERN_INFO "%s: attached PHY driver [%s] "
- "(mii_bus:phy_addr=%s, irq=%d)\n",
- DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+ "(mii_bus:phy_addr=%s, irq=%d, mdc_clk=%dHz(mdc_div=%d)"
+ "@sclk=%dMHz)\n",
+ DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq,
+ MDC_CLK, mdc_div, sclk/1000000);
return 0;
}
@@ -551,7 +536,7 @@
*/
if (current_tx_ptr->next->next == tx_list_head) {
while (tx_list_head->status.status_word == 0) {
- mdelay(10);
+ mdelay(1);
if (tx_list_head->status.status_word != 0
|| !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
goto adjust_head;
@@ -666,6 +651,12 @@
current_rx_ptr->skb = new_skb;
current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
+ /* Invidate the data cache of skb->data range when it is write back
+ * cache. It will prevent overwritting the new data from DMA
+ */
+ blackfin_dcache_invalidate_range((unsigned long)new_skb->head,
+ (unsigned long)new_skb->end);
+
len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
skb_put(skb, len);
blackfin_dcache_invalidate_range((unsigned long)skb->head,
@@ -767,7 +758,7 @@
#if defined(CONFIG_BFIN_MAC_RMII)
opmode |= RMII; /* For Now only 100MBit are supported */
-#ifdef CONFIG_BF_REV_0_2
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2
opmode |= TE;
#endif
#endif
@@ -792,6 +783,39 @@
netif_wake_queue(dev);
}
+static void bf537mac_multicast_hash(struct net_device *dev)
+{
+ u32 emac_hashhi, emac_hashlo;
+ struct dev_mc_list *dmi = dev->mc_list;
+ char *addrs;
+ int i;
+ u32 crc;
+
+ emac_hashhi = emac_hashlo = 0;
+
+ for (i = 0; i < dev->mc_count; i++) {
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ /* skip non-multicast addresses */
+ if (!(*addrs & 1))
+ continue;
+
+ crc = ether_crc(ETH_ALEN, addrs);
+ crc >>= 26;
+
+ if (crc & 0x20)
+ emac_hashhi |= 1 << (crc & 0x1f);
+ else
+ emac_hashlo |= 1 << (crc & 0x1f);
+ }
+
+ bfin_write_EMAC_HASHHI(emac_hashhi);
+ bfin_write_EMAC_HASHLO(emac_hashlo);
+
+ return;
+}
+
/*
* This routine will, depending on the values passed to it,
* either make it accept multicast packets, go into
@@ -807,11 +831,17 @@
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= RAF;
bfin_write_EMAC_OPMODE(sysctl);
- } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+ } else if (dev->flags & IFF_ALLMULTI) {
/* accept all multicast */
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= PAM;
bfin_write_EMAC_OPMODE(sysctl);
+ } else if (dev->mc_count) {
+ /* set up multicast hash table */
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl |= HM;
+ bfin_write_EMAC_OPMODE(sysctl);
+ bf537mac_multicast_hash(dev);
} else {
/* clear promisc or multicast mode */
sysctl = bfin_read_EMAC_OPMODE();
@@ -860,10 +890,10 @@
return retval;
phy_start(lp->phydev);
+ phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
setup_system_regs(dev);
bf537mac_disable();
bf537mac_enable();
-
pr_debug("hardware init finished\n");
netif_start_queue(dev);
netif_carrier_on(dev);
@@ -886,6 +916,7 @@
netif_carrier_off(dev);
phy_stop(lp->phydev);
+ phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
/* clear everything */
bf537mac_shutdown(dev);
@@ -970,7 +1001,7 @@
/* register irq handler */
if (request_irq
(IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
- "BFIN537_MAC_RX", dev)) {
+ "EMAC_RX", dev)) {
printk(KERN_WARNING DRV_NAME
": Unable to attach BlackFin MAC RX interrupt\n");
return -EBUSY;
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index 5970ea7..f774d5a 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -1,34 +1,11 @@
/*
- * File: drivers/net/bfin_mac.c
- * Based on:
- * Maintainer:
- * Bryan Wu <bryan.wu@analog.com>
+ * Blackfin On-Chip MAC Driver
*
- * Original author:
- * Luke Yang <luke.yang@analog.com>
+ * Copyright 2004-2007 Analog Devices Inc.
*
- * Created:
- * Description:
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program ; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#define BFIN_MAC_CSUM_OFFLOAD
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 2039f78..0942d82 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1464,10 +1464,12 @@
dev_set_allmulti(slave_dev, 1);
}
+ netif_tx_lock_bh(bond_dev);
/* upload master's mc_list to new slave */
for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
}
+ netif_tx_unlock_bh(bond_dev);
}
if (bond->params.mode == BOND_MODE_8023AD) {
@@ -1821,7 +1823,9 @@
}
/* flush master's mc_list from slave */
+ netif_tx_lock_bh(bond_dev);
bond_mc_list_flush(bond_dev, slave_dev);
+ netif_tx_unlock_bh(bond_dev);
}
netdev_set_master(slave_dev, NULL);
@@ -1942,7 +1946,9 @@
}
/* flush master's mc_list from slave */
+ netif_tx_lock_bh(bond_dev);
bond_mc_list_flush(bond_dev, slave_dev);
+ netif_tx_unlock_bh(bond_dev);
}
netdev_set_master(slave_dev, NULL);
@@ -2795,14 +2801,11 @@
}
if (do_failover) {
- rtnl_lock();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
- rtnl_unlock();
-
}
re_arm:
@@ -2859,8 +2862,6 @@
slave->link = BOND_LINK_UP;
- rtnl_lock();
-
write_lock_bh(&bond->curr_slave_lock);
if ((!bond->curr_active_slave) &&
@@ -2896,7 +2897,6 @@
}
write_unlock_bh(&bond->curr_slave_lock);
- rtnl_unlock();
}
} else {
read_lock(&bond->curr_slave_lock);
@@ -2966,7 +2966,6 @@
bond->dev->name,
slave->dev->name);
- rtnl_lock();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
@@ -2974,8 +2973,6 @@
write_unlock_bh(&bond->curr_slave_lock);
- rtnl_unlock();
-
bond->current_arp_slave = slave;
if (slave) {
@@ -2993,13 +2990,10 @@
bond->primary_slave->dev->name);
/* primary is up so switch to it */
- rtnl_lock();
write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, bond->primary_slave);
write_unlock_bh(&bond->curr_slave_lock);
- rtnl_unlock();
-
slave = bond->primary_slave;
slave->jiffies = jiffies;
} else {
@@ -3769,42 +3763,45 @@
{
struct bonding *bond = bond_dev->priv;
struct net_device_stats *stats = &(bond->stats), *sstats;
+ struct net_device_stats local_stats;
struct slave *slave;
int i;
- memset(stats, 0, sizeof(struct net_device_stats));
+ memset(&local_stats, 0, sizeof(struct net_device_stats));
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
sstats = slave->dev->get_stats(slave->dev);
- stats->rx_packets += sstats->rx_packets;
- stats->rx_bytes += sstats->rx_bytes;
- stats->rx_errors += sstats->rx_errors;
- stats->rx_dropped += sstats->rx_dropped;
+ local_stats.rx_packets += sstats->rx_packets;
+ local_stats.rx_bytes += sstats->rx_bytes;
+ local_stats.rx_errors += sstats->rx_errors;
+ local_stats.rx_dropped += sstats->rx_dropped;
- stats->tx_packets += sstats->tx_packets;
- stats->tx_bytes += sstats->tx_bytes;
- stats->tx_errors += sstats->tx_errors;
- stats->tx_dropped += sstats->tx_dropped;
+ local_stats.tx_packets += sstats->tx_packets;
+ local_stats.tx_bytes += sstats->tx_bytes;
+ local_stats.tx_errors += sstats->tx_errors;
+ local_stats.tx_dropped += sstats->tx_dropped;
- stats->multicast += sstats->multicast;
- stats->collisions += sstats->collisions;
+ local_stats.multicast += sstats->multicast;
+ local_stats.collisions += sstats->collisions;
- stats->rx_length_errors += sstats->rx_length_errors;
- stats->rx_over_errors += sstats->rx_over_errors;
- stats->rx_crc_errors += sstats->rx_crc_errors;
- stats->rx_frame_errors += sstats->rx_frame_errors;
- stats->rx_fifo_errors += sstats->rx_fifo_errors;
- stats->rx_missed_errors += sstats->rx_missed_errors;
+ local_stats.rx_length_errors += sstats->rx_length_errors;
+ local_stats.rx_over_errors += sstats->rx_over_errors;
+ local_stats.rx_crc_errors += sstats->rx_crc_errors;
+ local_stats.rx_frame_errors += sstats->rx_frame_errors;
+ local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
+ local_stats.rx_missed_errors += sstats->rx_missed_errors;
- stats->tx_aborted_errors += sstats->tx_aborted_errors;
- stats->tx_carrier_errors += sstats->tx_carrier_errors;
- stats->tx_fifo_errors += sstats->tx_fifo_errors;
- stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
- stats->tx_window_errors += sstats->tx_window_errors;
+ local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
+ local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
+ local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
+ local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+ local_stats.tx_window_errors += sstats->tx_window_errors;
}
+ memcpy(stats, &local_stats, sizeof(struct net_device_stats));
+
read_unlock_bh(&bond->lock);
return stats;
@@ -3937,8 +3934,6 @@
struct bonding *bond = bond_dev->priv;
struct dev_mc_list *dmi;
- write_lock_bh(&bond->lock);
-
/*
* Do promisc before checking multicast_mode
*/
@@ -3959,6 +3954,8 @@
bond_set_allmulti(bond, -1);
}
+ read_lock(&bond->lock);
+
bond->flags = bond_dev->flags;
/* looking for addresses to add to slaves' mc list */
@@ -3979,7 +3976,7 @@
bond_mc_list_destroy(bond);
bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC);
- write_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
}
/*
@@ -4526,7 +4523,9 @@
struct net_device *bond_dev = bond->dev;
bond_work_cancel_all(bond);
+ netif_tx_lock_bh(bond_dev);
bond_mc_list_destroy(bond);
+ netif_tx_unlock_bh(bond_dev);
/* Release the bonded slaves */
bond_release_all(bond_dev);
bond_deinit(bond_dev);
@@ -4549,14 +4548,19 @@
int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
{
int mode = -1, i, rv;
- char modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
+ char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
- rv = sscanf(buf, "%d", &mode);
- if (!rv) {
+ for (p = (char *)buf; *p; p++)
+ if (!(isdigit(*p) || isspace(*p)))
+ break;
+
+ if (*p)
rv = sscanf(buf, "%20s", modestr);
- if (!rv)
- return -1;
- }
+ else
+ rv = sscanf(buf, "%d", &mode);
+
+ if (!rv)
+ return -1;
for (i = 0; tbl[i].modename; i++) {
if (mode == tbl[i].mode)
@@ -4883,14 +4887,16 @@
down_write(&bonding_rwsem);
/* Check to see if the bond already exists. */
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
- if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
- printk(KERN_ERR DRV_NAME
+ if (name) {
+ list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+ if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
+ printk(KERN_ERR DRV_NAME
": cannot add bond %s; it already exists\n",
- name);
- res = -EPERM;
- goto out_rtnl;
- }
+ name);
+ res = -EPERM;
+ goto out_rtnl;
+ }
+ }
bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
ether_setup);
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 6d83be4..67ccad6 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.2.3"
-#define DRV_RELDATE "December 6, 2007"
+#define DRV_VERSION "3.2.4"
+#define DRV_RELDATE "January 28, 2008"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index d48c396..901c824 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1070,9 +1070,7 @@
*/
void cxgb_free_mem(void *addr)
{
- unsigned long p = (unsigned long)addr;
-
- if (p >= VMALLOC_START && p < VMALLOC_END)
+ if (is_vmalloc_addr(addr))
vfree(addr);
else
kfree(addr);
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
index 84c1ffa8..4c4d6e8 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/cxgb3/mc5.c
@@ -452,7 +452,7 @@
t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
}
-void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
{
#define K * 1024
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index cb684d3..9ca8c66 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -2836,7 +2836,7 @@
* defaults for the assorted SGE parameters, which admins can change until
* they are used to initialize the SGE.
*/
-void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+void t3_sge_prep(struct adapter *adap, struct sge_params *p)
{
int i;
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 7469935..a99496a 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -2675,7 +2675,7 @@
V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
}
-static void __devinit init_mtus(unsigned short mtus[])
+static void init_mtus(unsigned short mtus[])
{
/*
* See draft-mathis-plpmtud-00.txt for the values. The min is 88 so
@@ -2703,7 +2703,7 @@
/*
* Initial congestion control parameters.
*/
-static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+static void init_cong_ctrl(unsigned short *a, unsigned short *b)
{
a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
a[9] = 2;
@@ -3354,8 +3354,7 @@
* Determines a card's PCI mode and associated parameters, such as speed
* and width.
*/
-static void __devinit get_pci_mode(struct adapter *adapter,
- struct pci_params *p)
+static void get_pci_mode(struct adapter *adapter, struct pci_params *p)
{
static unsigned short speed_map[] = { 33, 66, 100, 133 };
u32 pci_mode, pcie_cap;
@@ -3395,8 +3394,7 @@
* capabilities and default speed/duplex/flow-control/autonegotiation
* settings.
*/
-static void __devinit init_link_config(struct link_config *lc,
- unsigned int caps)
+static void init_link_config(struct link_config *lc, unsigned int caps)
{
lc->supported = caps;
lc->requested_speed = lc->speed = SPEED_INVALID;
@@ -3419,7 +3417,7 @@
* Calculates the size of an MC7 memory in bytes from the value of its
* configuration register.
*/
-static unsigned int __devinit mc7_calc_size(u32 cfg)
+static unsigned int mc7_calc_size(u32 cfg)
{
unsigned int width = G_WIDTH(cfg);
unsigned int banks = !!(cfg & F_BKS) + 1;
@@ -3430,8 +3428,8 @@
return MBs << 20;
}
-static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
- unsigned int base_addr, const char *name)
+static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+ unsigned int base_addr, const char *name)
{
u32 cfg;
@@ -3517,7 +3515,7 @@
return 0;
}
-static int __devinit init_parity(struct adapter *adap)
+static int init_parity(struct adapter *adap)
{
int i, err, addr;
@@ -3552,8 +3550,8 @@
* for some adapter tunables, take PHYs out of reset, and initialize the MDIO
* interface.
*/
-int __devinit t3_prep_adapter(struct adapter *adapter,
- const struct adapter_info *ai, int reset)
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+ int reset)
{
int ret;
unsigned int i, j = 0;
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 51cf577..36ba6dc 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -94,7 +94,7 @@
* enabled. 82557 pads with 7Eh, while the later controllers pad
* with 00h.
*
- * IV. Recieve
+ * IV. Receive
*
* The Receive Frame Area (RFA) comprises a ring of Receive Frame
* Descriptors (RFD) + data buffer, thus forming the simplified mode
@@ -120,7 +120,7 @@
* and Rx indication and re-allocation happen in the same context,
* therefore no locking is required. A software-generated interrupt
* is generated from the watchdog to recover from a failed allocation
- * senario where all Rx resources have been indicated and none re-
+ * scenario where all Rx resources have been indicated and none re-
* placed.
*
* V. Miscellaneous
@@ -954,7 +954,7 @@
/* Quadwords to DMA into FIFO before starting frame transmit */
nic->tx_threshold = 0xE0;
- /* no interrupt for every tx completion, delay = 256us if not 557*/
+ /* no interrupt for every tx completion, delay = 256us if not 557 */
nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf |
((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
@@ -1497,7 +1497,7 @@
&s->complete;
/* Device's stats reporting may take several microseconds to
- * complete, so where always waiting for results of the
+ * complete, so we're always waiting for results of the
* previous command. */
if(*complete == cpu_to_le32(cuc_dump_reset_complete)) {
@@ -1958,7 +1958,7 @@
if(restart_required) {
// ack the rnr?
- writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+ iowrite8(stat_ack_rnr, &nic->csr->scb.stat_ack);
e100_start_receiver(nic, nic->rx_to_clean);
if(work_done)
(*work_done)++;
@@ -2774,7 +2774,7 @@
struct nic *nic = netdev_priv(netdev);
unregister_netdev(netdev);
e100_free(nic);
- iounmap(nic->csr);
+ pci_iounmap(pdev, nic->csr);
free_netdev(netdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -2858,17 +2858,17 @@
/**
* e100_io_error_detected - called when PCI error is detected.
* @pdev: Pointer to PCI device
- * @state: The current pci conneection state
+ * @state: The current pci connection state
*/
static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct nic *nic = netdev_priv(netdev);
- /* Similar to calling e100_down(), but avoids adpater I/O. */
+ /* Similar to calling e100_down(), but avoids adapter I/O. */
netdev->stop(netdev);
- /* Detach; put netif into state similar to hotplug unplug. */
+ /* Detach; put netif into a state similar to hotplug unplug. */
napi_enable(&nic->napi);
netif_device_detach(netdev);
pci_disable_device(pdev);
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 8c87940..7c5b05a 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -853,7 +853,7 @@
/**
* Dump the eeprom for users having checksum issues
**/
-void e1000_dump_eeprom(struct e1000_adapter *adapter)
+static void e1000_dump_eeprom(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct ethtool_eeprom eeprom;
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index f2175ea..6232c3e 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -63,6 +63,7 @@
#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */
/* Extended Device Control */
#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 6d9c27f..f77a742 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -690,8 +690,8 @@
return err;
}
-bool reg_pattern_test_array(struct e1000_adapter *adapter, u64 *data,
- int reg, int offset, u32 mask, u32 write)
+static bool reg_pattern_test_array(struct e1000_adapter *adapter, u64 *data,
+ int reg, int offset, u32 mask, u32 write)
{
int i;
u32 read;
@@ -1632,7 +1632,8 @@
return;
wol->supported = WAKE_UCAST | WAKE_MCAST |
- WAKE_BCAST | WAKE_MAGIC;
+ WAKE_BCAST | WAKE_MAGIC |
+ WAKE_PHY | WAKE_ARP;
/* apply any specific unsupported masks here */
if (adapter->flags & FLAG_NO_WAKE_UCAST) {
@@ -1651,6 +1652,10 @@
wol->wolopts |= WAKE_BCAST;
if (adapter->wol & E1000_WUFC_MAG)
wol->wolopts |= WAKE_MAGIC;
+ if (adapter->wol & E1000_WUFC_LNKC)
+ wol->wolopts |= WAKE_PHY;
+ if (adapter->wol & E1000_WUFC_ARP)
+ wol->wolopts |= WAKE_ARP;
}
static int e1000_set_wol(struct net_device *netdev,
@@ -1658,7 +1663,7 @@
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ if (wol->wolopts & WAKE_MAGICSECURE)
return -EOPNOTSUPP;
if (!(adapter->flags & FLAG_HAS_WOL))
@@ -1675,6 +1680,10 @@
adapter->wol |= E1000_WUFC_BC;
if (wol->wolopts & WAKE_MAGIC)
adapter->wol |= E1000_WUFC_MAG;
+ if (wol->wolopts & WAKE_PHY)
+ adapter->wol |= E1000_WUFC_LNKC;
+ if (wol->wolopts & WAKE_ARP)
+ adapter->wol |= E1000_WUFC_ARP;
return 0;
}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 0a2cb79..f58f017 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -945,11 +945,7 @@
int irq_flags = IRQF_SHARED;
int err;
- err = pci_enable_msi(adapter->pdev);
- if (err) {
- ndev_warn(netdev,
- "Unable to allocate MSI interrupt Error: %d\n", err);
- } else {
+ if (!pci_enable_msi(adapter->pdev)) {
adapter->flags |= FLAG_MSI_ENABLED;
handler = e1000_intr_msi;
irq_flags = 0;
@@ -958,10 +954,12 @@
err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
netdev);
if (err) {
+ ndev_err(netdev,
+ "Unable to allocate %s interrupt (return: %d)\n",
+ adapter->flags & FLAG_MSI_ENABLED ? "MSI":"INTx",
+ err);
if (adapter->flags & FLAG_MSI_ENABLED)
pci_disable_msi(adapter->pdev);
- ndev_err(netdev,
- "Unable to allocate interrupt Error: %d\n", err);
}
return err;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index d5459a8..2eb82ab 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -9,7 +9,7 @@
* Many modifications, and currently maintained, by
* Philip Blundell <philb@gnu.org>
* Added the Compaq LTE Alan Cox <alan@redhat.com>
- * Added MCA support Adam Fritzler <mid@auk.cx>
+ * Added MCA support Adam Fritzler
*
* Note - this driver is experimental still - it has problems on faster
* machines. Someone needs to sit down and go through it line by line with
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 5f82a46..88fb53e 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -458,4 +458,7 @@
int ehea_sense_port_attr(struct ehea_port *port);
int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
+extern u64 ehea_driver_flags;
+extern struct work_struct ehea_rereg_mr_task;
+
#endif /* __EHEA_H__ */
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index 679f40e..d768852 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -40,7 +40,7 @@
return ret;
if (netif_carrier_ok(dev)) {
- switch(port->port_speed) {
+ switch (port->port_speed) {
case EHEA_SPEED_10M: cmd->speed = SPEED_10; break;
case EHEA_SPEED_100M: cmd->speed = SPEED_100; break;
case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break;
@@ -78,7 +78,7 @@
goto doit;
}
- switch(cmd->speed) {
+ switch (cmd->speed) {
case SPEED_10:
if (cmd->duplex == DUPLEX_FULL)
sp = H_SPEED_10M_F;
diff --git a/drivers/net/ehea/ehea_hw.h b/drivers/net/ehea/ehea_hw.h
index 1af7ca4..567981b 100644
--- a/drivers/net/ehea/ehea_hw.h
+++ b/drivers/net/ehea/ehea_hw.h
@@ -29,10 +29,10 @@
#ifndef __EHEA_HW_H__
#define __EHEA_HW_H__
-#define QPX_SQA_VALUE EHEA_BMASK_IBM(48,63)
-#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48,63)
-#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48,63)
-#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_SQA_VALUE EHEA_BMASK_IBM(48, 63)
+#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48, 63)
+#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48, 63)
+#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48, 63)
#define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 869e160..c051c7e 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -6,9 +6,9 @@
* (C) Copyright IBM Corp. 2006
*
* Authors:
- * Christoph Raisch <raisch@de.ibm.com>
- * Jan-Bernd Themann <themann@de.ibm.com>
- * Thomas Klein <tklein@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -54,11 +54,11 @@
static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
-static int use_mcs = 0;
-static int use_lro = 0;
+static int use_mcs;
+static int use_lro;
static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
static int num_tx_qps = EHEA_NUM_TX_QP;
-static int prop_carrier_state = 0;
+static int prop_carrier_state;
module_param(msg_level, int, 0);
module_param(rq1_entries, int, 0);
@@ -94,9 +94,9 @@
MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
"Default = 0");
-static int port_name_cnt = 0;
+static int port_name_cnt;
static LIST_HEAD(adapter_list);
-u64 ehea_driver_flags = 0;
+u64 ehea_driver_flags;
struct work_struct ehea_rereg_mr_task;
struct semaphore dlpar_mem_lock;
@@ -121,12 +121,13 @@
.remove = ehea_remove,
};
-void ehea_dump(void *adr, int len, char *msg) {
+void ehea_dump(void *adr, int len, char *msg)
+{
int x;
unsigned char *deb = adr;
for (x = 0; x < len; x += 16) {
printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg,
- deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
+ deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
deb += 16;
}
}
@@ -518,7 +519,8 @@
last_wqe_index = wqe_index;
rmb();
if (!ehea_check_cqe(cqe, &rq)) {
- if (rq == 1) { /* LL RQ1 */
+ if (rq == 1) {
+ /* LL RQ1 */
skb = get_skb_by_index_ll(skb_arr_rq1,
skb_arr_rq1_len,
wqe_index);
@@ -531,10 +533,11 @@
if (!skb)
break;
}
- skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
+ skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
cqe->num_bytes_transfered - 4);
ehea_fill_skb(dev, skb, cqe);
- } else if (rq == 2) { /* RQ2 */
+ } else if (rq == 2) {
+ /* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
skb_arr_rq2_len, cqe);
if (unlikely(!skb)) {
@@ -544,7 +547,8 @@
}
ehea_fill_skb(dev, skb, cqe);
processed_rq2++;
- } else { /* RQ3 */
+ } else {
+ /* RQ3 */
skb = get_skb_by_index(skb_arr_rq3,
skb_arr_rq3_len, cqe);
if (unlikely(!skb)) {
@@ -592,7 +596,7 @@
unsigned long flags;
cqe = ehea_poll_cq(send_cq);
- while(cqe && (quota > 0)) {
+ while (cqe && (quota > 0)) {
ehea_inc_cq(send_cq);
cqe_counter++;
@@ -643,7 +647,8 @@
static int ehea_poll(struct napi_struct *napi, int budget)
{
- struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi);
+ struct ehea_port_res *pr = container_of(napi, struct ehea_port_res,
+ napi);
struct net_device *dev = pr->port->netdev;
struct ehea_cqe *cqe;
struct ehea_cqe *cqe_skb = NULL;
@@ -743,8 +748,9 @@
u64 hret;
struct hcp_ehea_port_cb0 *cb0;
- cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC); /* May be called via */
- if (!cb0) { /* ehea_neq_tasklet() */
+ /* may be called via ehea_neq_tasklet() */
+ cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+ if (!cb0) {
ehea_error("no mem for cb0");
ret = -ENOMEM;
goto out;
@@ -762,7 +768,7 @@
/* MAC address */
port->mac_addr = cb0->port_mac_addr << 16;
- if (!is_valid_ether_addr((u8*)&port->mac_addr)) {
+ if (!is_valid_ether_addr((u8 *)&port->mac_addr)) {
ret = -EADDRNOTAVAIL;
goto out_free;
}
@@ -994,7 +1000,7 @@
static void ehea_neq_tasklet(unsigned long data)
{
- struct ehea_adapter *adapter = (struct ehea_adapter*)data;
+ struct ehea_adapter *adapter = (struct ehea_adapter *)data;
struct ehea_eqe *eqe;
u64 event_mask;
@@ -1204,7 +1210,7 @@
static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
{
- int arr_size = sizeof(void*) * max_q_entries;
+ int arr_size = sizeof(void *) * max_q_entries;
q_skba->arr = vmalloc(arr_size);
if (!q_skba->arr)
@@ -1489,7 +1495,7 @@
nfrags = skb_shinfo(skb)->nr_frags;
sg1entry = &swqe->u.immdata_desc.sg_entry;
- sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
+ sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list;
swqe->descriptors = 0;
sg1entry_contains_frag_data = 0;
@@ -1542,7 +1548,7 @@
reg_type, port->mac_addr, 0, hcallid);
if (hret != H_SUCCESS) {
ehea_error("%sregistering bc address failed (tagged)",
- hcallid == H_REG_BCMC ? "" : "de");
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
goto out_herr;
}
@@ -1732,7 +1738,7 @@
}
}
-static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
+static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
{
struct ehea_mc_list *ehea_mcl_entry;
u64 hret;
@@ -1791,11 +1797,10 @@
goto out;
}
- for (i = 0, k_mcl_entry = dev->mc_list;
- i < dev->mc_count;
- i++, k_mcl_entry = k_mcl_entry->next) {
+ for (i = 0, k_mcl_entry = dev->mc_list; i < dev->mc_count; i++,
+ k_mcl_entry = k_mcl_entry->next)
ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr);
- }
+
}
out:
return;
@@ -1925,12 +1930,12 @@
if ((skb->protocol == htons(ETH_P_IP)) &&
(ip_hdr(skb)->protocol == IPPROTO_TCP)) {
- tcp = (struct tcphdr*)(skb_network_header(skb) + (ip_hdr(skb)->ihl * 4));
+ tcp = (struct tcphdr *)(skb_network_header(skb) +
+ (ip_hdr(skb)->ihl * 4));
tmp = (tcp->source + (tcp->dest << 16)) % 31;
tmp += ip_hdr(skb)->daddr % 31;
return tmp % num_qps;
- }
- else
+ } else
return 0;
}
@@ -2122,7 +2127,7 @@
u64 hret;
u16 dummy16 = 0;
u64 dummy64 = 0;
- struct hcp_modify_qp_cb0* cb0;
+ struct hcp_modify_qp_cb0 *cb0;
cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb0) {
@@ -2248,7 +2253,7 @@
int ret = 0;
int i;
- for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
ret |= ehea_clean_portres(port, &port->port_res[i]);
ret |= ehea_destroy_eq(port->qp_eq);
@@ -2300,7 +2305,7 @@
goto out_clean_pr;
}
- for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
if (ret) {
ehea_error("activate_qp failed");
@@ -2308,7 +2313,7 @@
}
}
- for(i = 0; i < port->num_def_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
ret = ehea_fill_port_res(&port->port_res[i]);
if (ret) {
ehea_error("out_free_irqs");
@@ -2425,7 +2430,7 @@
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
- struct hcp_modify_qp_cb0* cb0;
+ struct hcp_modify_qp_cb0 *cb0;
int ret = -EIO;
int dret;
int i;
@@ -2490,7 +2495,7 @@
return ret;
}
-void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr)
+void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
{
struct ehea_qp qp = *orig_qp;
struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2530,7 +2535,7 @@
int ret = 0;
int i;
- struct hcp_modify_qp_cb0* cb0;
+ struct hcp_modify_qp_cb0 *cb0;
u64 hret;
u64 dummy64 = 0;
u16 dummy16 = 0;
@@ -2804,34 +2809,6 @@
of_node_put(port->ofdev.node);
}
-static int ehea_driver_sysfs_add(struct device *dev,
- struct device_driver *driver)
-{
- int ret;
-
- ret = sysfs_create_link(&driver->kobj, &dev->kobj,
- kobject_name(&dev->kobj));
- if (ret == 0) {
- ret = sysfs_create_link(&dev->kobj, &driver->kobj,
- "driver");
- if (ret)
- sysfs_remove_link(&driver->kobj,
- kobject_name(&dev->kobj));
- }
- return ret;
-}
-
-static void ehea_driver_sysfs_remove(struct device *dev,
- struct device_driver *driver)
-{
- struct device_driver *drv = driver;
-
- if (drv) {
- sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
- sysfs_remove_link(&dev->kobj, "driver");
- }
-}
-
static struct device *ehea_register_port(struct ehea_port *port,
struct device_node *dn)
{
@@ -2856,16 +2833,8 @@
goto out_unreg_of_dev;
}
- ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver);
- if (ret) {
- ehea_error("failed to register sysfs driver link");
- goto out_rem_dev_file;
- }
-
return &port->ofdev.dev;
-out_rem_dev_file:
- device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
out_unreg_of_dev:
of_device_unregister(&port->ofdev);
out:
@@ -2874,7 +2843,6 @@
static void ehea_unregister_port(struct ehea_port *port)
{
- ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver);
device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
of_device_unregister(&port->ofdev);
}
@@ -3109,7 +3077,7 @@
of_node_put(eth_dn);
if (port) {
- for (i=0; i < EHEA_MAX_PORTS; i++)
+ for (i = 0; i < EHEA_MAX_PORTS; i++)
if (!adapter->port[i]) {
adapter->port[i] = port;
break;
@@ -3144,7 +3112,7 @@
ehea_shutdown_single_port(port);
- for (i=0; i < EHEA_MAX_PORTS; i++)
+ for (i = 0; i < EHEA_MAX_PORTS; i++)
if (adapter->port[i] == port) {
adapter->port[i] = NULL;
break;
@@ -3313,7 +3281,7 @@
}
static struct notifier_block ehea_reboot_nb = {
- .notifier_call = ehea_reboot_notifier,
+ .notifier_call = ehea_reboot_notifier,
};
static int check_module_parm(void)
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 95c4a7f..156eb63 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -6,9 +6,9 @@
* (C) Copyright IBM Corp. 2006
*
* Authors:
- * Christoph Raisch <raisch@de.ibm.com>
- * Jan-Bernd Themann <themann@de.ibm.com>
- * Thomas Klein <tklein@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -38,11 +38,11 @@
}
/* Defines for H_CALL H_ALLOC_RESOURCE */
-#define H_ALL_RES_TYPE_QP 1
-#define H_ALL_RES_TYPE_CQ 2
-#define H_ALL_RES_TYPE_EQ 3
-#define H_ALL_RES_TYPE_MR 5
-#define H_ALL_RES_TYPE_MW 6
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
static long ehea_plpar_hcall_norets(unsigned long opcode,
unsigned long arg1,
@@ -137,77 +137,77 @@
const u64 qp_handle, const u64 sel_mask, void *cb_addr)
{
return ehea_plpar_hcall_norets(H_QUERY_HEA_QP,
- adapter_handle, /* R4 */
- qp_category, /* R5 */
- qp_handle, /* R6 */
- sel_mask, /* R7 */
+ adapter_handle, /* R4 */
+ qp_category, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
virt_to_abs(cb_addr), /* R8 */
0, 0);
}
/* input param R5 */
-#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
-#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
-#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
-#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
-#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
-#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
-#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
-#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
-#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
-#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
+#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
+#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
+#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
+#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
+#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
/* input param R9 */
-#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32,63)
+#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32, 63)
/* input param R10 */
-#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
-#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
-#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
-#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
+#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
+#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
+#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
+#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
/* Max Send Scatter Gather Elements */
-#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
-#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
+#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
+#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
/* Max Receive SG Elements RQ1 */
-#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
-#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
+#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
+#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
/* input param R11 */
-#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
/* max swqe immediate data length */
-#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
+#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
/* input param R12 */
-#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
/* Threshold RQ2 */
-#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
/* Threshold RQ3 */
/* output param R6 */
-#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
-#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
-#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
-#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
+#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
+#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
/* output param, R7 */
-#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
-#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
-#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
-#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
+#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
+#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
/* output param R8,R9 */
-#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
-#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
/* output param R11,R12 */
-#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
-#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
struct ehea_qp_init_attr *init_attr, const u32 pd,
@@ -334,28 +334,28 @@
}
/* Defines for H_CALL H_ALLOC_RESOURCE */
-#define H_ALL_RES_TYPE_QP 1
-#define H_ALL_RES_TYPE_CQ 2
-#define H_ALL_RES_TYPE_EQ 3
-#define H_ALL_RES_TYPE_MR 5
-#define H_ALL_RES_TYPE_MW 6
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
/* input param R5 */
-#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
+#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
#define H_ALL_RES_EQ_NON_NEQ_ISN EHEA_BMASK_IBM(6, 7)
#define H_ALL_RES_EQ_INH_EQE_GEN EHEA_BMASK_IBM(16, 16)
-#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
+#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
/* input param R6 */
-#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
/* output param R6 */
-#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
/* output param R7 */
-#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
/* output param R8 */
-#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
/* output param R9 */
#define H_ALL_RES_EQ_ACT_EQ_IST_C EHEA_BMASK_IBM(30, 31)
@@ -453,12 +453,12 @@
hret = ehea_plpar_hcall9(H_REGISTER_SMR,
outs,
- adapter_handle , /* R4 */
- orig_mr_handle, /* R5 */
- vaddr_in, /* R6 */
- (((u64)access_ctrl) << 32ULL), /* R7 */
- pd, /* R8 */
- 0, 0, 0, 0); /* R9-R12 */
+ adapter_handle , /* R4 */
+ orig_mr_handle, /* R5 */
+ vaddr_in, /* R6 */
+ (((u64)access_ctrl) << 32ULL), /* R7 */
+ pd, /* R8 */
+ 0, 0, 0, 0); /* R9-R12 */
mr->handle = outs[0];
mr->lkey = (u32)outs[2];
@@ -471,11 +471,11 @@
u64 outs[PLPAR_HCALL9_BUFSIZE];
return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA,
- outs,
+ outs,
adapter_handle, /* R4 */
H_DISABLE_GET_EHEA_WQE_P, /* R5 */
qp_handle, /* R6 */
- 0, 0, 0, 0, 0, 0); /* R7-R12 */
+ 0, 0, 0, 0, 0, 0); /* R7-R12 */
}
u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
@@ -483,9 +483,9 @@
{
return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle, /* R4 */
- res_handle, /* R5 */
+ res_handle, /* R5 */
force_bit,
- 0, 0, 0, 0); /* R7-R10 */
+ 0, 0, 0, 0); /* R7-R10 */
}
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
@@ -493,13 +493,13 @@
const u32 pd, u64 *mr_handle, u32 *lkey)
{
u64 hret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
outs,
adapter_handle, /* R4 */
5, /* R5 */
- vaddr, /* R6 */
+ vaddr, /* R6 */
length, /* R7 */
(((u64) access_ctrl) << 32ULL), /* R8 */
pd, /* R9 */
@@ -619,8 +619,8 @@
void *rblock)
{
return ehea_plpar_hcall_norets(H_ERROR_DATA,
- adapter_handle, /* R4 */
- ressource_handle, /* R5 */
- virt_to_abs(rblock), /* R6 */
- 0, 0, 0, 0); /* R7-R12 */
+ adapter_handle, /* R4 */
+ ressource_handle, /* R5 */
+ virt_to_abs(rblock), /* R6 */
+ 0, 0, 0, 0); /* R7-R12 */
}
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index faa191d..f3628c8 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -93,7 +93,7 @@
static inline void hcp_epas_dtor(struct h_epas *epas)
{
if (epas->kernel.addr)
- iounmap((void __iomem*)((u64)epas->kernel.addr & PAGE_MASK));
+ iounmap((void __iomem *)((u64)epas->kernel.addr & PAGE_MASK));
epas->user.addr = 0;
epas->kernel.addr = 0;
@@ -388,23 +388,23 @@
const u64 qp_handle,
const u64 sel_mask,
void *cb_addr,
- u64 * inv_attr_id,
- u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
+ u64 *inv_attr_id,
+ u64 *proc_mask, u16 *out_swr, u16 *out_rwr);
u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
- struct ehea_eq_attr *eq_attr, u64 * eq_handle);
+ struct ehea_eq_attr *eq_attr, u64 *eq_handle);
u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
struct ehea_cq_attr *cq_attr,
- u64 * cq_handle, struct h_epas *epas);
+ u64 *cq_handle, struct h_epas *epas);
u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
struct ehea_qp_init_attr *init_attr,
const u32 pd,
- u64 * qp_handle, struct h_epas *h_epas);
+ u64 *qp_handle, struct h_epas *h_epas);
-#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48,55)
-#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62,63)
+#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48, 55)
+#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62, 63)
u64 ehea_h_register_rpage(const u64 adapter_handle,
const u8 pagesize,
@@ -426,7 +426,7 @@
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
const u64 length, const u32 access_ctrl,
- const u32 pd, u64 * mr_handle, u32 * lkey);
+ const u32 pd, u64 *mr_handle, u32 *lkey);
u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
const u8 pagesize, const u8 queue_type,
@@ -439,8 +439,8 @@
u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr);
/* output param R5 */
-#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40,47)
-#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48,63)
+#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40, 47)
+#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48, 63)
u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
const u8 cb_cat, const u64 select_mask,
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 83b7643..d522e90 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -33,8 +33,6 @@
struct ehea_busmap ehea_bmap = { 0, 0, NULL };
-extern u64 ehea_driver_flags;
-extern struct work_struct ehea_rereg_mr_task;
static void *hw_qpageit_get_inc(struct hw_queue *queue)
@@ -65,7 +63,7 @@
}
queue->queue_length = nr_of_pages * pagesize;
- queue->queue_pages = kmalloc(nr_of_pages * sizeof(void*), GFP_KERNEL);
+ queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
if (!queue->queue_pages) {
ehea_error("no mem for queue_pages");
return -ENOMEM;
@@ -78,11 +76,11 @@
*/
i = 0;
while (i < nr_of_pages) {
- u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+ u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
if (!kpage)
goto out_nomem;
for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
- (queue->queue_pages)[i] = (struct ehea_page*)kpage;
+ (queue->queue_pages)[i] = (struct ehea_page *)kpage;
kpage += pagesize;
i++;
}
@@ -235,8 +233,8 @@
return 0;
hcp_epas_dtor(&cq->epas);
-
- if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
+ hret = ehea_destroy_cq_res(cq, NORMAL_FREE);
+ if (hret == H_R_STATE) {
ehea_error_data(cq->adapter, cq->fw_handle);
hret = ehea_destroy_cq_res(cq, FORCE_FREE);
}
@@ -301,13 +299,13 @@
if (i == (eq->attr.nr_pages - 1)) {
/* last page */
vpage = hw_qpageit_get_inc(&eq->hw_queue);
- if ((hret != H_SUCCESS) || (vpage)) {
+ if ((hret != H_SUCCESS) || (vpage))
goto out_kill_hwq;
- }
+
} else {
- if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+ if ((hret != H_PAGE_REGISTERED) || (!vpage))
goto out_kill_hwq;
- }
+
}
}
@@ -331,7 +329,7 @@
unsigned long flags;
spin_lock_irqsave(&eq->spinlock, flags);
- eqe = (struct ehea_eqe*)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
+ eqe = (struct ehea_eqe *)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
spin_unlock_irqrestore(&eq->spinlock, flags);
return eqe;
@@ -364,7 +362,8 @@
hcp_epas_dtor(&eq->epas);
- if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
+ hret = ehea_destroy_eq_res(eq, NORMAL_FREE);
+ if (hret == H_R_STATE) {
ehea_error_data(eq->adapter, eq->fw_handle);
hret = ehea_destroy_eq_res(eq, FORCE_FREE);
}
@@ -546,7 +545,8 @@
hcp_epas_dtor(&qp->epas);
- if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+ hret = ehea_destroy_qp_res(qp, NORMAL_FREE);
+ if (hret == H_R_STATE) {
ehea_error_data(qp->adapter, qp->fw_handle);
hret = ehea_destroy_qp_res(qp, FORCE_FREE);
}
@@ -559,7 +559,7 @@
return 0;
}
-int ehea_create_busmap( void )
+int ehea_create_busmap(void)
{
u64 vaddr = EHEA_BUSMAP_START;
unsigned long high_section_index = 0;
@@ -595,7 +595,7 @@
return 0;
}
-void ehea_destroy_busmap( void )
+void ehea_destroy_busmap(void)
{
vfree(ehea_bmap.vaddr);
}
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index bc62d38..0bb6f92 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -41,8 +41,8 @@
#define EHEA_SECTSIZE (1UL << 24)
#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT)
-#if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
-#error eHEA module can't work if kernel sectionsize < ehea sectionsize
+#if ((1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE)
+#error eHEA module cannot work if kernel sectionsize < ehea sectionsize
#endif
/* Some abbreviations used here:
@@ -188,8 +188,8 @@
u64 entry;
};
-#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0,7)
+#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0, 7)
static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
{
@@ -279,7 +279,7 @@
static inline void *hw_eqit_eq_get_inc_valid(struct hw_queue *queue)
{
void *retvalue = hw_qeit_get(queue);
- u32 qe = *(u8*)retvalue;
+ u32 qe = *(u8 *)retvalue;
if ((qe >> 7) == (queue->toggle_state & 1))
hw_qeit_eq_get_inc(queue);
else
@@ -364,7 +364,7 @@
int ehea_destroy_cq(struct ehea_cq *cq);
-struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
+struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter, u32 pd,
struct ehea_qp_init_attr *init_attr);
int ehea_destroy_qp(struct ehea_qp *qp);
@@ -378,8 +378,8 @@
void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
-int ehea_create_busmap( void );
-void ehea_destroy_busmap( void );
+int ehea_create_busmap(void);
+void ehea_destroy_busmap(void);
u64 ehea_map_vaddr(void *caddr);
#endif /* __EHEA_QMR_H__ */
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 7667a62..d4843d0 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -13,7 +13,7 @@
* Copyright (C) 2004 Andrew de Quincey (wol support)
* Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
* IRQ rate fixes, bigendian fixes, cleanups, verification)
- * Copyright (c) 2004,5,6 NVIDIA Corporation
+ * Copyright (c) 2004,2005,2006,2007,2008 NVIDIA Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -226,7 +226,7 @@
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
- NvRegMacReset = 0x3c,
+ NvRegMacReset = 0x34,
#define NVREG_MAC_RESET_ASSERT 0x0F3
NvRegTransmitterControl = 0x084,
#define NVREG_XMITCTL_START 0x01
@@ -277,7 +277,9 @@
#define NVREG_MCASTADDRA_FORCE 0x01
NvRegMulticastAddrB = 0xB4,
NvRegMulticastMaskA = 0xB8,
+#define NVREG_MCASTMASKA_NONE 0xffffffff
NvRegMulticastMaskB = 0xBC,
+#define NVREG_MCASTMASKB_NONE 0xffff
NvRegPhyInterface = 0xC0,
#define PHY_RGMII 0x10000000
@@ -316,13 +318,13 @@
NvRegTxRingPhysAddrHigh = 0x148,
NvRegRxRingPhysAddrHigh = 0x14C,
NvRegTxPauseFrame = 0x170,
-#define NVREG_TX_PAUSEFRAME_DISABLE 0x1ff0080
-#define NVREG_TX_PAUSEFRAME_ENABLE 0x0c00030
+#define NVREG_TX_PAUSEFRAME_DISABLE 0x01ff0080
+#define NVREG_TX_PAUSEFRAME_ENABLE 0x01800010
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
-#define NVREG_MIISTAT_MASK 0x000f
-#define NVREG_MIISTAT_MASK2 0x000f
+#define NVREG_MIISTAT_MASK_RW 0x0007
+#define NVREG_MIISTAT_MASK_ALL 0x000f
NvRegMIIMask = 0x184,
#define NVREG_MII_LINKCHANGE 0x0008
@@ -471,9 +473,9 @@
#define NV_RX_AVAIL (1<<31)
#define NV_RX2_CHECKSUMMASK (0x1C000000)
-#define NV_RX2_CHECKSUMOK1 (0x10000000)
-#define NV_RX2_CHECKSUMOK2 (0x14000000)
-#define NV_RX2_CHECKSUMOK3 (0x18000000)
+#define NV_RX2_CHECKSUM_IP (0x10000000)
+#define NV_RX2_CHECKSUM_IP_TCP (0x14000000)
+#define NV_RX2_CHECKSUM_IP_UDP (0x18000000)
#define NV_RX2_DESCRIPTORVALID (1<<29)
#define NV_RX2_SUBSTRACT1 (1<<25)
#define NV_RX2_ERROR1 (1<<18)
@@ -622,6 +624,9 @@
#define NV_MSI_X_VECTOR_TX 0x1
#define NV_MSI_X_VECTOR_OTHER 0x2
+#define NV_RESTART_TX 0x1
+#define NV_RESTART_RX 0x2
+
/* statistics */
struct nv_ethtool_str {
char name[ETH_GSTRING_LEN];
@@ -1059,7 +1064,7 @@
u32 reg;
int retval;
- writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK_RW, base + NvRegMIIStatus);
reg = readl(base + NvRegMIIControl);
if (reg & NVREG_MIICTL_INUSE) {
@@ -1430,16 +1435,30 @@
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
+ u32 temp1, temp2, temp3;
dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
+
writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
+
+ /* save registers since they will be cleared on reset */
+ temp1 = readl(base + NvRegMacAddrA);
+ temp2 = readl(base + NvRegMacAddrB);
+ temp3 = readl(base + NvRegTransmitPoll);
+
writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
pci_push(base);
udelay(NV_MAC_RESET_DELAY);
writel(0, base + NvRegMacReset);
pci_push(base);
udelay(NV_MAC_RESET_DELAY);
+
+ /* restore saved registers */
+ writel(temp1, base + NvRegMacAddrA);
+ writel(temp2, base + NvRegMacAddrB);
+ writel(temp3, base + NvRegTransmitPoll);
+
writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
}
@@ -2375,14 +2394,9 @@
goto next_pkt;
}
}
- if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ if (((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_TCP) || /*ip and tcp */
+ ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_UDP)) /*ip and udp */
skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
- (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
- }
} else {
dev_kfree_skb(skb);
goto next_pkt;
@@ -2474,14 +2488,9 @@
}
}
- if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ if (((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_TCP) || /*ip and tcp */
+ ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_UDP)) /*ip and udp */
skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
- (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
- }
/* got a valid packet - forward it to the network core */
skb_put(skb, len);
@@ -2703,6 +2712,9 @@
addr[1] = alwaysOn[1];
mask[0] = alwaysOn[0] | alwaysOff[0];
mask[1] = alwaysOn[1] | alwaysOff[1];
+ } else {
+ mask[0] = NVREG_MCASTMASKA_NONE;
+ mask[1] = NVREG_MCASTMASKB_NONE;
}
}
addr[0] |= NVREG_MCASTADDRA_FORCE;
@@ -2772,6 +2784,7 @@
int mii_status;
int retval = 0;
u32 control_1000, status_1000, phyreg, pause_flags, txreg;
+ u32 txrxFlags = 0;
/* BMSR_LSTATUS is latched, read it twice:
* we want the current value.
@@ -2867,6 +2880,16 @@
np->duplex = newdup;
np->linkspeed = newls;
+ /* The transmitter and receiver must be restarted for safe update */
+ if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START) {
+ txrxFlags |= NV_RESTART_TX;
+ nv_stop_tx(dev);
+ }
+ if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
+ txrxFlags |= NV_RESTART_RX;
+ nv_stop_rx(dev);
+ }
+
if (np->gigabit == PHY_GIGABIT) {
phyreg = readl(base + NvRegRandomSeed);
phyreg &= ~(0x3FF00);
@@ -2955,6 +2978,11 @@
}
nv_update_pause(dev, pause_flags);
+ if (txrxFlags & NV_RESTART_TX)
+ nv_start_tx(dev);
+ if (txrxFlags & NV_RESTART_RX)
+ nv_start_rx(dev);
+
return retval;
}
@@ -2981,7 +3009,7 @@
u32 miistat;
miistat = readl(base + NvRegMIIStatus);
- writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_LINKCHANGE, base + NvRegMIIStatus);
dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat);
if (miistat & (NVREG_MIISTAT_LINKCHANGE))
@@ -4813,8 +4841,8 @@
nv_mac_reset(dev);
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
- writel(0, base + NvRegMulticastMaskA);
- writel(0, base + NvRegMulticastMaskB);
+ writel(NVREG_MCASTMASKA_NONE, base + NvRegMulticastMaskA);
+ writel(NVREG_MCASTMASKB_NONE, base + NvRegMulticastMaskB);
writel(0, base + NvRegPacketFilterFlags);
writel(0, base + NvRegTransmitterControl);
@@ -4856,7 +4884,7 @@
writel(0, base + NvRegMIIMask);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
- writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
@@ -4894,7 +4922,7 @@
nv_disable_hw_interrupts(dev, np->irqmask);
pci_push(base);
- writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
@@ -4908,8 +4936,8 @@
spin_lock_irq(&np->lock);
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
- writel(0, base + NvRegMulticastMaskA);
- writel(0, base + NvRegMulticastMaskB);
+ writel(NVREG_MCASTMASKA_NONE, base + NvRegMulticastMaskA);
+ writel(NVREG_MCASTMASKB_NONE, base + NvRegMulticastMaskB);
writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
/* One manual link speed update: Interrupts are enabled, future link
* speed changes cause interrupts and are handled by nv_link_irq().
@@ -4917,7 +4945,7 @@
{
u32 miistat;
miistat = readl(base + NvRegMIIStatus);
- writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
}
/* set linkspeed to invalid value, thus force nv_update_linkspeed
@@ -5285,7 +5313,7 @@
phystate &= ~NVREG_ADAPTCTL_RUNNING;
writel(phystate, base + NvRegAdapterControl);
}
- writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
if (id->driver_data & DEV_HAS_MGMT_UNIT) {
/* management unit running on the mac? */
@@ -5603,35 +5631,35 @@
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
{0,},
};
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 100bf41..6a647d9 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -127,7 +127,7 @@
struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
- spin_lock_bh(&bus->mdio_lock);
+ mutex_lock(&bus->mdio_lock);
/* Reset the management interface */
gfar_write(®s->miimcfg, MIIMCFG_RESET);
@@ -140,7 +140,7 @@
timeout--)
cpu_relax();
- spin_unlock_bh(&bus->mdio_lock);
+ mutex_unlock(&bus->mdio_lock);
if(timeout <= 0) {
printk(KERN_ERR "%s: The MII Bus is stuck!\n",
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 11b83da..e04bf99 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -262,8 +262,8 @@
static int io[MAX_NUM_DEVS] __initdata = { 0, };
-/* Beware! hw[] is also used in cleanup_module(). */
-static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE;
+/* Beware! hw[] is also used in dmascc_exit(). */
+static struct scc_hardware hw[NUM_TYPES] = HARDWARE;
/* Global variables */
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 46e2c52..95e3464 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -901,12 +901,12 @@
0x0000
};
-static char *ibmlana_adapter_names[] __initdata = {
+static char *ibmlana_adapter_names[] __devinitdata = {
"IBM LAN Adapter/A",
NULL
};
-static int ibmlana_init_one(struct device *kdev)
+static int __devinit ibmlana_init_one(struct device *kdev)
{
struct mca_device *mdev = to_mca_device(kdev);
struct net_device *dev;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index f3c144d..d4eb8e2 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -438,7 +438,6 @@
if (adapter->msix_entries) {
err = igb_request_msix(adapter);
if (!err) {
- struct e1000_hw *hw = &adapter->hw;
/* enable IAM, auto-mask,
* DO NOT USE EIAME or IAME in legacy mode */
wr32(E1000_IAM, IMS_ENABLE_MASK);
diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h
index e489c66..0787657 100644
--- a/drivers/net/irda/ali-ircc.h
+++ b/drivers/net/irda/ali-ircc.h
@@ -173,13 +173,13 @@
struct frame_cb {
void *start; /* Start of frame in DMA mem */
- int len; /* Lenght of frame in DMA mem */
+ int len; /* Length of frame in DMA mem */
};
struct tx_fifo {
struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
int ptr; /* Currently being sent */
- int len; /* Lenght of queue */
+ int len; /* Length of queue */
int free; /* Next free slot */
void *tail; /* Next free start in DMA mem */
};
diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h
index bbdc97f..29398a4 100644
--- a/drivers/net/irda/nsc-ircc.h
+++ b/drivers/net/irda/nsc-ircc.h
@@ -231,13 +231,13 @@
struct frame_cb {
void *start; /* Start of frame in DMA mem */
- int len; /* Lenght of frame in DMA mem */
+ int len; /* Length of frame in DMA mem */
};
struct tx_fifo {
struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
int ptr; /* Currently being sent */
- int len; /* Lenght of queue */
+ int len; /* Length of queue */
int free; /* Next free slot */
void *tail; /* Next free start in DMA mem */
};
diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h
index 204b1b3..9d012f0 100644
--- a/drivers/net/irda/via-ircc.h
+++ b/drivers/net/irda/via-ircc.h
@@ -54,13 +54,13 @@
struct frame_cb {
void *start; /* Start of frame in DMA mem */
- int len; /* Lenght of frame in DMA mem */
+ int len; /* Length of frame in DMA mem */
};
struct tx_fifo {
struct frame_cb queue[MAX_TX_WINDOW + 2]; /* Info about frames in queue */
int ptr; /* Currently being sent */
- int len; /* Lenght of queue */
+ int len; /* Length of queue */
int free; /* Next free slot */
void *tail; /* Next free start in DMA mem */
};
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 419861c..58d3bb6 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1020,7 +1020,7 @@
.get_link = veth_get_link,
};
-static struct net_device * __init veth_probe_one(int vlan,
+static struct net_device *veth_probe_one(int vlan,
struct vio_dev *vio_dev)
{
struct net_device *dev;
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index a021a6e..d0bf206 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -136,8 +136,6 @@
u16 head;
u16 tail;
- /* To protect race between sender and clean_tx_irq */
- spinlock_t tx_lock;
struct ixgbe_queue_stats stats;
@@ -174,7 +172,6 @@
struct vlan_group *vlgrp;
u16 bd_number;
u16 rx_buf_len;
- atomic_t irq_sem;
struct work_struct reset_task;
/* TX */
@@ -244,6 +241,7 @@
extern int ixgbe_up(struct ixgbe_adapter *adapter);
extern void ixgbe_down(struct ixgbe_adapter *adapter);
+extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter);
extern void ixgbe_reset(struct ixgbe_adapter *adapter);
extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 3635344..a119cbd 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -103,21 +103,41 @@
struct ethtool_cmd *ecmd)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 link_speed = 0;
+ bool link_up;
- ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
- ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
- ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_10000baseT_Full;
+ ecmd->autoneg = AUTONEG_ENABLE;
ecmd->transceiver = XCVR_EXTERNAL;
+ if (hw->phy.media_type == ixgbe_media_type_copper) {
+ ecmd->supported |= (SUPPORTED_1000baseT_Full |
+ SUPPORTED_TP | SUPPORTED_Autoneg);
- if (netif_carrier_ok(adapter->netdev)) {
- ecmd->speed = SPEED_10000;
+ ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg);
+ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+ ecmd->advertising |= ADVERTISED_10000baseT_Full;
+ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
+ ecmd->advertising |= ADVERTISED_1000baseT_Full;
+
+ ecmd->port = PORT_TP;
+ } else {
+ ecmd->supported |= SUPPORTED_FIBRE;
+ ecmd->advertising = (ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE);
+ ecmd->port = PORT_FIBRE;
+ }
+
+ adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up);
+ if (link_up) {
+ ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+ SPEED_10000 : SPEED_1000;
ecmd->duplex = DUPLEX_FULL;
} else {
ecmd->speed = -1;
ecmd->duplex = -1;
}
- ecmd->autoneg = AUTONEG_DISABLE;
return 0;
}
@@ -125,17 +145,17 @@
struct ethtool_cmd *ecmd)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
- if (ecmd->autoneg == AUTONEG_ENABLE ||
- ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
- return -EINVAL;
-
- if (netif_running(adapter->netdev)) {
- ixgbe_down(adapter);
- ixgbe_reset(adapter);
- ixgbe_up(adapter);
- } else {
- ixgbe_reset(adapter);
+ switch (hw->phy.media_type) {
+ case ixgbe_media_type_fiber:
+ if ((ecmd->autoneg == AUTONEG_ENABLE) ||
+ (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
+ return -EINVAL;
+ /* in this case we currently only support 10Gb/FULL */
+ break;
+ default:
+ break;
}
return 0;
@@ -147,7 +167,7 @@
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- pause->autoneg = AUTONEG_DISABLE;
+ pause->autoneg = (hw->fc.type == ixgbe_fc_full ? 1 : 0);
if (hw->fc.type == ixgbe_fc_rx_pause) {
pause->rx_pause = 1;
@@ -165,10 +185,8 @@
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- if (pause->autoneg == AUTONEG_ENABLE)
- return -EINVAL;
-
- if (pause->rx_pause && pause->tx_pause)
+ if ((pause->autoneg == AUTONEG_ENABLE) ||
+ (pause->rx_pause && pause->tx_pause))
hw->fc.type = ixgbe_fc_full;
else if (pause->rx_pause && !pause->tx_pause)
hw->fc.type = ixgbe_fc_rx_pause;
@@ -176,15 +194,15 @@
hw->fc.type = ixgbe_fc_tx_pause;
else if (!pause->rx_pause && !pause->tx_pause)
hw->fc.type = ixgbe_fc_none;
+ else
+ return -EINVAL;
hw->fc.original_type = hw->fc.type;
- if (netif_running(adapter->netdev)) {
- ixgbe_down(adapter);
- ixgbe_up(adapter);
- } else {
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
+ else
ixgbe_reset(adapter);
- }
return 0;
}
@@ -203,12 +221,10 @@
else
adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
- if (netif_running(netdev)) {
- ixgbe_down(adapter);
- ixgbe_up(adapter);
- } else {
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
+ else
ixgbe_reset(adapter);
- }
return 0;
}
@@ -662,7 +678,10 @@
return 0;
}
- if (netif_running(adapter->netdev))
+ while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (netif_running(netdev))
ixgbe_down(adapter);
/*
@@ -733,6 +752,7 @@
if (netif_running(adapter->netdev))
ixgbe_up(adapter);
+ clear_bit(__IXGBE_RESETTING, &adapter->state);
return err;
}
@@ -820,11 +840,8 @@
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- if (netif_running(netdev)) {
- ixgbe_down(adapter);
- ixgbe_reset(adapter);
- ixgbe_up(adapter);
- }
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
return 0;
}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 3732dd6..ead49e5 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -87,6 +87,25 @@
#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
+{
+ u32 ctrl_ext;
+
+ /* Let firmware take over control of h/w */
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+ ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+}
+
+static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
+{
+ u32 ctrl_ext;
+
+ /* Let firmware know the driver has taken over */
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+ ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+}
#ifdef DEBUG
/**
@@ -165,6 +184,15 @@
return false;
}
+#define IXGBE_MAX_TXD_PWR 14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+ (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
+
/**
* ixgbe_clean_tx_irq - Reclaim resources after transmit completes
* @adapter: board private structure
@@ -177,18 +205,34 @@
struct ixgbe_tx_buffer *tx_buffer_info;
unsigned int i, eop;
bool cleaned = false;
- int count = 0;
+ unsigned int total_tx_bytes = 0, total_tx_packets = 0;
i = tx_ring->next_to_clean;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
- for (cleaned = false; !cleaned;) {
+ cleaned = false;
+ while (!cleaned) {
tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
tx_buffer_info = &tx_ring->tx_buffer_info[i];
cleaned = (i == eop);
tx_ring->stats.bytes += tx_buffer_info->length;
+ if (cleaned) {
+ struct sk_buff *skb = tx_buffer_info->skb;
+#ifdef NETIF_F_TSO
+ unsigned int segs, bytecount;
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
+ total_tx_packets += segs;
+ total_tx_bytes += bytecount;
+#else
+ total_tx_packets++;
+ total_tx_bytes += skb->len;
+#endif
+ }
ixgbe_unmap_and_free_tx_resource(adapter,
tx_buffer_info);
tx_desc->wb.status = 0;
@@ -204,29 +248,36 @@
eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
/* weight of a sort for tx, avoid endless transmit cleanup */
- if (count++ >= tx_ring->work_limit)
+ if (total_tx_packets >= tx_ring->work_limit)
break;
}
tx_ring->next_to_clean = i;
-#define TX_WAKE_THRESHOLD 32
- spin_lock(&tx_ring->tx_lock);
-
- if (cleaned && netif_carrier_ok(netdev) &&
- (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) &&
- !test_bit(__IXGBE_DOWN, &adapter->state))
- netif_wake_queue(netdev);
-
- spin_unlock(&tx_ring->tx_lock);
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+ if (total_tx_packets && netif_carrier_ok(netdev) &&
+ (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+ if (netif_queue_stopped(netdev) &&
+ !test_bit(__IXGBE_DOWN, &adapter->state)) {
+ netif_wake_queue(netdev);
+ adapter->restart_queue++;
+ }
+ }
if (adapter->detect_tx_hung)
if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
netif_stop_queue(netdev);
- if (count >= tx_ring->work_limit)
+ if (total_tx_packets >= tx_ring->work_limit)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
+ adapter->net_stats.tx_bytes += total_tx_bytes;
+ adapter->net_stats.tx_packets += total_tx_packets;
+ cleaned = total_tx_packets ? true : false;
return cleaned;
}
@@ -255,25 +306,40 @@
}
}
+/**
+ * ixgbe_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: address of board private structure
+ * @status_err: hardware indication of status of receive
+ * @skb: skb currently being received and modified
+ **/
static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
u32 status_err,
struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
- /* Ignore Checksum bit is set */
+ /* Ignore Checksum bit is set, or rx csum disabled */
if ((status_err & IXGBE_RXD_STAT_IXSM) ||
- !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+ !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
return;
- /* TCP/UDP checksum error bit is set */
- if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) {
- /* let the stack verify checksum errors */
+
+ /* if IP and error */
+ if ((status_err & IXGBE_RXD_STAT_IPCS) &&
+ (status_err & IXGBE_RXDADV_ERR_IPE)) {
adapter->hw_csum_rx_error++;
return;
}
+
+ if (!(status_err & IXGBE_RXD_STAT_L4CS))
+ return;
+
+ if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+ adapter->hw_csum_rx_error++;
+ return;
+ }
+
/* It must be a TCP or UDP packet with a valid checksum */
- if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS))
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
adapter->hw_csum_rx_good++;
}
@@ -379,6 +445,7 @@
u16 hdr_info, vlan_tag;
bool is_vlan, cleaned = false;
int cleaned_count = 0;
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
i = rx_ring->next_to_clean;
upper_len = 0;
@@ -458,6 +525,11 @@
}
ixgbe_rx_checksum(adapter, staterr, skb);
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
skb->protocol = eth_type_trans(skb, netdev);
ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
netdev->last_rx = jiffies;
@@ -486,6 +558,9 @@
if (cleaned_count)
ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+ adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
+
return cleaned;
}
@@ -535,7 +610,9 @@
if (!test_bit(__IXGBE_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer, jiffies);
}
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
return IRQ_HANDLED;
}
@@ -713,7 +790,6 @@
if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
/* Disable interrupts and register for poll. The flush of the
* posted write is intentionally left out. */
- atomic_inc(&adapter->irq_sem);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
__netif_rx_schedule(netdev, &adapter->napi);
}
@@ -801,7 +877,6 @@
**/
static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
{
- atomic_inc(&adapter->irq_sem);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
IXGBE_WRITE_FLUSH(&adapter->hw);
synchronize_irq(adapter->pdev->irq);
@@ -813,15 +888,13 @@
**/
static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
{
- if (atomic_dec_and_test(&adapter->irq_sem)) {
- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
- (IXGBE_EIMS_ENABLE_MASK &
- ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
- IXGBE_EIMS_ENABLE_MASK);
- IXGBE_WRITE_FLUSH(&adapter->hw);
- }
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
+ (IXGBE_EIMS_ENABLE_MASK &
+ ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+ IXGBE_EIMS_ENABLE_MASK);
+ IXGBE_WRITE_FLUSH(&adapter->hw);
}
/**
@@ -1040,7 +1113,8 @@
struct ixgbe_adapter *adapter = netdev_priv(netdev);
u32 ctrl;
- ixgbe_irq_disable(adapter);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_disable(adapter);
adapter->vlgrp = grp;
if (grp) {
@@ -1051,7 +1125,8 @@
IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
}
- ixgbe_irq_enable(adapter);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable(adapter);
}
static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -1066,9 +1141,13 @@
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- ixgbe_irq_disable(adapter);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_disable(adapter);
+
vlan_group_set_device(adapter->vlgrp, vid, NULL);
- ixgbe_irq_enable(adapter);
+
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable(adapter);
/* remove VID from filter table */
ixgbe_set_vfta(&adapter->hw, vid, 0, false);
@@ -1170,6 +1249,8 @@
u32 txdctl, rxdctl, mhadd;
int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ ixgbe_get_hw_control(adapter);
+
if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED |
IXGBE_FLAG_MSI_ENABLED)) {
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
@@ -1224,6 +1305,16 @@
return 0;
}
+void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
+{
+ WARN_ON(in_interrupt());
+ while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+ msleep(1);
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ clear_bit(__IXGBE_RESETTING, &adapter->state);
+}
+
int ixgbe_up(struct ixgbe_adapter *adapter)
{
/* hardware has been reset, we need to reload some things */
@@ -1408,7 +1499,6 @@
msleep(10);
napi_disable(&adapter->napi);
- atomic_set(&adapter->irq_sem, 0);
ixgbe_irq_disable(adapter);
@@ -1447,6 +1537,8 @@
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
+ ixgbe_release_hw_control(adapter);
+
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1481,7 +1573,8 @@
/* If budget not fully consumed, exit the polling mode */
if (work_done < budget) {
netif_rx_complete(netdev, napi);
- ixgbe_irq_enable(adapter);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable(adapter);
}
return work_done;
@@ -1506,8 +1599,7 @@
adapter->tx_timeout_count++;
- ixgbe_down(adapter);
- ixgbe_up(adapter);
+ ixgbe_reinit_locked(adapter);
}
/**
@@ -1590,7 +1682,6 @@
return -ENOMEM;
}
- atomic_set(&adapter->irq_sem, 1);
set_bit(__IXGBE_DOWN, &adapter->state);
return 0;
@@ -1634,7 +1725,6 @@
txdr->next_to_use = 0;
txdr->next_to_clean = 0;
txdr->work_limit = txdr->count;
- spin_lock_init(&txdr->tx_lock);
return 0;
}
@@ -1828,10 +1918,8 @@
netdev->mtu = new_mtu;
- if (netif_running(netdev)) {
- ixgbe_down(adapter);
- ixgbe_up(adapter);
- }
+ if (netif_running(netdev))
+ ixgbe_reinit_locked(adapter);
return 0;
}
@@ -1852,14 +1940,8 @@
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
int err;
- u32 ctrl_ext;
u32 num_rx_queues = adapter->num_rx_queues;
- /* Let firmware know the driver has taken over */
- ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
- ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
-
try_intr_reinit:
/* allocate transmit descriptors */
err = ixgbe_setup_all_tx_resources(adapter);
@@ -1910,6 +1992,7 @@
return 0;
err_up:
+ ixgbe_release_hw_control(adapter);
ixgbe_free_irq(adapter);
err_req_irq:
ixgbe_free_all_rx_resources(adapter);
@@ -1935,7 +2018,6 @@
static int ixgbe_close(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- u32 ctrl_ext;
ixgbe_down(adapter);
ixgbe_free_irq(adapter);
@@ -1943,9 +2025,7 @@
ixgbe_free_all_tx_resources(adapter);
ixgbe_free_all_rx_resources(adapter);
- ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
- ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+ ixgbe_release_hw_control(adapter);
return 0;
}
@@ -1957,22 +2037,26 @@
void ixgbe_update_stats(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- u64 good_rx, missed_rx, bprc;
+ u64 total_mpc = 0;
+ u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
- good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC);
- missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6));
- missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7));
- adapter->stats.gprc += (good_rx - missed_rx);
+ for (i = 0; i < 8; i++) {
+ /* for packet buffers not used, the register should read 0 */
+ mpc = IXGBE_READ_REG(hw, IXGBE_MPC(i));
+ missed_rx += mpc;
+ adapter->stats.mpc[i] += mpc;
+ total_mpc += adapter->stats.mpc[i];
+ adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+ }
+ adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
+ /* work around hardware counting issue */
+ adapter->stats.gprc -= missed_rx;
- adapter->stats.mpc[0] += missed_rx;
+ /* 82598 hardware only has a 32 bit counter in the high register */
adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+ adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
adapter->stats.bprc += bprc;
adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
@@ -1984,35 +2068,37 @@
adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
-
adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
- adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC);
adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
- adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+ lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+ adapter->stats.lxontxc += lxon;
+ lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+ adapter->stats.lxofftxc += lxoff;
adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
- adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
- adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0));
+ adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+ /*
+ * 82598 errata - tx of flow control packets is included in tx counters
+ */
+ xon_off_tot = lxon + lxoff;
+ adapter->stats.gptc -= xon_off_tot;
+ adapter->stats.mptc -= xon_off_tot;
+ adapter->stats.gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
- adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+ adapter->stats.ptc64 -= xon_off_tot;
adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
- adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
/* Fill out the OS statistics structure */
- adapter->net_stats.rx_packets = adapter->stats.gprc;
- adapter->net_stats.tx_packets = adapter->stats.gptc;
- adapter->net_stats.rx_bytes = adapter->stats.gorc;
- adapter->net_stats.tx_bytes = adapter->stats.gotc;
adapter->net_stats.multicast = adapter->stats.mprc;
/* Rx Errors */
@@ -2021,8 +2107,7 @@
adapter->net_stats.rx_dropped = 0;
adapter->net_stats.rx_length_errors = adapter->stats.rlec;
adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
- adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0];
-
+ adapter->net_stats.rx_missed_errors = total_mpc;
}
/**
@@ -2076,15 +2161,6 @@
round_jiffies(jiffies + 2 * HZ));
}
-#define IXGBE_MAX_TXD_PWR 14
-#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
-
-/* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
- (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
-#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
- MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
-
static int ixgbe_tso(struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring, struct sk_buff *skb,
u32 tx_flags, u8 *hdr_len)
@@ -2356,6 +2432,37 @@
writel(i, adapter->hw.hw_addr + tx_ring->tail);
}
+static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
+ struct ixgbe_ring *tx_ring, int size)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ netif_stop_queue(netdev);
+ /* Herbert's original patch had:
+ * smp_mb__after_netif_stop_queue();
+ * but since that doesn't exist yet, just open code it. */
+ smp_mb();
+
+ /* We need to check again in a case another CPU has just
+ * made room available. */
+ if (likely(IXGBE_DESC_UNUSED(tx_ring) < size))
+ return -EBUSY;
+
+ /* A reprieve! - use start_queue because it doesn't call schedule */
+ netif_wake_queue(netdev);
+ ++adapter->restart_queue;
+ return 0;
+}
+
+static int ixgbe_maybe_stop_tx(struct net_device *netdev,
+ struct ixgbe_ring *tx_ring, int size)
+{
+ if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
+ return 0;
+ return __ixgbe_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+
static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -2363,7 +2470,6 @@
unsigned int len = skb->len;
unsigned int first;
unsigned int tx_flags = 0;
- unsigned long flags = 0;
u8 hdr_len;
int tso;
unsigned int mss = 0;
@@ -2389,14 +2495,10 @@
for (f = 0; f < nr_frags; f++)
count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
- spin_lock_irqsave(&tx_ring->tx_lock, flags);
- if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) {
+ if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) {
adapter->tx_busy++;
- netif_stop_queue(netdev);
- spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
- spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
tx_flags |= IXGBE_TX_FLAGS_VLAN;
tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
@@ -2423,11 +2525,7 @@
netdev->trans_start = jiffies;
- spin_lock_irqsave(&tx_ring->tx_lock, flags);
- /* Make sure there is space in the ring for the next send. */
- if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED)
- netif_stop_queue(netdev);
- spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
return NETDEV_TX_OK;
}
@@ -2697,6 +2795,7 @@
return 0;
err_register:
+ ixgbe_release_hw_control(adapter);
err_hw_init:
err_sw_init:
err_eeprom:
@@ -2732,6 +2831,8 @@
unregister_netdev(netdev);
+ ixgbe_release_hw_control(adapter);
+
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index c429a50..0c5447d 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -148,7 +148,7 @@
*
* "The author (me) didn't use spin_lock_irqsave because the slowness of the
* card means that approach caused horrible problems like losing serial data
- * at 38400 baud on some chips. Rememeber many 8390 nics on PCI were ISA
+ * at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA
* chips with FPGA front ends.
*
* Ok the logic behind the 8390 is very simple:
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index e10528e..81bf005 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -1084,7 +1084,7 @@
return phy_mii_ioctl(phydev, if_mii(rq), cmd);
}
-static int __devinit macb_probe(struct platform_device *pdev)
+static int __init macb_probe(struct platform_device *pdev)
{
struct eth_platform_data *pdata;
struct resource *regs;
@@ -1248,7 +1248,7 @@
return err;
}
-static int __devexit macb_remove(struct platform_device *pdev)
+static int __exit macb_remove(struct platform_device *pdev)
{
struct net_device *dev;
struct macb *bp;
@@ -1276,8 +1276,7 @@
}
static struct platform_driver macb_driver = {
- .probe = macb_probe,
- .remove = __devexit_p(macb_remove),
+ .remove = __exit_p(macb_remove),
.driver = {
.name = "macb",
},
@@ -1285,7 +1284,7 @@
static int __init macb_init(void)
{
- return platform_driver_register(&macb_driver);
+ return platform_driver_probe(&macb_driver, macb_probe);
}
static void __exit macb_exit(void)
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index aafc3ce..6d343ef 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -4,8 +4,6 @@
* for more details.
*/
-#define DEBUG
-
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -15,11 +13,93 @@
#include <linux/platform_device.h>
#include <asm/mips-boards/simint.h>
-#include "mipsnet.h" /* actual device IO mapping */
+#define MIPSNET_VERSION "2007-11-17"
-#define MIPSNET_VERSION "2005-06-20"
+/*
+ * Net status/control block as seen by sw in the core.
+ */
+struct mipsnet_regs {
+ /*
+ * Device info for probing, reads as MIPSNET%d where %d is some
+ * form of version.
+ */
+ u64 devId; /*0x00 */
-#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field))
+ /*
+ * read only busy flag.
+ * Set and cleared by the Net Device to indicate that an rx or a tx
+ * is in progress.
+ */
+ u32 busy; /*0x08 */
+
+ /*
+ * Set by the Net Device.
+ * The device will set it once data has been received.
+ * The value is the number of bytes that should be read from
+ * rxDataBuffer. The value will decrease till 0 until all the data
+ * from rxDataBuffer has been read.
+ */
+ u32 rxDataCount; /*0x0c */
+#define MIPSNET_MAX_RXTX_DATACOUNT (1 << 16)
+
+ /*
+ * Settable from the MIPS core, cleared by the Net Device.
+ * The core should set the number of bytes it wants to send,
+ * then it should write those bytes of data to txDataBuffer.
+ * The device will clear txDataCount has been processed (not
+ * necessarily sent).
+ */
+ u32 txDataCount; /*0x10 */
+
+ /*
+ * Interrupt control
+ *
+ * Used to clear the interrupted generated by this dev.
+ * Write a 1 to clear the interrupt. (except bit31).
+ *
+ * Bit0 is set if it was a tx-done interrupt.
+ * Bit1 is set when new rx-data is available.
+ * Until this bit is cleared there will be no other RXs.
+ *
+ * Bit31 is used for testing, it clears after a read.
+ * Writing 1 to this bit will cause an interrupt to be generated.
+ * To clear the test interrupt, write 0 to this register.
+ */
+ u32 interruptControl; /*0x14 */
+#define MIPSNET_INTCTL_TXDONE (1u << 0)
+#define MIPSNET_INTCTL_RXDONE (1u << 1)
+#define MIPSNET_INTCTL_TESTBIT (1u << 31)
+
+ /*
+ * Readonly core-specific interrupt info for the device to signal
+ * the core. The meaning of the contents of this field might change.
+ */
+ /* XXX: the whole memIntf interrupt scheme is messy: the device
+ * should have no control what so ever of what VPE/register set is
+ * being used.
+ * The MemIntf should only expose interrupt lines, and something in
+ * the config should be responsible for the line<->core/vpe bindings.
+ */
+ u32 interruptInfo; /*0x18 */
+
+ /*
+ * This is where the received data is read out.
+ * There is more data to read until rxDataReady is 0.
+ * Only 1 byte at this regs offset is used.
+ */
+ u32 rxDataBuffer; /*0x1c */
+
+ /*
+ * This is where the data to transmit is written.
+ * Data should be written for the amount specified in the
+ * txDataCount register.
+ * Only 1 byte at this regs offset is used.
+ */
+ u32 txDataBuffer; /*0x20 */
+};
+
+#define regaddr(dev, field) \
+ (dev->base_addr + offsetof(struct mipsnet_regs, field))
static char mipsnet_string[] = "mipsnet";
@@ -29,32 +109,27 @@
static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
int len)
{
- uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount));
-
- if (available_len < len)
- return -EFAULT;
-
for (; len > 0; len--, kdata++)
- *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer));
+ *kdata = inb(regaddr(dev, rxDataBuffer));
- return inl(mipsnet_reg_address(dev, rxDataCount));
+ return inl(regaddr(dev, rxDataCount));
}
-static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
+static inline void mipsnet_put_todevice(struct net_device *dev,
struct sk_buff *skb)
{
int count_to_go = skb->len;
char *buf_ptr = skb->data;
- outl(skb->len, mipsnet_reg_address(dev, txDataCount));
+ outl(skb->len, regaddr(dev, txDataCount));
for (; count_to_go; buf_ptr++, count_to_go--)
- outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
+ outb(*buf_ptr, regaddr(dev, txDataBuffer));
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- return skb->len;
+ dev_kfree_skb(skb);
}
static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -69,18 +144,20 @@
return 0;
}
-static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
+static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
{
struct sk_buff *skb;
- size_t len = count;
- skb = alloc_skb(len + 2, GFP_KERNEL);
+ if (!len)
+ return len;
+
+ skb = dev_alloc_skb(len + NET_IP_ALIGN);
if (!skb) {
dev->stats.rx_dropped++;
return -ENOMEM;
}
- skb_reserve(skb, 2);
+ skb_reserve(skb, NET_IP_ALIGN);
if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len))
return -EFAULT;
@@ -92,50 +169,42 @@
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
- return count;
+ return len;
}
static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
+ u32 int_flags;
+ irqreturn_t ret = IRQ_NONE;
- irqreturn_t retval = IRQ_NONE;
- uint64_t interruptFlags;
+ if (irq != dev->irq)
+ goto out_badirq;
- if (irq == dev->irq) {
- retval = IRQ_HANDLED;
-
- interruptFlags =
- inl(mipsnet_reg_address(dev, interruptControl));
-
- if (interruptFlags & MIPSNET_INTCTL_TXDONE) {
- outl(MIPSNET_INTCTL_TXDONE,
- mipsnet_reg_address(dev, interruptControl));
- /* only one packet at a time, we are done. */
- netif_wake_queue(dev);
- } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) {
- mipsnet_get_fromdev(dev,
- inl(mipsnet_reg_address(dev, rxDataCount)));
- outl(MIPSNET_INTCTL_RXDONE,
- mipsnet_reg_address(dev, interruptControl));
-
- } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) {
- /*
- * TESTBIT is cleared on read.
- * And takes effect after a write with 0
- */
- outl(0, mipsnet_reg_address(dev, interruptControl));
- } else {
- /* Maybe shared IRQ, just ignore, no clearing. */
- retval = IRQ_NONE;
- }
-
- } else {
- printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
- dev->name, __FUNCTION__, irq);
- retval = IRQ_NONE;
+ /* TESTBIT is cleared on read. */
+ int_flags = inl(regaddr(dev, interruptControl));
+ if (int_flags & MIPSNET_INTCTL_TESTBIT) {
+ /* TESTBIT takes effect after a write with 0. */
+ outl(0, regaddr(dev, interruptControl));
+ ret = IRQ_HANDLED;
+ } else if (int_flags & MIPSNET_INTCTL_TXDONE) {
+ /* Only one packet at a time, we are done. */
+ dev->stats.tx_packets++;
+ netif_wake_queue(dev);
+ outl(MIPSNET_INTCTL_TXDONE,
+ regaddr(dev, interruptControl));
+ ret = IRQ_HANDLED;
+ } else if (int_flags & MIPSNET_INTCTL_RXDONE) {
+ mipsnet_get_fromdev(dev, inl(regaddr(dev, rxDataCount)));
+ outl(MIPSNET_INTCTL_RXDONE, regaddr(dev, interruptControl));
+ ret = IRQ_HANDLED;
}
- return retval;
+ return ret;
+
+out_badirq:
+ printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
+ dev->name, __FUNCTION__, irq);
+ return ret;
}
static int mipsnet_open(struct net_device *dev)
@@ -144,18 +213,15 @@
err = request_irq(dev->irq, &mipsnet_interrupt,
IRQF_SHARED, dev->name, (void *) dev);
-
if (err) {
- release_region(dev->base_addr, MIPSNET_IO_EXTENT);
+ release_region(dev->base_addr, sizeof(struct mipsnet_regs));
return err;
}
netif_start_queue(dev);
/* test interrupt handler */
- outl(MIPSNET_INTCTL_TESTBIT,
- mipsnet_reg_address(dev, interruptControl));
-
+ outl(MIPSNET_INTCTL_TESTBIT, regaddr(dev, interruptControl));
return 0;
}
@@ -163,7 +229,7 @@
static int mipsnet_close(struct net_device *dev)
{
netif_stop_queue(dev);
-
+ free_irq(dev->irq, dev);
return 0;
}
@@ -194,10 +260,11 @@
*/
netdev->base_addr = 0x4200;
netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
- inl(mipsnet_reg_address(netdev, interruptInfo));
+ inl(regaddr(netdev, interruptInfo));
/* Get the io region now, get irq on open() */
- if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) {
+ if (!request_region(netdev->base_addr, sizeof(struct mipsnet_regs),
+ "mipsnet")) {
err = -EBUSY;
goto out_free_netdev;
}
@@ -217,7 +284,7 @@
return 0;
out_free_region:
- release_region(netdev->base_addr, MIPSNET_IO_EXTENT);
+ release_region(netdev->base_addr, sizeof(struct mipsnet_regs));
out_free_netdev:
free_netdev(netdev);
@@ -231,7 +298,7 @@
struct net_device *dev = dev_get_drvdata(device);
unregister_netdev(dev);
- release_region(dev->base_addr, MIPSNET_IO_EXTENT);
+ release_region(dev->base_addr, sizeof(struct mipsnet_regs));
free_netdev(dev);
dev_set_drvdata(device, NULL);
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h
deleted file mode 100644
index 0132c67..0000000
--- a/drivers/net/mipsnet.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.
- */
-#ifndef __MIPSNET_H
-#define __MIPSNET_H
-
-/*
- * Id of this Net device, as seen by the core.
- */
-#define MIPS_NET_DEV_ID ((uint64_t) \
- ((uint64_t) 'M' << 0)| \
- ((uint64_t) 'I' << 8)| \
- ((uint64_t) 'P' << 16)| \
- ((uint64_t) 'S' << 24)| \
- ((uint64_t) 'N' << 32)| \
- ((uint64_t) 'E' << 40)| \
- ((uint64_t) 'T' << 48)| \
- ((uint64_t) '0' << 56))
-
-/*
- * Net status/control block as seen by sw in the core.
- * (Why not use bit fields? can't be bothered with cross-platform struct
- * packing.)
- */
-struct net_control_block {
- /*
- * dev info for probing
- * reads as MIPSNET%d where %d is some form of version
- */
- uint64_t devId; /* 0x00 */
-
- /*
- * read only busy flag.
- * Set and cleared by the Net Device to indicate that an rx or a tx
- * is in progress.
- */
- uint32_t busy; /* 0x08 */
-
- /*
- * Set by the Net Device.
- * The device will set it once data has been received.
- * The value is the number of bytes that should be read from
- * rxDataBuffer. The value will decrease till 0 until all the data
- * from rxDataBuffer has been read.
- */
- uint32_t rxDataCount; /* 0x0c */
-#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
-
- /*
- * Settable from the MIPS core, cleared by the Net Device. The core
- * should set the number of bytes it wants to send, then it should
- * write those bytes of data to txDataBuffer. The device will clear
- * txDataCount has been processed (not necessarily sent).
- */
- uint32_t txDataCount; /* 0x10 */
-
- /*
- * Interrupt control
- *
- * Used to clear the interrupted generated by this dev.
- * Write a 1 to clear the interrupt. (except bit31).
- *
- * Bit0 is set if it was a tx-done interrupt.
- * Bit1 is set when new rx-data is available.
- * Until this bit is cleared there will be no other RXs.
- *
- * Bit31 is used for testing, it clears after a read.
- * Writing 1 to this bit will cause an interrupt to be generated.
- * To clear the test interrupt, write 0 to this register.
- */
- uint32_t interruptControl; /*0x14 */
-#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1 << 0))
-#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1 << 1))
-#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1 << 31))
-#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE | \
- MIPSNET_INTCTL_RXDONE | \
- MIPSNET_INTCTL_TESTBIT)
-
- /*
- * Readonly core-specific interrupt info for the device to signal the
- * core. The meaning of the contents of this field might change.
- *
- * TODO: the whole memIntf interrupt scheme is messy: the device should
- * have no control what so ever of what VPE/register set is being
- * used. The MemIntf should only expose interrupt lines, and
- * something in the config should be responsible for the
- * line<->core/vpe bindings.
- */
- uint32_t interruptInfo; /* 0x18 */
-
- /*
- * This is where the received data is read out.
- * There is more data to read until rxDataReady is 0.
- * Only 1 byte at this regs offset is used.
- */
- uint32_t rxDataBuffer; /* 0x1c */
-
- /*
- * This is where the data to transmit is written. Data should be
- * written for the amount specified in the txDataCount register. Only
- * 1 byte at this regs offset is used.
- */
- uint32_t txDataBuffer; /* 0x20 */
-};
-
-#define MIPSNET_IO_EXTENT 0x40 /* being generous */
-
-#define field_offset(field) (offsetof(struct net_control_block, field))
-
-#endif /* __MIPSNET_H */
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index 535a446..61dc495 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -617,9 +617,6 @@
int err;
#define QUERY_ADAPTER_OUT_SIZE 0x100
-#define QUERY_ADAPTER_VENDOR_ID_OFFSET 0x00
-#define QUERY_ADAPTER_DEVICE_ID_OFFSET 0x04
-#define QUERY_ADAPTER_REVISION_ID_OFFSET 0x08
#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10
#define QUERY_ADAPTER_VSD_OFFSET 0x20
@@ -633,9 +630,6 @@
if (err)
goto out;
- MLX4_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
- MLX4_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
- MLX4_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
MLX4_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index 7e1dd9e..e16dec8 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -99,9 +99,6 @@
};
struct mlx4_adapter {
- u32 vendor_id;
- u32 device_id;
- u32 revision_id;
char board_id[MLX4_BOARD_ID_LEN];
u8 inta_pin;
};
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 89b3f0b..08bfc13 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -71,7 +71,7 @@
#endif /* CONFIG_PCI_MSI */
-static const char mlx4_version[] __devinitdata =
+static char mlx4_version[] __devinitdata =
DRV_NAME ": Mellanox ConnectX core driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -163,7 +163,7 @@
return 0;
}
-static int __devinit mlx4_load_fw(struct mlx4_dev *dev)
+static int mlx4_load_fw(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
@@ -197,8 +197,8 @@
return err;
}
-static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
- int cmpt_entry_sz)
+static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
+ int cmpt_entry_sz)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
@@ -534,7 +534,6 @@
}
priv->eq_table.inta_pin = adapter.inta_pin;
- dev->rev_id = adapter.revision_id;
memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
return 0;
@@ -688,7 +687,7 @@
return err;
}
-static void __devinit mlx4_enable_msi_x(struct mlx4_dev *dev)
+static void mlx4_enable_msi_x(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct msix_entry entries[MLX4_NUM_EQ];
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 0c05a10..9c9e308 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -122,7 +122,7 @@
spin_unlock(&buddy->lock);
}
-static int __devinit mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
+static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
{
int i, s;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 651c269..b528ce7 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1652,6 +1652,11 @@
}
}
+static inline __be16 sum16_as_be(__sum16 sum)
+{
+ return (__force __be16)sum;
+}
+
/**
* eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw
*
@@ -1689,7 +1694,7 @@
desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- BUG_ON(skb->protocol != ETH_P_IP);
+ BUG_ON(skb->protocol != htons(ETH_P_IP));
cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
ETH_GEN_IP_V_4_CHECKSUM |
@@ -1698,10 +1703,10 @@
switch (ip_hdr(skb)->protocol) {
case IPPROTO_UDP:
cmd_sts |= ETH_UDP_FRAME;
- desc->l4i_chk = udp_hdr(skb)->check;
+ desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check));
break;
case IPPROTO_TCP:
- desc->l4i_chk = tcp_hdr(skb)->check;
+ desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check));
break;
default:
BUG();
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index c329a4f..0a3e604 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -203,22 +203,8 @@
IIId. Synchronization
Most operations are synchronized on the np->lock irq spinlock, except the
-performance critical codepaths:
-
-The rx process only runs in the interrupt handler. Access from outside
-the interrupt handler is only permitted after disable_irq().
-
-The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
-is set, then access is permitted under spin_lock_irq(&np->lock).
-
-Thus configuration functions that want to access everything must call
- disable_irq(dev->irq);
- netif_tx_lock_bh(dev);
- spin_lock_irq(&np->lock);
-
-IV. Notes
-
-NatSemi PCI network controllers are very uncommon.
+recieve and transmit paths which are synchronised using a combination of
+hardware descriptor ownership, disabling interrupts and NAPI poll scheduling.
IVb. References
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index bb88a41..2e39e028 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -62,6 +62,10 @@
#define LRO_MAX_AGGR 64
+#define PE_MIN_MTU 64
+#define PE_MAX_MTU 1500
+#define PE_DEF_MTU ETH_DATA_LEN
+
#define DEFAULT_MSG_ENABLE \
(NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
@@ -82,8 +86,6 @@
& ((ring)->size - 1))
#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring))
-#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
@@ -175,6 +177,24 @@
return -1;
}
+static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
+{
+ unsigned int flags;
+
+ flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+ flags &= ~PAS_MAC_CFG_PCFG_PE;
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
+static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
+{
+ unsigned int flags;
+
+ flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+ flags |= PAS_MAC_CFG_PCFG_PE;
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
static int pasemi_get_mac_addr(struct pasemi_mac *mac)
{
struct pci_dev *pdev = mac->pdev;
@@ -221,6 +241,33 @@
return 0;
}
+static int pasemi_mac_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ struct sockaddr *addr = p;
+ unsigned int adr0, adr1;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ adr0 = dev->dev_addr[2] << 24 |
+ dev->dev_addr[3] << 16 |
+ dev->dev_addr[4] << 8 |
+ dev->dev_addr[5];
+ adr1 = read_mac_reg(mac, PAS_MAC_CFG_ADR1);
+ adr1 &= ~0xffff;
+ adr1 |= dev->dev_addr[0] << 8 | dev->dev_addr[1];
+
+ pasemi_mac_intf_disable(mac);
+ write_mac_reg(mac, PAS_MAC_CFG_ADR0, adr0);
+ write_mac_reg(mac, PAS_MAC_CFG_ADR1, adr1);
+ pasemi_mac_intf_enable(mac);
+
+ return 0;
+}
+
static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
void **tcph, u64 *hdr_flags, void *data)
{
@@ -453,7 +500,7 @@
}
-static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
+static void pasemi_mac_free_rx_buffers(struct pasemi_mac *mac)
{
struct pasemi_mac_rxring *rx = rx_ring(mac);
unsigned int i;
@@ -473,7 +520,12 @@
}
for (i = 0; i < RX_RING_SIZE; i++)
- RX_DESC(rx, i) = 0;
+ RX_BUFF(rx, i) = 0;
+}
+
+static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
+{
+ pasemi_mac_free_rx_buffers(mac);
dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
rx_ring(mac)->buffers, rx_ring(mac)->buf_dma);
@@ -503,14 +555,14 @@
/* Entry in use? */
WARN_ON(*buff);
- skb = dev_alloc_skb(BUF_SIZE);
+ skb = dev_alloc_skb(mac->bufsz);
skb_reserve(skb, LOCAL_SKB_ALIGN);
if (unlikely(!skb))
break;
dma = pci_map_single(mac->dma_pdev, skb->data,
- BUF_SIZE - LOCAL_SKB_ALIGN,
+ mac->bufsz - LOCAL_SKB_ALIGN,
PCI_DMA_FROMDEVICE);
if (unlikely(dma_mapping_error(dma))) {
@@ -520,7 +572,7 @@
info->skb = skb;
info->dma = dma;
- *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+ *buff = XCT_RXB_LEN(mac->bufsz) | XCT_RXB_ADDR(dma);
fill++;
}
@@ -650,7 +702,7 @@
len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
- pci_unmap_single(pdev, dma, BUF_SIZE-LOCAL_SKB_ALIGN,
+ pci_unmap_single(pdev, dma, mac->bufsz - LOCAL_SKB_ALIGN,
PCI_DMA_FROMDEVICE);
if (macrx & XCT_MACRX_CRC) {
@@ -874,24 +926,6 @@
return IRQ_HANDLED;
}
-static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
-{
- unsigned int flags;
-
- flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
- flags &= ~PAS_MAC_CFG_PCFG_PE;
- write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
-}
-
-static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
-{
- unsigned int flags;
-
- flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
- flags |= PAS_MAC_CFG_PCFG_PE;
- write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
-}
-
static void pasemi_adjust_link(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
@@ -1148,11 +1182,71 @@
#define MAX_RETRIES 5000
+static void pasemi_mac_pause_txchan(struct pasemi_mac *mac)
+{
+ unsigned int sta, retries;
+ int txch = tx_ring(mac)->chan.chno;
+
+ write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
+ PAS_DMA_TXCHAN_TCMDSTA_ST);
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch));
+ if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+ break;
+ cond_resched();
+ }
+
+ if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ dev_err(&mac->dma_pdev->dev,
+ "Failed to stop tx channel, tcmdsta %08x\n", sta);
+
+ write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
+}
+
+static void pasemi_mac_pause_rxchan(struct pasemi_mac *mac)
+{
+ unsigned int sta, retries;
+ int rxch = rx_ring(mac)->chan.chno;
+
+ write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_ST);
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
+ if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+ break;
+ cond_resched();
+ }
+
+ if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ dev_err(&mac->dma_pdev->dev,
+ "Failed to stop rx channel, ccmdsta 08%x\n", sta);
+ write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
+}
+
+static void pasemi_mac_pause_rxint(struct pasemi_mac *mac)
+{
+ unsigned int sta, retries;
+
+ write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_ST);
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
+ break;
+ cond_resched();
+ }
+
+ if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
+ dev_err(&mac->dma_pdev->dev,
+ "Failed to stop rx interface, rcmdsta %08x\n", sta);
+ write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+}
+
static int pasemi_mac_close(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int sta;
- int retries;
int rxch, txch;
rxch = rx_ring(mac)->chan.chno;
@@ -1190,51 +1284,10 @@
pasemi_mac_clean_tx(tx_ring(mac));
pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
- /* Disable interface */
- write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
- PAS_DMA_TXCHAN_TCMDSTA_ST);
- write_dma_reg( PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- PAS_DMA_RXINT_RCMDSTA_ST);
- write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
- PAS_DMA_RXCHAN_CCMDSTA_ST);
-
- for (retries = 0; retries < MAX_RETRIES; retries++) {
- sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(rxch));
- if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
- break;
- cond_resched();
- }
-
- if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
- dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
-
- for (retries = 0; retries < MAX_RETRIES; retries++) {
- sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
- if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
- break;
- cond_resched();
- }
-
- if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
- dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
-
- for (retries = 0; retries < MAX_RETRIES; retries++) {
- sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
- if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
- break;
- cond_resched();
- }
-
- if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
- dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
-
- /* Then, disable the channel. This must be done separately from
- * stopping, since you can't disable when active.
- */
-
- write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
- write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
- write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+ pasemi_mac_pause_txchan(mac);
+ pasemi_mac_pause_rxint(mac);
+ pasemi_mac_pause_rxchan(mac);
+ pasemi_mac_intf_disable(mac);
free_irq(mac->tx->chan.irq, mac->tx);
free_irq(mac->rx->chan.irq, mac->rx);
@@ -1388,6 +1441,62 @@
return pkts;
}
+static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+ unsigned int rcmdsta;
+ int running;
+
+ if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU)
+ return -EINVAL;
+
+ running = netif_running(dev);
+
+ if (running) {
+ /* Need to stop the interface, clean out all already
+ * received buffers, free all unused buffers on the RX
+ * interface ring, then finally re-fill the rx ring with
+ * the new-size buffers and restart.
+ */
+
+ napi_disable(&mac->napi);
+ netif_tx_disable(dev);
+ pasemi_mac_intf_disable(mac);
+
+ rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ pasemi_mac_pause_rxint(mac);
+ pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
+ pasemi_mac_free_rx_buffers(mac);
+ }
+
+ /* Change maxf, i.e. what size frames are accepted.
+ * Need room for ethernet header and CRC word
+ */
+ reg = read_mac_reg(mac, PAS_MAC_CFG_MACCFG);
+ reg &= ~PAS_MAC_CFG_MACCFG_MAXF_M;
+ reg |= PAS_MAC_CFG_MACCFG_MAXF(new_mtu + ETH_HLEN + 4);
+ write_mac_reg(mac, PAS_MAC_CFG_MACCFG, reg);
+
+ dev->mtu = new_mtu;
+ /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+ mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+
+ if (running) {
+ write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN);
+
+ rx_ring(mac)->next_to_fill = 0;
+ pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE-1);
+
+ napi_enable(&mac->napi);
+ netif_start_queue(dev);
+ pasemi_mac_intf_enable(mac);
+ }
+
+ return 0;
+}
+
static int __devinit
pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -1475,6 +1584,12 @@
dev->stop = pasemi_mac_close;
dev->hard_start_xmit = pasemi_mac_start_tx;
dev->set_multicast_list = pasemi_mac_set_rx_mode;
+ dev->set_mac_address = pasemi_mac_set_mac_addr;
+ dev->mtu = PE_DEF_MTU;
+ /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+ mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+
+ dev->change_mtu = pasemi_mac_change_mtu;
if (err)
goto out;
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index 8bee2a6..99e7b93 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -59,6 +59,7 @@
struct phy_device *phydev;
struct napi_struct napi;
+ int bufsz; /* RX ring buffer size */
u8 type;
#define MAC_TYPE_GMAC 1
#define MAC_TYPE_XAUI 2
@@ -96,6 +97,9 @@
/* MAC CFG register offsets */
enum {
PAS_MAC_CFG_PCFG = 0x80,
+ PAS_MAC_CFG_MACCFG = 0x84,
+ PAS_MAC_CFG_ADR0 = 0x8c,
+ PAS_MAC_CFG_ADR1 = 0x90,
PAS_MAC_CFG_TXP = 0x98,
PAS_MAC_IPC_CHNL = 0x208,
};
@@ -130,6 +134,18 @@
#define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001
#define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002
#define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003
+
+#define PAS_MAC_CFG_MACCFG_TXT_M 0x70000000
+#define PAS_MAC_CFG_MACCFG_TXT_S 28
+#define PAS_MAC_CFG_MACCFG_PRES_M 0x0f000000
+#define PAS_MAC_CFG_MACCFG_PRES_S 24
+#define PAS_MAC_CFG_MACCFG_MAXF_M 0x00ffff00
+#define PAS_MAC_CFG_MACCFG_MAXF_S 8
+#define PAS_MAC_CFG_MACCFG_MAXF(x) (((x) << PAS_MAC_CFG_MACCFG_MAXF_S) & \
+ PAS_MAC_CFG_MACCFG_MAXF_M)
+#define PAS_MAC_CFG_MACCFG_MINF_M 0x000000ff
+#define PAS_MAC_CFG_MACCFG_MINF_S 0
+
#define PAS_MAC_CFG_TXP_FCF 0x01000000
#define PAS_MAC_CFG_TXP_FCE 0x00800000
#define PAS_MAC_CFG_TXP_FC 0x00400000
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index ed402e0..fffc49b 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -541,7 +541,7 @@
#define NETDRV_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
-#if MMIO_FLUSH_AUDIT_COMPLETE
+#ifdef MMIO_FLUSH_AUDIT_COMPLETE
/* write MMIO register */
#define NETDRV_W8(reg, val8) writeb ((val8), ioaddr + (reg))
@@ -603,7 +603,7 @@
return -ENOMEM;
}
SET_NETDEV_DEV(dev, &pdev->dev);
- tp = dev->priv;
+ tp = netdev_priv(dev);
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device (pdev);
@@ -759,7 +759,7 @@
return i;
}
- tp = dev->priv;
+ tp = netdev_priv(dev);
assert (ioaddr != NULL);
assert (dev != NULL);
@@ -783,7 +783,7 @@
dev->base_addr = (unsigned long) ioaddr;
/* dev->priv/tp zeroed and aligned in alloc_etherdev */
- tp = dev->priv;
+ tp = netdev_priv(dev);
/* note: tp->chipset set in netdrv_init_board */
tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
@@ -841,7 +841,7 @@
assert (dev != NULL);
- np = dev->priv;
+ np = netdev_priv(dev);
assert (np != NULL);
unregister_netdev (dev);
@@ -974,7 +974,7 @@
static int mdio_read (struct net_device *dev, int phy_id, int location)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *mdio_addr = tp->mmio_addr + Config4;
int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int retval = 0;
@@ -1017,7 +1017,7 @@
static void mdio_write (struct net_device *dev, int phy_id, int location,
int value)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *mdio_addr = tp->mmio_addr + Config4;
int mii_cmd =
(0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
@@ -1060,7 +1060,7 @@
static int netdrv_open (struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
int retval;
#ifdef NETDRV_DEBUG
void *ioaddr = tp->mmio_addr;
@@ -1121,7 +1121,7 @@
/* Start the hardware at open or resume. */
static void netdrv_hw_start (struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
u32 i;
@@ -1191,7 +1191,7 @@
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void netdrv_init_ring (struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
int i;
DPRINTK ("ENTER\n");
@@ -1213,7 +1213,7 @@
static void netdrv_timer (unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
int next_tick = 60 * HZ;
int mii_lpa;
@@ -1252,9 +1252,10 @@
}
-static void netdrv_tx_clear (struct netdrv_private *tp)
+static void netdrv_tx_clear (struct net_device *dev)
{
int i;
+ struct netdrv_private *tp = netdev_priv(dev);
atomic_set (&tp->cur_tx, 0);
atomic_set (&tp->dirty_tx, 0);
@@ -1278,7 +1279,7 @@
static void netdrv_tx_timeout (struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
int i;
u8 tmp8;
@@ -1311,7 +1312,7 @@
/* Stop a shared interrupt from scavenging while we are. */
spin_lock_irqsave (&tp->lock, flags);
- netdrv_tx_clear (tp);
+ netdrv_tx_clear (dev);
spin_unlock_irqrestore (&tp->lock, flags);
@@ -1325,7 +1326,7 @@
static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
int entry;
@@ -1525,7 +1526,7 @@
DPRINTK ("%s: netdrv_rx() status %4.4x, size %4.4x,"
" cur %4.4x.\n", dev->name, rx_status,
rx_size, cur_rx);
-#if NETDRV_DEBUG > 2
+#if defined(NETDRV_DEBUG) && (NETDRV_DEBUG > 2)
{
int i;
DPRINTK ("%s: Frame contents ", dev->name);
@@ -1648,7 +1649,7 @@
static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
int boguscnt = max_interrupt_work;
void *ioaddr = tp->mmio_addr;
int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
@@ -1711,7 +1712,7 @@
static int netdrv_close (struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
unsigned long flags;
@@ -1738,10 +1739,10 @@
spin_unlock_irqrestore (&tp->lock, flags);
- synchronize_irq ();
+ synchronize_irq (dev->irq);
free_irq (dev->irq, dev);
- netdrv_tx_clear (tp);
+ netdrv_tx_clear (dev);
pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
@@ -1762,7 +1763,7 @@
static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
struct mii_ioctl_data *data = if_mii(rq);
unsigned long flags;
int rc = 0;
@@ -1805,7 +1806,7 @@
static void netdrv_set_rx_mode (struct net_device *dev)
{
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
@@ -1862,7 +1863,7 @@
static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata (pdev);
- struct netdrv_private *tp = dev->priv;
+ struct netdrv_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
unsigned long flags;
@@ -1892,7 +1893,7 @@
static int netdrv_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
- struct netdrv_private *tp = dev->priv;
+ /*struct netdrv_private *tp = netdev_priv(dev);*/
if (!netif_running(dev))
return 0;
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 36a7ba3..3b78a38 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -230,10 +230,11 @@
static int tc574_config(struct pcmcia_device *link);
static void tc574_release(struct pcmcia_device *link);
-static void mdio_sync(kio_addr_t ioaddr, int bits);
-static int mdio_read(kio_addr_t ioaddr, int phy_id, int location);
-static void mdio_write(kio_addr_t ioaddr, int phy_id, int location, int value);
-static unsigned short read_eeprom(kio_addr_t ioaddr, int index);
+static void mdio_sync(unsigned int ioaddr, int bits);
+static int mdio_read(unsigned int ioaddr, int phy_id, int location);
+static void mdio_write(unsigned int ioaddr, int phy_id, int location,
+ int value);
+static unsigned short read_eeprom(unsigned int ioaddr, int index);
static void tc574_wait_for_completion(struct net_device *dev, int cmd);
static void tc574_reset(struct net_device *dev);
@@ -341,7 +342,7 @@
tuple_t tuple;
__le16 buf[32];
int last_fn, last_ret, i, j;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
__be16 *phys_addr;
char *cardname;
__u32 config;
@@ -515,7 +516,7 @@
static void dump_status(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
EL3WINDOW(1);
printk(KERN_INFO " irq status %04x, rx status %04x, tx status "
"%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
@@ -544,7 +545,7 @@
/* Read a word from the EEPROM using the regular EEPROM access register.
Assume that we are in register window zero.
*/
-static unsigned short read_eeprom(kio_addr_t ioaddr, int index)
+static unsigned short read_eeprom(unsigned int ioaddr, int index)
{
int timer;
outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
@@ -572,9 +573,9 @@
/* Generate the preamble required for initial synchronization and
a few older transceivers. */
-static void mdio_sync(kio_addr_t ioaddr, int bits)
+static void mdio_sync(unsigned int ioaddr, int bits)
{
- kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
/* Establish sync by sending at least 32 logic ones. */
while (-- bits >= 0) {
@@ -583,12 +584,12 @@
}
}
-static int mdio_read(kio_addr_t ioaddr, int phy_id, int location)
+static int mdio_read(unsigned int ioaddr, int phy_id, int location)
{
int i;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
unsigned int retval = 0;
- kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
if (mii_preamble_required)
mdio_sync(ioaddr, 32);
@@ -608,10 +609,10 @@
return (retval>>1) & 0xffff;
}
-static void mdio_write(kio_addr_t ioaddr, int phy_id, int location, int value)
+static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value)
{
int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
int i;
if (mii_preamble_required)
@@ -637,7 +638,7 @@
{
struct el3_private *lp = netdev_priv(dev);
int i;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
unsigned long flags;
tc574_wait_for_completion(dev, TotalReset|0x10);
@@ -695,7 +696,7 @@
mdio_write(ioaddr, lp->phys, 4, lp->advertising);
if (!auto_polarity) {
/* works for TDK 78Q2120 series MII's */
- int i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
+ i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
mdio_write(ioaddr, lp->phys, 16, i);
}
@@ -741,7 +742,7 @@
static void el3_tx_timeout(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
dump_status(dev);
@@ -756,7 +757,7 @@
static void pop_tx_status(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i;
/* Clear the Tx status stack. */
@@ -779,7 +780,7 @@
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
struct el3_private *lp = netdev_priv(dev);
unsigned long flags;
@@ -813,7 +814,7 @@
{
struct net_device *dev = (struct net_device *) dev_id;
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
unsigned status;
int work_budget = max_interrupt_work;
int handled = 0;
@@ -907,7 +908,7 @@
{
struct net_device *dev = (struct net_device *) arg;
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
unsigned long flags;
unsigned short /* cable, */ media, partner;
@@ -996,7 +997,7 @@
static void update_stats(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u8 rx, tx, up;
DEBUG(2, "%s: updating the statistics.\n", dev->name);
@@ -1033,7 +1034,7 @@
static int el3_rx(struct net_device *dev, int worklimit)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
short rx_status;
DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
@@ -1094,7 +1095,7 @@
static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_ifru;
int phy = lp->phys & 0x1f;
@@ -1148,7 +1149,7 @@
static void set_rx_mode(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
if (dev->flags & IFF_PROMISC)
outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
@@ -1161,7 +1162,7 @@
static int el3_close(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
struct el3_private *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index e862d14e..1b1abb1 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -145,7 +145,7 @@
static int tc589_config(struct pcmcia_device *link);
static void tc589_release(struct pcmcia_device *link);
-static u16 read_eeprom(kio_addr_t ioaddr, int index);
+static u16 read_eeprom(unsigned int ioaddr, int index);
static void tc589_reset(struct net_device *dev);
static void media_check(unsigned long arg);
static int el3_config(struct net_device *dev, struct ifmap *map);
@@ -254,7 +254,7 @@
__le16 buf[32];
__be16 *phys_addr;
int last_fn, last_ret, i, j, multi = 0, fifo;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
DECLARE_MAC_BUF(mac);
@@ -403,7 +403,7 @@
Read a word from the EEPROM using the regular EEPROM access register.
Assume that we are in register window zero.
*/
-static u16 read_eeprom(kio_addr_t ioaddr, int index)
+static u16 read_eeprom(unsigned int ioaddr, int index)
{
int i;
outw(EEPROM_READ + index, ioaddr + 10);
@@ -421,7 +421,7 @@
static void tc589_set_xcvr(struct net_device *dev, int if_port)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
EL3WINDOW(0);
switch (if_port) {
@@ -443,7 +443,7 @@
static void dump_status(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
EL3WINDOW(1);
printk(KERN_INFO " irq status %04x, rx status %04x, tx status "
"%02x tx free %04x\n", inw(ioaddr+EL3_STATUS),
@@ -459,7 +459,7 @@
/* Reset and restore all of the 3c589 registers. */
static void tc589_reset(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i;
EL3WINDOW(0);
@@ -567,7 +567,7 @@
static void el3_tx_timeout(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name);
dump_status(dev);
@@ -582,7 +582,7 @@
static void pop_tx_status(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i;
/* Clear the Tx status stack. */
@@ -604,7 +604,7 @@
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
struct el3_private *priv = netdev_priv(dev);
unsigned long flags;
@@ -641,7 +641,7 @@
{
struct net_device *dev = (struct net_device *) dev_id;
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
__u16 status;
int i = 0, handled = 1;
@@ -727,7 +727,7 @@
{
struct net_device *dev = (struct net_device *)(arg);
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 media, errs;
unsigned long flags;
@@ -828,7 +828,7 @@
static void update_stats(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
DEBUG(2, "%s: updating the statistics.\n", dev->name);
/* Turn off statistics updates while reading. */
@@ -855,7 +855,7 @@
static int el3_rx(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int worklimit = 32;
short rx_status;
@@ -909,7 +909,7 @@
{
struct el3_private *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 opts = SetRxFilter | RxStation | RxBroadcast;
if (!pcmcia_dev_present(link)) return;
@@ -924,7 +924,7 @@
{
struct el3_private *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 6d342f6..e8a63e4 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -96,8 +96,8 @@
static void ei_watchdog(u_long arg);
static void axnet_reset_8390(struct net_device *dev);
-static int mdio_read(kio_addr_t addr, int phy_id, int loc);
-static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value);
+static int mdio_read(unsigned int addr, int phy_id, int loc);
+static void mdio_write(unsigned int addr, int phy_id, int loc, int value);
static void get_8390_hdr(struct net_device *,
struct e8390_pkt_hdr *, int);
@@ -203,7 +203,7 @@
static int get_prom(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i, j;
/* This is based on drivers/net/ne.c */
@@ -473,7 +473,7 @@
#define MDIO_MASK 0x0f
#define MDIO_ENB_IN 0x02
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
{
int bits;
for (bits = 0; bits < 32; bits++) {
@@ -482,7 +482,7 @@
}
}
-static int mdio_read(kio_addr_t addr, int phy_id, int loc)
+static int mdio_read(unsigned int addr, int phy_id, int loc)
{
u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
int i, retval = 0;
@@ -501,7 +501,7 @@
return (retval>>1) & 0xffff;
}
-static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
+static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
{
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i;
@@ -575,7 +575,7 @@
static void axnet_reset_8390(struct net_device *dev)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
int i;
ei_status.txing = ei_status.dmaing = 0;
@@ -610,8 +610,8 @@
{
struct net_device *dev = (struct net_device *)(arg);
axnet_dev_t *info = PRIV(dev);
- kio_addr_t nic_base = dev->base_addr;
- kio_addr_t mii_addr = nic_base + AXNET_MII_EEP;
+ unsigned int nic_base = dev->base_addr;
+ unsigned int mii_addr = nic_base + AXNET_MII_EEP;
u_short link;
if (!netif_device_present(dev)) goto reschedule;
@@ -681,7 +681,7 @@
{
axnet_dev_t *info = PRIV(dev);
u16 *data = (u16 *)&rq->ifr_ifru;
- kio_addr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
+ unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP;
switch (cmd) {
case SIOCGMIIPHY:
data[0] = info->phy_id;
@@ -703,7 +703,7 @@
struct e8390_pkt_hdr *hdr,
int ring_page)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */
outb_p(ring_page, nic_base + EN0_RSARHI);
@@ -721,7 +721,7 @@
static void block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
int xfer_count = count;
char *buf = skb->data;
@@ -744,7 +744,7 @@
static void block_output(struct net_device *dev, int count,
const u_char *buf, const int start_page)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
#ifdef PCMCIA_DEBUG
if (ei_debug > 4)
@@ -991,7 +991,7 @@
*
* Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
*/
-int ax_close(struct net_device *dev)
+static int ax_close(struct net_device *dev)
{
unsigned long flags;
@@ -1014,7 +1014,7 @@
* completed (or failed) - i.e. never posted a Tx related interrupt.
*/
-void ei_tx_timeout(struct net_device *dev)
+static void ei_tx_timeout(struct net_device *dev)
{
long e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -1087,8 +1087,8 @@
ei_local->irqlock = 1;
- send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
-
+ send_length = max(length, ETH_ZLEN);
+
/*
* We have two Tx slots available for use. Find the first free
* slot, and then perform some sanity checks. With two Tx bufs,
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 949c6df..8f328a0 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -298,7 +298,8 @@
static int mfc_try_io_port(struct pcmcia_device *link)
{
int i, ret;
- static const kio_addr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+ static const unsigned int serial_base[5] =
+ { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
for (i = 0; i < 5; i++) {
link->io.BasePort2 = serial_base[i];
@@ -316,7 +317,7 @@
static int ungermann_try_io_port(struct pcmcia_device *link)
{
int ret;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
/*
Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
0x380,0x3c0 only for ioport.
@@ -342,7 +343,7 @@
cisparse_t parse;
u_short buf[32];
int i, last_fn = 0, last_ret = 0, ret;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
cardtype_t cardtype;
char *card_name = "unknown";
u_char *node_id;
@@ -610,7 +611,7 @@
u_char __iomem *base;
int i, j;
struct net_device *dev = link->priv;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
/* Allocate a small memory window */
req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
@@ -735,7 +736,7 @@
{
struct net_device *dev = dev_id;
local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
unsigned short tx_stat, rx_stat;
ioaddr = dev->base_addr;
@@ -789,7 +790,7 @@
static void fjn_tx_timeout(struct net_device *dev)
{
struct local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
dev->name, htons(inw(ioaddr + TX_STATUS)),
@@ -819,7 +820,7 @@
static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
short length = skb->len;
if (length < ETH_ZLEN)
@@ -892,7 +893,7 @@
static void fjn_reset(struct net_device *dev)
{
struct local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i;
DEBUG(4, "fjn_reset(%s) called.\n",dev->name);
@@ -971,7 +972,7 @@
static void fjn_rx(struct net_device *dev)
{
struct local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int boguscount = 10; /* 5 -> 10: by agy 19940922 */
DEBUG(4, "%s: in rx_packet(), rx_status %02x.\n",
@@ -1125,7 +1126,7 @@
{
struct local_info_t *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
DEBUG(4, "fjn_close('%s').\n", dev->name);
@@ -1168,7 +1169,7 @@
static void set_rx_mode(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_char mc_filter[8]; /* Multicast hash filter */
u_long flags;
int i;
@@ -1197,8 +1198,7 @@
outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */
} else {
struct dev_mc_list *mclist;
- int i;
-
+
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index a355a93..cfcbea9 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -518,7 +518,7 @@
assuming that during normal operation, the MACE is always in
bank 0.
---------------------------------------------------------------------------- */
-static int mace_read(mace_private *lp, kio_addr_t ioaddr, int reg)
+static int mace_read(mace_private *lp, unsigned int ioaddr, int reg)
{
int data = 0xFF;
unsigned long flags;
@@ -545,7 +545,8 @@
are assuming that during normal operation, the MACE is always in
bank 0.
---------------------------------------------------------------------------- */
-static void mace_write(mace_private *lp, kio_addr_t ioaddr, int reg, int data)
+static void mace_write(mace_private *lp, unsigned int ioaddr, int reg,
+ int data)
{
unsigned long flags;
@@ -567,7 +568,7 @@
mace_init
Resets the MACE chip.
---------------------------------------------------------------------------- */
-static int mace_init(mace_private *lp, kio_addr_t ioaddr, char *enet_addr)
+static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
{
int i;
int ct = 0;
@@ -657,7 +658,7 @@
tuple_t tuple;
u_char buf[64];
int i, last_ret, last_fn;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
DECLARE_MAC_BUF(mac);
DEBUG(0, "nmclan_config(0x%p)\n", link);
@@ -839,7 +840,7 @@
---------------------------------------------------------------------------- */
static int mace_open(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
mace_private *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
@@ -862,7 +863,7 @@
---------------------------------------------------------------------------- */
static int mace_close(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
mace_private *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
@@ -935,7 +936,7 @@
static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
mace_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
netif_stop_queue(dev);
@@ -996,7 +997,7 @@
{
struct net_device *dev = (struct net_device *) dev_id;
mace_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
int status;
int IntrCnt = MACE_MAX_IR_ITERATIONS;
@@ -1140,7 +1141,7 @@
static int mace_rx(struct net_device *dev, unsigned char RxCnt)
{
mace_private *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
unsigned char rx_framecnt;
unsigned short rx_status;
@@ -1302,7 +1303,7 @@
card's SRAM fast enough. If this happens, something is
seriously wrong with the hardware.
---------------------------------------------------------------------------- */
-static void update_stats(kio_addr_t ioaddr, struct net_device *dev)
+static void update_stats(unsigned int ioaddr, struct net_device *dev)
{
mace_private *lp = netdev_priv(dev);
@@ -1448,7 +1449,7 @@
mace_private *lp = netdev_priv(dev);
int num_addrs = lp->multicast_num_addrs;
int *ladrf = lp->multicast_ladrf;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i;
DEBUG(2, "%s: restoring Rx mode to %d addresses.\n",
@@ -1540,7 +1541,7 @@
static void restore_multicast_list(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
mace_private *lp = netdev_priv(dev);
DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name,
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 9ba56aa..6323988 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -349,7 +349,7 @@
static hw_info_t *get_prom(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_char prom[32];
int i, j;
@@ -425,7 +425,7 @@
static hw_info_t *get_ax88190(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i, j;
/* Not much of a test, but the alternatives are messy */
@@ -521,7 +521,7 @@
int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
int has_shmem = 0;
u_short buf[64];
- hw_info_t *hw_info;
+ hw_info_t *local_hw_info;
DECLARE_MAC_BUF(mac);
DEBUG(0, "pcnet_config(0x%p)\n", link);
@@ -590,23 +590,23 @@
dev->if_port = 0;
}
- hw_info = get_hwinfo(link);
- if (hw_info == NULL)
- hw_info = get_prom(link);
- if (hw_info == NULL)
- hw_info = get_dl10019(link);
- if (hw_info == NULL)
- hw_info = get_ax88190(link);
- if (hw_info == NULL)
- hw_info = get_hwired(link);
+ local_hw_info = get_hwinfo(link);
+ if (local_hw_info == NULL)
+ local_hw_info = get_prom(link);
+ if (local_hw_info == NULL)
+ local_hw_info = get_dl10019(link);
+ if (local_hw_info == NULL)
+ local_hw_info = get_ax88190(link);
+ if (local_hw_info == NULL)
+ local_hw_info = get_hwired(link);
- if (hw_info == NULL) {
+ if (local_hw_info == NULL) {
printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
" address for io base %#3lx\n", dev->base_addr);
goto failed;
}
- info->flags = hw_info->flags;
+ info->flags = local_hw_info->flags;
/* Check for user overrides */
info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
if ((link->manf_id == MANFID_SOCKET) &&
@@ -756,7 +756,7 @@
#define MDIO_DATA_READ 0x10
#define MDIO_MASK 0x0f
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
{
int bits, mask = inb(addr) & MDIO_MASK;
for (bits = 0; bits < 32; bits++) {
@@ -765,7 +765,7 @@
}
}
-static int mdio_read(kio_addr_t addr, int phy_id, int loc)
+static int mdio_read(unsigned int addr, int phy_id, int loc)
{
u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
int i, retval = 0, mask = inb(addr) & MDIO_MASK;
@@ -784,7 +784,7 @@
return (retval>>1) & 0xffff;
}
-static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
+static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
{
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i, mask = inb(addr) & MDIO_MASK;
@@ -818,10 +818,10 @@
#define DL19FDUPLX 0x0400 /* DL10019 Full duplex mode */
-static int read_eeprom(kio_addr_t ioaddr, int location)
+static int read_eeprom(unsigned int ioaddr, int location)
{
int i, retval = 0;
- kio_addr_t ee_addr = ioaddr + DLINK_EEPROM;
+ unsigned int ee_addr = ioaddr + DLINK_EEPROM;
int read_cmd = location | (EE_READ_CMD << 8);
outb(0, ee_addr);
@@ -852,10 +852,10 @@
In ASIC mode, EE_ADOT is used to output the data to the ASIC.
*/
-static void write_asic(kio_addr_t ioaddr, int location, short asic_data)
+static void write_asic(unsigned int ioaddr, int location, short asic_data)
{
int i;
- kio_addr_t ee_addr = ioaddr + DLINK_EEPROM;
+ unsigned int ee_addr = ioaddr + DLINK_EEPROM;
short dataval;
int read_cmd = location | (EE_READ_CMD << 8);
@@ -897,7 +897,7 @@
static void set_misc_reg(struct net_device *dev)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
pcnet_dev_t *info = PRIV(dev);
u_char tmp;
@@ -936,7 +936,7 @@
static void mii_phy_probe(struct net_device *dev)
{
pcnet_dev_t *info = PRIV(dev);
- kio_addr_t mii_addr = dev->base_addr + DLINK_GPIO;
+ unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
int i;
u_int tmp, phyid;
@@ -1014,7 +1014,7 @@
static void pcnet_reset_8390(struct net_device *dev)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
int i;
ei_status.txing = ei_status.dmaing = 0;
@@ -1074,8 +1074,8 @@
{
struct net_device *dev = (struct net_device *)arg;
pcnet_dev_t *info = PRIV(dev);
- kio_addr_t nic_base = dev->base_addr;
- kio_addr_t mii_addr = nic_base + DLINK_GPIO;
+ unsigned int nic_base = dev->base_addr;
+ unsigned int mii_addr = nic_base + DLINK_GPIO;
u_short link;
if (!netif_device_present(dev)) goto reschedule;
@@ -1177,7 +1177,7 @@
{
pcnet_dev_t *info = PRIV(dev);
u16 *data = (u16 *)&rq->ifr_ifru;
- kio_addr_t mii_addr = dev->base_addr + DLINK_GPIO;
+ unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
switch (cmd) {
case SIOCGMIIPHY:
data[0] = info->phy_id;
@@ -1199,7 +1199,7 @@
struct e8390_pkt_hdr *hdr,
int ring_page)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
if (ei_status.dmaing) {
printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
@@ -1230,7 +1230,7 @@
static void dma_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
int xfer_count = count;
char *buf = skb->data;
@@ -1285,7 +1285,7 @@
static void dma_block_output(struct net_device *dev, int count,
const u_char *buf, const int start_page)
{
- kio_addr_t nic_base = dev->base_addr;
+ unsigned int nic_base = dev->base_addr;
pcnet_dev_t *info = PRIV(dev);
#ifdef PCMCIA_DEBUG
int retries = 0;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index c9868e9..f18eca9 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -295,7 +295,7 @@
static void smc_set_xcvr(struct net_device *dev, int if_port);
static void smc_reset(struct net_device *dev);
static void media_check(u_long arg);
-static void mdio_sync(kio_addr_t addr);
+static void mdio_sync(unsigned int addr);
static int mdio_read(struct net_device *dev, int phy_id, int loc);
static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
static int smc_link_ok(struct net_device *dev);
@@ -601,8 +601,8 @@
{
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
- kio_addr_t iouart = link->io.BasePort2;
+ unsigned int ioaddr = dev->base_addr;
+ unsigned int iouart = link->io.BasePort2;
/* Set UART base address and force map with COR bit 1 */
writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0);
@@ -621,7 +621,7 @@
static int mot_setup(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int i, wait, loop;
u_int addr;
@@ -754,7 +754,7 @@
static int osi_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- static const kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+ static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
int i, j;
link->conf.Attributes |= CONF_ENABLE_SPKR;
@@ -900,7 +900,7 @@
static int check_sig(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int width;
u_short s;
@@ -960,7 +960,7 @@
struct smc_private *smc = netdev_priv(dev);
char *name;
int i, j, rev;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
u_long mir;
DECLARE_MAC_BUF(mac);
@@ -1136,7 +1136,7 @@
#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
#define MDIO_DATA_READ 0x02
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
{
int bits;
for (bits = 0; bits < 32; bits++) {
@@ -1147,7 +1147,7 @@
static int mdio_read(struct net_device *dev, int phy_id, int loc)
{
- kio_addr_t addr = dev->base_addr + MGMT;
+ unsigned int addr = dev->base_addr + MGMT;
u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
int i, retval = 0;
@@ -1167,7 +1167,7 @@
static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
{
- kio_addr_t addr = dev->base_addr + MGMT;
+ unsigned int addr = dev->base_addr + MGMT;
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i;
@@ -1193,7 +1193,7 @@
#ifdef PCMCIA_DEBUG
static void smc_dump(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_short i, w, save;
save = inw(ioaddr + BANK_SELECT);
for (w = 0; w < 4; w++) {
@@ -1248,7 +1248,7 @@
{
struct smc_private *smc = netdev_priv(dev);
struct pcmcia_device *link = smc->p_dev;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
DEBUG(0, "%s: smc_close(), status %4.4x.\n",
dev->name, inw(ioaddr + BANK_SELECT));
@@ -1285,7 +1285,7 @@
{
struct smc_private *smc = netdev_priv(dev);
struct sk_buff *skb = smc->saved_skb;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_char packet_no;
if (!skb) {
@@ -1349,7 +1349,7 @@
static void smc_tx_timeout(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
"Tx_status %2.2x status %4.4x.\n",
@@ -1364,7 +1364,7 @@
static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_short num_pages;
short time_out, ir;
unsigned long flags;
@@ -1434,7 +1434,7 @@
static void smc_tx_err(struct net_device * dev)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
int tx_status;
@@ -1478,7 +1478,7 @@
static void smc_eph_irq(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_short card_stats, ephs;
SMC_SELECT_BANK(0);
@@ -1513,7 +1513,7 @@
{
struct net_device *dev = dev_id;
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
u_short saved_bank, saved_pointer, mask, status;
unsigned int handled = 1;
char bogus_cnt = INTR_WORK; /* Work we are willing to do. */
@@ -1633,7 +1633,7 @@
static void smc_rx(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int rx_status;
int packet_length; /* Caution: not frame length, rather words
to transfer from the chip. */
@@ -1738,7 +1738,7 @@
static void set_rx_mode(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
u_int multicast_table[ 2 ] = { 0, };
unsigned long flags;
@@ -1804,7 +1804,7 @@
static void smc_set_xcvr(struct net_device *dev, int if_port)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_short saved_bank;
saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1827,7 +1827,7 @@
static void smc_reset(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
int i;
@@ -1904,7 +1904,7 @@
{
struct net_device *dev = (struct net_device *) arg;
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u_short i, media, saved_bank;
u_short link;
unsigned long flags;
@@ -2021,7 +2021,7 @@
static int smc_link_ok(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
if (smc->cfg & CFG_MII_SELECT) {
@@ -2035,7 +2035,7 @@
static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
@@ -2057,7 +2057,7 @@
static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
if (ecmd->speed != SPEED_10)
return -EINVAL;
@@ -2100,7 +2100,7 @@
static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 saved_bank = inw(ioaddr + BANK_SELECT);
int ret;
@@ -2118,7 +2118,7 @@
static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 saved_bank = inw(ioaddr + BANK_SELECT);
int ret;
@@ -2136,7 +2136,7 @@
static u32 smc_get_link(struct net_device *dev)
{
struct smc_private *smc = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 saved_bank = inw(ioaddr + BANK_SELECT);
u32 ret;
@@ -2164,7 +2164,7 @@
{
struct smc_private *smc = netdev_priv(dev);
if (smc->cfg & CFG_MII_SELECT) {
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 saved_bank = inw(ioaddr + BANK_SELECT);
int res;
@@ -2196,7 +2196,7 @@
struct mii_ioctl_data *mii = if_mii(rq);
int rc = 0;
u16 saved_bank;
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
if (!netif_running(dev))
return -EINVAL;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 1f09bea..d041f83 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -273,12 +273,12 @@
static unsigned maxrx_bytes = 22000;
/* MII management prototypes */
-static void mii_idle(kio_addr_t ioaddr);
-static void mii_putbit(kio_addr_t ioaddr, unsigned data);
-static int mii_getbit(kio_addr_t ioaddr);
-static void mii_wbits(kio_addr_t ioaddr, unsigned data, int len);
-static unsigned mii_rd(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg);
-static void mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg,
+static void mii_idle(unsigned int ioaddr);
+static void mii_putbit(unsigned int ioaddr, unsigned data);
+static int mii_getbit(unsigned int ioaddr);
+static void mii_wbits(unsigned int ioaddr, unsigned data, int len);
+static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg);
+static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg,
unsigned data, int len);
/*
@@ -403,7 +403,7 @@
static void
PrintRegisters(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
if (pc_debug > 1) {
int i, page;
@@ -439,7 +439,7 @@
* Turn around for read
*/
static void
-mii_idle(kio_addr_t ioaddr)
+mii_idle(unsigned int ioaddr)
{
PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */
udelay(1);
@@ -451,7 +451,7 @@
* Write a bit to MDI/O
*/
static void
-mii_putbit(kio_addr_t ioaddr, unsigned data)
+mii_putbit(unsigned int ioaddr, unsigned data)
{
#if 1
if (data) {
@@ -484,7 +484,7 @@
* Get a bit from MDI/O
*/
static int
-mii_getbit(kio_addr_t ioaddr)
+mii_getbit(unsigned int ioaddr)
{
unsigned d;
@@ -497,7 +497,7 @@
}
static void
-mii_wbits(kio_addr_t ioaddr, unsigned data, int len)
+mii_wbits(unsigned int ioaddr, unsigned data, int len)
{
unsigned m = 1 << (len-1);
for (; m; m >>= 1)
@@ -505,7 +505,7 @@
}
static unsigned
-mii_rd(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg)
+mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg)
{
int i;
unsigned data=0, m;
@@ -527,7 +527,8 @@
}
static void
-mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len)
+mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data,
+ int len)
{
int i;
@@ -726,7 +727,7 @@
local_info_t *local = netdev_priv(dev);
tuple_t tuple;
cisparse_t parse;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
int err, i;
u_char buf[64];
cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
@@ -1104,7 +1105,7 @@
{
struct net_device *dev = (struct net_device *)dev_id;
local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
u_char saved_page;
unsigned bytes_rcvd;
unsigned int_status, eth_status, rx_status, tx_status;
@@ -1209,7 +1210,7 @@
unsigned i;
u_long *p = skb_put(skb, pktlen);
register u_long a;
- kio_addr_t edpreg = ioaddr+XIRCREG_EDP-2;
+ unsigned int edpreg = ioaddr+XIRCREG_EDP-2;
for (i=0; i < len ; i += 4, p++) {
a = inl(edpreg);
__asm__("rorl $16,%0\n\t"
@@ -1346,7 +1347,7 @@
do_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
local_info_t *lp = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
int okay;
unsigned freespace;
unsigned pktlen = skb->len;
@@ -1415,7 +1416,7 @@
static void
set_addresses(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
local_info_t *lp = netdev_priv(dev);
struct dev_mc_list *dmi = dev->mc_list;
unsigned char *addr;
@@ -1459,7 +1460,7 @@
static void
set_multicast_list(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
SelectPage(0x42);
if (dev->flags & IFF_PROMISC) { /* snoop */
@@ -1543,7 +1544,7 @@
do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
local_info_t *local = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_ifru;
DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n",
@@ -1575,7 +1576,7 @@
hardreset(struct net_device *dev)
{
local_info_t *local = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
SelectPage(4);
udelay(1);
@@ -1592,7 +1593,7 @@
do_reset(struct net_device *dev, int full)
{
local_info_t *local = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
unsigned value;
DEBUG(0, "%s: do_reset(%p,%d)\n", dev? dev->name:"eth?", dev, full);
@@ -1753,7 +1754,7 @@
init_mii(struct net_device *dev)
{
local_info_t *local = netdev_priv(dev);
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
unsigned control, status, linkpartner;
int i;
@@ -1826,7 +1827,7 @@
do_powerdown(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
DEBUG(0, "do_powerdown(%p)\n", dev);
@@ -1838,7 +1839,7 @@
static int
do_stop(struct net_device *dev)
{
- kio_addr_t ioaddr = dev->base_addr;
+ unsigned int ioaddr = dev->base_addr;
local_info_t *lp = netdev_priv(dev);
struct pcmcia_device *link = lp->p_dev;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 7fe03ce..f4ca059 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -60,6 +60,11 @@
---help---
Currently supports the IP175C PHY.
+config REALTEK_PHY
+ tristate "Drivers for Realtek PHYs"
+ ---help---
+ Supports the Realtek 821x PHY.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3d6cc7b..5997d6e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,5 +12,6 @@
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 29666c8..5b80358 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -141,6 +141,20 @@
.driver = { .owner = THIS_MODULE },
};
+static struct phy_driver bcm5482_driver = {
+ .phy_id = 0x0143bcb0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM5482",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = bcm54xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm54xx_ack_interrupt,
+ .config_intr = bcm54xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
static int __init broadcom_init(void)
{
int ret;
@@ -154,8 +168,13 @@
ret = phy_driver_register(&bcm5461_driver);
if (ret)
goto out_5461;
+ ret = phy_driver_register(&bcm5482_driver);
+ if (ret)
+ goto out_5482;
return ret;
+out_5482:
+ phy_driver_unregister(&bcm5461_driver);
out_5461:
phy_driver_unregister(&bcm5421_driver);
out_5421:
@@ -166,6 +185,7 @@
static void __exit broadcom_exit(void)
{
+ phy_driver_unregister(&bcm5482_driver);
phy_driver_unregister(&bcm5461_driver);
phy_driver_unregister(&bcm5421_driver);
phy_driver_unregister(&bcm5411_driver);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index c30196d..6e9f619 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -49,7 +49,7 @@
int i;
int err = 0;
- spin_lock_init(&bus->mdio_lock);
+ mutex_init(&bus->mdio_lock);
if (NULL == bus || NULL == bus->name ||
NULL == bus->read ||
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7c9e6e3..12fccb1 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -26,7 +26,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
@@ -72,9 +71,11 @@
int retval;
struct mii_bus *bus = phydev->bus;
- spin_lock_bh(&bus->mdio_lock);
+ BUG_ON(in_interrupt());
+
+ mutex_lock(&bus->mdio_lock);
retval = bus->read(bus, phydev->addr, regnum);
- spin_unlock_bh(&bus->mdio_lock);
+ mutex_unlock(&bus->mdio_lock);
return retval;
}
@@ -95,9 +96,11 @@
int err;
struct mii_bus *bus = phydev->bus;
- spin_lock_bh(&bus->mdio_lock);
+ BUG_ON(in_interrupt());
+
+ mutex_lock(&bus->mdio_lock);
err = bus->write(bus, phydev->addr, regnum, val);
- spin_unlock_bh(&bus->mdio_lock);
+ mutex_unlock(&bus->mdio_lock);
return err;
}
@@ -428,7 +431,7 @@
{
int err;
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
if (AUTONEG_DISABLE == phydev->autoneg)
phy_sanitize_settings(phydev);
@@ -449,13 +452,14 @@
}
out_unlock:
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
return err;
}
EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
+static void phy_state_machine(struct work_struct *work);
static void phy_timer(unsigned long data);
/**
@@ -476,6 +480,7 @@
{
phydev->adjust_state = handler;
+ INIT_WORK(&phydev->state_queue, phy_state_machine);
init_timer(&phydev->phy_timer);
phydev->phy_timer.function = &phy_timer;
phydev->phy_timer.data = (unsigned long) phydev;
@@ -493,11 +498,12 @@
void phy_stop_machine(struct phy_device *phydev)
{
del_timer_sync(&phydev->phy_timer);
+ cancel_work_sync(&phydev->state_queue);
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
if (phydev->state > PHY_UP)
phydev->state = PHY_UP;
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
phydev->adjust_state = NULL;
}
@@ -541,9 +547,9 @@
*/
void phy_error(struct phy_device *phydev)
{
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
phydev->state = PHY_HALTED;
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
}
/**
@@ -705,10 +711,10 @@
if (err)
goto phy_err;
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
phydev->state = PHY_CHANGELINK;
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
atomic_dec(&phydev->irq_disable);
enable_irq(phydev->irq);
@@ -735,7 +741,7 @@
*/
void phy_stop(struct phy_device *phydev)
{
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
if (PHY_HALTED == phydev->state)
goto out_unlock;
@@ -751,7 +757,7 @@
phydev->state = PHY_HALTED;
out_unlock:
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
/*
* Cannot call flush_scheduled_work() here as desired because
@@ -773,7 +779,7 @@
*/
void phy_start(struct phy_device *phydev)
{
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
switch (phydev->state) {
case PHY_STARTING:
@@ -787,19 +793,26 @@
default:
break;
}
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
}
EXPORT_SYMBOL(phy_stop);
EXPORT_SYMBOL(phy_start);
-/* PHY timer which handles the state machine */
-static void phy_timer(unsigned long data)
+/**
+ * phy_state_machine - Handle the state machine
+ * @work: work_struct that describes the work to be done
+ *
+ * Description: Scheduled by the state_queue workqueue each time
+ * phy_timer is triggered.
+ */
+static void phy_state_machine(struct work_struct *work)
{
- struct phy_device *phydev = (struct phy_device *)data;
+ struct phy_device *phydev =
+ container_of(work, struct phy_device, state_queue);
int needs_aneg = 0;
int err = 0;
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
if (phydev->adjust_state)
phydev->adjust_state(phydev->attached_dev);
@@ -965,7 +978,7 @@
break;
}
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
if (needs_aneg)
err = phy_start_aneg(phydev);
@@ -976,3 +989,14 @@
mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
}
+/* PHY timer which schedules the state machine work */
+static void phy_timer(unsigned long data)
+{
+ struct phy_device *phydev = (struct phy_device *)data;
+
+ /*
+ * PHY I/O operations can potentially sleep so we ensure that
+ * it's done from a process context
+ */
+ schedule_work(&phydev->state_queue);
+}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 5b9e175..f4c4fd8 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -25,7 +25,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
@@ -80,7 +79,7 @@
dev->state = PHY_DOWN;
- spin_lock_init(&dev->lock);
+ mutex_init(&dev->lock);
return dev;
}
@@ -656,7 +655,7 @@
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
phydev->irq = PHY_POLL;
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
/* Start out supporting everything. Eventually,
* a controller will attach, and may modify one
@@ -670,7 +669,7 @@
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
return err;
@@ -682,9 +681,9 @@
phydev = to_phy_device(dev);
- spin_lock_bh(&phydev->lock);
+ mutex_lock(&phydev->lock);
phydev->state = PHY_DOWN;
- spin_unlock_bh(&phydev->lock);
+ mutex_unlock(&phydev->lock);
if (phydev->drv->remove)
phydev->drv->remove(phydev);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
new file mode 100644
index 0000000..a052a67
--- /dev/null
+++ b/drivers/net/phy/realtek.c
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+ * Author: Johnson Leung <r58129@freescale.com>
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/phy.h>
+
+#define RTL821x_PHYSR 0x11
+#define RTL821x_PHYSR_DUPLEX 0x2000
+#define RTL821x_PHYSR_SPEED 0xc000
+#define RTL821x_INER 0x12
+#define RTL821x_INER_INIT 0x6400
+#define RTL821x_INSR 0x13
+
+MODULE_DESCRIPTION("Realtek PHY driver");
+MODULE_AUTHOR("Johnson Leung");
+MODULE_LICENSE("GPL");
+
+static int rtl821x_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read(phydev, RTL821x_INSR);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl821x_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, RTL821x_INER,
+ RTL821x_INER_INIT);
+ else
+ err = phy_write(phydev, RTL821x_INER, 0);
+
+ return err;
+}
+
+/* RTL8211B */
+static struct phy_driver rtl821x_driver = {
+ .phy_id = 0x001cc912,
+ .name = "RTL821x Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl821x_ack_interrupt,
+ .config_intr = &rtl821x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init realtek_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&rtl821x_driver);
+
+ return ret;
+}
+
+static void __exit realtek_exit(void)
+{
+ phy_driver_unregister(&rtl821x_driver);
+}
+
+module_init(realtek_init);
+module_exit(realtek_exit);
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 1b51bb6..5aa0a80 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -2468,9 +2468,10 @@
out:
return err;
-
+#ifdef CONFIG_PROC_FS
out_unregister_pppox_proto:
unregister_pppox_proto(PX_PROTO_OL2TP);
+#endif
out_unregister_pppol2tp_proto:
proto_unregister(&pppol2tp_sk_proto);
goto out;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 5fab7d7..6179a0a 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -8118,7 +8118,7 @@
lro->iph = ip;
lro->tcph = tcp;
lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
- lro->tcp_ack = ntohl(tcp->ack_seq);
+ lro->tcp_ack = tcp->ack_seq;
lro->sg_num = 1;
lro->total_len = ntohs(ip->tot_len);
lro->frags_len = 0;
@@ -8127,10 +8127,10 @@
* already been done.
*/
if (tcp->doff == 8) {
- u32 *ptr;
- ptr = (u32 *)(tcp+1);
+ __be32 *ptr;
+ ptr = (__be32 *)(tcp+1);
lro->saw_ts = 1;
- lro->cur_tsval = *(ptr+1);
+ lro->cur_tsval = ntohl(*(ptr+1));
lro->cur_tsecr = *(ptr+2);
}
lro->in_use = 1;
@@ -8156,7 +8156,7 @@
/* Update tsecr field if this session has timestamps enabled */
if (lro->saw_ts) {
- u32 *ptr = (u32 *)(tcp + 1);
+ __be32 *ptr = (__be32 *)(tcp + 1);
*(ptr+2) = lro->cur_tsecr;
}
@@ -8181,10 +8181,10 @@
lro->window = tcp->window;
if (lro->saw_ts) {
- u32 *ptr;
+ __be32 *ptr;
/* Update tsecr and tsval from this packet */
- ptr = (u32 *) (tcp + 1);
- lro->cur_tsval = *(ptr + 1);
+ ptr = (__be32 *)(tcp+1);
+ lro->cur_tsval = ntohl(*(ptr+1));
lro->cur_tsecr = *(ptr + 2);
}
}
@@ -8235,11 +8235,11 @@
/* Ensure timestamp value increases monotonically */
if (l_lro)
- if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
+ if (l_lro->cur_tsval > ntohl(*((__be32 *)(ptr+2))))
return -1;
/* timestamp echo reply should be non-zero */
- if (*((u32 *)(ptr+6)) == 0)
+ if (*((__be32 *)(ptr+6)) == 0)
return -1;
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 9f6016c..64b88eb 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -809,7 +809,7 @@
int in_use;
__be16 window;
u32 cur_tsval;
- u32 cur_tsecr;
+ __be32 cur_tsecr;
u8 saw_ts;
};
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index b570402..2e9e88b 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -326,7 +326,7 @@
{ "SiS 191 PCI Gigabit Ethernet adapter" },
};
-static struct pci_device_id sis190_pci_tbl[] __devinitdata = {
+static struct pci_device_id sis190_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
{ 0, },
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index 62b0132..889f987 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -598,7 +598,7 @@
req->cmd.sba_cmd = REQUEST_ALLOCATION ;
/*
- * set the parameter type and parameter lenght of all used
+ * set the parameter type and parameter length of all used
* parameters
*/
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index a45205d..76dc8ad 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -398,7 +398,7 @@
/* u_long td; transmit descriptor */
/* struct fddi_mac *mac; mac frame pointer */
/* unsigned off; start address within buffer memory */
-/* int len ; lenght of the frame including the FC */
+/* int len ; length of the frame including the FC */
{
int i ;
u_int *p ;
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
index 8a430a3..46e3393 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/skfp/hwmtm.c
@@ -1185,7 +1185,7 @@
DB_RX("frame length = %d",len,0,4) ;
/*
- * check the frame_lenght and all error flags
+ * check the frame_length and all error flags
*/
if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
if (rfsw & RD_S_MSRABT) {
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 626190e..9a62959 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -623,6 +623,7 @@
static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
/* Turn on/off phy power saving */
if (onoff)
@@ -634,7 +635,8 @@
reg1 |= coma_mode[port];
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ sky2_pci_read32(hw, PCI_DEV_REG1);
udelay(100);
}
@@ -855,7 +857,7 @@
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
/* On chips without ram buffer, pause is controled by MAC level */
- if (sky2_read8(hw, B2_E_0) == 0) {
+ if (!(hw->flags & SKY2_HW_RAM_BUFFER)) {
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
@@ -1192,7 +1194,7 @@
struct sk_buff *skb;
int i;
- if (sky2->hw->flags & SKY2_HW_FIFO_HANG_CHECK) {
+ if (sky2->hw->flags & SKY2_HW_RAM_BUFFER) {
unsigned char *start;
/*
* Workaround for a bug in FIFO that cause hang
@@ -1385,6 +1387,7 @@
if (ramsize > 0) {
u32 rxspace;
+ hw->flags |= SKY2_HW_RAM_BUFFER;
pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
if (ramsize < 16)
rxspace = ramsize / 2;
@@ -1422,6 +1425,7 @@
imask |= portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
+ sky2_set_multicast(dev);
return 0;
err_out:
@@ -2023,7 +2027,7 @@
synchronize_irq(hw->pdev->irq);
- if (sky2_read8(hw, B2_E_0) == 0)
+ if (!(hw->flags & SKY2_HW_RAM_BUFFER))
sky2_set_tx_stfwd(hw, port);
ctl = gma_read16(hw, port, GM_GP_CTRL);
@@ -2436,6 +2440,7 @@
if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
u16 pci_err;
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
pci_err = sky2_pci_read16(hw, PCI_STATUS);
if (net_ratelimit())
dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
@@ -2443,12 +2448,14 @@
sky2_pci_write16(hw, PCI_STATUS,
pci_err | PCI_STATUS_ERROR_BITS);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
if (status & Y2_IS_PCI_EXP) {
/* PCI-Express uncorrectable Error occurred */
u32 err;
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
0xfffffffful);
@@ -2456,6 +2463,7 @@
dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
if (status & Y2_HWE_L1_MASK)
@@ -2559,7 +2567,7 @@
++active;
/* For chips with Rx FIFO, check if stuck */
- if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) &&
+ if ((hw->flags & SKY2_HW_RAM_BUFFER) &&
sky2_rx_hung(dev)) {
pr_info(PFX "%s: receiver hang detected\n",
dev->name);
@@ -2715,11 +2723,7 @@
switch(hw->chip_id) {
case CHIP_ID_YUKON_XL:
- hw->flags = SKY2_HW_GIGABIT
- | SKY2_HW_NEWER_PHY;
- if (hw->chip_rev < 3)
- hw->flags |= SKY2_HW_FIFO_HANG_CHECK;
-
+ hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
break;
case CHIP_ID_YUKON_EC_U:
@@ -2745,7 +2749,7 @@
dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
return -EOPNOTSUPP;
}
- hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK;
+ hw->flags = SKY2_HW_GIGABIT;
break;
case CHIP_ID_YUKON_FE:
@@ -2831,6 +2835,7 @@
}
sky2_power_on(hw);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
for (i = 0; i < hw->ports; i++) {
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -3554,8 +3559,6 @@
err = sky2_up(dev);
if (err)
dev_close(dev);
- else
- sky2_set_multicast(dev);
}
return err;
@@ -4389,8 +4392,6 @@
dev_close(dev);
goto out;
}
-
- sky2_set_multicast(dev);
}
}
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 2bced1a..5ab5c1c 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2045,7 +2045,7 @@
#define SKY2_HW_FIBRE_PHY 0x00000002
#define SKY2_HW_GIGABIT 0x00000004
#define SKY2_HW_NEWER_PHY 0x00000008
-#define SKY2_HW_FIFO_HANG_CHECK 0x00000010
+#define SKY2_HW_RAM_BUFFER 0x00000010
#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */
#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index fe3ac6f..0e4a88d 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1075,7 +1075,7 @@
.get_link = bigmac_get_link,
};
-static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
{
struct net_device *dev;
static int version_printed;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index ff23c64..e811331 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -747,7 +747,7 @@
qecp->gregs + GLOB_RSIZE);
}
-static u8 __init qec_get_burst(struct device_node *dp)
+static u8 __devinit qec_get_burst(struct device_node *dp)
{
u8 bsizes, bsizes_more;
@@ -767,7 +767,7 @@
return bsizes;
}
-static struct sunqec * __init get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
{
struct sbus_dev *qec_sdev = child_sdev->parent;
struct sunqec *qecp;
@@ -823,7 +823,7 @@
return NULL;
}
-static int __init qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct sbus_dev *sdev)
{
static unsigned version_printed;
struct net_device *dev;
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 4a0035f..6415ce1 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -1130,7 +1130,7 @@
.handshake_complete = vnet_handshake_complete,
};
-static void print_version(void)
+static void __devinit print_version(void)
{
static int version_printed;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index c99ce74..3af5b92 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -465,7 +465,7 @@
static int __init tlan_probe(void)
{
- static int pad_allocated;
+ int rc = -ENODEV;
printk(KERN_INFO "%s", tlan_banner);
@@ -473,17 +473,22 @@
if (TLanPadBuffer == NULL) {
printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto err_out;
}
memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE);
- pad_allocated = 1;
TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
/* Use new style PCI probing. Now the kernel will
do most of this for us */
- pci_register_driver(&tlan_driver);
+ rc = pci_register_driver(&tlan_driver);
+
+ if (rc != 0) {
+ printk(KERN_ERR "TLAN: Could not register pci driver.\n");
+ goto err_out_pci_free;
+ }
TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n");
TLan_EisaProbe();
@@ -493,11 +498,17 @@
tlan_have_pci, tlan_have_eisa);
if (TLanDevicesInstalled == 0) {
- pci_unregister_driver(&tlan_driver);
- pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
- return -ENODEV;
+ rc = -ENODEV;
+ goto err_out_pci_unreg;
}
return 0;
+
+err_out_pci_unreg:
+ pci_unregister_driver(&tlan_driver);
+err_out_pci_free:
+ pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
+err_out:
+ return rc;
}
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 124cfd4..7a7de04 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -10,7 +10,7 @@
* - Madge Smart 16/4 PCI Mk2
*
* Maintainer(s):
- * AF Adam Fritzler mid@auk.cx
+ * AF Adam Fritzler
*
* Modification History:
* 30-Dec-99 AF Split off from the tms380tr driver.
diff --git a/drivers/net/tokenring/abyss.h b/drivers/net/tokenring/abyss.h
index 0ee6e4f..b0a473b 100644
--- a/drivers/net/tokenring/abyss.h
+++ b/drivers/net/tokenring/abyss.h
@@ -2,7 +2,7 @@
* abyss.h: Header for the abyss tms380tr module
*
* Authors:
- * - Adam Fritzler <mid@auk.cx>
+ * - Adam Fritzler
*/
#ifndef __LINUX_MADGETR_H
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 5a41513..c9c5a2b 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -11,7 +11,7 @@
* - Madge Smart 16/4 Ringnode MC32 (??)
*
* Maintainer(s):
- * AF Adam Fritzler mid@auk.cx
+ * AF Adam Fritzler
*
* Modification History:
* 16-Jan-00 AF Created
diff --git a/drivers/net/tokenring/madgemc.h b/drivers/net/tokenring/madgemc.h
index 2dd8222..fe88e27 100644
--- a/drivers/net/tokenring/madgemc.h
+++ b/drivers/net/tokenring/madgemc.h
@@ -2,7 +2,7 @@
* madgemc.h: Header for the madgemc tms380tr module
*
* Authors:
- * - Adam Fritzler <mid@auk.cx>
+ * - Adam Fritzler
*/
#ifndef __LINUX_MADGEMC_H
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index e7b4adc..433c994 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -434,7 +434,7 @@
}
-static int olympic_open(struct net_device *dev)
+static int __devinit olympic_open(struct net_device *dev)
{
struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index ca6b659..00ea945 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -12,7 +12,7 @@
* - Proteon 1392, 1392+
*
* Maintainer(s):
- * AF Adam Fritzler mid@auk.cx
+ * AF Adam Fritzler
* JF Jochen Friedrich jochen@scram.de
*
* Modification History:
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 32e8d5a..41b6999 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -13,7 +13,7 @@
* - SysKonnect TR4/16(+) ISA (SK-4190)
*
* Maintainer(s):
- * AF Adam Fritzler mid@auk.cx
+ * AF Adam Fritzler
* JF Jochen Friedrich jochen@scram.de
*
* Modification History:
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index d5fa36d..d07c452 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -30,7 +30,7 @@
* Maintainer(s):
* JS Jay Schulist jschlst@samba.org
* CG Christoph Goos cgoos@syskonnect.de
- * AF Adam Fritzler mid@auk.cx
+ * AF Adam Fritzler
* MLP Mike Phillips phillim@amtrak.com
* JF Jochen Friedrich jochen@scram.de
*
diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h
index 7daf74e..7af76d7 100644
--- a/drivers/net/tokenring/tms380tr.h
+++ b/drivers/net/tokenring/tms380tr.h
@@ -3,7 +3,7 @@
*
* Authors:
* - Christoph Goos <cgoos@syskonnect.de>
- * - Adam Fritzler <mid@auk.cx>
+ * - Adam Fritzler
*/
#ifndef __LINUX_TMS380TR_H
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 1c18f78..5f0ee88 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -14,7 +14,7 @@
* - 3Com 3C339 Token Link Velocity
*
* Maintainer(s):
- * AF Adam Fritzler mid@auk.cx
+ * AF Adam Fritzler
*
* Modification History:
* 30-Dec-99 AF Split off from the tms380tr driver.
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 8fc7274..6b93d016 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -441,7 +441,7 @@
spin_unlock_irqrestore(&card->lock,flags);
trigger_transmit(card);
- return -EIO;
+ return NETDEV_TX_BUSY;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 46339f6..038c1ef 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -529,9 +529,13 @@
if (ifr->ifr_flags & IFF_NO_PI)
tun->flags |= TUN_NO_PI;
+ else
+ tun->flags &= ~TUN_NO_PI;
if (ifr->ifr_flags & IFF_ONE_QUEUE)
tun->flags |= TUN_ONE_QUEUE;
+ else
+ tun->flags &= ~TUN_ONE_QUEUE;
file->private_data = tun;
tun->attached = 1;
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 4ffd873..fba0811 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -2084,8 +2084,10 @@
if (!ugeth)
return;
- if (ugeth->uccf)
+ if (ugeth->uccf) {
ucc_fast_free(ugeth->uccf);
+ ugeth->uccf = NULL;
+ }
if (ugeth->p_thread_data_tx) {
qe_muram_free(ugeth->thread_dat_tx_offset);
@@ -2305,10 +2307,6 @@
ug_info = ugeth->ug_info;
uf_info = &ug_info->uf_info;
- /* Create CQs for hash tables */
- INIT_LIST_HEAD(&ugeth->group_hash_q);
- INIT_LIST_HEAD(&ugeth->ind_hash_q);
-
if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
(uf_info->bd_mem_part == MEM_PART_MURAM))) {
if (netif_msg_probe(ugeth))
@@ -3668,6 +3666,23 @@
return IRQ_HANDLED;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ucc_netpoll(struct net_device *dev)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ int irq = ugeth->ug_info->uf_info.irq;
+
+ disable_irq(irq);
+ ucc_geth_irq_handler(irq, dev);
+ enable_irq(irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
/* Called when something needs to use the ethernet device */
/* Returns 0 for success. */
static int ucc_geth_open(struct net_device *dev)
@@ -3990,6 +4005,10 @@
ugeth = netdev_priv(dev);
spin_lock_init(&ugeth->lock);
+ /* Create CQs for hash tables */
+ INIT_LIST_HEAD(&ugeth->group_hash_q);
+ INIT_LIST_HEAD(&ugeth->ind_hash_q);
+
dev_set_drvdata(device, dev);
/* Set the dev->base_addr to the gfar reg region */
@@ -4006,6 +4025,9 @@
#ifdef CONFIG_UGETH_NAPI
netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
#endif /* CONFIG_UGETH_NAPI */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = ucc_netpoll;
+#endif
dev->stop = ucc_geth_close;
// dev->change_mtu = ucc_geth_change_mtu;
dev->mtu = 1500;
@@ -4040,9 +4062,10 @@
struct net_device *dev = dev_get_drvdata(device);
struct ucc_geth_private *ugeth = netdev_priv(dev);
- dev_set_drvdata(device, NULL);
- ucc_geth_memclean(ugeth);
+ unregister_netdev(dev);
free_netdev(dev);
+ ucc_geth_memclean(ugeth);
+ dev_set_drvdata(device, NULL);
return 0;
}
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index e3ba14a..c69e654 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -109,7 +109,7 @@
struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
- spin_lock_bh(&bus->mdio_lock);
+ mutex_lock(&bus->mdio_lock);
/* Reset the management interface */
out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT);
@@ -121,7 +121,7 @@
while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--)
cpu_relax();
- spin_unlock_bh(&bus->mdio_lock);
+ mutex_unlock(&bus->mdio_lock);
if (timeout <= 0) {
printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 33cbc30..7e1f001 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -926,7 +926,6 @@
netdev->set_multicast_list = rtl8150_set_multicast;
netdev->set_mac_address = rtl8150_set_mac_address;
netdev->get_stats = rtl8150_netdev_stats;
- netdev->mtu = RTL8150_MTU;
SET_ETHTOOL_OPS(netdev, &ops);
dev->intr_interval = 100; /* 100ms */
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 87c180b..7c851b1 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -606,7 +606,7 @@
}
#endif
-static void rhine_hw_init(struct net_device *dev, long pioaddr)
+static void __devinit rhine_hw_init(struct net_device *dev, long pioaddr)
{
struct rhine_private *rp = netdev_priv(dev);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 35cd65d..8c9fb82 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -8,7 +8,6 @@
* for 64bit hardware platforms.
*
* TODO
- * Big-endian support
* rx_copybreak/alignment
* Scatter gather
* More testing
@@ -681,7 +680,7 @@
* Init state, all RD entries belong to the NIC
*/
for (i = 0; i < vptr->options.numrx; ++i)
- vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC;
+ vptr->rd_ring[i].rdesc0.len |= OWNED_BY_NIC;
writew(vptr->options.numrx, ®s->RBRDU);
writel(vptr->rd_pool_dma, ®s->RDBaseLo);
@@ -777,7 +776,7 @@
vptr->int_mask = INT_MASK_DEF;
- writel(cpu_to_le32(vptr->rd_pool_dma), ®s->RDBaseLo);
+ writel(vptr->rd_pool_dma, ®s->RDBaseLo);
writew(vptr->options.numrx - 1, ®s->RDCSize);
mac_rx_queue_run(regs);
mac_rx_queue_wake(regs);
@@ -785,7 +784,7 @@
writew(vptr->options.numtx - 1, ®s->TDCSize);
for (i = 0; i < vptr->num_txq; i++) {
- writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i]));
+ writel(vptr->td_pool_dma[i], ®s->TDBaseLo[i]);
mac_tx_queue_run(regs, i);
}
@@ -1195,7 +1194,7 @@
dirty = vptr->rd_dirty - unusable;
for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
- vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
+ vptr->rd_ring[dirty].rdesc0.len |= OWNED_BY_NIC;
}
writew(vptr->rd_filled & 0xfffc, ®s->RBRDU);
@@ -1210,7 +1209,7 @@
struct rx_desc *rd = vptr->rd_ring + dirty;
/* Fine for an all zero Rx desc at init time as well */
- if (rd->rdesc0.owner == OWNED_BY_NIC)
+ if (rd->rdesc0.len & OWNED_BY_NIC)
break;
if (!vptr->rd_info[dirty].skb) {
@@ -1413,7 +1412,7 @@
if (!vptr->rd_info[rd_curr].skb)
break;
- if (rd->rdesc0.owner == OWNED_BY_NIC)
+ if (rd->rdesc0.len & OWNED_BY_NIC)
break;
rmb();
@@ -1421,7 +1420,7 @@
/*
* Don't drop CE or RL error frame although RXOK is off
*/
- if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
+ if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
if (velocity_receive_frame(vptr, rd_curr) < 0)
stats->rx_dropped++;
} else {
@@ -1433,7 +1432,7 @@
stats->rx_dropped++;
}
- rd->inten = 1;
+ rd->size |= RX_INTEN;
vptr->dev->last_rx = jiffies;
@@ -1554,7 +1553,7 @@
struct net_device_stats *stats = &vptr->stats;
struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
struct rx_desc *rd = &(vptr->rd_ring[idx]);
- int pkt_len = rd->rdesc0.len;
+ int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
struct sk_buff *skb;
if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
@@ -1637,8 +1636,7 @@
*/
*((u32 *) & (rd->rdesc0)) = 0;
- rd->len = cpu_to_le32(vptr->rx_buf_sz);
- rd->inten = 1;
+ rd->size = cpu_to_le16(vptr->rx_buf_sz) | RX_INTEN;
rd->pa_low = cpu_to_le32(rd_info->skb_dma);
rd->pa_high = 0;
return 0;
@@ -1674,7 +1672,7 @@
td = &(vptr->td_rings[qnum][idx]);
tdinfo = &(vptr->td_infos[qnum][idx]);
- if (td->tdesc0.owner == OWNED_BY_NIC)
+ if (td->tdesc0.len & OWNED_BY_NIC)
break;
if ((works++ > 15))
@@ -1874,7 +1872,7 @@
for (i = 0; i < tdinfo->nskb_dma; i++) {
#ifdef VELOCITY_ZERO_COPY_SUPPORT
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], td->tdesc1.len, PCI_DMA_TODEVICE);
+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
#else
pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE);
#endif
@@ -2067,8 +2065,8 @@
struct velocity_td_info *tdinfo;
unsigned long flags;
int index;
-
int pktlen = skb->len;
+ __le16 len = cpu_to_le16(pktlen);
#ifdef VELOCITY_ZERO_COPY_SUPPORT
if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
@@ -2083,9 +2081,8 @@
td_ptr = &(vptr->td_rings[qnum][index]);
tdinfo = &(vptr->td_infos[qnum][index]);
- td_ptr->tdesc1.TCPLS = TCPLS_NORMAL;
td_ptr->tdesc1.TCR = TCR0_TIC;
- td_ptr->td_buf[0].queue = 0;
+ td_ptr->td_buf[0].size &= ~TD_QUEUE;
/*
* Pad short frames.
@@ -2093,16 +2090,16 @@
if (pktlen < ETH_ZLEN) {
/* Cannot occur until ZC support */
pktlen = ETH_ZLEN;
+ len = cpu_to_le16(ETH_ZLEN);
skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
tdinfo->skb = skb;
tdinfo->skb_dma[0] = tdinfo->buf_dma;
- td_ptr->tdesc0.pktsize = pktlen;
+ td_ptr->tdesc0.len = len;
td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+ td_ptr->td_buf[0].size = len; /* queue is 0 anyway */
tdinfo->nskb_dma = 1;
- td_ptr->tdesc1.CMDZ = 2;
} else
#ifdef VELOCITY_ZERO_COPY_SUPPORT
if (skb_shinfo(skb)->nr_frags > 0) {
@@ -2111,36 +2108,35 @@
if (nfrags > 6) {
skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
tdinfo->skb_dma[0] = tdinfo->buf_dma;
- td_ptr->tdesc0.pktsize =
+ td_ptr->tdesc0.len = len;
td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+ td_ptr->td_buf[0].size = len; /* queue is 0 anyway */
tdinfo->nskb_dma = 1;
- td_ptr->tdesc1.CMDZ = 2;
} else {
int i = 0;
tdinfo->nskb_dma = 0;
- tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, skb->len - skb->data_len, PCI_DMA_TODEVICE);
+ tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
+ skb_headlen(skb), PCI_DMA_TODEVICE);
- td_ptr->tdesc0.pktsize = pktlen;
+ td_ptr->tdesc0.len = len;
/* FIXME: support 48bit DMA later */
td_ptr->td_buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
td_ptr->td_buf[i].pa_high = 0;
- td_ptr->td_buf[i].bufsize = skb->len->skb->data_len;
+ td_ptr->td_buf[i].size = cpu_to_le16(skb_headlen(skb));
for (i = 0; i < nfrags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- void *addr = ((void *) page_address(frag->page + frag->page_offset));
+ void *addr = (void *)page_address(frag->page) + frag->page_offset;
tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
td_ptr->td_buf[i + 1].pa_high = 0;
- td_ptr->td_buf[i + 1].bufsize = frag->size;
+ td_ptr->td_buf[i + 1].size = cpu_to_le16(frag->size);
}
tdinfo->nskb_dma = i - 1;
- td_ptr->tdesc1.CMDZ = i;
}
} else
@@ -2152,18 +2148,16 @@
*/
tdinfo->skb = skb;
tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
- td_ptr->tdesc0.pktsize = pktlen;
+ td_ptr->tdesc0.len = len;
td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+ td_ptr->td_buf[0].size = len;
tdinfo->nskb_dma = 1;
- td_ptr->tdesc1.CMDZ = 2;
}
+ td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
- td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb);
- td_ptr->tdesc1.pqinf.priority = 0;
- td_ptr->tdesc1.pqinf.CFI = 0;
+ td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
td_ptr->tdesc1.TCR |= TCR0_VETAG;
}
@@ -2185,7 +2179,7 @@
if (prev < 0)
prev = vptr->options.numtx - 1;
- td_ptr->tdesc0.owner = OWNED_BY_NIC;
+ td_ptr->tdesc0.len |= OWNED_BY_NIC;
vptr->td_used[qnum]++;
vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx;
@@ -2193,7 +2187,7 @@
netif_stop_queue(dev);
td_ptr = &(vptr->td_rings[qnum][prev]);
- td_ptr->td_buf[0].queue = 1;
+ td_ptr->td_buf[0].size |= TD_QUEUE;
mac_tx_queue_wake(vptr->mac_regs, qnum);
}
dev->trans_start = jiffies;
@@ -3410,7 +3404,7 @@
velocity_save_context(vptr, &vptr->context);
velocity_shutdown(vptr);
velocity_set_wol(vptr);
- pci_enable_wake(pdev, 3, 1);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
pci_set_power_state(pdev, PCI_D3hot);
} else {
velocity_save_context(vptr, &vptr->context);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index aa917962..7387be4 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -70,40 +70,27 @@
* Bits in the RSR0 register
*/
-#define RSR_DETAG 0x0080
-#define RSR_SNTAG 0x0040
-#define RSR_RXER 0x0020
-#define RSR_RL 0x0010
-#define RSR_CE 0x0008
-#define RSR_FAE 0x0004
-#define RSR_CRC 0x0002
-#define RSR_VIDM 0x0001
+#define RSR_DETAG cpu_to_le16(0x0080)
+#define RSR_SNTAG cpu_to_le16(0x0040)
+#define RSR_RXER cpu_to_le16(0x0020)
+#define RSR_RL cpu_to_le16(0x0010)
+#define RSR_CE cpu_to_le16(0x0008)
+#define RSR_FAE cpu_to_le16(0x0004)
+#define RSR_CRC cpu_to_le16(0x0002)
+#define RSR_VIDM cpu_to_le16(0x0001)
/*
* Bits in the RSR1 register
*/
-#define RSR_RXOK 0x8000 // rx OK
-#define RSR_PFT 0x4000 // Perfect filtering address match
-#define RSR_MAR 0x2000 // MAC accept multicast address packet
-#define RSR_BAR 0x1000 // MAC accept broadcast address packet
-#define RSR_PHY 0x0800 // MAC accept physical address packet
-#define RSR_VTAG 0x0400 // 802.1p/1q tagging packet indicator
-#define RSR_STP 0x0200 // start of packet
-#define RSR_EDP 0x0100 // end of packet
-
-/*
- * Bits in the RSR1 register
- */
-
-#define RSR1_RXOK 0x80 // rx OK
-#define RSR1_PFT 0x40 // Perfect filtering address match
-#define RSR1_MAR 0x20 // MAC accept multicast address packet
-#define RSR1_BAR 0x10 // MAC accept broadcast address packet
-#define RSR1_PHY 0x08 // MAC accept physical address packet
-#define RSR1_VTAG 0x04 // 802.1p/1q tagging packet indicator
-#define RSR1_STP 0x02 // start of packet
-#define RSR1_EDP 0x01 // end of packet
+#define RSR_RXOK cpu_to_le16(0x8000) // rx OK
+#define RSR_PFT cpu_to_le16(0x4000) // Perfect filtering address match
+#define RSR_MAR cpu_to_le16(0x2000) // MAC accept multicast address packet
+#define RSR_BAR cpu_to_le16(0x1000) // MAC accept broadcast address packet
+#define RSR_PHY cpu_to_le16(0x0800) // MAC accept physical address packet
+#define RSR_VTAG cpu_to_le16(0x0400) // 802.1p/1q tagging packet indicator
+#define RSR_STP cpu_to_le16(0x0200) // start of packet
+#define RSR_EDP cpu_to_le16(0x0100) // end of packet
/*
* Bits in the CSM register
@@ -120,33 +107,21 @@
* Bits in the TSR0 register
*/
-#define TSR0_ABT 0x0080 // Tx abort because of excessive collision
-#define TSR0_OWT 0x0040 // Jumbo frame Tx abort
-#define TSR0_OWC 0x0020 // Out of window collision
-#define TSR0_COLS 0x0010 // experience collision in this transmit event
-#define TSR0_NCR3 0x0008 // collision retry counter[3]
-#define TSR0_NCR2 0x0004 // collision retry counter[2]
-#define TSR0_NCR1 0x0002 // collision retry counter[1]
-#define TSR0_NCR0 0x0001 // collision retry counter[0]
-#define TSR0_TERR 0x8000 //
-#define TSR0_FDX 0x4000 // current transaction is serviced by full duplex mode
-#define TSR0_GMII 0x2000 // current transaction is serviced by GMII mode
-#define TSR0_LNKFL 0x1000 // packet serviced during link down
-#define TSR0_SHDN 0x0400 // shutdown case
-#define TSR0_CRS 0x0200 // carrier sense lost
-#define TSR0_CDH 0x0100 // AQE test fail (CD heartbeat)
-
-/*
- * Bits in the TSR1 register
- */
-
-#define TSR1_TERR 0x80 //
-#define TSR1_FDX 0x40 // current transaction is serviced by full duplex mode
-#define TSR1_GMII 0x20 // current transaction is serviced by GMII mode
-#define TSR1_LNKFL 0x10 // packet serviced during link down
-#define TSR1_SHDN 0x04 // shutdown case
-#define TSR1_CRS 0x02 // carrier sense lost
-#define TSR1_CDH 0x01 // AQE test fail (CD heartbeat)
+#define TSR0_ABT cpu_to_le16(0x0080) // Tx abort because of excessive collision
+#define TSR0_OWT cpu_to_le16(0x0040) // Jumbo frame Tx abort
+#define TSR0_OWC cpu_to_le16(0x0020) // Out of window collision
+#define TSR0_COLS cpu_to_le16(0x0010) // experience collision in this transmit event
+#define TSR0_NCR3 cpu_to_le16(0x0008) // collision retry counter[3]
+#define TSR0_NCR2 cpu_to_le16(0x0004) // collision retry counter[2]
+#define TSR0_NCR1 cpu_to_le16(0x0002) // collision retry counter[1]
+#define TSR0_NCR0 cpu_to_le16(0x0001) // collision retry counter[0]
+#define TSR0_TERR cpu_to_le16(0x8000) //
+#define TSR0_FDX cpu_to_le16(0x4000) // current transaction is serviced by full duplex mode
+#define TSR0_GMII cpu_to_le16(0x2000) // current transaction is serviced by GMII mode
+#define TSR0_LNKFL cpu_to_le16(0x1000) // packet serviced during link down
+#define TSR0_SHDN cpu_to_le16(0x0400) // shutdown case
+#define TSR0_CRS cpu_to_le16(0x0200) // carrier sense lost
+#define TSR0_CDH cpu_to_le16(0x0100) // AQE test fail (CD heartbeat)
//
// Bits in the TCR0 register
@@ -197,25 +172,26 @@
*/
struct rdesc0 {
- u16 RSR; /* Receive status */
- u16 len:14; /* Received packet length */
- u16 reserved:1;
- u16 owner:1; /* Who owns this buffer ? */
+ __le16 RSR; /* Receive status */
+ __le16 len; /* bits 0--13; bit 15 - owner */
};
struct rdesc1 {
- u16 PQTAG;
+ __le16 PQTAG;
u8 CSM;
u8 IPKT;
};
+enum {
+ RX_INTEN = __constant_cpu_to_le16(0x8000)
+};
+
struct rx_desc {
struct rdesc0 rdesc0;
struct rdesc1 rdesc1;
- u32 pa_low; /* Low 32 bit PCI address */
- u16 pa_high; /* Next 16 bit PCI address (48 total) */
- u16 len:15; /* Frame size */
- u16 inten:1; /* Enable interrupt */
+ __le32 pa_low; /* Low 32 bit PCI address */
+ __le16 pa_high; /* Next 16 bit PCI address (48 total) */
+ __le16 size; /* bits 0--14 - frame size, bit 15 - enable int. */
} __attribute__ ((__packed__));
/*
@@ -223,32 +199,24 @@
*/
struct tdesc0 {
- u16 TSR; /* Transmit status register */
- u16 pktsize:14; /* Size of frame */
- u16 reserved:1;
- u16 owner:1; /* Who owns the buffer */
+ __le16 TSR; /* Transmit status register */
+ __le16 len; /* bits 0--13 - size of frame, bit 15 - owner */
};
-struct pqinf { /* Priority queue info */
- u16 VID:12;
- u16 CFI:1;
- u16 priority:3;
+struct tdesc1 {
+ __le16 vlan;
+ u8 TCR;
+ u8 cmd; /* bits 0--1 - TCPLS, bits 4--7 - CMDZ */
} __attribute__ ((__packed__));
-struct tdesc1 {
- struct pqinf pqinf;
- u8 TCR;
- u8 TCPLS:2;
- u8 reserved:2;
- u8 CMDZ:4;
-} __attribute__ ((__packed__));
+enum {
+ TD_QUEUE = __constant_cpu_to_le16(0x8000)
+};
struct td_buf {
- u32 pa_low;
- u16 pa_high;
- u16 bufsize:14;
- u16 reserved:1;
- u16 queue:1;
+ __le32 pa_low;
+ __le16 pa_high;
+ __le16 size; /* bits 0--13 - size, bit 15 - queue */
} __attribute__ ((__packed__));
struct tx_desc {
@@ -276,7 +244,7 @@
enum velocity_owner {
OWNED_BY_HOST = 0,
- OWNED_BY_NIC = 1
+ OWNED_BY_NIC = __constant_cpu_to_le16(0x8000)
};
@@ -1012,45 +980,45 @@
volatile u8 RCR;
volatile u8 TCR;
- volatile u32 CR0Set; /* 0x08 */
- volatile u32 CR0Clr; /* 0x0C */
+ volatile __le32 CR0Set; /* 0x08 */
+ volatile __le32 CR0Clr; /* 0x0C */
volatile u8 MARCAM[8]; /* 0x10 */
- volatile u32 DecBaseHi; /* 0x18 */
- volatile u16 DbfBaseHi; /* 0x1C */
- volatile u16 reserved_1E;
+ volatile __le32 DecBaseHi; /* 0x18 */
+ volatile __le16 DbfBaseHi; /* 0x1C */
+ volatile __le16 reserved_1E;
- volatile u16 ISRCTL; /* 0x20 */
+ volatile __le16 ISRCTL; /* 0x20 */
volatile u8 TXESR;
volatile u8 RXESR;
- volatile u32 ISR; /* 0x24 */
- volatile u32 IMR;
+ volatile __le32 ISR; /* 0x24 */
+ volatile __le32 IMR;
- volatile u32 TDStatusPort; /* 0x2C */
+ volatile __le32 TDStatusPort; /* 0x2C */
- volatile u16 TDCSRSet; /* 0x30 */
+ volatile __le16 TDCSRSet; /* 0x30 */
volatile u8 RDCSRSet;
volatile u8 reserved_33;
- volatile u16 TDCSRClr;
+ volatile __le16 TDCSRClr;
volatile u8 RDCSRClr;
volatile u8 reserved_37;
- volatile u32 RDBaseLo; /* 0x38 */
- volatile u16 RDIdx; /* 0x3C */
- volatile u16 reserved_3E;
+ volatile __le32 RDBaseLo; /* 0x38 */
+ volatile __le16 RDIdx; /* 0x3C */
+ volatile __le16 reserved_3E;
- volatile u32 TDBaseLo[4]; /* 0x40 */
+ volatile __le32 TDBaseLo[4]; /* 0x40 */
- volatile u16 RDCSize; /* 0x50 */
- volatile u16 TDCSize; /* 0x52 */
- volatile u16 TDIdx[4]; /* 0x54 */
- volatile u16 tx_pause_timer; /* 0x5C */
- volatile u16 RBRDU; /* 0x5E */
+ volatile __le16 RDCSize; /* 0x50 */
+ volatile __le16 TDCSize; /* 0x52 */
+ volatile __le16 TDIdx[4]; /* 0x54 */
+ volatile __le16 tx_pause_timer; /* 0x5C */
+ volatile __le16 RBRDU; /* 0x5E */
- volatile u32 FIFOTest0; /* 0x60 */
- volatile u32 FIFOTest1; /* 0x64 */
+ volatile __le32 FIFOTest0; /* 0x60 */
+ volatile __le32 FIFOTest1; /* 0x64 */
volatile u8 CAMADDR; /* 0x68 */
volatile u8 CAMCR; /* 0x69 */
@@ -1063,18 +1031,18 @@
volatile u8 PHYSR1;
volatile u8 MIICR;
volatile u8 MIIADR;
- volatile u16 MIIDATA;
+ volatile __le16 MIIDATA;
- volatile u16 SoftTimer0; /* 0x74 */
- volatile u16 SoftTimer1;
+ volatile __le16 SoftTimer0; /* 0x74 */
+ volatile __le16 SoftTimer1;
volatile u8 CFGA; /* 0x78 */
volatile u8 CFGB;
volatile u8 CFGC;
volatile u8 CFGD;
- volatile u16 DCFG; /* 0x7C */
- volatile u16 MCFG;
+ volatile __le16 DCFG; /* 0x7C */
+ volatile __le16 MCFG;
volatile u8 TBIST; /* 0x80 */
volatile u8 RBIST;
@@ -1086,9 +1054,9 @@
volatile u8 rev_id;
volatile u8 PORSTS;
- volatile u32 MIBData; /* 0x88 */
+ volatile __le32 MIBData; /* 0x88 */
- volatile u16 EEWrData;
+ volatile __le16 EEWrData;
volatile u8 reserved_8E;
volatile u8 BPMDWr;
@@ -1098,7 +1066,7 @@
volatile u8 EECHKSUM; /* 0x92 */
volatile u8 EECSR;
- volatile u16 EERdData; /* 0x94 */
+ volatile __le16 EERdData; /* 0x94 */
volatile u8 EADDR;
volatile u8 EMBCMD;
@@ -1112,22 +1080,22 @@
volatile u8 DEBUG;
volatile u8 CHIPGCR;
- volatile u16 WOLCRSet; /* 0xA0 */
+ volatile __le16 WOLCRSet; /* 0xA0 */
volatile u8 PWCFGSet;
volatile u8 WOLCFGSet;
- volatile u16 WOLCRClr; /* 0xA4 */
+ volatile __le16 WOLCRClr; /* 0xA4 */
volatile u8 PWCFGCLR;
volatile u8 WOLCFGClr;
- volatile u16 WOLSRSet; /* 0xA8 */
- volatile u16 reserved_AA;
+ volatile __le16 WOLSRSet; /* 0xA8 */
+ volatile __le16 reserved_AA;
- volatile u16 WOLSRClr; /* 0xAC */
- volatile u16 reserved_AE;
+ volatile __le16 WOLSRClr; /* 0xAC */
+ volatile __le16 reserved_AE;
- volatile u16 PatternCRC[8]; /* 0xB0 */
- volatile u32 ByteMask[4][4]; /* 0xC0 */
+ volatile __le16 PatternCRC[8]; /* 0xB0 */
+ volatile __le32 ByteMask[4][4]; /* 0xC0 */
} __attribute__ ((__packed__));
@@ -1238,12 +1206,12 @@
struct arp_packet {
u8 dest_mac[ETH_ALEN];
u8 src_mac[ETH_ALEN];
- u16 type;
- u16 ar_hrd;
- u16 ar_pro;
+ __be16 type;
+ __be16 ar_hrd;
+ __be16 ar_pro;
u8 ar_hln;
u8 ar_pln;
- u16 ar_op;
+ __be16 ar_op;
u8 ar_sha[ETH_ALEN];
u8 ar_sip[4];
u8 ar_tha[ETH_ALEN];
@@ -1253,7 +1221,7 @@
struct _magic_packet {
u8 dest_mac[6];
u8 src_mac[6];
- u16 type;
+ __be16 type;
u8 MAC[16][6];
u8 password[6];
} __attribute__ ((__packed__));
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 5413dbf..fdc2367 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -24,6 +24,13 @@
#include <linux/virtio_net.h>
#include <linux/scatterlist.h>
+static int napi_weight = 128;
+module_param(napi_weight, int, 0444);
+
+static int csum = 1, gso = 1;
+module_param(csum, bool, 0444);
+module_param(gso, bool, 0444);
+
/* FIXME: MTU in config. */
#define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
@@ -52,13 +59,14 @@
sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
}
-static bool skb_xmit_done(struct virtqueue *rvq)
+static void skb_xmit_done(struct virtqueue *svq)
{
- struct virtnet_info *vi = rvq->vdev->priv;
+ struct virtnet_info *vi = svq->vdev->priv;
- /* In case we were waiting for output buffers. */
+ /* Suppress further interrupts. */
+ svq->vq_ops->disable_cb(svq);
+ /* We were waiting for more output buffers. */
netif_wake_queue(vi->dev);
- return true;
}
static void receive_skb(struct net_device *dev, struct sk_buff *skb,
@@ -83,28 +91,16 @@
if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
pr_debug("Needs csum!\n");
- skb->ip_summed = CHECKSUM_PARTIAL;
- skb->csum_start = hdr->csum_start;
- skb->csum_offset = hdr->csum_offset;
- if (skb->csum_start > skb->len - 2
- || skb->csum_offset > skb->len - 2) {
- if (net_ratelimit())
- printk(KERN_WARNING "%s: csum=%u/%u len=%u\n",
- dev->name, skb->csum_start,
- skb->csum_offset, skb->len);
+ if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset))
goto frame_err;
- }
}
if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
pr_debug("GSO!\n");
- switch (hdr->gso_type) {
+ switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
case VIRTIO_NET_HDR_GSO_TCPV4:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
break;
- case VIRTIO_NET_HDR_GSO_TCPV4_ECN:
- skb_shinfo(skb)->gso_type = SKB_GSO_TCP_ECN;
- break;
case VIRTIO_NET_HDR_GSO_UDP:
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
break;
@@ -118,6 +114,9 @@
goto frame_err;
}
+ if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
+ skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+
skb_shinfo(skb)->gso_size = hdr->gso_size;
if (skb_shinfo(skb)->gso_size == 0) {
if (net_ratelimit())
@@ -170,12 +169,14 @@
vi->rvq->vq_ops->kick(vi->rvq);
}
-static bool skb_recv_done(struct virtqueue *rvq)
+static void skb_recv_done(struct virtqueue *rvq)
{
struct virtnet_info *vi = rvq->vdev->priv;
- netif_rx_schedule(vi->dev, &vi->napi);
- /* Suppress further interrupts. */
- return false;
+ /* Schedule NAPI, Suppress further interrupts if successful. */
+ if (netif_rx_schedule_prep(vi->dev, &vi->napi)) {
+ rvq->vq_ops->disable_cb(rvq);
+ __netif_rx_schedule(vi->dev, &vi->napi);
+ }
}
static int virtnet_poll(struct napi_struct *napi, int budget)
@@ -201,7 +202,7 @@
/* Out of packets? */
if (received < budget) {
netif_rx_complete(vi->dev, napi);
- if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))
+ if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq))
&& netif_rx_reschedule(vi->dev, napi))
goto again;
}
@@ -236,8 +237,6 @@
pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
- free_old_xmit_skbs(vi);
-
/* Encode metadata header at front. */
hdr = skb_vnet_hdr(skb);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -250,10 +249,9 @@
}
if (skb_is_gso(skb)) {
+ hdr->hdr_len = skb_transport_header(skb) - skb->data;
hdr->gso_size = skb_shinfo(skb)->gso_size;
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
- hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN;
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
@@ -261,19 +259,34 @@
hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
+ hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
} else {
hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
- hdr->gso_size = 0;
+ hdr->gso_size = hdr->hdr_len = 0;
}
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
__skb_queue_head(&vi->send, skb);
+
+again:
+ /* Free up any pending old buffers before queueing new ones. */
+ free_old_xmit_skbs(vi);
err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
if (err) {
pr_debug("%s: virtio not prepared to send\n", dev->name);
- skb_unlink(skb, &vi->send);
netif_stop_queue(dev);
+
+ /* Activate callback for using skbs: if this fails it
+ * means some were used in the meantime. */
+ if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+ printk("Unlikely: restart svq failed\n");
+ netif_start_queue(dev);
+ goto again;
+ }
+ __skb_unlink(skb, &vi->send);
+
return NETDEV_TX_BUSY;
}
vi->svq->vq_ops->kick(vi->svq);
@@ -285,45 +298,33 @@
{
struct virtnet_info *vi = netdev_priv(dev);
- try_fill_recv(vi);
-
- /* If we didn't even get one input buffer, we're useless. */
- if (vi->num == 0)
- return -ENOMEM;
-
napi_enable(&vi->napi);
+
+ /* If all buffers were filled by other side before we napi_enabled, we
+ * won't get another interrupt, so process any outstanding packets
+ * now. virtnet_poll wants re-enable the queue, so we disable here.
+ * We synchronize against interrupts via NAPI_STATE_SCHED */
+ if (netif_rx_schedule_prep(dev, &vi->napi)) {
+ vi->rvq->vq_ops->disable_cb(vi->rvq);
+ __netif_rx_schedule(dev, &vi->napi);
+ }
return 0;
}
static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
- struct sk_buff *skb;
napi_disable(&vi->napi);
- /* networking core has neutered skb_xmit_done/skb_recv_done, so don't
- * worry about races vs. get(). */
- vi->rvq->vq_ops->shutdown(vi->rvq);
- while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
- kfree_skb(skb);
- vi->num--;
- }
- vi->svq->vq_ops->shutdown(vi->svq);
- while ((skb = __skb_dequeue(&vi->send)) != NULL)
- kfree_skb(skb);
-
- BUG_ON(vi->num != 0);
return 0;
}
static int virtnet_probe(struct virtio_device *vdev)
{
int err;
- unsigned int len;
struct net_device *dev;
struct virtnet_info *vi;
- void *token;
/* Allocate ourselves a network device with room for our info */
dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -331,7 +332,6 @@
return -ENOMEM;
/* Set up network device as normal. */
- ether_setup(dev);
dev->open = virtnet_open;
dev->stop = virtnet_close;
dev->hard_start_xmit = start_xmit;
@@ -339,42 +339,37 @@
SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */
- token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_F, &len);
- if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_NO_CSUM)) {
+ if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
- if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4))
- dev->features |= NETIF_F_TSO;
- if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_UFO))
- dev->features |= NETIF_F_UFO;
- if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4_ECN))
- dev->features |= NETIF_F_TSO_ECN;
- if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO6))
- dev->features |= NETIF_F_TSO6;
+ if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+ dev->features |= NETIF_F_TSO | NETIF_F_UFO
+ | NETIF_F_TSO_ECN | NETIF_F_TSO6;
+ }
}
/* Configuration may specify what MAC to use. Otherwise random. */
- token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_MAC_F, &len);
- if (token) {
- dev->addr_len = len;
- vdev->config->get(vdev, token, dev->dev_addr, len);
+ if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
+ vdev->config->get(vdev,
+ offsetof(struct virtio_net_config, mac),
+ dev->dev_addr, dev->addr_len);
} else
random_ether_addr(dev->dev_addr);
/* Set up our device-specific information */
vi = netdev_priv(dev);
- netif_napi_add(dev, &vi->napi, virtnet_poll, 16);
+ netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight);
vi->dev = dev;
vi->vdev = vdev;
/* We expect two virtqueues, receive then send. */
- vi->rvq = vdev->config->find_vq(vdev, skb_recv_done);
+ vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
if (IS_ERR(vi->rvq)) {
err = PTR_ERR(vi->rvq);
goto free;
}
- vi->svq = vdev->config->find_vq(vdev, skb_xmit_done);
+ vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
if (IS_ERR(vi->svq)) {
err = PTR_ERR(vi->svq);
goto free_recv;
@@ -389,10 +384,22 @@
pr_debug("virtio_net: registering device failed\n");
goto free_send;
}
+
+ /* Last of all, set up some receive buffers. */
+ try_fill_recv(vi);
+
+ /* If we didn't even get one input buffer, we're useless. */
+ if (vi->num == 0) {
+ err = -ENOMEM;
+ goto unregister;
+ }
+
pr_debug("virtnet: registered device %s\n", dev->name);
vdev->priv = vi;
return 0;
+unregister:
+ unregister_netdev(dev);
free_send:
vdev->config->del_vq(vi->svq);
free_recv:
@@ -405,6 +412,20 @@
static void virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+ struct sk_buff *skb;
+
+ /* Stop all the virtqueues. */
+ vdev->config->reset(vdev);
+
+ /* Free our skbs in send and recv queues, if any. */
+ while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
+ kfree_skb(skb);
+ vi->num--;
+ }
+ while ((skb = __skb_dequeue(&vi->send)) != NULL)
+ kfree_skb(skb);
+
+ BUG_ON(vi->num != 0);
vdev->config->del_vq(vi->svq);
vdev->config->del_vq(vi->rvq);
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index d347d59..d14e667 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -322,7 +322,7 @@
void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
u32 i;
- /* boot buffer lenght */
+ /* boot buffer length */
writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
writew(GEN_DEFPAR, pt_boot_cmd);
@@ -353,7 +353,7 @@
void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
u32 i;
- /* boot buffer lenght */
+ /* boot buffer length */
writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
writew(GEN_DEFPAR, pt_boot_cmd);
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index d553e6f..39951d0 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -1,7 +1,7 @@
/*
* Generic HDLC support routines for Linux
*
- * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -39,7 +39,7 @@
#include <net/net_namespace.h>
-static const char* version = "HDLC support module revision 1.21";
+static const char* version = "HDLC support module revision 1.22";
#undef DEBUG_LINK
@@ -66,19 +66,15 @@
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p, struct net_device *orig_dev)
{
- struct hdlc_device_desc *desc = dev_to_desc(dev);
+ struct hdlc_device *hdlc = dev_to_hdlc(dev);
if (dev->nd_net != &init_net) {
kfree_skb(skb);
return 0;
}
- if (desc->netif_rx)
- return desc->netif_rx(skb);
-
- desc->stats.rx_dropped++; /* Shouldn't happen */
- dev_kfree_skb(skb);
- return NET_RX_DROP;
+ BUG_ON(!hdlc->proto->netif_rx);
+ return hdlc->proto->netif_rx(skb);
}
@@ -87,7 +83,7 @@
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto->start)
- return hdlc->proto->start(dev);
+ hdlc->proto->start(dev);
}
@@ -96,7 +92,7 @@
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto->stop)
- return hdlc->proto->stop(dev);
+ hdlc->proto->stop(dev);
}
@@ -263,8 +259,7 @@
struct net_device *alloc_hdlcdev(void *priv)
{
struct net_device *dev;
- dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
- sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+ dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup);
if (dev)
dev_to_hdlc(dev)->priv = priv;
return dev;
@@ -281,7 +276,7 @@
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
- int (*rx)(struct sk_buff *skb), size_t size)
+ size_t size)
{
detach_hdlc_protocol(dev);
@@ -297,7 +292,6 @@
return -ENOBUFS;
}
dev_to_hdlc(dev)->proto = proto;
- dev_to_desc(dev)->netif_rx = rx;
return 0;
}
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 038a6e7..7133c68 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -250,7 +250,7 @@
return NET_RX_DROP;
rx_error:
- dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
+ dev_to_hdlc(dev)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -314,6 +314,7 @@
.stop = cisco_stop,
.type_trans = cisco_type_trans,
.ioctl = cisco_ioctl,
+ .netif_rx = cisco_rx,
.module = THIS_MODULE,
};
@@ -360,7 +361,7 @@
if (result)
return result;
- result = attach_hdlc_protocol(dev, &proto, cisco_rx,
+ result = attach_hdlc_protocol(dev, &proto,
sizeof(struct cisco_state));
if (result)
return result;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 071a64c..c4ab032 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -42,7 +42,6 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/pkt_sched.h>
-#include <linux/random.h>
#include <linux/inetdevice.h>
#include <linux/lapb.h>
#include <linux/rtnetlink.h>
@@ -136,6 +135,10 @@
}state;
}pvc_device;
+struct pvc_desc {
+ struct net_device_stats stats;
+ pvc_device *pvc;
+};
struct frad_state {
fr_proto settings;
@@ -171,17 +174,20 @@
}
-static inline struct frad_state * state(hdlc_device *hdlc)
+static inline struct frad_state* state(hdlc_device *hdlc)
{
return(struct frad_state *)(hdlc->state);
}
-
-static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static inline struct pvc_desc* pvcdev_to_desc(struct net_device *dev)
{
return dev->priv;
}
+static inline struct net_device_stats* pvc_get_stats(struct net_device *dev)
+{
+ return &pvcdev_to_desc(dev)->stats;
+}
static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
{
@@ -351,7 +357,7 @@
static int pvc_open(struct net_device *dev)
{
- pvc_device *pvc = dev_to_pvc(dev);
+ pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
if ((pvc->frad->flags & IFF_UP) == 0)
return -EIO; /* Frad must be UP in order to activate PVC */
@@ -371,7 +377,7 @@
static int pvc_close(struct net_device *dev)
{
- pvc_device *pvc = dev_to_pvc(dev);
+ pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
if (--pvc->open_count == 0) {
hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
@@ -390,7 +396,7 @@
static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- pvc_device *pvc = dev_to_pvc(dev);
+ pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
fr_proto_pvc_info info;
if (ifr->ifr_settings.type == IF_GET_PROTO) {
@@ -416,17 +422,9 @@
return -EINVAL;
}
-
-static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
-{
- return &dev_to_desc(dev)->stats;
-}
-
-
-
static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
{
- pvc_device *pvc = dev_to_pvc(dev);
+ pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
struct net_device_stats *stats = pvc_get_stats(dev);
if (pvc->state.active) {
@@ -957,7 +955,7 @@
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- dev_to_desc(frad)->stats.rx_dropped++;
+ dev_to_hdlc(frad)->stats.rx_dropped++;
return NET_RX_DROP;
}
@@ -1018,7 +1016,7 @@
}
rx_error:
- dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
+ dev_to_hdlc(frad)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -1109,11 +1107,10 @@
used = pvc_is_used(pvc);
if (type == ARPHRD_ETHER)
- dev = alloc_netdev(sizeof(struct net_device_stats),
- "pvceth%d", ether_setup);
+ dev = alloc_netdev(sizeof(struct pvc_desc), "pvceth%d",
+ ether_setup);
else
- dev = alloc_netdev(sizeof(struct net_device_stats),
- "pvc%d", pvc_setup);
+ dev = alloc_netdev(sizeof(struct pvc_desc), "pvc%d", pvc_setup);
if (!dev) {
printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
@@ -1122,10 +1119,9 @@
return -ENOBUFS;
}
- if (type == ARPHRD_ETHER) {
- memcpy(dev->dev_addr, "\x00\x01", 2);
- get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
- } else {
+ if (type == ARPHRD_ETHER)
+ random_ether_addr(dev->dev_addr);
+ else {
*(__be16*)dev->dev_addr = htons(dlci);
dlci_to_q922(dev->broadcast, dlci);
}
@@ -1137,7 +1133,7 @@
dev->change_mtu = pvc_change_mtu;
dev->mtu = HDLC_MAX_MTU;
dev->tx_queue_len = 0;
- dev->priv = pvc;
+ pvcdev_to_desc(dev)->pvc = pvc;
result = dev_alloc_name(dev, dev->name);
if (result < 0) {
@@ -1219,6 +1215,7 @@
.stop = fr_stop,
.detach = fr_destroy,
.ioctl = fr_ioctl,
+ .netif_rx = fr_rx,
.module = THIS_MODULE,
};
@@ -1277,7 +1274,7 @@
return result;
if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
- result = attach_hdlc_protocol(dev, &proto, fr_rx,
+ result = attach_hdlc_protocol(dev, &proto,
sizeof(struct frad_state));
if (result)
return result;
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 519e155..10396d9 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -122,7 +122,7 @@
if (result)
return result;
- result = attach_hdlc_protocol(dev, &proto, NULL,
+ result = attach_hdlc_protocol(dev, &proto,
sizeof(struct ppp_state));
if (result)
return result;
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index e23bc66..bbbb819 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -82,7 +82,7 @@
if (result)
return result;
- result = attach_hdlc_protocol(dev, &proto, NULL,
+ result = attach_hdlc_protocol(dev, &proto,
sizeof(raw_hdlc_proto));
if (result)
return result;
diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
index 8895394..d20c685 100644
--- a/drivers/net/wan/hdlc_raw_eth.c
+++ b/drivers/net/wan/hdlc_raw_eth.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/pkt_sched.h>
-#include <linux/random.h>
#include <linux/inetdevice.h>
#include <linux/lapb.h>
#include <linux/rtnetlink.h>
@@ -96,7 +95,7 @@
if (result)
return result;
- result = attach_hdlc_protocol(dev, &proto, NULL,
+ result = attach_hdlc_protocol(dev, &proto,
sizeof(raw_hdlc_proto));
if (result)
return result;
@@ -107,8 +106,7 @@
ether_setup(dev);
dev->change_mtu = old_ch_mtu;
dev->tx_queue_len = old_qlen;
- memcpy(dev->dev_addr, "\x00\x01", 2);
- get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+ random_ether_addr(dev->dev_addr);
netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index cd7b22f..c15cc11 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -164,17 +164,17 @@
static int x25_rx(struct sk_buff *skb)
{
- struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
+ struct hdlc_device *hdlc = dev_to_hdlc(skb->dev);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- desc->stats.rx_dropped++;
+ hdlc->stats.rx_dropped++;
return NET_RX_DROP;
}
if (lapb_data_received(skb->dev, skb) == LAPB_OK)
return NET_RX_SUCCESS;
- desc->stats.rx_errors++;
+ hdlc->stats.rx_errors++;
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -184,6 +184,7 @@
.open = x25_open,
.close = x25_close,
.ioctl = x25_ioctl,
+ .netif_rx = x25_rx,
.module = THIS_MODULE,
};
@@ -211,8 +212,7 @@
if (result)
return result;
- if ((result = attach_hdlc_protocol(dev, &proto,
- x25_rx, 0)) != 0)
+ if ((result = attach_hdlc_protocol(dev, &proto, 0)))
return result;
dev->hard_start_xmit = x25_xmit;
dev->type = ARPHRD_X25;
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index d6599d2..ddc8714 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -153,7 +153,7 @@
#define ath5k_pci_resume NULL
#endif /* CONFIG_PM */
-static struct pci_driver ath5k_pci_drv_id = {
+static struct pci_driver ath5k_pci_driver = {
.name = "ath5k_pci",
.id_table = ath5k_pci_id_table,
.probe = ath5k_pci_probe,
@@ -329,7 +329,7 @@
ath5k_debug_init();
- ret = pci_register_driver(&ath5k_pci_drv_id);
+ ret = pci_register_driver(&ath5k_pci_driver);
if (ret) {
printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
return ret;
@@ -341,7 +341,7 @@
static void __exit
exit_ath5k_pci(void)
{
- pci_unregister_driver(&ath5k_pci_drv_id);
+ pci_unregister_driver(&ath5k_pci_driver);
ath5k_debug_finish();
}
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 32a24f5..08a011f 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -724,6 +724,7 @@
bool short_preamble; /* TRUE, if short preamble is enabled. */
bool short_slot; /* TRUE, if short slot timing is enabled. */
bool radio_hw_enable; /* saved state of radio hardware enabled state */
+ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
/* PHY/Radio device. */
struct b43_phy phy;
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 8a708b7..3dfb28a 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -337,7 +337,7 @@
return idx_to_prio[index];
}
-u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
{
static const u16 map64[] = {
B43_MMIO_DMA64_BASE0,
@@ -356,7 +356,7 @@
B43_MMIO_DMA32_BASE5,
};
- if (dma64bit) {
+ if (type == B43_DMA_64BIT) {
B43_WARN_ON(!(controller_idx >= 0 &&
controller_idx < ARRAY_SIZE(map64)));
return map64[controller_idx];
@@ -437,7 +437,7 @@
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
* which accounts for the GFP_DMA flag below.
*/
- if (ring->dma64)
+ if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
@@ -459,7 +459,8 @@
}
/* Reset the RX DMA channel */
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
+ enum b43_dmatype type)
{
int i;
u32 value;
@@ -467,12 +468,13 @@
might_sleep();
- offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+ offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
b43_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
- offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+ offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
+ B43_DMA32_RXSTATUS;
value = b43_read32(dev, mmio_base + offset);
- if (dma64) {
+ if (type == B43_DMA_64BIT) {
value &= B43_DMA64_RXSTAT;
if (value == B43_DMA64_RXSTAT_DISABLED) {
i = -1;
@@ -496,7 +498,8 @@
}
/* Reset the TX DMA channel */
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
+ enum b43_dmatype type)
{
int i;
u32 value;
@@ -505,9 +508,10 @@
might_sleep();
for (i = 0; i < 10; i++) {
- offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+ offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+ B43_DMA32_TXSTATUS;
value = b43_read32(dev, mmio_base + offset);
- if (dma64) {
+ if (type == B43_DMA_64BIT) {
value &= B43_DMA64_TXSTAT;
if (value == B43_DMA64_TXSTAT_DISABLED ||
value == B43_DMA64_TXSTAT_IDLEWAIT ||
@@ -522,12 +526,13 @@
}
msleep(1);
}
- offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+ offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
b43_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
- offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+ offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+ B43_DMA32_TXSTATUS;
value = b43_read32(dev, mmio_base + offset);
- if (dma64) {
+ if (type == B43_DMA_64BIT) {
value &= B43_DMA64_TXSTAT;
if (value == B43_DMA64_TXSTAT_DISABLED) {
i = -1;
@@ -552,6 +557,33 @@
return 0;
}
+/* Check if a DMA mapping address is invalid. */
+static bool b43_dma_mapping_error(struct b43_dmaring *ring,
+ dma_addr_t addr,
+ size_t buffersize)
+{
+ if (unlikely(dma_mapping_error(addr)))
+ return 1;
+
+ switch (ring->type) {
+ case B43_DMA_30BIT:
+ if ((u64)addr + buffersize > (1ULL << 30))
+ return 1;
+ break;
+ case B43_DMA_32BIT:
+ if ((u64)addr + buffersize > (1ULL << 32))
+ return 1;
+ break;
+ case B43_DMA_64BIT:
+ /* Currently we can't have addresses beyond
+ * 64bit in the kernel. */
+ break;
+ }
+
+ /* The address is OK. */
+ return 0;
+}
+
static int setup_rx_descbuffer(struct b43_dmaring *ring,
struct b43_dmadesc_generic *desc,
struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
@@ -567,7 +599,7 @@
if (unlikely(!skb))
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
- if (dma_mapping_error(dmaaddr)) {
+ if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
/* ugh. try to realloc in zone_dma */
gfp_flags |= GFP_DMA;
@@ -580,7 +612,7 @@
ring->rx_buffersize, 0);
}
- if (dma_mapping_error(dmaaddr)) {
+ if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
dev_kfree_skb_any(skb);
return -EIO;
}
@@ -645,7 +677,7 @@
u32 trans = ssb_dma_translation(ring->dev->dev);
if (ring->tx) {
- if (ring->dma64) {
+ if (ring->type == B43_DMA_64BIT) {
u64 ringbase = (u64) (ring->dmabase);
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -677,7 +709,7 @@
err = alloc_initial_descbuffers(ring);
if (err)
goto out;
- if (ring->dma64) {
+ if (ring->type == B43_DMA_64BIT) {
u64 ringbase = (u64) (ring->dmabase);
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -722,16 +754,16 @@
{
if (ring->tx) {
b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
- ring->dma64);
- if (ring->dma64) {
+ ring->type);
+ if (ring->type == B43_DMA_64BIT) {
b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
} else
b43_dma_write(ring, B43_DMA32_TXRING, 0);
} else {
b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
- ring->dma64);
- if (ring->dma64) {
+ ring->type);
+ if (ring->type == B43_DMA_64BIT) {
b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
} else
@@ -786,7 +818,8 @@
static
struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
int controller_index,
- int for_tx, int dma64)
+ int for_tx,
+ enum b43_dmatype type)
{
struct b43_dmaring *ring;
int err;
@@ -796,6 +829,7 @@
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
goto out;
+ ring->type = type;
nr_slots = B43_RXRING_SLOTS;
if (for_tx)
@@ -818,7 +852,7 @@
b43_txhdr_size(dev),
DMA_TO_DEVICE);
- if (dma_mapping_error(dma_test)) {
+ if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
/* ugh realloc */
kfree(ring->txhdr_cache);
ring->txhdr_cache = kcalloc(nr_slots,
@@ -832,7 +866,8 @@
b43_txhdr_size(dev),
DMA_TO_DEVICE);
- if (dma_mapping_error(dma_test))
+ if (b43_dma_mapping_error(ring, dma_test,
+ b43_txhdr_size(dev)))
goto err_kfree_txhdr_cache;
}
@@ -843,10 +878,9 @@
ring->dev = dev;
ring->nr_slots = nr_slots;
- ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+ ring->mmio_base = b43_dmacontroller_base(type, controller_index);
ring->index = controller_index;
- ring->dma64 = !!dma64;
- if (dma64)
+ if (type == B43_DMA_64BIT)
ring->ops = &dma64_ops;
else
ring->ops = &dma32_ops;
@@ -896,8 +930,8 @@
if (!ring)
return;
- b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
- (ring->dma64) ? "64" : "32",
+ b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
+ (unsigned int)(ring->type),
ring->mmio_base,
(ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
/* Device IRQs are disabled prior entering this function,
@@ -941,12 +975,22 @@
struct b43_dmaring *ring;
int err;
u64 dmamask;
- int dma64 = 0;
+ enum b43_dmatype type;
dmamask = supported_dma_mask(dev);
- if (dmamask == DMA_64BIT_MASK)
- dma64 = 1;
-
+ switch (dmamask) {
+ default:
+ B43_WARN_ON(1);
+ case DMA_30BIT_MASK:
+ type = B43_DMA_30BIT;
+ break;
+ case DMA_32BIT_MASK:
+ type = B43_DMA_32BIT;
+ break;
+ case DMA_64BIT_MASK:
+ type = B43_DMA_64BIT;
+ break;
+ }
err = ssb_dma_set_mask(dev->dev, dmamask);
if (err) {
b43err(dev->wl, "The machine/kernel does not support "
@@ -958,52 +1002,51 @@
err = -ENOMEM;
/* setup TX DMA channels. */
- ring = b43_setup_dmaring(dev, 0, 1, dma64);
+ ring = b43_setup_dmaring(dev, 0, 1, type);
if (!ring)
goto out;
dma->tx_ring0 = ring;
- ring = b43_setup_dmaring(dev, 1, 1, dma64);
+ ring = b43_setup_dmaring(dev, 1, 1, type);
if (!ring)
goto err_destroy_tx0;
dma->tx_ring1 = ring;
- ring = b43_setup_dmaring(dev, 2, 1, dma64);
+ ring = b43_setup_dmaring(dev, 2, 1, type);
if (!ring)
goto err_destroy_tx1;
dma->tx_ring2 = ring;
- ring = b43_setup_dmaring(dev, 3, 1, dma64);
+ ring = b43_setup_dmaring(dev, 3, 1, type);
if (!ring)
goto err_destroy_tx2;
dma->tx_ring3 = ring;
- ring = b43_setup_dmaring(dev, 4, 1, dma64);
+ ring = b43_setup_dmaring(dev, 4, 1, type);
if (!ring)
goto err_destroy_tx3;
dma->tx_ring4 = ring;
- ring = b43_setup_dmaring(dev, 5, 1, dma64);
+ ring = b43_setup_dmaring(dev, 5, 1, type);
if (!ring)
goto err_destroy_tx4;
dma->tx_ring5 = ring;
/* setup RX DMA channels. */
- ring = b43_setup_dmaring(dev, 0, 0, dma64);
+ ring = b43_setup_dmaring(dev, 0, 0, type);
if (!ring)
goto err_destroy_tx5;
dma->rx_ring0 = ring;
if (dev->dev->id.revision < 5) {
- ring = b43_setup_dmaring(dev, 3, 0, dma64);
+ ring = b43_setup_dmaring(dev, 3, 0, type);
if (!ring)
goto err_destroy_rx0;
dma->rx_ring3 = ring;
}
- b43dbg(dev->wl, "%d-bit DMA initialized\n",
- (dmamask == DMA_64BIT_MASK) ? 64 :
- (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+ b43dbg(dev->wl, "%u-bit DMA initialized\n",
+ (unsigned int)type);
err = 0;
out:
return err;
@@ -1146,7 +1189,7 @@
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
hdrsize, 1);
- if (dma_mapping_error(meta_hdr->dmaaddr)) {
+ if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
return -EIO;
@@ -1165,7 +1208,7 @@
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */
- if (dma_mapping_error(meta->dmaaddr)) {
+ if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb) {
ring->current_slot = old_top_slot;
@@ -1179,7 +1222,7 @@
skb = bounce_skb;
meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
- if (dma_mapping_error(meta->dmaaddr)) {
+ if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -EIO;
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index 58db03a..c0d6b69 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -203,6 +203,12 @@
void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
};
+enum b43_dmatype {
+ B43_DMA_30BIT = 30,
+ B43_DMA_32BIT = 32,
+ B43_DMA_64BIT = 64,
+};
+
struct b43_dmaring {
/* Lowlevel DMA ops. */
const struct b43_dma_ops *ops;
@@ -235,8 +241,8 @@
int index;
/* Boolean. Is this a TX ring? */
bool tx;
- /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
- bool dma64;
+ /* The type of DMA engine used. */
+ enum b43_dmatype type;
/* Boolean. Is this ring stopped at ieee80211 level? */
bool stopped;
/* Lock, only used for TX. */
@@ -255,8 +261,7 @@
return b43_read32(ring->dev, ring->mmio_base + offset);
}
-static inline
- void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
{
b43_write32(ring->dev, ring->mmio_base + offset, value);
}
@@ -264,13 +269,6 @@
int b43_dma_init(struct b43_wldev *dev);
void b43_dma_free(struct b43_wldev *dev);
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
- u16 dmacontroller_mmio_base, int dma64);
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
- u16 dmacontroller_mmio_base, int dma64);
-
-u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
void b43_dma_tx_suspend(struct b43_wldev *dev);
void b43_dma_tx_resume(struct b43_wldev *dev);
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index 4b590d8..0908335 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -116,7 +116,10 @@
{
if (!led->dev)
return;
- led_classdev_unregister(&led->led_dev);
+ if (led->dev->suspend_in_progress)
+ led_classdev_unregister_suspended(&led->led_dev);
+ else
+ led_classdev_unregister(&led->led_dev);
b43_led_turn_off(led->dev, led->index, led->activelow);
led->dev = NULL;
}
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 64c154d..ef65c41 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -38,6 +38,7 @@
#include <linux/wireless.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
+#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <asm/unaligned.h>
@@ -2554,10 +2555,10 @@
return (sizeof(u16));
}
-static void b43_rng_exit(struct b43_wl *wl)
+static void b43_rng_exit(struct b43_wl *wl, bool suspended)
{
if (wl->rng_initialized)
- hwrng_unregister(&wl->rng);
+ __hwrng_unregister(&wl->rng, suspended);
}
static int b43_rng_init(struct b43_wl *wl)
@@ -3417,8 +3418,10 @@
macctl |= B43_MACCTL_PSM_JMP0;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
- b43_leds_exit(dev);
- b43_rng_exit(dev->wl);
+ if (!dev->suspend_in_progress) {
+ b43_leds_exit(dev);
+ b43_rng_exit(dev->wl, false);
+ }
b43_dma_free(dev);
b43_chip_exit(dev);
b43_radio_turn_off(dev, 1);
@@ -3534,11 +3537,13 @@
ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
b43_upload_card_macaddress(dev);
b43_security_init(dev);
- b43_rng_init(wl);
+ if (!dev->suspend_in_progress)
+ b43_rng_init(wl);
b43_set_status(dev, B43_STAT_INITIALIZED);
- b43_leds_init(dev);
+ if (!dev->suspend_in_progress)
+ b43_leds_init(dev);
out:
return err;
@@ -4135,6 +4140,7 @@
b43dbg(wl, "Suspending...\n");
mutex_lock(&wl->mutex);
+ wldev->suspend_in_progress = true;
wldev->suspend_init_status = b43_status(wldev);
if (wldev->suspend_init_status >= B43_STAT_STARTED)
b43_wireless_core_stop(wldev);
@@ -4166,15 +4172,17 @@
if (wldev->suspend_init_status >= B43_STAT_STARTED) {
err = b43_wireless_core_start(wldev);
if (err) {
+ b43_leds_exit(wldev);
+ b43_rng_exit(wldev->wl, true);
b43_wireless_core_exit(wldev);
b43err(wl, "Resume failed at core start\n");
goto out;
}
}
- mutex_unlock(&wl->mutex);
-
b43dbg(wl, "Device resumed.\n");
- out:
+ out:
+ wldev->suspend_in_progress = false;
+ mutex_unlock(&wl->mutex);
return err;
}
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 83161d9..6e08405e 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1164,7 +1164,7 @@
{
const struct b43legacy_dma_ops *ops = ring->ops;
u8 *header;
- int slot;
+ int slot, old_top_slot, old_used_slots;
int err;
struct b43legacy_dmadesc_generic *desc;
struct b43legacy_dmadesc_meta *meta;
@@ -1174,6 +1174,9 @@
#define SLOTS_PER_PACKET 2
B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+ old_top_slot = ring->current_slot;
+ old_used_slots = ring->used_slots;
+
/* Get a slot for the header. */
slot = request_slot(ring);
desc = ops->idx2desc(ring, slot, &meta_hdr);
@@ -1181,9 +1184,14 @@
header = &(ring->txhdr_cache[slot * sizeof(
struct b43legacy_txhdr_fw3)]);
- b43legacy_generate_txhdr(ring->dev, header,
+ err = b43legacy_generate_txhdr(ring->dev, header,
skb->data, skb->len, ctl,
generate_cookie(ring, slot));
+ if (unlikely(err)) {
+ ring->current_slot = old_top_slot;
+ ring->used_slots = old_used_slots;
+ return err;
+ }
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
sizeof(struct b43legacy_txhdr_fw3), 1);
@@ -1206,6 +1214,8 @@
if (dma_mapping_error(meta->dmaaddr)) {
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb) {
+ ring->current_slot = old_top_slot;
+ ring->used_slots = old_used_slots;
err = -ENOMEM;
goto out_unmap_hdr;
}
@@ -1216,6 +1226,8 @@
meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
if (dma_mapping_error(meta->dmaaddr)) {
+ ring->current_slot = old_top_slot;
+ ring->used_slots = old_used_slots;
err = -EIO;
goto out_free_bounce;
}
@@ -1282,6 +1294,13 @@
B43legacy_BUG_ON(ring->stopped);
err = dma_tx_fragment(ring, skb, ctl);
+ if (unlikely(err == -ENOKEY)) {
+ /* Drop this packet, as we don't have the encryption key
+ * anymore and must not transmit it unencrypted. */
+ dev_kfree_skb_any(skb);
+ err = 0;
+ goto out_unlock;
+ }
if (unlikely(err)) {
b43legacyerr(dev->wl, "DMA tx mapping failure\n");
goto out_unlock;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index aa20d5d..53f7f2e 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3160,8 +3160,6 @@
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
- memset(wl->bssid, 0, ETH_ALEN);
- memset(wl->mac_addr, 0, ETH_ALEN);
b43legacy_upload_card_macaddress(dev);
b43legacy_security_init(dev);
b43legacy_rng_init(wl);
@@ -3263,6 +3261,13 @@
* LEDs that are registered later depend on it. */
b43legacy_rfkill_init(dev);
+ /* Kill all old instance specific information to make sure
+ * the card won't use it in the short timeframe between start
+ * and mac80211 reconfiguring it. */
+ memset(wl->bssid, 0, ETH_ALEN);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ wl->filter_flags = 0;
+
mutex_lock(&wl->mutex);
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index e4f4c5c..bcdd54e 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -181,7 +181,7 @@
struct b43legacy_txhdr_fw3 txhdr_fw3;
};
-static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
struct sk_buff *skb,
struct b43legacy_pio_txpacket *packet,
size_t txhdr_size)
@@ -189,14 +189,17 @@
union txhdr_union txhdr_data;
u8 *txhdr = NULL;
unsigned int octets;
+ int err;
txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
- b43legacy_generate_txhdr(queue->dev,
+ err = b43legacy_generate_txhdr(queue->dev,
txhdr, skb->data, skb->len,
&packet->txstat.control,
generate_cookie(queue, packet));
+ if (err)
+ return err;
tx_start(queue);
octets = skb->len + txhdr_size;
@@ -204,6 +207,8 @@
octets--;
tx_data(queue, txhdr, (u8 *)skb->data, octets);
tx_complete(queue, skb);
+
+ return 0;
}
static void free_txpacket(struct b43legacy_pio_txpacket *packet,
@@ -226,6 +231,7 @@
struct b43legacy_pioqueue *queue = packet->queue;
struct sk_buff *skb = packet->skb;
u16 octets;
+ int err;
octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
if (queue->tx_devq_size < octets) {
@@ -247,8 +253,14 @@
if (queue->tx_devq_used + octets > queue->tx_devq_size)
return -EBUSY;
/* Now poke the device. */
- pio_tx_write_fragment(queue, skb, packet,
+ err = pio_tx_write_fragment(queue, skb, packet,
sizeof(struct b43legacy_txhdr_fw3));
+ if (unlikely(err == -ENOKEY)) {
+ /* Drop this packet, as we don't have the encryption key
+ * anymore and must not transmit it unencrypted. */
+ free_txpacket(packet, 1);
+ return 0;
+ }
/* Account for the packet size.
* (We must not overflow the device TX queue)
@@ -486,6 +498,9 @@
queue = parse_cookie(dev, status->cookie, &packet);
B43legacy_WARN_ON(!queue);
+ if (!packet->skb)
+ return;
+
queue->tx_devq_packets--;
queue->tx_devq_used -= (packet->skb->len +
sizeof(struct b43legacy_txhdr_fw3));
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index e20c552..d84408a 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -181,7 +181,7 @@
return 0;
}
-static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
+static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
struct b43legacy_txhdr_fw3 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
@@ -252,6 +252,13 @@
iv_len = min((size_t)txctl->iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
+ } else {
+ /* This key is invalid. This might only happen
+ * in a short timeframe after machine resume before
+ * we were able to reconfigure keys.
+ * Drop this packet completely. Do not transmit it
+ * unencrypted to avoid leaking information. */
+ return -ENOKEY;
}
}
b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
@@ -345,16 +352,18 @@
/* Apply the bitfields */
txhdr->mac_ctl = cpu_to_le32(mac_ctl);
txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+
+ return 0;
}
-void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl,
u16 cookie)
{
- generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+ return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
fragment_data, fragment_len,
txctl, cookie);
}
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index 8a155d0..bab4792 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -76,7 +76,7 @@
-void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 2ab107f..5bf9e00 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -162,7 +162,7 @@
#include <linux/firmware.h>
#include <linux/acpi.h>
#include <linux/ctype.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include "ipw2100.h"
@@ -1701,7 +1701,7 @@
/* the ipw2100 hardware really doesn't want power management delays
* longer than 175usec
*/
- modify_acceptable_latency("ipw2100", 175);
+ pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175);
/* If the interrupt is enabled, turn it off... */
spin_lock_irqsave(&priv->low_lock, flags);
@@ -1856,7 +1856,8 @@
ipw2100_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->low_lock, flags);
- modify_acceptable_latency("ipw2100", INFINITE_LATENCY);
+ pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
+ PM_QOS_DEFAULT_VALUE);
/* We have to signal any supplicant if we are disassociating */
if (associated)
@@ -6554,7 +6555,8 @@
if (ret)
goto out;
- set_acceptable_latency("ipw2100", INFINITE_LATENCY);
+ pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
+ PM_QOS_DEFAULT_VALUE);
#ifdef CONFIG_IPW2100_DEBUG
ipw2100_debug_level = debug;
ret = driver_create_file(&ipw2100_pci_driver.driver,
@@ -6576,7 +6578,7 @@
&driver_attr_debug_level);
#endif
pci_unregister_driver(&ipw2100_pci_driver);
- remove_acceptable_latency("ipw2100");
+ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100");
}
module_init(ipw2100_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 4fdeb53..8d4d91d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -238,9 +238,10 @@
priv->last_statistics_time = jiffies;
}
-void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb,
- struct iwl3945_rx_frame_hdr *rx_hdr,
- struct ieee80211_rx_status *stats)
+static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
+ struct sk_buff *skb,
+ struct iwl3945_rx_frame_hdr *rx_hdr,
+ struct ieee80211_rx_status *stats)
{
/* First cache any information we need before we overwrite
* the information provided in the skb from the hardware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 569347f..d727de8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -4658,17 +4658,30 @@
struct ieee80211_ht_info *sta_ht_inf)
{
__le32 sta_flags;
+ u8 mimo_ps_mode;
if (!sta_ht_inf || !sta_ht_inf->ht_supported)
goto done;
+ mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
+
sta_flags = priv->stations[index].sta.station_flags;
- if (((sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS >> 2))
- == IWL_MIMO_PS_DYNAMIC)
+ sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
+
+ switch (mimo_ps_mode) {
+ case WLAN_HT_CAP_MIMO_PS_STATIC:
+ sta_flags |= STA_FLG_MIMO_DIS_MSK;
+ break;
+ case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
- else
- sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
+ break;
+ case WLAN_HT_CAP_MIMO_PS_DISABLED:
+ break;
+ default:
+ IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
+ break;
+ }
sta_flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
@@ -4679,7 +4692,7 @@
if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf))
sta_flags |= STA_FLG_FAT_EN_MSK;
else
- sta_flags &= (~STA_FLG_FAT_EN_MSK);
+ sta_flags &= ~STA_FLG_FAT_EN_MSK;
priv->stations[index].sta.station_flags = sta_flags;
done:
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index cb009f4..8993cca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -147,9 +147,6 @@
#define QOS_CONTROL_LEN 2
-#define IEEE80211_STYPE_BACK_REQ 0x0080
-#define IEEE80211_STYPE_BACK 0x0090
-
static inline int ieee80211_is_management(u16 fc)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 33239f1..5ee1ad6 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4207,13 +4207,13 @@
* Conversion assumes that levels are voltages (20*log), not powers (10*log). */
int iwl3945_calc_db_from_ratio(int sig_ratio)
{
- /* Anything above 1000:1 just report as 60 dB */
- if (sig_ratio > 1000)
+ /* 1000:1 or higher just report as 60 dB */
+ if (sig_ratio >= 1000)
return 60;
- /* Above 100:1, divide by 10 and use table,
+ /* 100:1 or higher, divide by 10 and use table,
* add 20 dB to make up for divide by 10 */
- if (sig_ratio > 100)
+ if (sig_ratio >= 100)
return (20 + (int)ratio2dB[sig_ratio/10]);
/* We shouldn't see this */
@@ -6330,6 +6330,11 @@
return -ENODEV;
}
+ if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+ IWL_ERROR("ucode not available for device bringup\n");
+ return -EIO;
+ }
+
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl3945_read32(priv, CSR_GP_CNTRL) &
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@@ -6342,11 +6347,6 @@
}
}
- if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
- IWL_ERROR("ucode not available for device bringup\n");
- return -EIO;
- }
-
iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
rc = iwl3945_hw_nic_init(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index bf3a60c..f423241 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -6755,6 +6755,11 @@
return -ENODEV;
}
+ if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+ IWL_ERROR("ucode not available for device bringup\n");
+ return -EIO;
+ }
+
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl4965_read32(priv, CSR_GP_CNTRL) &
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@@ -6767,11 +6772,6 @@
}
}
- if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
- IWL_ERROR("ucode not available for device bringup\n");
- return -EIO;
- }
-
iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
rc = iwl4965_hw_nic_init(priv);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 9a61188..69f94c9 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -1473,7 +1473,7 @@
* Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
* from cmd.c
*
- * Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
+ * Sends a fixed length data part (specifying the BSS type and BSSID filters)
* as well as a variable number/length of TLVs to the firmware.
*
* @param priv A pointer to struct lbs_private structure
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index d2fa079..f479c1a 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -195,7 +195,7 @@
static void netwave_detach(struct pcmcia_device *p_dev); /* Destroy instance */
/* Hardware configuration */
-static void netwave_doreset(kio_addr_t iobase, u_char __iomem *ramBase);
+static void netwave_doreset(unsigned int iobase, u_char __iomem *ramBase);
static void netwave_reset(struct net_device *dev);
/* Misc device stuff */
@@ -309,7 +309,7 @@
}
static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase,
- kio_addr_t iobase) {
+ unsigned int iobase) {
u_short resultBuffer;
/* if time since last snapshot is > 1 sec. (100 jiffies?) then take
@@ -340,7 +340,7 @@
static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
{
unsigned long flags;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
netwave_private *priv = netdev_priv(dev);
u_char __iomem *ramBase = priv->ramBase;
struct iw_statistics* wstats;
@@ -471,7 +471,7 @@
char *extra)
{
unsigned long flags;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
netwave_private *priv = netdev_priv(dev);
u_char __iomem *ramBase = priv->ramBase;
@@ -518,7 +518,7 @@
char *key)
{
unsigned long flags;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
netwave_private *priv = netdev_priv(dev);
u_char __iomem *ramBase = priv->ramBase;
@@ -621,7 +621,7 @@
char *extra)
{
unsigned long flags;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
netwave_private *priv = netdev_priv(dev);
u_char __iomem *ramBase = priv->ramBase;
@@ -874,7 +874,7 @@
*
* Proper hardware reset of the card.
*/
-static void netwave_doreset(kio_addr_t ioBase, u_char __iomem *ramBase)
+static void netwave_doreset(unsigned int ioBase, u_char __iomem *ramBase)
{
/* Reset card */
wait_WOC(ioBase);
@@ -892,7 +892,7 @@
/* u_char state; */
netwave_private *priv = netdev_priv(dev);
u_char __iomem *ramBase = priv->ramBase;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
DEBUG(0, "netwave_reset: Done with hardware reset\n");
@@ -973,7 +973,7 @@
netwave_private *priv = netdev_priv(dev);
u_char __iomem * ramBase = priv->ramBase;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
/* Disable interrupts & save flags */
spin_lock_irqsave(&priv->spinlock, flags);
@@ -1065,7 +1065,7 @@
*/
static irqreturn_t netwave_interrupt(int irq, void* dev_id)
{
- kio_addr_t iobase;
+ unsigned int iobase;
u_char __iomem *ramBase;
struct net_device *dev = (struct net_device *)dev_id;
struct netwave_private *priv = netdev_priv(dev);
@@ -1235,7 +1235,7 @@
{
netwave_private *priv = netdev_priv(dev);
u_char __iomem *ramBase = priv->ramBase;
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
u_char rxStatus;
struct sk_buff *skb = NULL;
unsigned int curBuffer,
@@ -1388,7 +1388,7 @@
*/
static void set_multicast_list(struct net_device *dev)
{
- kio_addr_t iobase = dev->base_addr;
+ unsigned int iobase = dev->base_addr;
netwave_private *priv = netdev_priv(dev);
u_char __iomem * ramBase = priv->ramBase;
u_char rcvMode = 0;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index c2037b2..06eea6a 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -149,7 +149,7 @@
net_local *lp = netdev_priv(dev);
u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1);
int count = 0;
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
/* As there seem to have no flag PSA_BUSY as in the ISA model, we are
* oblige to verify this address to know when the PSA is ready... */
volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
@@ -708,7 +708,7 @@
/* Perform a handover to a new WavePoint */
static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
{
- kio_addr_t base = lp->dev->base_addr;
+ unsigned int base = lp->dev->base_addr;
mm_t m;
unsigned long flags;
@@ -821,7 +821,7 @@
int cmd,
int result)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
int status;
int wait_completed;
long spin;
@@ -945,7 +945,7 @@
char * buf,
int len)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
int ring_ptr = addr;
int chunk_len;
char * buf_ptr = buf;
@@ -1096,7 +1096,7 @@
static void
wv_mmc_show(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local * lp = netdev_priv(dev);
mmr_t m;
@@ -1275,7 +1275,7 @@
static inline void
wv_init_info(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
psa_t psa;
DECLARE_MAC_BUF(mac);
@@ -1294,7 +1294,7 @@
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff */
- printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, "
+ printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, "
"hw_addr %s",
dev->name, base, dev->irq,
print_mac(mac, dev->dev_addr));
@@ -1828,7 +1828,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
psa_t psa;
mm_t m;
@@ -1918,7 +1918,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
unsigned long flags;
int ret;
@@ -1948,7 +1948,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
@@ -1994,7 +1994,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
@@ -2060,7 +2060,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
unsigned long flags;
psa_t psa;
@@ -2130,7 +2130,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
@@ -2349,7 +2349,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
@@ -2425,7 +2425,7 @@
union iwreq_data *wrqu,
char *extra)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local *lp = netdev_priv(dev);
psa_t psa;
unsigned long flags;
@@ -2701,7 +2701,7 @@
static iw_stats *
wavelan_get_wireless_stats(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local * lp = netdev_priv(dev);
mmr_t m;
iw_stats * wstats;
@@ -2764,7 +2764,7 @@
int rfp, /* end of frame */
int wrap) /* start of buffer */
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
int rp;
int len;
@@ -2925,7 +2925,7 @@
static inline void
wv_packet_rcv(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local * lp = netdev_priv(dev);
int newrfp;
int rp;
@@ -3062,7 +3062,7 @@
short length)
{
net_local * lp = netdev_priv(dev);
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
unsigned long flags;
int clen = length;
register u_short xmtdata_base = TX_BASE;
@@ -3183,7 +3183,7 @@
static inline int
wv_mmc_init(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
psa_t psa;
mmw_t m;
int configured;
@@ -3377,7 +3377,7 @@
static int
wv_ru_stop(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local * lp = netdev_priv(dev);
unsigned long flags;
int status;
@@ -3440,7 +3440,7 @@
static int
wv_ru_start(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local * lp = netdev_priv(dev);
unsigned long flags;
@@ -3528,7 +3528,7 @@
static int
wv_82593_config(struct net_device * dev)
{
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
net_local * lp = netdev_priv(dev);
struct i82593_conf_block cfblk;
int ret = TRUE;
@@ -3765,7 +3765,7 @@
wv_hw_config(struct net_device * dev)
{
net_local * lp = netdev_priv(dev);
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
unsigned long flags;
int ret = FALSE;
@@ -4047,7 +4047,7 @@
{
struct net_device * dev = dev_id;
net_local * lp;
- kio_addr_t base;
+ unsigned int base;
int status0;
u_int tx_status;
@@ -4306,7 +4306,7 @@
wavelan_watchdog(struct net_device * dev)
{
net_local * lp = netdev_priv(dev);
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
unsigned long flags;
int aborted = FALSE;
@@ -4382,7 +4382,7 @@
{
net_local * lp = netdev_priv(dev);
struct pcmcia_device * link = lp->link;
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
@@ -4436,7 +4436,7 @@
wavelan_close(struct net_device * dev)
{
struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link;
- kio_addr_t base = dev->base_addr;
+ unsigned int base = dev->base_addr;
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
diff --git a/drivers/nubus/Makefile b/drivers/nubus/Makefile
index f5ef03c..21bda20 100644
--- a/drivers/nubus/Makefile
+++ b/drivers/nubus/Makefile
@@ -4,5 +4,4 @@
obj-y := nubus.o
-obj-$(CONFIG_MODULES) += nubus_syms.o
obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index e503c9c..2f047e5 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <asm/setup.h>
#include <asm/system.h>
#include <asm/page.h>
@@ -186,6 +187,7 @@
len--;
}
}
+EXPORT_SYMBOL(nubus_get_rsrc_mem);
void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent,
int len)
@@ -200,6 +202,7 @@
len--;
}
}
+EXPORT_SYMBOL(nubus_get_rsrc_str);
int nubus_get_root_dir(const struct nubus_board* board,
struct nubus_dir* dir)
@@ -209,6 +212,7 @@
dir->mask = board->lanes;
return 0;
}
+EXPORT_SYMBOL(nubus_get_root_dir);
/* This is a slyly renamed version of the above */
int nubus_get_func_dir(const struct nubus_dev* dev,
@@ -219,6 +223,7 @@
dir->mask = dev->board->lanes;
return 0;
}
+EXPORT_SYMBOL(nubus_get_func_dir);
int nubus_get_board_dir(const struct nubus_board* board,
struct nubus_dir* dir)
@@ -237,6 +242,7 @@
return -1;
return 0;
}
+EXPORT_SYMBOL(nubus_get_board_dir);
int nubus_get_subdir(const struct nubus_dirent *ent,
struct nubus_dir *dir)
@@ -246,6 +252,7 @@
dir->mask = ent->mask;
return 0;
}
+EXPORT_SYMBOL(nubus_get_subdir);
int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
{
@@ -274,12 +281,14 @@
ent->mask = nd->mask;
return 0;
}
+EXPORT_SYMBOL(nubus_readdir);
int nubus_rewinddir(struct nubus_dir* dir)
{
dir->ptr = dir->base;
return 0;
}
+EXPORT_SYMBOL(nubus_rewinddir);
/* Driver interface functions, more or less like in pci.c */
@@ -303,6 +312,7 @@
}
return NULL;
}
+EXPORT_SYMBOL(nubus_find_device);
struct nubus_dev*
nubus_find_type(unsigned short category,
@@ -320,6 +330,7 @@
}
return NULL;
}
+EXPORT_SYMBOL(nubus_find_type);
struct nubus_dev*
nubus_find_slot(unsigned int slot,
@@ -335,6 +346,7 @@
}
return NULL;
}
+EXPORT_SYMBOL(nubus_find_slot);
int
nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type,
@@ -346,13 +358,14 @@
}
return -1;
}
+EXPORT_SYMBOL(nubus_find_rsrc);
/* Initialization functions - decide which slots contain stuff worth
looking at, and print out lots and lots of information from the
resource blocks. */
/* FIXME: A lot of this stuff will eventually be useful after
- initializaton, for intelligently probing Ethernet and video chips,
+ initialization, for intelligently probing Ethernet and video chips,
among other things. The rest of it should go in the /proc code.
For now, we just use it to give verbose boot logs. */
diff --git a/drivers/nubus/nubus_syms.c b/drivers/nubus/nubus_syms.c
deleted file mode 100644
index 9204f04..0000000
--- a/drivers/nubus/nubus_syms.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Exported symbols for NuBus services
-
- (c) 1999 David Huggins-Daines <dhd@debian.org> */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/nubus.h>
-
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(nubus_proc_attach_device);
-EXPORT_SYMBOL(nubus_proc_detach_device);
-#endif
-
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(nubus_find_device);
-EXPORT_SYMBOL(nubus_find_type);
-EXPORT_SYMBOL(nubus_find_slot);
-EXPORT_SYMBOL(nubus_get_root_dir);
-EXPORT_SYMBOL(nubus_get_board_dir);
-EXPORT_SYMBOL(nubus_get_func_dir);
-EXPORT_SYMBOL(nubus_readdir);
-EXPORT_SYMBOL(nubus_find_rsrc);
-EXPORT_SYMBOL(nubus_rewinddir);
-EXPORT_SYMBOL(nubus_get_subdir);
-EXPORT_SYMBOL(nubus_get_rsrc_mem);
-EXPORT_SYMBOL(nubus_get_rsrc_str);
-
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index 5271a4a..e07492b 100644
--- a/drivers/nubus/proc.c
+++ b/drivers/nubus/proc.c
@@ -22,6 +22,8 @@
#include <linux/nubus.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/module.h>
+
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -140,6 +142,7 @@
return 0;
}
+EXPORT_SYMBOL(nubus_proc_attach_device);
/* FIXME: this is certainly broken! */
int nubus_proc_detach_device(struct nubus_dev *dev)
@@ -154,6 +157,7 @@
}
return 0;
}
+EXPORT_SYMBOL(nubus_proc_detach_device);
void __init proc_bus_nubus_add_devices(void)
{
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 7c60cbd..d08b284 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -363,7 +363,7 @@
if (pages_needed <= 8) {
/*
* LAN traffic will not thrash the TLB IFF the same NIC
- * uses 8 adjacent pages to map seperate payload data.
+ * uses 8 adjacent pages to map separate payload data.
* ie the same byte in the resource bit map.
*/
#if 0
@@ -941,7 +941,7 @@
** w/o this association, we wouldn't have coherent DMA!
** Access to the virtual address is what forces a two pass algorithm.
*/
- coalesced = iommu_coalesce_chunks(ioc, sglist, nents, ccio_alloc_range);
+ coalesced = iommu_coalesce_chunks(ioc, dev, sglist, nents, ccio_alloc_range);
/*
** Program the I/O Pdir
@@ -1589,7 +1589,7 @@
}
/**
- * ccio_init - ccio initalization procedure.
+ * ccio_init - ccio initialization procedure.
*
* Register this driver.
*/
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index a728a7c..65eee67 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -95,7 +95,7 @@
};
/**
- * hppb_init - HP-PB bus initalization procedure.
+ * hppb_init - HP-PB bus initialization procedure.
*
* Register this driver.
*/
diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h
index 0a1f99a..97ba828 100644
--- a/drivers/parisc/iommu-helpers.h
+++ b/drivers/parisc/iommu-helpers.h
@@ -95,12 +95,14 @@
*/
static inline unsigned int
-iommu_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents,
+iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
+ struct scatterlist *startsg, int nents,
int (*iommu_alloc_range)(struct ioc *, size_t))
{
struct scatterlist *contig_sg; /* contig chunk head */
unsigned long dma_offset, dma_len; /* start/len of DMA stream */
unsigned int n_mappings = 0;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
while (nents > 0) {
@@ -142,6 +144,9 @@
IOVP_SIZE) > DMA_CHUNK_SIZE))
break;
+ if (startsg->length + dma_len > max_seg_size)
+ break;
+
/*
** Next see if we can append the next chunk (i.e.
** it must end on one page and begin on another
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index e527a0e..d06627c 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -946,7 +946,7 @@
** w/o this association, we wouldn't have coherent DMA!
** Access to the virtual address is what forces a two pass algorithm.
*/
- coalesced = iommu_coalesce_chunks(ioc, sglist, nents, sba_alloc_range);
+ coalesced = iommu_coalesce_chunks(ioc, dev, sglist, nents, sba_alloc_range);
/*
** Program the I/O Pdir
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index e9743d3..238628d 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1540,6 +1540,38 @@
smsc_check(0x3f0,0x44);
smsc_check(0x370,0x44);
}
+
+static void __devinit detect_and_report_it87(void)
+{
+ u16 dev;
+ u8 r;
+ if (verbose_probing)
+ printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
+ if (!request_region(0x2e, 1, __FUNCTION__))
+ return;
+ outb(0x87, 0x2e);
+ outb(0x01, 0x2e);
+ outb(0x55, 0x2e);
+ outb(0x55, 0x2e);
+ outb(0x20, 0x2e);
+ dev = inb(0x2f) << 8;
+ outb(0x21, 0x2e);
+ dev |= inb(0x2f);
+ if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 ||
+ dev == 0x8716 || dev == 0x8718 || dev == 0x8726) {
+ printk(KERN_INFO "IT%04X SuperIO detected.\n", dev);
+ outb(0x07, 0x2E); /* Parallel Port */
+ outb(0x03, 0x2F);
+ outb(0xF0, 0x2E); /* BOOT 0x80 off */
+ r = inb(0x2f);
+ outb(0xF0, 0x2E);
+ outb(r | 8, 0x2F);
+ outb(0x02, 0x2E); /* Lock */
+ outb(0x02, 0x2F);
+
+ release_region(0x2e, 1);
+ }
+}
#endif /* CONFIG_PARPORT_PC_SUPERIO */
static int get_superio_dma (struct parport *p)
@@ -2767,6 +2799,7 @@
netmos_9755,
netmos_9805,
netmos_9815,
+ quatech_sppxp100,
};
@@ -2843,6 +2876,7 @@
/* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
/* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */
/* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
+ /* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
};
static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2926,6 +2960,9 @@
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+ /* Quatech SPPXP-100 Parallel port PCI ExpressCard */
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
@@ -3159,24 +3196,25 @@
int count = 0, err;
#ifdef CONFIG_PARPORT_PC_SUPERIO
- detect_and_report_winbond ();
- detect_and_report_smsc ();
+ detect_and_report_it87();
+ detect_and_report_winbond();
+ detect_and_report_smsc();
#endif
/* Onboard SuperIO chipsets that show themselves on the PCI bus. */
- count += parport_pc_init_superio (autoirq, autodma);
+ count += parport_pc_init_superio(autoirq, autodma);
/* PnP ports, skip detection if SuperIO already found them */
if (!count) {
- err = pnp_register_driver (&parport_pc_pnp_driver);
+ err = pnp_register_driver(&parport_pc_pnp_driver);
if (!err)
pnp_registered_parport = 1;
}
/* ISA ports and whatever (see asm/parport.h). */
- parport_pc_find_nonpci_ports (autoirq, autodma);
+ parport_pc_find_nonpci_ports(autoirq, autodma);
- err = pci_register_driver (&parport_pc_pci_driver);
+ err = pci_register_driver(&parport_pc_pci_driver);
if (!err)
pci_registered_parport = 1;
}
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index bd6ad8b..e2e95b3 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -77,7 +77,7 @@
/* titan_110l */ { 1, { { 3, -1 }, } },
/* titan_210l */ { 1, { { 3, -1 }, } },
/* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init },
- /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init },
+ /* netmos_9855 */ { 1, { { 2, -1 }, }, netmos_parallel_init },
/* avlab_1s1p */ { 1, { { 1, 2}, } },
/* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} },
/* avlab_2s1p */ { 1, { { 2, 3}, } },
@@ -185,7 +185,7 @@
.uart_offset = 8,
},
[netmos_9855] = {
- .flags = FL_BASE2 | FL_BASE_BARS,
+ .flags = FL_BASE4 | FL_BASE_BARS,
.num_ports = 1,
.base_baud = 115200,
.uart_offset = 8,
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index 853a15f..cd565bb 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -163,7 +163,7 @@
idlens[1] = idlens[0]+2;
if (belen != lelen) {
int off = 2;
- /* Don't try lenghts of 0x100 and 0x200 as 1 and 2 */
+ /* Don't try lengths of 0x100 and 0x200 as 1 and 2 */
if (idlens[0] <= 2)
off = 0;
idlens[off] = max(belen, lelen);
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index f697f3d..9f04d17 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -13,6 +13,9 @@
# Build the PCI Hotplug drivers if we were asked to
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
+ifdef CONFIG_HOTPLUG_PCI
+obj-y += hotplug-pci.o
+endif
# Build the PCI MSI interrupt support
obj-$(CONFIG_PCI_MSI) += msi.o
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 9e5ea07..ef5a6a2 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -108,6 +108,7 @@
void pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
+ struct pci_bus *child_bus;
int retval;
list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -138,11 +139,19 @@
up_write(&pci_bus_sem);
}
pci_bus_add_devices(dev->subordinate);
- retval = sysfs_create_link(&dev->subordinate->class_dev.kobj,
- &dev->dev.kobj, "bridge");
+
+ /* register the bus with sysfs as the parent is now
+ * properly registered. */
+ child_bus = dev->subordinate;
+ child_bus->dev.parent = child_bus->bridge;
+ retval = device_register(&child_bus->dev);
+ if (!retval)
+ retval = device_create_file(&child_bus->dev,
+ &dev_attr_cpuaffinity);
if (retval)
- dev_err(&dev->dev, "Error creating sysfs "
- "bridge symlink, continuing...\n");
+ dev_err(&dev->dev, "Error registering pci_bus"
+ " device bridge symlink,"
+ " continuing...\n");
}
}
}
@@ -204,7 +213,6 @@
}
up_read(&pci_bus_sem);
}
-EXPORT_SYMBOL_GPL(pci_walk_bus);
EXPORT_SYMBOL(pci_bus_alloc_resource);
EXPORT_SYMBOL_GPL(pci_bus_add_device);
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 5dfdfda..8ed2648 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -25,6 +25,8 @@
#include <linux/pci.h>
#include <linux/dmar.h>
+#include "iova.h"
+#include "intel-iommu.h"
#undef PREFIX
#define PREFIX "DMAR:"
@@ -263,8 +265,8 @@
if (!dmar)
return -ENODEV;
- if (!dmar->width) {
- printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
+ if (dmar->width < PAGE_SHIFT_4K - 1) {
+ printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
return -EINVAL;
}
@@ -301,11 +303,24 @@
int __init dmar_table_init(void)
{
- parse_dmar_table();
+ int ret;
+
+ ret = parse_dmar_table();
+ if (ret) {
+ printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+ return ret;
+ }
+
if (list_empty(&dmar_drhd_units)) {
printk(KERN_INFO PREFIX "No DMAR devices found\n");
return -ENODEV;
}
+
+ if (list_empty(&dmar_rmrr_units)) {
+ printk(KERN_INFO PREFIX "No RMRR found\n");
+ return -ENODEV;
+ }
+
return 0;
}
diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c
new file mode 100644
index 0000000..a590ef6
--- /dev/null
+++ b/drivers/pci/hotplug-pci.c
@@ -0,0 +1,20 @@
+/* Core PCI functionality used only by PCI hotplug */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+
+unsigned int pci_do_scan_bus(struct pci_bus *bus)
+{
+ unsigned int max;
+
+ max = pci_scan_child_bus(bus);
+
+ /*
+ * Make the discovered devices available.
+ */
+ pci_bus_add_devices(bus);
+
+ return max;
+}
+EXPORT_SYMBOL(pci_do_scan_bus);
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index a64449d..2cdd832 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -3,8 +3,8 @@
#
menuconfig HOTPLUG_PCI
- tristate "Support for PCI Hotplug (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL && HOTPLUG
+ tristate "Support for PCI Hotplug"
+ depends on PCI && HOTPLUG
---help---
Say Y here if you have a motherboard with a PCI Hotplug controller.
This allows you to add and remove PCI cards while the machine is
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 34a1891..9bdbe1a 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -3,7 +3,6 @@
#
obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
-obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
@@ -16,6 +15,9 @@
obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o
obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o
+# Link this last so it doesn't claim devices that have a real hotplug driver
+obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o
+
pci_hotplug-objs := pci_hotplug_core.o
ifdef CONFIG_HOTPLUG_PCI_CPCI
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 1ef417c..7a29164 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -113,7 +113,6 @@
u8 device; /* pci device# */
u32 sun; /* ACPI _SUN (slot unique number) */
- u32 slotno; /* slot number relative to bridge */
u32 flags; /* see below */
};
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index ff1b1c7..cf22f9e 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -102,7 +102,7 @@
}
-/* callback routine to check the existence of ejectable slots */
+/* callback routine to check for the existence of ejectable slots */
static acpi_status
is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
{
@@ -117,7 +117,7 @@
}
}
-/* callback routine to check for the existance of a pci dock device */
+/* callback routine to check for the existence of a pci dock device */
static acpi_status
is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
{
@@ -1528,7 +1528,6 @@
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
dbg("%s: re-enumerating slots under %s\n",
__FUNCTION__, objname);
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
acpiphp_check_bridge(bridge);
}
return AE_OK ;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index d7a293e..94b6401 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -39,6 +39,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include "../pci.h"
#if !defined(MODULE)
@@ -63,10 +64,16 @@
struct list_head node;
struct hotplug_slot *slot;
struct pci_dev *dev;
+ struct work_struct remove_work;
+ unsigned long removed;
};
static int debug;
static LIST_HEAD(slot_list);
+static struct workqueue_struct *dummyphp_wq;
+
+static void pci_rescan_worker(struct work_struct *work);
+static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
static int enable_slot (struct hotplug_slot *slot);
static int disable_slot (struct hotplug_slot *slot);
@@ -109,7 +116,7 @@
slot->name = &dev->dev.bus_id[0];
dbg("slot->name = %s\n", slot->name);
- dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+ dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
if (!dslot)
goto error_info;
@@ -164,6 +171,14 @@
err("Problem unregistering a slot %s\n", dslot->slot->name);
}
+/* called from the single-threaded workqueue handler to remove a slot */
+static void remove_slot_worker(struct work_struct *work)
+{
+ struct dummy_slot *dslot =
+ container_of(work, struct dummy_slot, remove_work);
+ remove_slot(dslot);
+}
+
/**
* pci_rescan_slot - Rescan slot
* @temp: Device template. Should be set: bus and devfn.
@@ -267,11 +282,17 @@
pci_rescan_buses(&pci_root_buses);
}
+/* called from the single-threaded workqueue handler to rescan all pci buses */
+static void pci_rescan_worker(struct work_struct *work)
+{
+ pci_rescan();
+}
static int enable_slot(struct hotplug_slot *hotplug_slot)
{
/* mis-use enable_slot for rescanning of the pci bus */
- pci_rescan();
+ cancel_work_sync(&pci_rescan_work);
+ queue_work(dummyphp_wq, &pci_rescan_work);
return -ENODEV;
}
@@ -306,6 +327,10 @@
err("Can't remove PCI devices with other PCI devices behind it yet.\n");
return -ENODEV;
}
+ if (test_and_set_bit(0, &dslot->removed)) {
+ dbg("Slot already scheduled for removal\n");
+ return -ENODEV;
+ }
/* search for subfunctions and disable them first */
if (!(dslot->dev->devfn & 7)) {
for (func = 1; func < 8; func++) {
@@ -328,8 +353,9 @@
/* remove the device from the pci core */
pci_remove_bus_device(dslot->dev);
- /* blow away this sysfs entry and other parts. */
- remove_slot(dslot);
+ /* queue work item to blow away this sysfs entry and other parts. */
+ INIT_WORK(&dslot->remove_work, remove_slot_worker);
+ queue_work(dummyphp_wq, &dslot->remove_work);
return 0;
}
@@ -340,6 +366,7 @@
struct list_head *next;
struct dummy_slot *dslot;
+ destroy_workqueue(dummyphp_wq);
list_for_each_safe (tmp, next, &slot_list) {
dslot = list_entry (tmp, struct dummy_slot, node);
remove_slot(dslot);
@@ -351,6 +378,10 @@
{
info(DRIVER_DESC "\n");
+ dummyphp_wq = create_singlethread_workqueue(MY_NAME);
+ if (!dummyphp_wq)
+ return -ENOMEM;
+
return pci_scan_buses();
}
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index a90c28d..87b6b8b 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -761,10 +761,13 @@
debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0);
for (j = 0; j < 0x08; j++) {
- temp = pci_find_slot(func->busno, (func->device << 3) | j);
- if (temp)
+ temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
+ if (temp) {
pci_remove_bus_device(temp);
+ pci_dev_put(temp);
+ }
}
+ pci_dev_put(func->dev);
}
/*
@@ -823,7 +826,7 @@
if (!(bus_structure_fixup(func->busno)))
flag = 1;
if (func->dev == NULL)
- func->dev = pci_find_slot(func->busno,
+ func->dev = pci_get_bus_and_slot(func->busno,
PCI_DEVFN(func->device, func->function));
if (func->dev == NULL) {
@@ -836,7 +839,7 @@
if (num)
pci_bus_add_devices(bus);
- func->dev = pci_find_slot(func->busno,
+ func->dev = pci_get_bus_and_slot(func->busno,
PCI_DEVFN(func->device, func->function));
if (func->dev == NULL) {
err("ERROR... : pci_dev still NULL\n");
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 47bb0e1..dd59a05 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -137,7 +137,7 @@
int retval = 0; \
if (try_module_get(ops->owner)) { \
if (ops->get_##name) \
- retval = ops->get_##name (slot, value); \
+ retval = ops->get_##name(slot, value); \
else \
*value = slot->info->name; \
module_put(ops->owner); \
@@ -625,7 +625,7 @@
if ((slot->info == NULL) || (slot->ops == NULL))
return -EINVAL;
if (slot->release == NULL) {
- dbg("Why are you trying to register a hotplug slot"
+ dbg("Why are you trying to register a hotplug slot "
"without a proper release function?\n");
return -EINVAL;
}
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 7959c22..ca656b2 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -82,24 +82,18 @@
};
struct controller {
- struct controller *next;
struct mutex crit_sect; /* critical section mutex */
struct mutex ctrl_lock; /* controller lock */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
struct list_head slot_list;
- struct slot *slot;
struct hpc_ops *hpc_ops;
wait_queue_head_t queue; /* sleep & wake process */
- u8 bus;
- u8 device;
- u8 function;
u8 slot_device_offset;
u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */
u8 slot_bus; /* Bus where the slots handled by this controller sit */
u8 ctrlcap;
- u16 vendor_id;
u8 cap_base;
struct timer_list poll_timer;
volatile int cmd_busy;
@@ -161,6 +155,9 @@
extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void pciehp_queue_pushbutton_work(struct work_struct *work);
int pcie_init(struct controller *ctrl, struct pcie_device *dev);
+int pciehp_enable_slot(struct slot *p_slot);
+int pciehp_disable_slot(struct slot *p_slot);
+int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev);
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 6462ac3..7f4836b8 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -453,13 +453,9 @@
pci_set_drvdata(pdev, ctrl);
- ctrl->bus = pdev->bus->number; /* ctrl bus */
- ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */
-
- ctrl->device = PCI_SLOT(pdev->devfn);
- ctrl->function = PCI_FUNC(pdev->devfn);
- dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
- ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
+ dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
+ __FUNCTION__, pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn), pdev->irq);
/* Setup the slot information structures */
rc = init_slots(ctrl);
@@ -471,6 +467,11 @@
t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
+ if (value) {
+ rc = pciehp_enable_slot(t_slot);
+ if (rc) /* -ENODEV: shouldn't happen, but deal with it */
+ value = 0;
+ }
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
if (rc)
@@ -509,6 +510,24 @@
static int pciehp_resume (struct pcie_device *dev)
{
printk("%s ENTRY\n", __FUNCTION__);
+ if (pciehp_force) {
+ struct pci_dev *pdev = dev->port;
+ struct controller *ctrl = pci_get_drvdata(pdev);
+ struct slot *t_slot;
+ u8 status;
+
+ /* reinitialize the chipset's event detection logic */
+ pcie_init_hardware_part2(ctrl, dev);
+
+ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
+
+ /* Check if slot is occupied */
+ t_slot->hpc_ops->get_adapter_status(t_slot, &status);
+ if (status)
+ pciehp_enable_slot(t_slot);
+ else
+ pciehp_disable_slot(t_slot);
+ }
return 0;
}
#endif
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index f1e0966..b23061c 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -37,8 +37,6 @@
#include "pciehp.h"
static void interrupt_event_handler(struct work_struct *work);
-static int pciehp_enable_slot(struct slot *p_slot);
-static int pciehp_disable_slot(struct slot *p_slot);
static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
{
@@ -197,12 +195,6 @@
__FUNCTION__);
return;
}
- /*
- * After turning power off, we must wait for at least
- * 1 second before taking any action that relies on
- * power having been removed from the slot/adapter.
- */
- msleep(1000);
}
}
@@ -215,15 +207,12 @@
*/
static int board_added(struct slot *p_slot)
{
- u8 hp_slot;
int retval = 0;
struct controller *ctrl = p_slot->ctrl;
- hp_slot = p_slot->device - ctrl->slot_device_offset;
-
dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
__FUNCTION__, p_slot->device,
- ctrl->slot_device_offset, hp_slot);
+ ctrl->slot_device_offset, p_slot->hp_slot);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
@@ -281,8 +270,6 @@
*/
static int remove_board(struct slot *p_slot)
{
- u8 device;
- u8 hp_slot;
int retval = 0;
struct controller *ctrl = p_slot->ctrl;
@@ -290,11 +277,7 @@
if (retval)
return retval;
- device = p_slot->device;
- hp_slot = p_slot->device - ctrl->slot_device_offset;
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
- dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+ dbg("In %s, hp_slot = %d\n", __FUNCTION__, p_slot->hp_slot);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
@@ -621,12 +604,6 @@
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
- /*
- * After turning power off, we must wait for at least
- * 1 second before taking any action that relies on
- * power having been removed from the slot/adapter.
- */
- msleep(1000);
}
ret = remove_board(p_slot);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 06d025b..6eba9b2 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -636,15 +636,57 @@
return retval;
}
+static inline int pcie_mask_bad_dllp(struct controller *ctrl)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ int pos;
+ u32 reg;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ if (!pos)
+ return 0;
+ pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®);
+ if (reg & PCI_ERR_COR_BAD_DLLP)
+ return 0;
+ reg |= PCI_ERR_COR_BAD_DLLP;
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
+ return 1;
+}
+
+static inline void pcie_unmask_bad_dllp(struct controller *ctrl)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ u32 reg;
+ int pos;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ if (!pos)
+ return;
+ pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®);
+ if (!(reg & PCI_ERR_COR_BAD_DLLP))
+ return;
+ reg &= ~PCI_ERR_COR_BAD_DLLP;
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
+}
+
static int hpc_power_off_slot(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
int retval = 0;
+ int changed;
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
+ /*
+ * Set Bad DLLP Mask bit in Correctable Error Mask
+ * Register. This is the workaround against Bad DLLP error
+ * that sometimes happens during turning power off the slot
+ * which conforms to PCI Express 1.0a spec.
+ */
+ changed = pcie_mask_bad_dllp(ctrl);
+
slot_cmd = POWER_OFF;
cmd_mask = PWR_CTRL;
/*
@@ -674,6 +716,16 @@
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ /*
+ * After turning power off, we must wait for at least 1 second
+ * before taking any action that relies on power having been
+ * removed from the slot/adapter.
+ */
+ msleep(1000);
+
+ if (changed)
+ pcie_unmask_bad_dllp(ctrl);
+
return retval;
}
@@ -1067,13 +1119,143 @@
}
#endif
-int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+static int pcie_init_hardware_part1(struct controller *ctrl,
+ struct pcie_device *dev)
{
int rc;
u16 temp_word;
- u16 cap_reg;
+ u32 slot_cap;
+ u16 slot_status;
+
+ rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
+ if (rc) {
+ err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* Mask Hot-plug Interrupt Enable */
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+ if (rc) {
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+ return -1;
+ }
+
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
+ temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+ 0x00;
+
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+ if (rc) {
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+ return -1;
+ }
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (rc) {
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ return -1;
+ }
+
+ temp_word = 0x1F; /* Clear all events */
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
+ if (rc) {
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
+{
+ int rc;
+ u16 temp_word;
u16 intr_enable = 0;
u32 slot_cap;
+ u16 slot_status;
+
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+ if (rc) {
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+ goto abort;
+ }
+
+ intr_enable = intr_enable | PRSN_DETECT_ENABLE;
+
+ rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
+ if (rc) {
+ err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
+ goto abort;
+ }
+
+ if (ATTN_BUTTN(slot_cap))
+ intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
+
+ if (POWER_CTRL(slot_cap))
+ intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
+
+ if (MRL_SENS(slot_cap))
+ intr_enable = intr_enable | MRL_DETECT_ENABLE;
+
+ temp_word = (temp_word & ~intr_enable) | intr_enable;
+
+ if (pciehp_poll_mode) {
+ temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
+ } else {
+ temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+ }
+
+ /*
+ * Unmask Hot-plug Interrupt Enable for the interrupt
+ * notification mechanism case.
+ */
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+ if (rc) {
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+ goto abort;
+ }
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (rc) {
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ goto abort_disable_intr;
+ }
+
+ temp_word = 0x1F; /* Clear all events */
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
+ if (rc) {
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+ goto abort_disable_intr;
+ }
+
+ if (pciehp_force) {
+ dbg("Bypassing BIOS check for pciehp use on %s\n",
+ pci_name(ctrl->pci_dev));
+ } else {
+ rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
+ if (rc)
+ goto abort_disable_intr;
+ }
+
+ return 0;
+
+ /* We end up here for the many possible ways to fail this API. */
+abort_disable_intr:
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+ if (!rc) {
+ temp_word &= ~(intr_enable | HP_INTR_ENABLE);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+ }
+ if (rc)
+ err("%s : disabling interrupts failed\n", __FUNCTION__);
+abort:
+ return -1;
+}
+
+int pcie_init(struct controller *ctrl, struct pcie_device *dev)
+{
+ int rc;
+ u16 cap_reg;
+ u32 slot_cap;
int cap_base;
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
@@ -1084,9 +1266,10 @@
dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
__FUNCTION__, pdev->vendor, pdev->device);
- if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
+ cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (cap_base == 0) {
dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
ctrl->cap_base = cap_base;
@@ -1096,7 +1279,7 @@
rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
if (rc) {
err("%s: Cannot read CAPREG register\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: CAPREG offset %x cap_reg %x\n",
__FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
@@ -1106,26 +1289,26 @@
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
dbg("%s : This is not a root port or the port is not "
"connected to a slot\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
if (rc) {
err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: SLOTCAP offset %x slot_cap %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
if (!(slot_cap & HP_CAP)) {
dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
/* For debugging purpose */
rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
__FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
@@ -1133,7 +1316,7 @@
rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
@@ -1161,36 +1344,9 @@
ctrl->first_slot = slot_cap >> 19;
ctrl->ctrlcap = slot_cap & 0x0000007f;
- /* Mask Hot-plug Interrupt Enable */
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- goto abort_free_ctlr;
- }
-
- dbg("%s: SLOTCTRL %x value read %x\n",
- __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
- 0x00;
-
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
- goto abort_free_ctlr;
- }
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
- goto abort_free_ctlr;
- }
-
- temp_word = 0x1F; /* Clear all events */
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
- goto abort_free_ctlr;
- }
+ rc = pcie_init_hardware_part1(ctrl, dev);
+ if (rc)
+ goto abort;
if (pciehp_poll_mode) {
/* Install interrupt polling timer. Start with 10 sec delay */
@@ -1206,7 +1362,7 @@
if (rc) {
err("Can't get irq %d for the hotplug controller\n",
ctrl->pci_dev->irq);
- goto abort_free_ctlr;
+ goto abort;
}
}
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
@@ -1224,82 +1380,16 @@
}
}
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- goto abort_free_irq;
+ rc = pcie_init_hardware_part2(ctrl, dev);
+ if (rc == 0) {
+ ctrl->hpc_ops = &pciehp_hpc_ops;
+ return 0;
}
-
- intr_enable = intr_enable | PRSN_DETECT_ENABLE;
-
- if (ATTN_BUTTN(slot_cap))
- intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
- if (POWER_CTRL(slot_cap))
- intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
- if (MRL_SENS(slot_cap))
- intr_enable = intr_enable | MRL_DETECT_ENABLE;
-
- temp_word = (temp_word & ~intr_enable) | intr_enable;
-
- if (pciehp_poll_mode) {
- temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
- } else {
- temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- }
-
- /*
- * Unmask Hot-plug Interrupt Enable for the interrupt
- * notification mechanism case.
- */
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
- goto abort_free_irq;
- }
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
- goto abort_disable_intr;
- }
-
- temp_word = 0x1F; /* Clear all events */
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
- goto abort_disable_intr;
- }
-
- if (pciehp_force) {
- dbg("Bypassing BIOS check for pciehp use on %s\n",
- pci_name(ctrl->pci_dev));
- } else {
- rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
- if (rc)
- goto abort_disable_intr;
- }
-
- ctrl->hpc_ops = &pciehp_hpc_ops;
-
- return 0;
-
- /* We end up here for the many possible ways to fail this API. */
-abort_disable_intr:
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (!rc) {
- temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- }
- if (rc)
- err("%s : disabling interrupts failed\n", __FUNCTION__);
-
abort_free_irq:
if (pciehp_poll_mode)
del_timer_sync(&ctrl->poll_timer);
else
free_irq(ctrl->pci_dev->irq, ctrl);
-
-abort_free_ctlr:
+abort:
return -1;
}
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index c424ade..dd50713 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -105,12 +105,7 @@
}
/* Find Advanced Error Reporting Enhanced Capability */
- pos = 256;
- do {
- pci_read_config_dword(dev, pos, ®32);
- if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
- break;
- } while ((pos = PCI_EXT_CAP_NEXT(reg32)));
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return;
@@ -248,11 +243,15 @@
u8 bctl = 0;
u8 presence = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
+ u16 command;
dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
p_slot->device);
+ ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence);
+ if (ret)
+ presence = 0;
- for (j=0; j<8 ; j++) {
+ for (j = 0; j < 8; j++) {
struct pci_dev* temp = pci_get_slot(parent,
(p_slot->device << 3) | j);
if (!temp)
@@ -263,21 +262,26 @@
pci_dev_put(temp);
continue;
}
- if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- ret = p_slot->hpc_ops->get_adapter_status(p_slot,
- &presence);
- if (!ret && presence) {
- pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
- &bctl);
- if (bctl & PCI_BRIDGE_CTL_VGA) {
- err("Cannot remove display device %s\n",
- pci_name(temp));
- pci_dev_put(temp);
- continue;
- }
+ if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
+ pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
+ if (bctl & PCI_BRIDGE_CTL_VGA) {
+ err("Cannot remove display device %s\n",
+ pci_name(temp));
+ pci_dev_put(temp);
+ continue;
}
}
pci_remove_bus_device(temp);
+ /*
+ * Ensure that no new Requests will be generated from
+ * the device.
+ */
+ if (presence) {
+ pci_read_config_word(temp, PCI_COMMAND, &command);
+ command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+ command |= PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(temp, PCI_COMMAND, command);
+ }
pci_dev_put(temp);
}
/*
@@ -288,4 +292,3 @@
return rc;
}
-
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index c822a77..7d5921b 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -74,7 +74,6 @@
u32 type;
u32 power_domain;
char *name;
- char *location;
struct device_node *dn;
struct pci_bus *bus;
struct list_head *pci_devs;
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index 0de8453..6571e9b 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -64,19 +64,6 @@
return rc;
}
-static void set_slot_name(struct slot *slot)
-{
- struct pci_bus *bus = slot->bus;
- struct pci_dev *bridge;
-
- bridge = bus->self;
- if (bridge)
- strcpy(slot->name, pci_name(bridge));
- else
- sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus),
- bus->number);
-}
-
/**
* rpaphp_enable_slot - record slot state, config pci device
* @slot: target &slot
@@ -115,7 +102,6 @@
info->adapter_status = EMPTY;
slot->bus = bus;
slot->pci_devs = &bus->devices;
- set_slot_name(slot);
/* if there's an adapter in the slot, go add the pci devices */
if (state == PRESENT) {
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index d4ee872..8ad3deb 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -33,23 +33,31 @@
#include <asm/rtas.h>
#include "rpaphp.h"
-static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
+static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf)
{
- char *value;
- int retval = -ENOENT;
+ int retval;
struct slot *slot = (struct slot *)php_slot->private;
+ struct pci_bus *bus;
if (!slot)
- return retval;
+ return -ENOENT;
- value = slot->location;
- retval = sprintf (buf, "%s\n", value);
+ bus = slot->bus;
+ if (!bus)
+ return -ENOENT;
+
+ if (bus->self)
+ retval = sprintf(buf, pci_name(bus->self));
+ else
+ retval = sprintf(buf, "%04x:%02x:00.0",
+ pci_domain_nr(bus), bus->number);
+
return retval;
}
-static struct hotplug_slot_attribute php_attr_location = {
- .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
- .show = location_read_file,
+static struct hotplug_slot_attribute php_attr_address = {
+ .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
+ .show = address_read_file,
};
/* free up the memory used by a slot */
@@ -64,7 +72,6 @@
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
- kfree(slot->location);
kfree(slot);
}
@@ -83,16 +90,13 @@
GFP_KERNEL);
if (!slot->hotplug_slot->info)
goto error_hpslot;
- slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL);
+ slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
if (!slot->hotplug_slot->name)
goto error_info;
- slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
- if (!slot->location)
- goto error_name;
slot->name = slot->hotplug_slot->name;
+ strcpy(slot->name, drc_name);
slot->dn = dn;
slot->index = drc_index;
- strcpy(slot->location, drc_name);
slot->power_domain = power_domain;
slot->hotplug_slot->private = slot;
slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
@@ -100,8 +104,6 @@
return (slot);
-error_name:
- kfree(slot->hotplug_slot->name);
error_info:
kfree(slot->hotplug_slot->info);
error_hpslot:
@@ -133,8 +135,8 @@
list_del(&slot->rpaphp_slot_list);
- /* remove "phy_location" file */
- sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr);
+ /* remove "address" file */
+ sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr);
retval = pci_hp_deregister(php_slot);
if (retval)
@@ -166,8 +168,8 @@
return retval;
}
- /* create "phy_location" file */
- retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr);
+ /* create "address" file */
+ retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr);
if (retval) {
err("sysfs_create_file failed with error %d\n", retval);
goto sysfs_fail;
@@ -175,8 +177,7 @@
/* add slot to our internal list */
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
- info("Slot [%s](PCI location=%s) registered\n", slot->name,
- slot->location);
+ info("Slot [%s] registered\n", slot->name);
return 0;
sysfs_fail:
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 5183a45..e8aa138 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -597,7 +597,7 @@
cleanup_slots(ctrl);
/*
- * Mask SERR and System Interrut generation
+ * Mask SERR and System Interrupt generation
*/
serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index e079a52..31fa6c9 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -1088,7 +1088,7 @@
int i;
u64 addr, size;
- init_iova_domain(&reserved_iova_list);
+ init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
/* IOAPIC ranges shouldn't be accessed by DMA */
iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
@@ -1142,7 +1142,7 @@
int adjust_width, agaw;
unsigned long sagaw;
- init_iova_domain(&domain->iovad);
+ init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
spin_lock_init(&domain->mapping_lock);
domain_reserve_special_ranges(domain);
@@ -1781,7 +1781,7 @@
/*
* First try to allocate an io virtual address in
* DMA_32BIT_MASK and if that fails then try allocating
- * from higer range
+ * from higher range
*/
iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
if (!iova)
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
index 459ad1f..0e48626 100644
--- a/drivers/pci/intel-iommu.h
+++ b/drivers/pci/intel-iommu.h
@@ -23,10 +23,24 @@
#include <linux/types.h>
#include <linux/msi.h>
+#include <linux/sysdev.h>
#include "iova.h"
#include <linux/io.h>
/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K (12)
+#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
+
+/*
* Intel IOMMU register specification per version 1.0 public spec.
*/
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
index a84571c..8de7ab6c 100644
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -9,19 +9,19 @@
#include "iova.h"
void
-init_iova_domain(struct iova_domain *iovad)
+init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
{
spin_lock_init(&iovad->iova_alloc_lock);
spin_lock_init(&iovad->iova_rbtree_lock);
iovad->rbroot = RB_ROOT;
iovad->cached32_node = NULL;
-
+ iovad->dma_32bit_pfn = pfn_32bit;
}
static struct rb_node *
__get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
{
- if ((*limit_pfn != DMA_32BIT_PFN) ||
+ if ((*limit_pfn != iovad->dma_32bit_pfn) ||
(iovad->cached32_node == NULL))
return rb_last(&iovad->rbroot);
else {
@@ -37,7 +37,7 @@
__cached_rbnode_insert_update(struct iova_domain *iovad,
unsigned long limit_pfn, struct iova *new)
{
- if (limit_pfn != DMA_32BIT_PFN)
+ if (limit_pfn != iovad->dma_32bit_pfn)
return;
iovad->cached32_node = &new->node;
}
diff --git a/drivers/pci/iova.h b/drivers/pci/iova.h
index ae3028d..d521b5b 100644
--- a/drivers/pci/iova.h
+++ b/drivers/pci/iova.h
@@ -15,22 +15,9 @@
#include <linux/rbtree.h>
#include <linux/dma-mapping.h>
-/*
- * We need a fixed PAGE_SIZE of 4K irrespective of
- * arch PAGE_SIZE for IOMMU page tables.
- */
-#define PAGE_SHIFT_4K (12)
-#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
/* IO virtual address start page frame number */
#define IOVA_START_PFN (1)
-#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
-#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
-#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
-
/* iova structure */
struct iova {
struct rb_node node;
@@ -44,6 +31,7 @@
spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */
struct rb_root rbroot; /* iova domain rbtree root */
struct rb_node *cached32_node; /* Save last alloced node */
+ unsigned long dma_32bit_pfn;
};
struct iova *alloc_iova_mem(void);
@@ -56,7 +44,7 @@
struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
unsigned long pfn_hi);
void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
-void init_iova_domain(struct iova_domain *iovad);
+void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit);
struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
void put_iova_domain(struct iova_domain *iovad);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 07c9f09..26938da 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -25,6 +25,51 @@
static int pci_msi_enable = 1;
+/* Arch hooks */
+
+int __attribute__ ((weak))
+arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+ return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
+{
+ return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ struct msi_desc *entry;
+ int ret;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ ret = arch_setup_msi_irq(dev, entry);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
+{
+ return;
+}
+
+void __attribute__ ((weak))
+arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq != 0)
+ arch_teardown_msi_irq(entry->irq);
+ }
+}
+
static void msi_set_enable(struct pci_dev *dev, int enable)
{
int pos;
@@ -230,7 +275,6 @@
pci_intx(dev, enable);
}
-#ifdef CONFIG_PM
static void __pci_restore_msi_state(struct pci_dev *dev)
{
int pos;
@@ -288,7 +332,7 @@
__pci_restore_msi_state(dev);
__pci_restore_msix_state(dev);
}
-#endif /* CONFIG_PM */
+EXPORT_SYMBOL_GPL(pci_restore_msi_state);
/**
* msi_capability_init - configure device's MSI capability structure
@@ -683,49 +727,3 @@
{
INIT_LIST_HEAD(&dev->msi_list);
}
-
-
-/* Arch hooks */
-
-int __attribute__ ((weak))
-arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
-{
- return 0;
-}
-
-int __attribute__ ((weak))
-arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
-{
- return 0;
-}
-
-int __attribute__ ((weak))
-arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
-{
- struct msi_desc *entry;
- int ret;
-
- list_for_each_entry(entry, &dev->msi_list, list) {
- ret = arch_setup_msi_irq(dev, entry);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
-{
- return;
-}
-
-void __attribute__ ((weak))
-arch_teardown_msi_irqs(struct pci_dev *dev)
-{
- struct msi_desc *entry;
-
- list_for_each_entry(entry, &dev->msi_list, list) {
- if (entry->irq != 0)
- arch_teardown_msi_irq(entry->irq);
- }
-}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 5c6a5d0..e569645 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -156,13 +156,13 @@
}
/**
- * pci_osc_support_set - register OS support to Firmware
+ * __pci_osc_support_set - register OS support to Firmware
* @flags: OS support bits
*
* Update OS support fields and doing a _OSC Query to obtain an update
* from Firmware on supported control bits.
**/
-acpi_status pci_osc_support_set(u32 flags)
+acpi_status __pci_osc_support_set(u32 flags, const char *hid)
{
u32 temp;
acpi_status retval;
@@ -176,7 +176,7 @@
temp = ctrlset_buf[OSC_CONTROL_TYPE];
ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
- acpi_get_devices ( PCI_ROOT_HID_STRING,
+ acpi_get_devices(hid,
acpi_query_osc,
ctrlset_buf,
(void **) &retval );
@@ -188,7 +188,6 @@
}
return AE_OK;
}
-EXPORT_SYMBOL(pci_osc_support_set);
/**
* pci_osc_control_set - commit requested control to Firmware
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index c4fa35d..e571c72 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -186,13 +186,11 @@
set_cpus_allowed(current, node_to_cpumask(node));
/* And set default memory allocation policy */
oldpol = current->mempolicy;
- current->mempolicy = &default_policy;
- mpol_get(current->mempolicy);
+ current->mempolicy = NULL; /* fall back to system default policy */
#endif
error = drv->probe(dev, id);
#ifdef CONFIG_NUMA
set_cpus_allowed(current, oldmask);
- mpol_free(current->mempolicy);
current->mempolicy = oldpol;
#endif
return error;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 7d18773..8dcf145 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -358,7 +358,7 @@
char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(container_of(kobj,
- struct class_device,
+ struct device,
kobj));
/* Only support 1, 2 or 4 byte accesses */
@@ -383,7 +383,7 @@
char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(container_of(kobj,
- struct class_device,
+ struct device,
kobj));
/* Only support 1, 2 or 4 byte accesses */
if (count != 1 && count != 2 && count != 4)
@@ -407,7 +407,7 @@
struct vm_area_struct *vma)
{
struct pci_bus *bus = to_pci_bus(container_of(kobj,
- struct class_device,
+ struct device,
kobj));
return pci_mmap_legacy_page_range(bus, vma);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 7d4ce90..ae3df46 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -314,6 +314,24 @@
}
EXPORT_SYMBOL_GPL(pci_find_ht_capability);
+void pcie_wait_pending_transaction(struct pci_dev *dev)
+{
+ int pos;
+ u16 reg16;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return;
+ while (1) {
+ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16);
+ if (!(reg16 & PCI_EXP_DEVSTA_TRPND))
+ break;
+ cpu_relax();
+ }
+
+}
+EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction);
+
/**
* pci_find_parent_resource - return resource region of parent bus of given region
* @dev: PCI device structure contains resources to be searched
@@ -353,7 +371,7 @@
* Restore the BAR values for a given device, so as to make it
* accessible by its driver.
*/
-void
+static void
pci_restore_bars(struct pci_dev *dev)
{
int i, numres;
@@ -551,6 +569,7 @@
int pos, i = 0;
struct pci_cap_saved_state *save_state;
u16 *cap;
+ int found = 0;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (pos <= 0)
@@ -559,6 +578,8 @@
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state)
save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
+ else
+ found = 1;
if (!save_state) {
dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
return -ENOMEM;
@@ -569,7 +590,9 @@
pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
- pci_add_saved_cap(dev, save_state);
+ save_state->cap_nr = PCI_CAP_ID_EXP;
+ if (!found)
+ pci_add_saved_cap(dev, save_state);
return 0;
}
@@ -597,14 +620,17 @@
int pos, i = 0;
struct pci_cap_saved_state *save_state;
u16 *cap;
+ int found = 0;
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (pos <= 0)
return 0;
- save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
if (!save_state)
save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
+ else
+ found = 1;
if (!save_state) {
dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
return -ENOMEM;
@@ -612,7 +638,9 @@
cap = (u16 *)&save_state->data[0];
pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]);
- pci_add_saved_cap(dev, save_state);
+ save_state->cap_nr = PCI_CAP_ID_PCIX;
+ if (!found)
+ pci_add_saved_cap(dev, save_state);
return 0;
}
@@ -713,23 +741,19 @@
return 0;
}
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- * Initialize device before it's used by a driver. Ask low-level code
- * to enable selected I/O and memory resources. Wake up the device if it
- * was suspended. Beware, this function can fail.
- */
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int __pci_enable_device_flags(struct pci_dev *dev,
+ resource_size_t flags)
{
int err;
+ int i, bars = 0;
if (atomic_add_return(1, &dev->enable_cnt) > 1)
return 0; /* already enabled */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (dev->resource[i].flags & flags)
+ bars |= (1 << i);
+
err = do_pci_enable_device(dev, bars);
if (err < 0)
atomic_dec(&dev->enable_cnt);
@@ -737,6 +761,32 @@
}
/**
+ * pci_enable_device_io - Initialize a device for use with IO space
+ * @dev: PCI device to be initialized
+ *
+ * Initialize device before it's used by a driver. Ask low-level code
+ * to enable I/O resources. Wake up the device if it was suspended.
+ * Beware, this function can fail.
+ */
+int pci_enable_device_io(struct pci_dev *dev)
+{
+ return __pci_enable_device_flags(dev, IORESOURCE_IO);
+}
+
+/**
+ * pci_enable_device_mem - Initialize a device for use with Memory space
+ * @dev: PCI device to be initialized
+ *
+ * Initialize device before it's used by a driver. Ask low-level code
+ * to enable Memory resources. Wake up the device if it was suspended.
+ * Beware, this function can fail.
+ */
+int pci_enable_device_mem(struct pci_dev *dev)
+{
+ return __pci_enable_device_flags(dev, IORESOURCE_MEM);
+}
+
+/**
* pci_enable_device - Initialize device before it's used by a driver.
* @dev: PCI device to be initialized
*
@@ -749,7 +799,7 @@
*/
int pci_enable_device(struct pci_dev *dev)
{
- return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+ return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
}
/*
@@ -885,6 +935,9 @@
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
+ /* Wait for all transactions are finished before disabling the device */
+ pcie_wait_pending_transaction(dev);
+
pci_read_config_word(dev, PCI_COMMAND, &pci_command);
if (pci_command & PCI_COMMAND_MASTER) {
pci_command &= ~PCI_COMMAND_MASTER;
@@ -1398,6 +1451,22 @@
}
#endif
+#ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE
+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
+{
+ return dma_set_max_seg_size(&dev->dev, size);
+}
+EXPORT_SYMBOL(pci_set_dma_max_seg_size);
+#endif
+
+#ifndef HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY
+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
+{
+ return dma_set_seg_boundary(&dev->dev, mask);
+}
+EXPORT_SYMBOL(pci_set_dma_seg_boundary);
+#endif
+
/**
* pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
* @dev: PCI device to query
@@ -1619,9 +1688,9 @@
device_initcall(pci_init);
-EXPORT_SYMBOL_GPL(pci_restore_bars);
EXPORT_SYMBOL(pci_reenable_device);
-EXPORT_SYMBOL(pci_enable_device_bars);
+EXPORT_SYMBOL(pci_enable_device_io);
+EXPORT_SYMBOL(pci_enable_device_mem);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pcim_enable_device);
EXPORT_SYMBOL(pcim_pin_device);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fc87e14..eabeb1f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -6,8 +6,10 @@
extern void pci_cleanup_rom(struct pci_dev *dev);
/* Firmware callbacks */
-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
-extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev,
+ pm_message_t state);
+extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
+ pci_power_t state);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
@@ -45,12 +47,6 @@
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
-#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
-void pci_restore_msi_state(struct pci_dev *dev);
-#else
-static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-#endif
-
#ifdef CONFIG_PCIEAER
void pci_no_aer(void);
#else
@@ -68,14 +64,14 @@
}
extern int pcie_mch_quirk;
extern struct device_attribute pci_dev_attrs[];
-extern struct class_device_attribute class_device_attr_cpuaffinity;
+extern struct device_attribute dev_attr_cpuaffinity;
/**
* pci_match_one_device - Tell if a PCI device structure has a matching
* PCI device id structure
* @id: single PCI device id structure to match
* @dev: the PCI device structure to match against
- *
+ *
* Returns the matching pci_device_id structure or %NULL if there is no match.
*/
static inline const struct pci_device_id *
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index 1a1eb45..8c199ae 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -31,26 +31,16 @@
{
acpi_status status = AE_NOT_FOUND;
struct pci_dev *pdev = pciedev->port;
- acpi_handle handle = DEVICE_ACPI_HANDLE(&pdev->dev);
- struct pci_bus *parent;
+ acpi_handle handle = 0;
- while (!handle) {
- if (!pdev || !pdev->bus->parent)
- break;
- parent = pdev->bus->parent;
- if (!parent->self)
- /* Parent must be a host bridge */
- handle = acpi_get_pci_rootbridge_handle(
- pci_domain_nr(parent),
- parent->number);
- else
- handle = DEVICE_ACPI_HANDLE(
- &(parent->self->dev));
- pdev = parent->self;
- }
+ /* Find root host bridge */
+ while (pdev->bus && pdev->bus->self)
+ pdev = pdev->bus->self;
+ handle = acpi_get_pci_rootbridge_handle(
+ pci_domain_nr(pdev->bus), pdev->bus->number);
if (handle) {
- pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
+ pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
status = pci_osc_control_set(handle,
OSC_PCI_EXPRESS_AER_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index b20a9b8..23d9eb0 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -192,9 +192,8 @@
if (reg32 & SLOT_HP_CAPABLE_MASK)
services |= PCIE_PORT_SERVICE_HP;
}
- /* PME Capable */
- pos = pci_find_capability(dev, PCI_CAP_ID_PME);
- if (pos)
+ /* PME Capable - root port capability */
+ if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
services |= PCIE_PORT_SERVICE_PME;
pos = PCI_CFG_SPACE_SIZE;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5fd5852..4d23b9f 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -53,7 +53,7 @@
b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
b->legacy_io->read = pci_read_legacy_io;
b->legacy_io->write = pci_write_legacy_io;
- class_device_create_bin_file(&b->class_dev, b->legacy_io);
+ device_create_bin_file(&b->dev, b->legacy_io);
/* Allocated above after the legacy_io struct */
b->legacy_mem = b->legacy_io + 1;
@@ -61,15 +61,15 @@
b->legacy_mem->size = 1024*1024;
b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
b->legacy_mem->mmap = pci_mmap_legacy_mem;
- class_device_create_bin_file(&b->class_dev, b->legacy_mem);
+ device_create_bin_file(&b->dev, b->legacy_mem);
}
}
void pci_remove_legacy_files(struct pci_bus *b)
{
if (b->legacy_io) {
- class_device_remove_bin_file(&b->class_dev, b->legacy_io);
- class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
+ device_remove_bin_file(&b->dev, b->legacy_io);
+ device_remove_bin_file(&b->dev, b->legacy_mem);
kfree(b->legacy_io); /* both are allocated here */
}
}
@@ -81,26 +81,27 @@
/*
* PCI Bus Class Devices
*/
-static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev,
+static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
+ struct device_attribute *attr,
char *buf)
{
int ret;
cpumask_t cpumask;
- cpumask = pcibus_to_cpumask(to_pci_bus(class_dev));
+ cpumask = pcibus_to_cpumask(to_pci_bus(dev));
ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
if (ret < PAGE_SIZE)
buf[ret++] = '\n';
return ret;
}
-CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
+DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
/*
* PCI Bus Class
*/
-static void release_pcibus_dev(struct class_device *class_dev)
+static void release_pcibus_dev(struct device *dev)
{
- struct pci_bus *pci_bus = to_pci_bus(class_dev);
+ struct pci_bus *pci_bus = to_pci_bus(dev);
if (pci_bus->bridge)
put_device(pci_bus->bridge);
@@ -109,7 +110,7 @@
static struct class pcibus_class = {
.name = "pci_bus",
- .release = &release_pcibus_dev,
+ .dev_release = &release_pcibus_dev,
};
static int __init pcibus_class_init(void)
@@ -392,7 +393,6 @@
{
struct pci_bus *child;
int i;
- int retval;
/*
* Allocate a new bus, and inherit stuff from the parent..
@@ -408,15 +408,12 @@
child->bus_flags = parent->bus_flags;
child->bridge = get_device(&bridge->dev);
- child->class_dev.class = &pcibus_class;
- sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
- retval = class_device_register(&child->class_dev);
- if (retval)
- goto error_register;
- retval = class_device_create_file(&child->class_dev,
- &class_device_attr_cpuaffinity);
- if (retval)
- goto error_file_create;
+ /* initialize some portions of the bus device, but don't register it
+ * now as the parent is not properly set up yet. This device will get
+ * registered later in pci_bus_add_devices()
+ */
+ child->dev.class = &pcibus_class;
+ sprintf(child->dev.bus_id, "%04x:%02x", pci_domain_nr(child), busnr);
/*
* Set up the primary, secondary and subordinate
@@ -434,15 +431,9 @@
bridge->subordinate = child;
return child;
-
-error_file_create:
- class_device_unregister(&child->class_dev);
-error_register:
- kfree(child);
- return NULL;
}
-struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{
struct pci_bus *child;
@@ -471,8 +462,6 @@
}
}
-unsigned int pci_scan_child_bus(struct pci_bus *bus);
-
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
@@ -641,13 +630,13 @@
(child->number > bus->subordinate) ||
(child->number < bus->number) ||
(child->subordinate < bus->number)) {
- pr_debug("PCI: Bus #%02x (-#%02x) is %s"
+ pr_debug("PCI: Bus #%02x (-#%02x) is %s "
"hidden behind%s bridge #%02x (-#%02x)\n",
child->number, child->subordinate,
(bus->number > child->subordinate &&
bus->subordinate < child->number) ?
- "wholly " : " partially",
- bus->self->transparent ? " transparent" : " ",
+ "wholly" : "partially",
+ bus->self->transparent ? " transparent" : "",
bus->number, bus->subordinate);
}
bus = bus->parent;
@@ -944,8 +933,12 @@
set_dev_node(&dev->dev, pcibus_to_node(bus));
dev->dev.dma_mask = &dev->dma_mask;
+ dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
+ pci_set_dma_max_seg_size(dev, 65536);
+ pci_set_dma_seg_boundary(dev, 0xffffffff);
+
/* Fix up broken headers */
pci_fixup_device(pci_fixup_header, dev);
@@ -959,7 +952,7 @@
up_write(&pci_bus_sem);
}
-struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
+struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
@@ -971,6 +964,7 @@
return dev;
}
+EXPORT_SYMBOL(pci_scan_single_device);
/**
* pci_scan_slot - scan a PCI slot on a bus for devices.
@@ -1050,20 +1044,6 @@
return max;
}
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
-{
- unsigned int max;
-
- max = pci_scan_child_bus(bus);
-
- /*
- * Make the discovered devices available.
- */
- pci_bus_add_devices(bus);
-
- return max;
-}
-
struct pci_bus * pci_create_bus(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
@@ -1103,32 +1083,27 @@
goto dev_reg_err;
b->bridge = get_device(dev);
- b->class_dev.class = &pcibus_class;
- sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus);
- error = class_device_register(&b->class_dev);
+ b->dev.class = &pcibus_class;
+ b->dev.parent = b->bridge;
+ sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
+ error = device_register(&b->dev);
if (error)
goto class_dev_reg_err;
- error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity);
+ error = device_create_file(&b->dev, &dev_attr_cpuaffinity);
if (error)
- goto class_dev_create_file_err;
+ goto dev_create_file_err;
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(b);
- error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
- if (error)
- goto sys_create_link_err;
-
b->number = b->secondary = bus;
b->resource[0] = &ioport_resource;
b->resource[1] = &iomem_resource;
return b;
-sys_create_link_err:
- class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity);
-class_dev_create_file_err:
- class_device_unregister(&b->class_dev);
+dev_create_file_err:
+ device_unregister(&b->dev);
class_dev_reg_err:
device_unregister(dev);
dev_reg_err:
@@ -1140,7 +1115,6 @@
kfree(b);
return NULL;
}
-EXPORT_SYMBOL_GPL(pci_create_bus);
struct pci_bus *pci_scan_bus_parented(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
@@ -1156,10 +1130,8 @@
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_add_new_bus);
-EXPORT_SYMBOL(pci_do_scan_bus);
EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_scan_bridge);
-EXPORT_SYMBOL(pci_scan_single_device);
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
#endif
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 716439e..68aeeb7 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/smp_lock.h>
#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -202,15 +203,18 @@
int write_combine;
};
-static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
- const struct proc_dir_entry *dp = PDE(inode);
+ const struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
struct pci_dev *dev = dp->data;
#ifdef HAVE_PCI_MMAP
struct pci_filp_private *fpriv = file->private_data;
#endif /* HAVE_PCI_MMAP */
int ret = 0;
+ lock_kernel();
+
switch (cmd) {
case PCIIOC_CONTROLLER:
ret = pci_domain_nr(dev->bus);
@@ -239,6 +243,7 @@
break;
};
+ unlock_kernel();
return ret;
}
@@ -291,7 +296,7 @@
.llseek = proc_bus_pci_lseek,
.read = proc_bus_pci_read,
.write = proc_bus_pci_write,
- .ioctl = proc_bus_pci_ioctl,
+ .unlocked_ioctl = proc_bus_pci_ioctl,
#ifdef HAVE_PCI_MMAP
.open = proc_bus_pci_open,
.release = proc_bus_pci_release,
@@ -370,7 +375,7 @@
return 0;
}
-static struct seq_operations proc_bus_pci_devices_op = {
+static const struct seq_operations proc_bus_pci_devices_op = {
.start = pci_seq_start,
.next = pci_seq_next,
.stop = pci_seq_stop,
@@ -480,7 +485,3 @@
__initcall(pci_proc_init);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_proc_detach_bus);
-#endif
-
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 72e0bd5..0a953d4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/acpi.h>
+#include <linux/kallsyms.h>
#include "pci.h"
/* The Mellanox Tavor device gives false positive parity errors
@@ -46,14 +47,14 @@
while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
pci_read_config_byte(d, 0x82, &dlc);
if (!(dlc & 1<<1)) {
- printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d));
+ dev_err(&d->dev, "PIIX3: Enabling Passive Release\n");
dlc |= 1<<1;
pci_write_config_byte(d, 0x82, dlc);
}
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release);
/* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
but VIA don't answer queries. If you happen to have good contacts at VIA
@@ -68,20 +69,20 @@
{
if (!isa_dma_bridge_buggy) {
isa_dma_bridge_buggy=1;
- printk(KERN_INFO "Activating ISA DMA hang workarounds.\n");
+ dev_info(&dev->dev, "Activating ISA DMA hang workarounds\n");
}
}
/*
* Its not totally clear which chipsets are the problematic ones
* We know 82C586 and 82C596 variants are affected.
*/
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs);
int pci_pci_problems;
EXPORT_SYMBOL(pci_pci_problems);
@@ -92,12 +93,12 @@
static void __devinit quirk_nopcipci(struct pci_dev *dev)
{
if ((pci_pci_problems & PCIPCI_FAIL)==0) {
- printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n");
+ dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n");
pci_pci_problems |= PCIPCI_FAIL;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci);
static void __devinit quirk_nopciamd(struct pci_dev *dev)
{
@@ -105,11 +106,11 @@
pci_read_config_byte(dev, 0x08, &rev);
if (rev == 0x13) {
/* Erratum 24 */
- printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n");
+ dev_info(&dev->dev, "Chipset erratum: Disabling direct PCI/AGP transfers\n");
pci_pci_problems |= PCIAGP_FAIL;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd);
/*
* Triton requires workarounds to be used by the drivers
@@ -117,14 +118,14 @@
static void __devinit quirk_triton(struct pci_dev *dev)
{
if ((pci_pci_problems&PCIPCI_TRITON)==0) {
- printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+ dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
pci_pci_problems |= PCIPCI_TRITON;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, quirk_triton);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, quirk_triton);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_triton);
/*
* VIA Apollo KT133 needs PCI latency patch
@@ -139,25 +140,22 @@
static void quirk_vialatency(struct pci_dev *dev)
{
struct pci_dev *p;
- u8 rev;
u8 busarb;
/* Ok we have a potential problem chipset here. Now see if we have
a buggy southbridge */
p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
if (p!=NULL) {
- pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
/* Check for buggy part revisions */
- if (rev < 0x40 || rev > 0x42)
+ if (p->revision < 0x40 || p->revision > 0x42)
goto exit;
} else {
p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
if (p==NULL) /* No problem parts */
goto exit;
- pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
/* Check for buggy part revisions */
- if (rev < 0x10 || rev > 0x12)
+ if (p->revision < 0x10 || p->revision > 0x12)
goto exit;
}
@@ -180,17 +178,17 @@
busarb &= ~(1<<5);
busarb |= (1<<4);
pci_write_config_byte(dev, 0x76, busarb);
- printk(KERN_INFO "Applying VIA southbridge workaround.\n");
+ dev_info(&dev->dev, "Applying VIA southbridge workaround\n");
exit:
pci_dev_put(p);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency);
/* Must restore this on a resume from RAM */
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency);
/*
* VIA Apollo VP3 needs ETBF on BT848/878
@@ -198,20 +196,20 @@
static void __devinit quirk_viaetbf(struct pci_dev *dev)
{
if ((pci_pci_problems&PCIPCI_VIAETBF)==0) {
- printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+ dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
pci_pci_problems |= PCIPCI_VIAETBF;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf);
static void __devinit quirk_vsfx(struct pci_dev *dev)
{
if ((pci_pci_problems&PCIPCI_VSFX)==0) {
- printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+ dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
pci_pci_problems |= PCIPCI_VSFX;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx);
/*
* Ali Magik requires workarounds to be used by the drivers
@@ -222,12 +220,12 @@
static void __init quirk_alimagik(struct pci_dev *dev)
{
if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) {
- printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+ dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1647, quirk_alimagik);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagik);
/*
* Natoma has some interesting boundary conditions with Zoran stuff
@@ -236,16 +234,16 @@
static void __devinit quirk_natoma(struct pci_dev *dev)
{
if ((pci_pci_problems&PCIPCI_NATOMA)==0) {
- printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+ dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
pci_pci_problems |= PCIPCI_NATOMA;
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma);
/*
* This chip can cause PCI parity errors if config register 0xA0 is read
@@ -255,7 +253,7 @@
{
dev->cfg_size = 0xA0;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_citrine);
/*
* S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
@@ -270,8 +268,8 @@
r->end = 0x3ffffff;
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M);
static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
unsigned size, int nr, const char *name)
@@ -292,7 +290,7 @@
pcibios_bus_to_resource(dev, res, &bus_region);
pci_claim_resource(dev, nr);
- printk("PCI quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name);
+ dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name);
}
}
@@ -302,12 +300,12 @@
*/
static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
{
- printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
+ dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n");
/* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */
request_region(0x3b0, 0x0C, "RadeonIGP");
request_region(0x3d3, 0x01, "RadeonIGP");
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce);
/*
* Let's make the southbridge information explicit instead
@@ -329,7 +327,7 @@
pci_read_config_word(dev, 0xE2, ®ion);
quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);
static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
{
@@ -354,7 +352,7 @@
* let's get enough confirmation reports first.
*/
base &= -size;
- printk("%s PIO at %04x-%04x\n", name, base, base + size - 1);
+ dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
}
static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
@@ -379,7 +377,7 @@
* reserve it, but let's get enough confirmation reports first.
*/
base &= -size;
- printk("%s MMIO at %04x-%04x\n", name, base, base + size - 1);
+ dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
}
/*
@@ -418,8 +416,8 @@
piix4_io_quirk(dev, "PIIX4 devres I", 0x78, 1 << 20);
piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20);
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi);
/*
* ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
@@ -436,16 +434,16 @@
pci_read_config_dword(dev, 0x58, ®ion);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO");
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi);
static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
{
@@ -457,20 +455,20 @@
pci_read_config_dword(dev, 0x48, ®ion);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO");
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi);
/*
* VIA ACPI: One IO region pointed to by longword at
@@ -486,7 +484,7 @@
quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi);
/*
* VIA VT82C686 ACPI: Three IO region pointed to by (long)words at
@@ -509,7 +507,7 @@
smb &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi);
/*
* VIA VT8235 ISA Bridge: Two IO regions pointed to by words at
@@ -551,14 +549,14 @@
else
tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
- printk(KERN_INFO "PCI: %sbling Via external APIC routing\n",
+ dev_info(&dev->dev, "%sbling VIA external APIC routing\n",
tmp == 0 ? "Disa" : "Ena");
/* Offset 0x58: External APIC IRQ output control */
pci_write_config_byte (dev, 0x58, tmp);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic);
/*
* VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
@@ -573,7 +571,7 @@
pci_read_config_byte(dev, 0x5B, &misc_control2);
if (!(misc_control2 & BYPASS_APIC_DEASSERT)) {
- printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n");
+ dev_info(&dev->dev, "Bypassing VIA 8237 APIC De-Assert Message\n");
pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT);
}
}
@@ -592,18 +590,18 @@
static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
{
if (dev->revision >= 0x02) {
- printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
- printk(KERN_WARNING " : booting with the \"noapic\" option.\n");
+ dev_warn(&dev->dev, "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
+ dev_warn(&dev->dev, " : booting with the \"noapic\" option\n");
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic);
static void __init quirk_ioapic_rmw(struct pci_dev *dev)
{
if (dev->devfn == 0 && dev->bus->number == 0)
sis_apic_bug = 1;
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw);
#define AMD8131_revA0 0x01
#define AMD8131_revB0 0x11
@@ -617,7 +615,7 @@
return;
if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) {
- printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n");
+ dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n");
pci_read_config_byte( dev, AMD8131_MISC, &tmp);
tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
pci_write_config_byte( dev, AMD8131_MISC, tmp);
@@ -634,8 +632,8 @@
static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
{
if (dev->subordinate && dev->revision <= 0x12) {
- printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
- "MMRBC\n", dev->revision);
+ dev_info(&dev->dev, "AMD8131 rev %x detected; "
+ "disabling PCI-X MMRBC\n", dev->revision);
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
}
}
@@ -660,8 +658,8 @@
if (irq && (irq != 2))
d->irq = irq;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi);
/*
@@ -742,8 +740,8 @@
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (new_irq != irq) {
- printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n",
- pci_name(dev), irq, new_irq);
+ dev_info(&dev->dev, "VIA VLink IRQ fixup, from %d to %d\n",
+ irq, new_irq);
udelay(15); /* unknown if delay really needed */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
@@ -761,7 +759,7 @@
pci_write_config_byte(dev, 0xfc, 0);
pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id);
/*
* CardBus controllers have a legacy base address that enables them
@@ -791,15 +789,15 @@
pci_read_config_dword(dev, 0x4C, &pcic);
if ((pcic&6)!=6) {
pcic |= 6;
- printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n");
+ dev_warn(&dev->dev, "BIOS failed to enable PCI standards compliance; fixing this error\n");
pci_write_config_dword(dev, 0x4C, pcic);
pci_read_config_dword(dev, 0x84, &pcic);
pcic |= (1<<23); /* Required in this mode */
pci_write_config_dword(dev, 0x84, pcic);
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering);
/*
* DreamWorks provided workaround for Dunord I-3000 problem
@@ -814,7 +812,7 @@
r->start = 0;
r->end = 0xffffff;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord);
/*
* i82380FB mobile docking controller: its PCI-to-PCI bridge
@@ -826,8 +824,8 @@
{
dev->transparent = 1;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge);
/*
* Common misconfiguration of the MediaGX/Geode PCI master that will
@@ -841,12 +839,12 @@
pci_read_config_byte(dev, 0x41, ®);
if (reg & 2) {
reg &= ~2;
- printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
+ dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
pci_write_config_byte(dev, 0x41, reg);
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master);
/*
* Ensure C0 rev restreaming is off. This is normally done by
@@ -863,11 +861,11 @@
if (config & (1<<6)) {
config &= ~(1<<6);
pci_write_config_word(pdev, 0x40, config);
- printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n");
+ dev_info(&pdev->dev, "C0 revision 450NX. Disabling PCI restreaming\n");
}
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb);
static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
@@ -902,7 +900,7 @@
/* PCI layer will sort out resources */
}
}
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide );
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide);
/*
* Intel 82801CAM ICH3-M datasheet says IDE modes must be the same
@@ -914,7 +912,7 @@
pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) {
- printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n");
+ dev_info(&pdev->dev, "IDE mode mismatch; forcing legacy mode\n");
prog &= ~5;
pdev->class &= ~5;
pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
@@ -929,7 +927,7 @@
{
dev->class = PCI_CLASS_BRIDGE_EISA << 8;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge);
/*
@@ -1022,6 +1020,11 @@
case 0x12bd: /* HP D530 */
asus_hides_smbus = 1;
}
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB)
+ switch (dev->subsystem_device) {
+ case 0x12bf: /* HP xw4100 */
+ asus_hides_smbus = 1;
+ }
else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x099c: /* HP Compaq nx6110 */
@@ -1049,17 +1052,18 @@
}
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge);
static void asus_hides_smbus_lpc(struct pci_dev *dev)
{
@@ -1073,25 +1077,25 @@
pci_write_config_word(dev, 0xF2, val & (~0x8));
pci_read_config_word(dev, 0xF2, &val);
if (val & 0x8)
- printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
+ dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
else
- printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
+ dev_info(&dev->dev, "Enabled i801 SMBus device\n");
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc);
static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
{
@@ -1106,10 +1110,10 @@
val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */
writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */
iounmap(base);
- printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n");
+ dev_info(&dev->dev, "Enabled ICH6/i801 SMBus device\n");
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6);
/*
* SiS 96x south bridge: BIOS typically hides SMBus device...
@@ -1119,18 +1123,18 @@
u8 val = 0;
pci_read_config_byte(dev, 0x77, &val);
if (val & 0x10) {
- printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
+ dev_info(&dev->dev, "Enabling SiS 96x SMBus\n");
pci_write_config_byte(dev, 0x77, val & ~0x10);
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus);
/*
* ... This is further complicated by the fact that some SiS96x south
@@ -1163,8 +1167,8 @@
dev->device = devid;
quirk_sis_96x_smbus(dev);
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503);
/*
@@ -1191,13 +1195,13 @@
pci_write_config_byte(dev, 0x50, val & (~0xc0));
pci_read_config_byte(dev, 0x50, &val);
if (val & 0xc0)
- printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
+ dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
else
- printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n");
+ dev_info(&dev->dev, "Enabled onboard AC97/MC97 devices\n");
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
@@ -1292,7 +1296,7 @@
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic);
#endif
int pcie_mch_quirk;
@@ -1302,9 +1306,9 @@
{
pcie_mch_quirk = 1;
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch);
/*
@@ -1314,11 +1318,8 @@
static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
{
pci_msi_off(dev);
-
dev->no_msi = 1;
-
- printk(KERN_WARNING "PCI: PXH quirk detected, "
- "disabling MSI for SHPC device\n");
+ dev_warn(&dev->dev, "PXH quirk detected; SHPC device MSI disabled\n");
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHD_0, quirk_pcie_pxh);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHD_1, quirk_pcie_pxh);
@@ -1399,7 +1400,7 @@
case PCI_DEVICE_ID_NETMOS_9855:
if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
num_parallel) {
- printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+ dev_info(&dev->dev, "Netmos %04x (%u parallel, "
"%u serial); changing class SERIAL to OTHER "
"(use parport_serial)\n",
dev->device, num_parallel, num_serial);
@@ -1412,9 +1413,10 @@
static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
{
- u16 command;
+ u16 command, pmcsr;
u8 __iomem *csr;
u8 cmd_hi;
+ int pm;
switch (dev->device) {
/* PCI IDs taken from drivers/net/e100.c */
@@ -1448,18 +1450,28 @@
if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0))
return;
+ /*
+ * Check that the device is in the D0 power state. If it's not,
+ * there is no point to look any further.
+ */
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (pm) {
+ pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+ if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0)
+ return;
+ }
+
/* Convert from PCI bus to resource space. */
csr = ioremap(pci_resource_start(dev, 0), 8);
if (!csr) {
- printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
- pci_name(dev));
+ dev_warn(&dev->dev, "Can't map e100 registers\n");
return;
}
cmd_hi = readb(csr + 3);
if (cmd_hi == 0) {
- printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts "
- "enabled, disabling\n", pci_name(dev));
+ dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; "
+ "disabling\n");
writeb(1, csr + 3);
}
@@ -1474,7 +1486,7 @@
*/
if (dev->class == PCI_CLASS_NOT_DEFINED) {
- printk(KERN_INFO "NCR 53c810 rev 1 detected, setting PCI class.\n");
+ dev_info(&dev->dev, "NCR 53c810 rev 1 detected; setting PCI class\n");
dev->class = PCI_CLASS_STORAGE_SCSI;
}
}
@@ -1485,7 +1497,11 @@
while (f < end) {
if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
(f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
- pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
+#ifdef DEBUG
+ dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook);
+ print_fn_descriptor_symbol(": %s()\n",
+ (unsigned long) f->hook);
+#endif
f->hook(dev);
}
f++;
@@ -1553,7 +1569,7 @@
pci_read_config_word(dev, 0x40, &en1k);
if (en1k & 0x200) {
- printk(KERN_INFO "PCI: Enable I/O Space to 1 KB Granularity\n");
+ dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n");
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
@@ -1585,7 +1601,7 @@
iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
if (iobl_adr != iobl_adr_1k) {
- printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+ dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n",
iobl_adr,iobl_adr_1k);
pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
}
@@ -1603,9 +1619,8 @@
if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
if (!(b & 0x20)) {
pci_write_config_byte(dev, 0xf41, b | 0x20);
- printk(KERN_INFO
- "PCI: Linking AER extended capability on %s\n",
- pci_name(dev));
+ dev_info(&dev->dev,
+ "Linking AER extended capability\n");
}
}
}
@@ -1614,6 +1629,34 @@
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_pcie_aer_ext_cap);
+static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
+{
+ /*
+ * Disable PCI Bus Parking and PCI Master read caching on CX700
+ * which causes unspecified timing errors with a VT6212L on the PCI
+ * bus leading to USB2.0 packet loss. The defaults are that these
+ * features are turned off but some BIOSes turn them on.
+ */
+
+ uint8_t b;
+ if (pci_read_config_byte(dev, 0x76, &b) == 0) {
+ if (b & 0x40) {
+ /* Turn off PCI Bus Parking */
+ pci_write_config_byte(dev, 0x76, b ^ 0x40);
+
+ /* Turn off PCI Master read caching */
+ pci_write_config_byte(dev, 0x72, 0x0);
+ pci_write_config_byte(dev, 0x75, 0x1);
+ pci_write_config_byte(dev, 0x77, 0x0);
+
+ printk(KERN_INFO
+ "PCI: VIA CX700 PCI parking/caching fixup on %s\n",
+ pci_name(dev));
+ }
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
+
#ifdef CONFIG_PCI_MSI
/* Some chipsets do not support MSI. We cannot easily rely on setting
* PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
@@ -1624,7 +1667,7 @@
static void __init quirk_disable_all_msi(struct pci_dev *dev)
{
pci_no_msi();
- printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
+ dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
@@ -1635,9 +1678,8 @@
static void __devinit quirk_disable_msi(struct pci_dev *dev)
{
if (dev->subordinate) {
- printk(KERN_WARNING "PCI: MSI quirk detected. "
- "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
- pci_name(dev));
+ dev_warn(&dev->dev, "MSI quirk detected; "
+ "subordinate MSI disabled\n");
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
}
}
@@ -1656,9 +1698,9 @@
if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
&flags) == 0)
{
- printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n",
+ dev_info(&dev->dev, "Found %s HT MSI Mapping\n",
flags & HT_MSI_FLAGS_ENABLE ?
- "enabled" : "disabled", pci_name(dev));
+ "enabled" : "disabled");
return (flags & HT_MSI_FLAGS_ENABLE) != 0;
}
@@ -1672,17 +1714,40 @@
static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
{
if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
- printk(KERN_WARNING "PCI: MSI quirk detected. "
- "MSI disabled on chipset %s.\n",
- pci_name(dev));
+ dev_warn(&dev->dev, "MSI quirk detected; "
+ "subordinate MSI disabled\n");
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
quirk_msi_ht_cap);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS,
- PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
- quirk_msi_ht_cap);
+
+
+/*
+ * Force enable MSI mapping capability on HT bridges
+ */
+static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev)
+{
+ int pos, ttl = 48;
+
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+ while (pos && ttl--) {
+ u8 flags;
+
+ if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) {
+ printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n",
+ pci_name(dev));
+
+ pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+ flags | HT_MSI_FLAGS_ENABLE);
+ }
+ pos = pci_find_next_ht_capability(dev, pos,
+ HT_CAPTYPE_MSI_MAPPING);
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
+ quirk_msi_ht_cap_enable);
/* The nVidia CK804 chipset may have 2 HT MSI mappings.
* MSI are supported if the MSI capability set in any of these mappings.
@@ -1701,9 +1766,8 @@
if (!pdev)
return;
if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) {
- printk(KERN_WARNING "PCI: MSI quirk detected. "
- "MSI disabled on chipset %s.\n",
- pci_name(dev));
+ dev_warn(&dev->dev, "MSI quirk detected; "
+ "subordinate MSI disabled\n");
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
}
pci_dev_put(pdev);
@@ -1715,6 +1779,23 @@
{
dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
}
+static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev)
+{
+ struct pci_dev *p;
+
+ /* SB700 MSI issue will be fixed at HW level from revision A21,
+ * we need check PCI REVISION ID of SMBus controller to get SB700
+ * revision.
+ */
+ p = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+ NULL);
+ if (!p)
+ return;
+
+ if ((p->revision < 0x3B) && (p->revision >= 0x30))
+ dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+ pci_dev_put(p);
+}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
PCI_DEVICE_ID_TIGON3_5780,
quirk_msi_intx_disable_bug);
@@ -1735,17 +1816,15 @@
quirk_msi_intx_disable_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390,
- quirk_msi_intx_disable_bug);
+ quirk_msi_intx_disable_ati_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391,
- quirk_msi_intx_disable_bug);
+ quirk_msi_intx_disable_ati_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392,
- quirk_msi_intx_disable_bug);
+ quirk_msi_intx_disable_ati_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393,
- quirk_msi_intx_disable_bug);
+ quirk_msi_intx_disable_ati_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394,
- quirk_msi_intx_disable_bug);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395,
- quirk_msi_intx_disable_bug);
+ quirk_msi_intx_disable_ati_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373,
quirk_msi_intx_disable_bug);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 430281b..9684e1b 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -74,10 +74,8 @@
list_del(&pci_bus->node);
up_write(&pci_bus_sem);
pci_remove_legacy_files(pci_bus);
- class_device_remove_file(&pci_bus->class_dev,
- &class_device_attr_cpuaffinity);
- sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge");
- class_device_unregister(&pci_bus->class_dev);
+ device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
+ device_unregister(&pci_bus->dev);
}
EXPORT_SYMBOL(pci_remove_bus);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index dbbcc04..a98b247 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -162,6 +162,7 @@
return rom;
}
+#if 0
/**
* pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
* @pdev: pointer to pci device struct
@@ -196,6 +197,7 @@
return (void __iomem *)(unsigned long)res->start;
}
+#endif /* 0 */
/**
* pci_unmap_rom - unmap the ROM from kernel space
@@ -218,6 +220,7 @@
pci_disable_rom(pdev);
}
+#if 0
/**
* pci_remove_rom - disable the ROM and remove its sysfs attribute
* @pdev: pointer to pci device struct
@@ -236,6 +239,7 @@
IORESOURCE_ROM_COPY)))
pci_disable_rom(pdev);
}
+#endif /* 0 */
/**
* pci_cleanup_rom - internal routine for freeing the ROM copy created
@@ -256,6 +260,4 @@
}
EXPORT_SYMBOL(pci_map_rom);
-EXPORT_SYMBOL(pci_map_rom_copy);
EXPORT_SYMBOL(pci_unmap_rom);
-EXPORT_SYMBOL(pci_remove_rom);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 401e03c..262b043 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -89,8 +89,9 @@
* The IO resource is allocated a range twice as large as it
* would normally need. This allows us to set both IO regs.
*/
- printk(" IO window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
@@ -99,8 +100,9 @@
pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]);
if (bus->resource[1]->flags & IORESOURCE_IO) {
- printk(" IO window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " IO window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
@@ -109,8 +111,9 @@
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_MEM) {
- printk(" PREFETCH window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " PREFETCH window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
@@ -119,8 +122,9 @@
pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]);
if (bus->resource[3]->flags & IORESOURCE_MEM) {
- printk(" MEM window: %08lx-%08lx\n",
- region.start, region.end);
+ printk(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
@@ -145,7 +149,7 @@
{
struct pci_dev *bridge = bus->self;
struct pci_bus_region region;
- u32 l, io_upper16;
+ u32 l, bu, lu, io_upper16;
DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
@@ -159,7 +163,8 @@
/* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
DBG(KERN_INFO " IO window: %04lx-%04lx\n",
- region.start, region.end);
+ (unsigned long)region.start,
+ (unsigned long)region.end);
}
else {
/* Clear upper 16 bits of I/O base/limit. */
@@ -180,8 +185,9 @@
if (bus->resource[1]->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- DBG(KERN_INFO " MEM window: %08lx-%08lx\n",
- region.start, region.end);
+ DBG(KERN_INFO " MEM window: 0x%08lx-0x%08lx\n",
+ (unsigned long)region.start,
+ (unsigned long)region.end);
}
else {
l = 0x0000fff0;
@@ -195,12 +201,18 @@
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */
+ bu = lu = 0;
pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]);
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- DBG(KERN_INFO " PREFETCH window: %08lx-%08lx\n",
- region.start, region.end);
+#ifdef CONFIG_RESOURCES_64BIT
+ bu = region.start >> 32;
+ lu = region.end >> 32;
+#endif
+ DBG(KERN_INFO " PREFETCH window: 0x%016llx-0x%016llx\n",
+ (unsigned long long)region.start,
+ (unsigned long long)region.end);
}
else {
l = 0x0000fff0;
@@ -208,8 +220,9 @@
}
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
- /* Clear out the upper 32 bits of PREF base. */
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+ /* Set the upper 32 bits of PREF base & limit. */
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
+ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}
@@ -323,8 +336,8 @@
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
{
struct pci_dev *dev;
- unsigned long min_align, align, size;
- unsigned long aligns[12]; /* Alignments from 1Mb to 2Gb */
+ resource_size_t min_align, align, size;
+ resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
@@ -340,7 +353,7 @@
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
- unsigned long r_size;
+ resource_size_t r_size;
if (r->parent || (r->flags & mask) != type)
continue;
@@ -350,10 +363,10 @@
order = __ffs(align) - 20;
if (order > 11) {
printk(KERN_WARNING "PCI: region %s/%d "
- "too large: %llx-%llx\n",
+ "too large: 0x%016llx-0x%016llx\n",
pci_name(dev), i,
- (unsigned long long)r->start,
- (unsigned long long)r->end);
+ (unsigned long long)r->start,
+ (unsigned long long)r->end);
r->flags = 0;
continue;
}
@@ -372,8 +385,11 @@
align = 0;
min_align = 0;
for (order = 0; order <= max_order; order++) {
- unsigned long align1 = 1UL << (order + 20);
-
+#ifdef CONFIG_RESOURCES_64BIT
+ resource_size_t align1 = 1ULL << (order + 20);
+#else
+ resource_size_t align1 = 1U << (order + 20);
+#endif
if (!align)
min_align = align1;
else if (ALIGN(align + min_align, min_align) < align1)
@@ -440,7 +456,7 @@
}
}
-void pci_bus_size_bridges(struct pci_bus *bus)
+void __ref pci_bus_size_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
unsigned long mask, prefmask;
@@ -495,7 +511,7 @@
}
EXPORT_SYMBOL(pci_bus_size_bridges);
-void pci_bus_assign_resources(struct pci_bus *bus)
+void __ref pci_bus_assign_resources(struct pci_bus *bus)
{
struct pci_bus *b;
struct pci_dev *dev;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 6dfd861..4be7ccf 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -51,10 +51,12 @@
pcibios_resource_to_bus(dev, ®ion, res);
- pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+ pr_debug(" got res [%llx:%llx] bus [%llx:%llx] flags %lx for "
"BAR %d of %s\n", (unsigned long long)res->start,
(unsigned long long)res->end,
- region.start, region.end, res->flags, resno, pci_name(dev));
+ (unsigned long long)region.start,
+ (unsigned long long)region.end,
+ (unsigned long)res->flags, resno, pci_name(dev));
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO)
@@ -125,7 +127,6 @@
return err;
}
-EXPORT_SYMBOL_GPL(pci_claim_resource);
int pci_assign_resource(struct pci_dev *dev, int resno)
{
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index 2ac050d..645d7a6 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -34,7 +34,6 @@
if (!dev)
goto error;
- lock_kernel();
switch (len) {
case 1:
cfg_ret = pci_user_read_config_byte(dev, off, &byte);
@@ -47,10 +46,8 @@
break;
default:
err = -EINVAL;
- unlock_kernel();
goto error;
};
- unlock_kernel();
err = -EIO;
if (cfg_ret != PCIBIOS_SUCCESSFUL)
@@ -107,7 +104,6 @@
if (!dev)
return -ENODEV;
- lock_kernel();
switch(len) {
case 1:
err = get_user(byte, (u8 __user *)buf);
@@ -140,7 +136,6 @@
err = -EINVAL;
break;
}
- unlock_kernel();
pci_dev_put(dev);
return err;
}
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index eb6abd3..385e145 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -21,9 +21,9 @@
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/sizes.h>
+#include <asm/gpio.h>
#include <asm/arch/board.h>
-#include <asm/arch/gpio.h>
#include <asm/arch/at91rm9200_mc.h>
@@ -56,7 +56,7 @@
static inline int at91_cf_present(struct at91_cf_socket *cf)
{
- return !at91_get_gpio_value(cf->board->det_pin);
+ return !gpio_get_value(cf->board->det_pin);
}
/*--------------------------------------------------------------------------*/
@@ -100,9 +100,9 @@
int vcc = cf->board->vcc_pin;
*sp = SS_DETECT | SS_3VCARD;
- if (!rdy || at91_get_gpio_value(rdy))
+ if (!rdy || gpio_get_value(rdy))
*sp |= SS_READY;
- if (!vcc || at91_get_gpio_value(vcc))
+ if (!vcc || gpio_get_value(vcc))
*sp |= SS_POWERON;
} else
*sp = 0;
@@ -121,10 +121,10 @@
if (cf->board->vcc_pin) {
switch (s->Vcc) {
case 0:
- at91_set_gpio_value(cf->board->vcc_pin, 0);
+ gpio_set_value(cf->board->vcc_pin, 0);
break;
case 33:
- at91_set_gpio_value(cf->board->vcc_pin, 1);
+ gpio_set_value(cf->board->vcc_pin, 1);
break;
default:
return -EINVAL;
@@ -132,7 +132,7 @@
}
/* toggle reset if needed */
- at91_set_gpio_value(cf->board->rst_pin, s->flags & SS_RESET);
+ gpio_set_value(cf->board->rst_pin, s->flags & SS_RESET);
pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
@@ -239,11 +239,24 @@
platform_set_drvdata(pdev, cf);
/* must be a GPIO; ergo must trigger on both edges */
- status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
+ status = gpio_request(board->det_pin, "cf_det");
if (status < 0)
goto fail0;
+ status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
+ if (status < 0)
+ goto fail00;
device_init_wakeup(&pdev->dev, 1);
+ status = gpio_request(board->rst_pin, "cf_rst");
+ if (status < 0)
+ goto fail0a;
+
+ if (board->vcc_pin) {
+ status = gpio_request(board->vcc_pin, "cf_vcc");
+ if (status < 0)
+ goto fail0b;
+ }
+
/*
* The card driver will request this irq later as needed.
* but it causes lots of "irqNN: nobody cared" messages
@@ -251,16 +264,20 @@
* (Note: DK board doesn't wire the IRQ pin...)
*/
if (board->irq_pin) {
+ status = gpio_request(board->irq_pin, "cf_irq");
+ if (status < 0)
+ goto fail0c;
status = request_irq(board->irq_pin, at91_cf_irq,
IRQF_SHARED, driver_name, cf);
if (status < 0)
- goto fail0a;
+ goto fail0d;
cf->socket.pci_irq = board->irq_pin;
} else
cf->socket.pci_irq = NR_IRQS + 1;
/* pcmcia layer only remaps "real" memory not iospace */
- cf->socket.io_offset = (unsigned long) ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K);
+ cf->socket.io_offset = (unsigned long)
+ ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K);
if (!cf->socket.io_offset) {
status = -ENXIO;
goto fail1;
@@ -296,11 +313,21 @@
fail1:
if (cf->socket.io_offset)
iounmap((void __iomem *) cf->socket.io_offset);
- if (board->irq_pin)
+ if (board->irq_pin) {
free_irq(board->irq_pin, cf);
+fail0d:
+ gpio_free(board->irq_pin);
+ }
+fail0c:
+ if (board->vcc_pin)
+ gpio_free(board->vcc_pin);
+fail0b:
+ gpio_free(board->rst_pin);
fail0a:
device_init_wakeup(&pdev->dev, 0);
free_irq(board->det_pin, cf);
+fail00:
+ gpio_free(board->det_pin);
fail0:
kfree(cf);
return status;
@@ -313,13 +340,18 @@
struct resource *io = cf->socket.io[0].res;
pcmcia_unregister_socket(&cf->socket);
- if (board->irq_pin)
+ release_mem_region(io->start, io->end + 1 - io->start);
+ iounmap((void __iomem *) cf->socket.io_offset);
+ if (board->irq_pin) {
free_irq(board->irq_pin, cf);
+ gpio_free(board->irq_pin);
+ }
+ if (board->vcc_pin)
+ gpio_free(board->vcc_pin);
+ gpio_free(board->rst_pin);
device_init_wakeup(&pdev->dev, 0);
free_irq(board->det_pin, cf);
- iounmap((void __iomem *) cf->socket.io_offset);
- release_mem_region(io->start, io->end + 1 - io->start);
-
+ gpio_free(board->det_pin);
kfree(cf);
return 0;
}
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index a1bd763..714baae 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -143,7 +143,7 @@
/* Config space? */
if (space == 0) {
if (addr + len > 0x100)
- goto fail;
+ goto failput;
for (; len; addr++, ptr++, len--)
pci_read_config_byte(dev, addr, ptr);
return 0;
@@ -171,6 +171,8 @@
memcpy_fromio(ptr, s->cb_cis_virt + addr, len);
return 0;
+failput:
+ pci_dev_put(dev);
fail:
memset(ptr, 0xff, len);
return -1;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 15c18f5..5a85871 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -865,11 +865,12 @@
ds_dbg(1, "trying to load CIS file %s\n", filename);
if (strlen(filename) > 14) {
- printk(KERN_WARNING "pcmcia: CIS filename is too long\n");
+ printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n",
+ filename);
return -EINVAL;
}
- snprintf(path, 20, "%s", filename);
+ snprintf(path, sizeof(path), "%s", filename);
if (request_firmware(&fw, path, &dev->dev) == 0) {
if (fw->size >= CISTPL_MAX_CIS_SIZE) {
@@ -1130,8 +1131,6 @@
down(&dev->sem);
rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
up(&dev->sem);
- if (!rc)
- dev->power.power_state.event = PM_EVENT_SUSPEND;
return rc;
}
@@ -1142,8 +1141,6 @@
down(&dev->sem);
rc = pcmcia_dev_resume(dev);
up(&dev->sem);
- if (!rc)
- dev->power.power_state.event = PM_EVENT_ON;
}
/************************ per-device sysfs output ***************************/
@@ -1265,6 +1262,9 @@
struct pcmcia_driver *p_drv = NULL;
int ret = 0;
+ if (p_dev->suspended)
+ return 0;
+
ds_dbg(2, "suspending %s\n", dev->bus_id);
if (dev->driver)
@@ -1301,6 +1301,9 @@
struct pcmcia_driver *p_drv = NULL;
int ret = 0;
+ if (!p_dev->suspended)
+ return 0;
+
ds_dbg(2, "resuming %s\n", dev->bus_id);
if (dev->driver)
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index df21e2d..7495155 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -82,7 +82,7 @@
1 = empty socket,
2 = card but not initialized,
3 = operational card */
- kio_addr_t io_base; /* base io address of the socket */
+ unsigned int io_base; /* base io address of the socket */
struct pcmcia_socket socket;
struct pci_dev *dev; /* The PCI device for the socket */
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 839bb1c..32a2ab1 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -164,7 +164,7 @@
u_short type, flags;
struct pcmcia_socket socket;
unsigned int number;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
u_short psock;
u_char cs_irq, intr;
union {
@@ -238,7 +238,7 @@
unsigned long flags;
spin_lock_irqsave(&bus_lock,flags);
{
- kio_addr_t port = socket[sock].ioaddr;
+ unsigned int port = socket[sock].ioaddr;
u_char val;
reg = I365_REG(socket[sock].psock, reg);
outb(reg, port); val = inb(port+1);
@@ -252,7 +252,7 @@
unsigned long flags;
spin_lock_irqsave(&bus_lock,flags);
{
- kio_addr_t port = socket[sock].ioaddr;
+ unsigned int port = socket[sock].ioaddr;
u_char val = I365_REG(socket[sock].psock, reg);
outb(val, port); outb(data, port+1);
spin_unlock_irqrestore(&bus_lock,flags);
@@ -588,7 +588,7 @@
/*====================================================================*/
-static int __init identify(kio_addr_t port, u_short sock)
+static int __init identify(unsigned int port, u_short sock)
{
u_char val;
int type = -1;
@@ -659,7 +659,7 @@
static int __init is_alive(u_short sock)
{
u_char stat;
- kio_addr_t start, stop;
+ unsigned int start, stop;
stat = i365_get(sock, I365_STATUS);
start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
@@ -678,7 +678,7 @@
/*====================================================================*/
-static void __init add_socket(kio_addr_t port, int psock, int type)
+static void __init add_socket(unsigned int port, int psock, int type)
{
socket[sockets].ioaddr = port;
socket[sockets].psock = psock;
@@ -698,7 +698,7 @@
base = sockets-ns;
if (base == 0) printk("\n");
printk(KERN_INFO " %s", pcic[type].name);
- printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x",
+ printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
t->ioaddr, t->psock*0x40);
printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
@@ -772,7 +772,7 @@
static void __init isa_probe(void)
{
int i, j, sock, k, ns, id;
- kio_addr_t port;
+ unsigned int port;
#ifdef CONFIG_PNP
struct isapnp_device_id *devid;
struct pnp_dev *dev;
@@ -1053,7 +1053,7 @@
u_char map, ioctl;
debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#lx-%#lx)\n", sock, io->map, io->flags,
+ "%#x-%#x)\n", sock, io->map, io->flags,
io->speed, io->start, io->stop);
map = io->map;
if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 91da15b..3616da2 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -58,7 +58,7 @@
u_short type, flags;
struct pcmcia_socket socket;
unsigned int number;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
u_long mapaddr;
u_long base; /* PCC register base */
u_char cs_irq1, cs_irq2, intr;
@@ -298,7 +298,8 @@
return 0;
}
-static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr)
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr,
+ unsigned int ioaddr)
{
pcc_socket_t *t = &socket[pcc_sockets];
@@ -738,7 +739,7 @@
#else /* CONFIG_PLAT_USRV */
{
ulong base, mapaddr;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
for (i = 0 ; i < M32R_MAX_PCC ; i++) {
base = (ulong)PLD_CFRSTCR;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index c5e0d89..2b42b71 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -65,7 +65,7 @@
u_short type, flags;
struct pcmcia_socket socket;
unsigned int number;
- kio_addr_t ioaddr;
+ unsigned int ioaddr;
u_long mapaddr;
u_long base; /* PCC register base */
u_char cs_irq, intr;
@@ -310,7 +310,8 @@
return 0;
}
-static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr)
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr,
+ unsigned int ioaddr)
{
pcc_socket_t *t = &socket[pcc_sockets];
@@ -368,7 +369,7 @@
handled = 1;
irc = pcc_get(i, PCIRC);
irc >>=16;
- debug(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc);
+ debug(2, "m32r-pcc:interrupt: socket %d pcirc 0x%02x ", i, irc);
if (!irc)
continue;
@@ -491,7 +492,7 @@
u_char map;
debug(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#lx-%#lx)\n", sock, io->map, io->flags,
+ "%#x-%#x)\n", sock, io->map, io->flags,
io->speed, io->start, io->stop);
map = io->map;
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index d182760..ac70d2c 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -851,7 +851,7 @@
I tried to control the CxOE signal with SS_OUTPUT_ENA,
but the reset signal seems connected via the 541.
If the CxOE is left high are some signals tristated and
- no pullups are present -> the cards act wierd.
+ no pullups are present -> the cards act weird.
So right now the buffers are enabled if the power is on. */
if (state->Vcc || state->Vpp)
@@ -1174,8 +1174,10 @@
pcmcia_schlvl = irq_of_parse_and_map(np, 0);
hwirq = irq_map[pcmcia_schlvl].hwirq;
- if (pcmcia_schlvl < 0)
+ if (pcmcia_schlvl < 0) {
+ iounmap(pcmcia);
return -EINVAL;
+ }
m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
@@ -1189,6 +1191,7 @@
driver_name, socket)) {
pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
pcmcia_schlvl);
+ iounmap(pcmcia);
return -1;
}
@@ -1284,6 +1287,7 @@
}
for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
pcmcia_unregister_socket(&socket[i].socket);
+ iounmap(pcmcia);
free_irq(pcmcia_schlvl, NULL);
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 0ce39de..1d128fb 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -65,23 +65,23 @@
* Special stuff for managing IO windows, because they are scarce
*/
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
- ioaddr_t num, u_int lines)
+static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
+ unsigned int *base, unsigned int num, u_int lines)
{
int i;
- kio_addr_t try, align;
+ unsigned int try, align;
align = (*base) ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
if (*base) {
- ds_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
+ ds_dbg(s, 0, "odd IO request: num %#x align %#x\n",
num, align);
align = 0;
} else
while (align && (align < num)) align <<= 1;
}
if (*base & ~(align-1)) {
- ds_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
+ ds_dbg(s, 0, "odd IO request: base %#x align %#x\n",
*base, align);
align = 0;
}
@@ -132,8 +132,8 @@
} /* alloc_io_space */
-static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
- ioaddr_t num)
+static void release_io_space(struct pcmcia_socket *s, unsigned int base,
+ unsigned int num)
{
int i;
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index bfcaad6..a8d1007 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -186,15 +186,16 @@
======================================================================*/
#ifdef CONFIG_PCMCIA_PROBE
-static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num)
+static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
+ unsigned int num)
{
struct resource *res;
struct socket_data *s_data = s->resource_data;
- kio_addr_t i, j, bad;
+ unsigned int i, j, bad;
int any;
u_char *b, hole, most;
- printk(KERN_INFO "cs: IO port probe %#lx-%#lx:",
+ printk(KERN_INFO "cs: IO port probe %#x-%#x:",
base, base+num-1);
/* First, what does a floating port look like? */
@@ -233,7 +234,7 @@
} else {
if (bad) {
sub_interval(&s_data->io_db, bad, i-bad);
- printk(" %#lx-%#lx", bad, i-1);
+ printk(" %#x-%#x", bad, i-1);
bad = 0;
}
}
@@ -244,7 +245,7 @@
return;
} else {
sub_interval(&s_data->io_db, bad, i-bad);
- printk(" %#lx-%#lx", bad, i-1);
+ printk(" %#x-%#x", bad, i-1);
}
}
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
index af485ae..6284c35d 100644
--- a/drivers/pcmcia/sa1100_jornada720.c
+++ b/drivers/pcmcia/sa1100_jornada720.c
@@ -101,7 +101,7 @@
.socket_suspend = sa1111_pcmcia_socket_suspend,
};
-int __init pcmcia_jornada720_init(struct device *dev)
+int __devinit pcmcia_jornada720_init(struct device *dev)
{
int ret = -ENODEV;
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 749ac37..5792bd5 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -719,7 +719,7 @@
u_short base, len, ioctl;
debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#lx-%#lx)\n", psock, io->map, io->flags,
+ "%#x-%#x)\n", psock, io->map, io->flags,
io->speed, io->start, io->stop);
if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
(io->stop < io->start)) return -EINVAL;
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index a262762..12a1645 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -161,8 +161,7 @@
return error;
}
- if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) &&
- pnp_can_disable(pnp_dev)) {
+ if (pnp_can_disable(pnp_dev)) {
error = pnp_stop_dev(pnp_dev);
if (error)
return error;
@@ -185,14 +184,17 @@
if (pnp_dev->protocol && pnp_dev->protocol->resume)
pnp_dev->protocol->resume(pnp_dev);
- if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
+ if (pnp_can_write(pnp_dev)) {
error = pnp_start_dev(pnp_dev);
if (error)
return error;
}
- if (pnp_drv->resume)
- return pnp_drv->resume(pnp_dev);
+ if (pnp_drv->resume) {
+ error = pnp_drv->resume(pnp_dev);
+ if (error)
+ return error;
+ }
return 0;
}
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 3154804..9826584 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -10,9 +10,12 @@
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/types.h>
+#include <linux/pnp.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.h>
#include "base.h"
@@ -315,8 +318,6 @@
return ret;
}
-extern struct semaphore pnp_res_mutex;
-
static ssize_t
pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
const char *ubuf, size_t count)
@@ -361,10 +362,10 @@
goto done;
}
if (!strnicmp(buf, "get", 3)) {
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
if (pnp_can_read(dev))
dev->protocol->get(dev, &dev->res);
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
goto done;
}
if (!strnicmp(buf, "set", 3)) {
@@ -373,7 +374,7 @@
goto done;
buf += 3;
pnp_init_resource_table(&dev->res);
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
while (1) {
while (isspace(*buf))
++buf;
@@ -455,7 +456,7 @@
}
break;
}
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
goto done;
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index c6b3d4e..c28caf2 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -12,9 +12,10 @@
#include <linux/pnp.h>
#include <linux/slab.h>
#include <linux/bitmap.h>
+#include <linux/mutex.h>
#include "base.h"
-DECLARE_MUTEX(pnp_res_mutex);
+DEFINE_MUTEX(pnp_res_mutex);
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
@@ -297,7 +298,7 @@
if (!pnp_can_configure(dev))
return -ENODEV;
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
if (dev->independent) {
port = dev->independent->port;
@@ -366,12 +367,12 @@
} else if (dev->dependent)
goto fail;
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
return 1;
fail:
pnp_clean_resource_table(&dev->res);
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
return 0;
}
@@ -396,7 +397,7 @@
return -ENOMEM;
*bak = dev->res;
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
dev->res = *res;
if (!(mode & PNP_CONFIG_FORCE)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
@@ -416,14 +417,14 @@
goto fail;
}
}
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
kfree(bak);
return 0;
fail:
dev->res = *bak;
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
kfree(bak);
return -EINVAL;
}
@@ -513,7 +514,7 @@
int error;
if (dev->active)
- return 0; /* the device is already active */
+ return 0;
/* ensure resources are allocated */
if (pnp_auto_config_dev(dev))
@@ -524,7 +525,7 @@
return error;
dev->active = 1;
- return 1;
+ return 0;
}
/**
@@ -538,7 +539,7 @@
int error;
if (!dev->active)
- return 0; /* the device is already disabled */
+ return 0;
error = pnp_stop_dev(dev);
if (error)
@@ -547,11 +548,11 @@
dev->active = 0;
/* release the resources so that other devices can use them */
- down(&pnp_res_mutex);
+ mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(&dev->res);
- up(&pnp_res_mutex);
+ mutex_unlock(&pnp_res_mutex);
- return 1;
+ return 0;
}
/**
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index dada899..662b4c2 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -183,7 +183,7 @@
if (ACPI_SUCCESS(status))
dev->capabilities |= PNP_CONFIGURABLE;
dev->capabilities |= PNP_READ;
- if (device->flags.dynamic_status)
+ if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
dev->capabilities |= PNP_WRITE;
if (device->flags.removable)
dev->capabilities |= PNP_REMOVABLE;
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 6b9840c..6aa231e 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -391,8 +391,8 @@
pnpacpi_allocated_resource, res);
}
-static void pnpacpi_parse_dma_option(struct pnp_option *option,
- struct acpi_resource_dma *p)
+static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
+ struct acpi_resource_dma *p)
{
int i;
struct pnp_dma *dma;
@@ -411,8 +411,8 @@
pnp_register_dma_resource(option, dma);
}
-static void pnpacpi_parse_irq_option(struct pnp_option *option,
- struct acpi_resource_irq *p)
+static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
+ struct acpi_resource_irq *p)
{
int i;
struct pnp_irq *irq;
@@ -431,8 +431,8 @@
pnp_register_irq_resource(option, irq);
}
-static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
- struct acpi_resource_extended_irq *p)
+static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+ struct acpi_resource_extended_irq *p)
{
int i;
struct pnp_irq *irq;
@@ -451,8 +451,8 @@
pnp_register_irq_resource(option, irq);
}
-static void pnpacpi_parse_port_option(struct pnp_option *option,
- struct acpi_resource_io *io)
+static __init void pnpacpi_parse_port_option(struct pnp_option *option,
+ struct acpi_resource_io *io)
{
struct pnp_port *port;
@@ -470,8 +470,8 @@
pnp_register_port_resource(option, port);
}
-static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
- struct acpi_resource_fixed_io *io)
+static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+ struct acpi_resource_fixed_io *io)
{
struct pnp_port *port;
@@ -487,8 +487,8 @@
pnp_register_port_resource(option, port);
}
-static void pnpacpi_parse_mem24_option(struct pnp_option *option,
- struct acpi_resource_memory24 *p)
+static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
+ struct acpi_resource_memory24 *p)
{
struct pnp_mem *mem;
@@ -508,8 +508,8 @@
pnp_register_mem_resource(option, mem);
}
-static void pnpacpi_parse_mem32_option(struct pnp_option *option,
- struct acpi_resource_memory32 *p)
+static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
+ struct acpi_resource_memory32 *p)
{
struct pnp_mem *mem;
@@ -529,8 +529,8 @@
pnp_register_mem_resource(option, mem);
}
-static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
- struct acpi_resource_fixed_memory32 *p)
+static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+ struct acpi_resource_fixed_memory32 *p)
{
struct pnp_mem *mem;
@@ -549,8 +549,8 @@
pnp_register_mem_resource(option, mem);
}
-static void pnpacpi_parse_address_option(struct pnp_option *option,
- struct acpi_resource *r)
+static __init void pnpacpi_parse_address_option(struct pnp_option *option,
+ struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
@@ -596,8 +596,8 @@
struct pnp_dev *dev;
};
-static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
- void *data)
+static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
+ void *data)
{
int priority = 0;
struct acpipnp_parse_option_s *parse_data = data;
@@ -696,8 +696,8 @@
return AE_OK;
}
-acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
- struct pnp_dev * dev)
+acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle,
+ struct pnp_dev *dev)
{
acpi_status status;
struct acpipnp_parse_option_s parse_data;
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index e33e03f..f7e6719 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -315,7 +315,7 @@
.disable = pnpbios_disable_resources,
};
-static int insert_device(struct pnp_bios_node *node)
+static int __init insert_device(struct pnp_bios_node *node)
{
struct list_head *pos;
struct pnp_dev *dev;
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 3fabf11..caade35 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -262,8 +262,8 @@
* Resource Configuration Options
*/
-static void pnpbios_parse_mem_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -278,8 +278,8 @@
pnp_register_mem_resource(option, mem);
}
-static void pnpbios_parse_mem32_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -294,8 +294,8 @@
pnp_register_mem_resource(option, mem);
}
-static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -309,7 +309,7 @@
pnp_register_mem_resource(option, mem);
}
-static void pnpbios_parse_irq_option(unsigned char *p, int size,
+static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_irq *irq;
@@ -327,7 +327,7 @@
pnp_register_irq_resource(option, irq);
}
-static void pnpbios_parse_dma_option(unsigned char *p, int size,
+static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_dma *dma;
@@ -340,8 +340,8 @@
pnp_register_dma_resource(option, dma);
}
-static void pnpbios_parse_port_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_port_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_port *port;
@@ -356,8 +356,8 @@
pnp_register_port_resource(option, port);
}
-static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_port *port;
@@ -371,9 +371,9 @@
pnp_register_port_resource(option, port);
}
-static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p,
- unsigned char *end,
- struct pnp_dev *dev)
+static __init unsigned char *
+pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
+ struct pnp_dev *dev)
{
unsigned int len, tag;
int priority = 0;
@@ -781,7 +781,8 @@
* Core Parsing Functions
*/
-int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node)
+int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
+ struct pnp_bios_node *node)
{
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e903b8c..4065139 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/pnp.h>
#include <linux/io.h>
+#include <linux/dmi.h>
#include <linux/kallsyms.h>
#include "base.h"
@@ -108,6 +109,46 @@
"pnp: SB audio device quirk - increasing port range\n");
}
+static void quirk_supermicro_h8dce_system(struct pnp_dev *dev)
+{
+ int i;
+ static struct dmi_system_id supermicro_h8dce[] = {
+ {
+ .ident = "Supermicro H8DCE",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"),
+ },
+ },
+ { }
+ };
+
+ if (!dmi_check_system(supermicro_h8dce))
+ return;
+
+ /*
+ * On the Supermicro H8DCE, there's a system device with resources
+ * that overlap BAR 6 of the built-in SATA PCI adapter. If the PNP
+ * system device claims them, the sata_nv driver won't be able to.
+ * More details at:
+ * https://bugzilla.redhat.com/show_bug.cgi?id=280641
+ * https://bugzilla.redhat.com/show_bug.cgi?id=313491
+ * http://lkml.org/lkml/2008/1/9/449
+ * http://thread.gmane.org/gmane.linux.acpi.devel/27312
+ */
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) &&
+ (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) {
+ dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent"
+ " conflict with sata_nv PCI device\n",
+ (unsigned long long) pnp_mem_start(dev, i),
+ (unsigned long long) (pnp_mem_start(dev, i) +
+ pnp_mem_len(dev, i) - 1));
+ pnp_mem_flags(dev, i) = 0;
+ }
+ }
+}
+
/*
* PnP Quirks
* Cards or devices that need some tweaking due to incomplete resource info
@@ -128,6 +169,8 @@
{"CTL0043", quirk_sb16audio_resources},
{"CTL0044", quirk_sb16audio_resources},
{"CTL0045", quirk_sb16audio_resources},
+ {"PNP0c01", quirk_supermicro_h8dce_system},
+ {"PNP0c02", quirk_supermicro_h8dce_system},
{""}
};
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 7e29b90..a489227 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -13,7 +13,7 @@
#include <linux/power_supply.h>
#include <linux/apm-emulation.h>
-static DEFINE_MUTEX(apm_mutex);
+
#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
POWER_SUPPLY_PROP_##prop, val)
@@ -22,8 +22,15 @@
#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
+static DEFINE_MUTEX(apm_mutex);
static struct power_supply *main_battery;
+enum apm_source {
+ SOURCE_ENERGY,
+ SOURCE_CHARGE,
+ SOURCE_VOLTAGE,
+};
+
struct find_bat_param {
struct power_supply *main;
struct power_supply *bat;
@@ -107,7 +114,7 @@
}
}
-static int calculate_time(int status, int using_charge)
+static int do_calculate_time(int status, enum apm_source source)
{
union power_supply_propval full;
union power_supply_propval empty;
@@ -126,20 +133,37 @@
return -1;
}
- if (using_charge) {
+ if (!I.intval)
+ return 0;
+
+ switch (source) {
+ case SOURCE_CHARGE:
full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
- } else {
+ break;
+ case SOURCE_ENERGY:
full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
+ break;
+ case SOURCE_VOLTAGE:
+ full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+ full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
+ empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+ empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
+ cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
+ cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+ break;
+ default:
+ printk(KERN_ERR "Unsupported source: %d\n", source);
+ return -1;
}
if (_MPSY_PROP(full_prop, &full)) {
@@ -166,7 +190,26 @@
return -((cur.intval - empty.intval) * 60L) / I.intval;
}
-static int calculate_capacity(int using_charge)
+static int calculate_time(int status)
+{
+ int time;
+
+ time = do_calculate_time(status, SOURCE_ENERGY);
+ if (time != -1)
+ return time;
+
+ time = do_calculate_time(status, SOURCE_CHARGE);
+ if (time != -1)
+ return time;
+
+ time = do_calculate_time(status, SOURCE_VOLTAGE);
+ if (time != -1)
+ return time;
+
+ return -1;
+}
+
+static int calculate_capacity(enum apm_source source)
{
enum power_supply_property full_prop, empty_prop;
enum power_supply_property full_design_prop, empty_design_prop;
@@ -174,20 +217,33 @@
union power_supply_propval empty, full, cur;
int ret;
- if (using_charge) {
+ switch (source) {
+ case SOURCE_CHARGE:
full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
- } else {
+ break;
+ case SOURCE_ENERGY:
full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+ case SOURCE_VOLTAGE:
+ full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+ empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+ full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
+ empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
+ now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+ avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
+ break;
+ default:
+ printk(KERN_ERR "Unsupported source: %d\n", source);
+ return -1;
}
if (_MPSY_PROP(full_prop, &full)) {
@@ -254,10 +310,12 @@
info->battery_life = capacity.intval;
} else {
/* try calculate using energy */
- info->battery_life = calculate_capacity(0);
+ info->battery_life = calculate_capacity(SOURCE_ENERGY);
/* if failed try calculate using charge instead */
if (info->battery_life == -1)
- info->battery_life = calculate_capacity(1);
+ info->battery_life = calculate_capacity(SOURCE_CHARGE);
+ if (info->battery_life == -1)
+ info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
}
/* charging status */
@@ -280,22 +338,16 @@
if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
- !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
+ !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
info->time = time_to_full.intval / 60;
- } else {
- info->time = calculate_time(status.intval, 0);
- if (info->time == -1)
- info->time = calculate_time(status.intval, 1);
- }
+ else
+ info->time = calculate_time(status.intval);
} else {
if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
- !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
+ !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
info->time = time_to_empty.intval / 60;
- } else {
- info->time = calculate_time(status.intval, 0);
- if (info->time == -1)
- info->time = calculate_time(status.intval, 1);
- }
+ else
+ info->time = calculate_time(status.intval);
}
mutex_unlock(&apm_mutex);
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index c998e68..af7a231 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -226,14 +226,6 @@
return ret;
val->intval = ec_byte;
break;
- case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
- if (ec_byte & BAT_STAT_FULL)
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
- else if (ec_byte & BAT_STAT_LOW)
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
- else
- val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
- break;
case POWER_SUPPLY_PROP_TEMP:
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
@@ -265,7 +257,6 @@
POWER_SUPPLY_PROP_VOLTAGE_AVG,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CAPACITY,
- POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_MANUFACTURER,
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index c058f28..c8aa55b 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -32,6 +32,18 @@
static struct resource *ac_irq, *usb_irq;
static struct timer_list charger_timer;
static struct timer_list supply_timer;
+static struct timer_list polling_timer;
+static int polling;
+
+enum {
+ PDA_PSY_OFFLINE = 0,
+ PDA_PSY_ONLINE = 1,
+ PDA_PSY_TO_CHANGE,
+};
+static int new_ac_status = -1;
+static int new_usb_status = -1;
+static int ac_status = -1;
+static int usb_status = -1;
static int pda_power_get_property(struct power_supply *psy,
enum power_supply_property psp,
@@ -61,36 +73,44 @@
"backup-battery",
};
-static struct power_supply pda_power_supplies[] = {
- {
- .name = "ac",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .supplied_to = pda_power_supplied_to,
- .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
- .properties = pda_power_props,
- .num_properties = ARRAY_SIZE(pda_power_props),
- .get_property = pda_power_get_property,
- },
- {
- .name = "usb",
- .type = POWER_SUPPLY_TYPE_USB,
- .supplied_to = pda_power_supplied_to,
- .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
- .properties = pda_power_props,
- .num_properties = ARRAY_SIZE(pda_power_props),
- .get_property = pda_power_get_property,
- },
+static struct power_supply pda_psy_ac = {
+ .name = "ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .supplied_to = pda_power_supplied_to,
+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
+ .properties = pda_power_props,
+ .num_properties = ARRAY_SIZE(pda_power_props),
+ .get_property = pda_power_get_property,
};
+static struct power_supply pda_psy_usb = {
+ .name = "usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .supplied_to = pda_power_supplied_to,
+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
+ .properties = pda_power_props,
+ .num_properties = ARRAY_SIZE(pda_power_props),
+ .get_property = pda_power_get_property,
+};
+
+static void update_status(void)
+{
+ if (pdata->is_ac_online)
+ new_ac_status = !!pdata->is_ac_online();
+
+ if (pdata->is_usb_online)
+ new_usb_status = !!pdata->is_usb_online();
+}
+
static void update_charger(void)
{
if (!pdata->set_charge)
return;
- if (pdata->is_ac_online && pdata->is_ac_online()) {
+ if (new_ac_status > 0) {
dev_dbg(dev, "charger on (AC)\n");
pdata->set_charge(PDA_POWER_CHARGE_AC);
- } else if (pdata->is_usb_online && pdata->is_usb_online()) {
+ } else if (new_usb_status > 0) {
dev_dbg(dev, "charger on (USB)\n");
pdata->set_charge(PDA_POWER_CHARGE_USB);
} else {
@@ -99,34 +119,81 @@
}
}
-static void supply_timer_func(unsigned long power_supply_ptr)
+static void supply_timer_func(unsigned long unused)
{
- void *power_supply = (void *)power_supply_ptr;
+ if (ac_status == PDA_PSY_TO_CHANGE) {
+ ac_status = new_ac_status;
+ power_supply_changed(&pda_psy_ac);
+ }
- power_supply_changed(power_supply);
+ if (usb_status == PDA_PSY_TO_CHANGE) {
+ usb_status = new_usb_status;
+ power_supply_changed(&pda_psy_usb);
+ }
}
-static void charger_timer_func(unsigned long power_supply_ptr)
+static void psy_changed(void)
{
update_charger();
- /* Okay, charger set. Now wait a bit before notifying supplicants,
- * charge power should stabilize. */
- supply_timer.data = power_supply_ptr;
+ /*
+ * Okay, charger set. Now wait a bit before notifying supplicants,
+ * charge power should stabilize.
+ */
mod_timer(&supply_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_charger));
}
+static void charger_timer_func(unsigned long unused)
+{
+ update_status();
+ psy_changed();
+}
+
static irqreturn_t power_changed_isr(int irq, void *power_supply)
{
- /* Wait a bit before reading ac/usb line status and setting charger,
- * because ac/usb status readings may lag from irq. */
- charger_timer.data = (unsigned long)power_supply;
+ if (power_supply == &pda_psy_ac)
+ ac_status = PDA_PSY_TO_CHANGE;
+ else if (power_supply == &pda_psy_usb)
+ usb_status = PDA_PSY_TO_CHANGE;
+ else
+ return IRQ_NONE;
+
+ /*
+ * Wait a bit before reading ac/usb line status and setting charger,
+ * because ac/usb status readings may lag from irq.
+ */
mod_timer(&charger_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_status));
+
return IRQ_HANDLED;
}
+static void polling_timer_func(unsigned long unused)
+{
+ int changed = 0;
+
+ dev_dbg(dev, "polling...\n");
+
+ update_status();
+
+ if (!ac_irq && new_ac_status != ac_status) {
+ ac_status = PDA_PSY_TO_CHANGE;
+ changed = 1;
+ }
+
+ if (!usb_irq && new_usb_status != usb_status) {
+ usb_status = PDA_PSY_TO_CHANGE;
+ changed = 1;
+ }
+
+ if (changed)
+ psy_changed();
+
+ mod_timer(&polling_timer,
+ jiffies + msecs_to_jiffies(pdata->polling_interval));
+}
+
static int pda_power_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -142,6 +209,7 @@
pdata = pdev->dev.platform_data;
+ update_status();
update_charger();
if (!pdata->wait_for_status)
@@ -150,93 +218,147 @@
if (!pdata->wait_for_charger)
pdata->wait_for_charger = 500;
+ if (!pdata->polling_interval)
+ pdata->polling_interval = 2000;
+
setup_timer(&charger_timer, charger_timer_func, 0);
setup_timer(&supply_timer, supply_timer_func, 0);
ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
- if (!ac_irq && !usb_irq) {
- dev_err(dev, "no ac/usb irq specified\n");
- ret = -ENODEV;
- goto noirqs;
- }
if (pdata->supplied_to) {
- pda_power_supplies[0].supplied_to = pdata->supplied_to;
- pda_power_supplies[1].supplied_to = pdata->supplied_to;
- pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
- pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
+ pda_psy_ac.supplied_to = pdata->supplied_to;
+ pda_psy_ac.num_supplicants = pdata->num_supplicants;
+ pda_psy_usb.supplied_to = pdata->supplied_to;
+ pda_psy_usb.num_supplicants = pdata->num_supplicants;
}
- ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
- if (ret) {
- dev_err(dev, "failed to register %s power supply\n",
- pda_power_supplies[0].name);
- goto supply0_failed;
- }
-
- ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
- if (ret) {
- dev_err(dev, "failed to register %s power supply\n",
- pda_power_supplies[1].name);
- goto supply1_failed;
- }
-
- if (ac_irq) {
- ret = request_irq(ac_irq->start, power_changed_isr,
- get_irq_flags(ac_irq), ac_irq->name,
- &pda_power_supplies[0]);
+ if (pdata->is_ac_online) {
+ ret = power_supply_register(&pdev->dev, &pda_psy_ac);
if (ret) {
- dev_err(dev, "request ac irq failed\n");
- goto ac_irq_failed;
+ dev_err(dev, "failed to register %s power supply\n",
+ pda_psy_ac.name);
+ goto ac_supply_failed;
+ }
+
+ if (ac_irq) {
+ ret = request_irq(ac_irq->start, power_changed_isr,
+ get_irq_flags(ac_irq), ac_irq->name,
+ &pda_psy_ac);
+ if (ret) {
+ dev_err(dev, "request ac irq failed\n");
+ goto ac_irq_failed;
+ }
+ } else {
+ polling = 1;
}
}
- if (usb_irq) {
- ret = request_irq(usb_irq->start, power_changed_isr,
- get_irq_flags(usb_irq), usb_irq->name,
- &pda_power_supplies[1]);
+ if (pdata->is_usb_online) {
+ ret = power_supply_register(&pdev->dev, &pda_psy_usb);
if (ret) {
- dev_err(dev, "request usb irq failed\n");
- goto usb_irq_failed;
+ dev_err(dev, "failed to register %s power supply\n",
+ pda_psy_usb.name);
+ goto usb_supply_failed;
+ }
+
+ if (usb_irq) {
+ ret = request_irq(usb_irq->start, power_changed_isr,
+ get_irq_flags(usb_irq),
+ usb_irq->name, &pda_psy_usb);
+ if (ret) {
+ dev_err(dev, "request usb irq failed\n");
+ goto usb_irq_failed;
+ }
+ } else {
+ polling = 1;
}
}
- goto success;
+ if (polling) {
+ dev_dbg(dev, "will poll for status\n");
+ setup_timer(&polling_timer, polling_timer_func, 0);
+ mod_timer(&polling_timer,
+ jiffies + msecs_to_jiffies(pdata->polling_interval));
+ }
+
+ if (ac_irq || usb_irq)
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
usb_irq_failed:
- if (ac_irq)
- free_irq(ac_irq->start, &pda_power_supplies[0]);
+ if (pdata->is_usb_online)
+ power_supply_unregister(&pda_psy_usb);
+usb_supply_failed:
+ if (pdata->is_ac_online && ac_irq)
+ free_irq(ac_irq->start, &pda_psy_ac);
ac_irq_failed:
- power_supply_unregister(&pda_power_supplies[1]);
-supply1_failed:
- power_supply_unregister(&pda_power_supplies[0]);
-supply0_failed:
-noirqs:
+ if (pdata->is_ac_online)
+ power_supply_unregister(&pda_psy_ac);
+ac_supply_failed:
wrongid:
-success:
return ret;
}
static int pda_power_remove(struct platform_device *pdev)
{
- if (usb_irq)
- free_irq(usb_irq->start, &pda_power_supplies[1]);
- if (ac_irq)
- free_irq(ac_irq->start, &pda_power_supplies[0]);
+ if (pdata->is_usb_online && usb_irq)
+ free_irq(usb_irq->start, &pda_psy_usb);
+ if (pdata->is_ac_online && ac_irq)
+ free_irq(ac_irq->start, &pda_psy_ac);
+
+ if (polling)
+ del_timer_sync(&polling_timer);
del_timer_sync(&charger_timer);
del_timer_sync(&supply_timer);
- power_supply_unregister(&pda_power_supplies[1]);
- power_supply_unregister(&pda_power_supplies[0]);
+
+ if (pdata->is_usb_online)
+ power_supply_unregister(&pda_psy_usb);
+ if (pdata->is_ac_online)
+ power_supply_unregister(&pda_psy_ac);
+
return 0;
}
+#ifdef CONFIG_PM
+static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (device_may_wakeup(&pdev->dev)) {
+ if (ac_irq)
+ enable_irq_wake(ac_irq->start);
+ if (usb_irq)
+ enable_irq_wake(usb_irq->start);
+ }
+
+ return 0;
+}
+
+static int pda_power_resume(struct platform_device *pdev)
+{
+ if (device_may_wakeup(&pdev->dev)) {
+ if (usb_irq)
+ disable_irq_wake(usb_irq->start);
+ if (ac_irq)
+ disable_irq_wake(ac_irq->start);
+ }
+
+ return 0;
+}
+#else
+#define pda_power_suspend NULL
+#define pda_power_resume NULL
+#endif /* CONFIG_PM */
+
static struct platform_driver pda_power_pdrv = {
.driver = {
.name = "pda-power",
},
.probe = pda_power_probe,
.remove = pda_power_remove,
+ .suspend = pda_power_suspend,
+ .resume = pda_power_resume,
};
static int __init pda_power_init(void)
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
index 7f8f359..fa3034f 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/power_supply_leds.c
@@ -10,8 +10,11 @@
* You may use this code as per GPL version 2
*/
+#include <linux/kernel.h>
#include <linux/power_supply.h>
+#include "power_supply.h"
+
/* Battery specific LEDs triggers. */
static void power_supply_update_bat_leds(struct power_supply *psy)
@@ -46,28 +49,20 @@
{
int rc = 0;
- psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
- sizeof("-charging-or-full"), GFP_KERNEL);
+ psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
+ "%s-charging-or-full", psy->name);
if (!psy->charging_full_trig_name)
goto charging_full_failed;
- psy->charging_trig_name = kmalloc(strlen(psy->name) +
- sizeof("-charging"), GFP_KERNEL);
+ psy->charging_trig_name = kasprintf(GFP_KERNEL,
+ "%s-charging", psy->name);
if (!psy->charging_trig_name)
goto charging_failed;
- psy->full_trig_name = kmalloc(strlen(psy->name) +
- sizeof("-full"), GFP_KERNEL);
+ psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->name);
if (!psy->full_trig_name)
goto full_failed;
- strcpy(psy->charging_full_trig_name, psy->name);
- strcat(psy->charging_full_trig_name, "-charging-or-full");
- strcpy(psy->charging_trig_name, psy->name);
- strcat(psy->charging_trig_name, "-charging");
- strcpy(psy->full_trig_name, psy->name);
- strcat(psy->full_trig_name, "-full");
-
led_trigger_register_simple(psy->charging_full_trig_name,
&psy->charging_full_trig);
led_trigger_register_simple(psy->charging_trig_name,
@@ -118,14 +113,10 @@
{
int rc = 0;
- psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
- GFP_KERNEL);
+ psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", psy->name);
if (!psy->online_trig_name)
goto online_failed;
- strcpy(psy->online_trig_name, psy->name);
- strcat(psy->online_trig_name, "-online");
-
led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
goto success;
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 249f61b..ad2bed0 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -14,6 +14,8 @@
#include <linux/ctype.h>
#include <linux/power_supply.h>
+#include "power_supply.h"
+
/*
* This is because the name "current" breaks the device attr macro.
* The "current" word resolves to "(get_current())" so instead of
@@ -46,10 +48,8 @@
"Unspecified failure"
};
static char *technology_text[] = {
- "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd"
- };
- static char *capacity_level_text[] = {
- "Unknown", "Critical", "Low", "Normal", "High", "Full"
+ "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
+ "LiMn"
};
ssize_t ret;
struct power_supply *psy = dev_get_drvdata(dev);
@@ -71,9 +71,6 @@
return sprintf(buf, "%s\n", health_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
return sprintf(buf, "%s\n", technology_text[value.intval]);
- else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
- return sprintf(buf, "%s\n",
- capacity_level_text[value.intval]);
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
return sprintf(buf, "%s\n", value.strval);
@@ -88,6 +85,8 @@
POWER_SUPPLY_ATTR(present),
POWER_SUPPLY_ATTR(online),
POWER_SUPPLY_ATTR(technology),
+ POWER_SUPPLY_ATTR(voltage_max),
+ POWER_SUPPLY_ATTR(voltage_min),
POWER_SUPPLY_ATTR(voltage_max_design),
POWER_SUPPLY_ATTR(voltage_min_design),
POWER_SUPPLY_ATTR(voltage_now),
@@ -117,6 +116,7 @@
/* Properties of type `const char *' */
POWER_SUPPLY_ATTR(model_name),
POWER_SUPPLY_ATTR(manufacturer),
+ POWER_SUPPLY_ATTR(serial_number),
};
static ssize_t power_supply_show_static_attrs(struct device *dev,
@@ -159,8 +159,7 @@
&power_supply_attrs[psy->properties[j]]);
statics_failed:
while (i--)
- device_remove_file(psy->dev,
- &power_supply_static_attrs[psy->properties[i]]);
+ device_remove_file(psy->dev, &power_supply_static_attrs[i]);
succeed:
return rc;
}
@@ -170,8 +169,7 @@
int i;
for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
- device_remove_file(psy->dev,
- &power_supply_static_attrs[i]);
+ device_remove_file(psy->dev, &power_supply_static_attrs[i]);
for (i = 0; i < psy->num_properties; i++)
device_remove_file(psy->dev,
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 87b3493..6f2f90e 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -78,23 +78,21 @@
u32 aspect;
u32 x;
u32 y;
- u32 interlace;
- u32 freq;
} video_mode_table[] = {
{ 0, }, /* auto */
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50},
- {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50},
- { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60},
- { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60},
- { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200},
};
/* supported CIDs */
@@ -544,7 +542,7 @@
static void ps3av_set_videomode_cont(u32 id, u32 old_id)
{
- static int vesa = 0;
+ static int vesa;
int res;
/* video signal off */
@@ -554,9 +552,9 @@
* AV backend needs non-VESA mode setting at least one time
* when VESA mode is used.
*/
- if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) {
+ if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) {
/* vesa mode */
- ps3av_set_videomode_packet(2); /* 480P */
+ ps3av_set_videomode_packet(PS3AV_MODE_480P);
}
vesa = 1;
@@ -596,20 +594,21 @@
unsigned mask : 19;
unsigned id : 4;
} ps3av_preferred_modes[] = {
- { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 },
- { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 },
- { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 },
- { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 },
- { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 },
- { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 },
- { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 },
- { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 },
- { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 },
- { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 },
- { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 },
+ { PS3AV_RESBIT_WUXGA << SHIFT_VESA, PS3AV_MODE_WUXGA },
+ { PS3AV_RESBIT_1920x1080P << SHIFT_60, PS3AV_MODE_1080P60 },
+ { PS3AV_RESBIT_1920x1080P << SHIFT_50, PS3AV_MODE_1080P50 },
+ { PS3AV_RESBIT_1920x1080I << SHIFT_60, PS3AV_MODE_1080I60 },
+ { PS3AV_RESBIT_1920x1080I << SHIFT_50, PS3AV_MODE_1080I50 },
+ { PS3AV_RESBIT_SXGA << SHIFT_VESA, PS3AV_MODE_SXGA },
+ { PS3AV_RESBIT_WXGA << SHIFT_VESA, PS3AV_MODE_WXGA },
+ { PS3AV_RESBIT_1280x720P << SHIFT_60, PS3AV_MODE_720P60 },
+ { PS3AV_RESBIT_1280x720P << SHIFT_50, PS3AV_MODE_720P50 },
+ { PS3AV_RESBIT_720x480P << SHIFT_60, PS3AV_MODE_480P },
+ { PS3AV_RESBIT_720x576P << SHIFT_50, PS3AV_MODE_576P },
};
-static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
+static enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60,
+ u32 res_vesa)
{
unsigned int i;
u32 res_all;
@@ -638,9 +637,9 @@
return 0;
}
-static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
+static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
{
- int id;
+ enum ps3av_mode_num id;
if (safe_mode)
return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
@@ -854,7 +853,7 @@
/* auto mode */
option = id & ~PS3AV_MODE_MASK;
- if ((id & PS3AV_MODE_MASK) == 0) {
+ if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) {
id = ps3av_auto_videomode(&ps3av->av_hw_conf);
if (id < 1) {
printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
@@ -889,36 +888,6 @@
EXPORT_SYMBOL_GPL(ps3av_get_mode);
-int ps3av_get_scanmode(int id)
-{
- int size;
-
- id = id & PS3AV_MODE_MASK;
- size = ARRAY_SIZE(video_mode_table);
- if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
- return -EINVAL;
- }
- return video_mode_table[id].interlace;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_scanmode);
-
-int ps3av_get_refresh_rate(int id)
-{
- int size;
-
- id = id & PS3AV_MODE_MASK;
- size = ARRAY_SIZE(video_mode_table);
- if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
- return -EINVAL;
- }
- return video_mode_table[id].freq;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);
-
/* get resolution by video_mode */
int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
{
@@ -990,7 +959,7 @@
return -ENOMEM;
mutex_init(&ps3av->mutex);
- ps3av->ps3av_mode = 0;
+ ps3av->ps3av_mode = PS3AV_MODE_AUTO;
ps3av->dev = dev;
INIT_WORK(&ps3av->work, ps3avd);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 45e4b96..6402d69 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -20,6 +20,10 @@
if RTC_CLASS
+if GEN_RTC || RTC
+comment "Conflicting RTC option has been selected, check GEN_RTC and RTC"
+endif
+
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
depends on RTC_CLASS = y
@@ -49,7 +53,7 @@
If the clock you specify here is not battery backed, it may still
be useful to reinitialize system time when resuming from system
- sleep states. Do not specify an RTC here unless it stays powered
+ sleep states. Do not specify an RTC here unless it stays powered
during all this system's supported sleep states.
config RTC_DEBUG
@@ -142,7 +146,7 @@
will be called rtc-ds1307.
config RTC_DRV_DS1374
- tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+ tristate "Dallas/Maxim DS1374"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for Dallas Semiconductor
@@ -162,7 +166,7 @@
will be called rtc-ds1672.
config RTC_DRV_MAX6900
- tristate "Maxim 6900"
+ tristate "Maxim MAX6900"
help
If you say yes here you will get support for the
Maxim MAX6900 I2C RTC chip.
@@ -180,10 +184,10 @@
will be called rtc-rs5c372.
config RTC_DRV_ISL1208
- tristate "Intersil 1208"
+ tristate "Intersil ISL1208"
help
If you say yes here you get support for the
- Intersil 1208 RTC chip.
+ Intersil ISL1208 RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-isl1208.
@@ -220,7 +224,7 @@
will be called rtc-pcf8583.
config RTC_DRV_M41T80
- tristate "ST M41T80 series RTC"
+ tristate "ST M41T80/81/82/83/84/85/87"
help
If you say Y here you will get support for the
ST M41T80 RTC chips series. Currently following chips are
@@ -252,6 +256,24 @@
if SPI_MASTER
+config RTC_DRV_MAX6902
+ tristate "Maxim MAX6902"
+ help
+ If you say yes here you will get support for the
+ Maxim MAX6902 SPI RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max6902.
+
+config RTC_DRV_R9701
+ tristate "Epson RTC-9701JE"
+ help
+ If you say yes here you will get support for the
+ Epson RTC-9701JE SPI RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-r9701.
+
config RTC_DRV_RS5C348
tristate "Ricoh RS5C348A/B"
help
@@ -261,15 +283,6 @@
This driver can also be built as a module. If so, the module
will be called rtc-rs5c348.
-config RTC_DRV_MAX6902
- tristate "Maxim 6902"
- help
- If you say yes here you will get support for the
- Maxim MAX6902 SPI RTC chip.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-max6902.
-
endif # SPI_MASTER
comment "Platform RTC drivers"
@@ -302,15 +315,40 @@
help
If you say yes here you get support for the Dallas DS1216 RTC chips.
-config RTC_DRV_DS1553
- tristate "Dallas DS1553"
+config RTC_DRV_DS1302
+ tristate "Dallas DS1302"
+ depends on SH_SECUREEDGE5410
+ help
+ If you say yes here you get support for the Dallas DS1302 RTC chips.
+
+config RTC_DRV_DS1511
+ tristate "Dallas DS1511"
+ depends on RTC_CLASS
help
If you say yes here you get support for the
- Dallas DS1553 timekeeping chip.
+ Dallas DS1511 timekeeping/watchdog chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1511.
+
+config RTC_DRV_DS1553
+ tristate "Maxim/Dallas DS1553"
+ help
+ If you say yes here you get support for the
+ Maxim/Dallas DS1553 timekeeping chip.
This driver can also be built as a module. If so, the module
will be called rtc-ds1553.
+config RTC_DRV_DS1742
+ tristate "Maxim/Dallas DS1742/1743"
+ help
+ If you say yes here you get support for the
+ Maxim/Dallas DS1742/1743 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1742.
+
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
depends on RTC_CLASS
@@ -321,15 +359,6 @@
This driver can also be built as a module. If so, the module
will be called rtc-stk17ta8.
-config RTC_DRV_DS1742
- tristate "Dallas DS1742/1743"
- help
- If you say yes here you get support for the
- Dallas DS1742/1743 timekeeping chip.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-ds1742.
-
config RTC_DRV_M48T86
tristate "ST M48T86/Dallas DS12887"
help
@@ -440,10 +469,47 @@
AT32AP700x family processors.
config RTC_DRV_AT91RM9200
- tristate "AT91RM9200"
- depends on ARCH_AT91RM9200
+ tristate "AT91RM9200 or AT91SAM9RL"
+ depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
help
- Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+ Driver for the internal RTC (Realtime Clock) module found on
+ Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips
+ this is powered by the backup power supply.
+
+config RTC_DRV_AT91SAM9
+ tristate "AT91SAM9x"
+ depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
+ help
+ RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer).
+ These timers are powered by the backup power supply (such as a
+ small coin cell battery), but do not need to be used as RTCs.
+
+ (On AT91SAM9rl chips you probably want to use the dedicated RTC
+ module and leave the RTT available for other uses.)
+
+config RTC_DRV_AT91SAM9_RTT
+ int
+ range 0 1
+ default 0
+ prompt "RTT module Number" if ARCH_AT91SAM9263
+ depends on RTC_DRV_AT91SAM9
+ help
+ More than one RTT module is available. You can choose which
+ one will be used as an RTC. The default of zero is normally
+ OK to use, though some systems use that for non-RTC purposes.
+
+config RTC_DRV_AT91SAM9_GPBR
+ int
+ range 0 3 if !ARCH_AT91SAM9263
+ range 0 15 if ARCH_AT91SAM9263
+ default 0
+ prompt "Backup Register Number"
+ depends on RTC_DRV_AT91SAM9
+ help
+ The RTC driver needs to use one of the General Purpose Backup
+ Registers (GPBRs) as well as the RTT. You can choose which one
+ will be used. The default of zero is normally OK to use, but
+ on some systems other software needs to use that register.
config RTC_DRV_BFIN
tristate "Blackfin On-Chip RTC"
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 465db4d..ec703f3 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,11 +19,14 @@
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
+obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
@@ -38,6 +41,7 @@
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
new file mode 100644
index 0000000..bbf10ec
--- /dev/null
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -0,0 +1,520 @@
+/*
+ * "RTT as Real Time Clock" driver for AT91SAM9 SoC family
+ *
+ * (C) 2007 Michel Benoit
+ *
+ * Based on rtc-at91rm9200.c by Rick Bronson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+
+#include <asm/mach/time.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91_rtt.h>
+
+
+/*
+ * This driver uses two configurable hardware resources that live in the
+ * AT91SAM9 backup power domain (intended to be powered at all times)
+ * to implement the Real Time Clock interfaces
+ *
+ * - A "Real-time Timer" (RTT) counts up in seconds from a base time.
+ * We can't assign the counter value (CRTV) ... but we can reset it.
+ *
+ * - One of the "General Purpose Backup Registers" (GPBRs) holds the
+ * base time, normally an offset from the beginning of the POSIX
+ * epoch (1970-Jan-1 00:00:00 UTC). Some systems also include the
+ * local timezone's offset.
+ *
+ * The RTC's value is the RTT counter plus that offset. The RTC's alarm
+ * is likewise a base (ALMV) plus that offset.
+ *
+ * Not all RTTs will be used as RTCs; some systems have multiple RTTs to
+ * choose from, or a "real" RTC module. All systems have multiple GPBR
+ * registers available, likewise usable for more than "RTC" support.
+ */
+
+/*
+ * We store ALARM_DISABLED in ALMV to record that no alarm is set.
+ * It's also the reset value for that field.
+ */
+#define ALARM_DISABLED ((u32)~0)
+
+
+struct sam9_rtc {
+ void __iomem *rtt;
+ struct rtc_device *rtcdev;
+ u32 imr;
+};
+
+#define rtt_readl(rtc, field) \
+ __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
+#define rtt_writel(rtc, field, val) \
+ __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+
+#define gpbr_readl(rtc) \
+ at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+#define gpbr_writel(rtc, val) \
+ at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ u32 secs, secs2;
+ u32 offset;
+
+ /* read current time offset */
+ offset = gpbr_readl(rtc);
+ if (offset == 0)
+ return -EILSEQ;
+
+ /* reread the counter to help sync the two clock domains */
+ secs = rtt_readl(rtc, VR);
+ secs2 = rtt_readl(rtc, VR);
+ if (secs != secs2)
+ secs = rtt_readl(rtc, VR);
+
+ rtc_time_to_tm(offset + secs, tm);
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ int err;
+ u32 offset, alarm, mr;
+ unsigned long secs;
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ err = rtc_tm_to_time(tm, &secs);
+ if (err != 0)
+ return err;
+
+ mr = rtt_readl(rtc, MR);
+
+ /* disable interrupts */
+ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+
+ /* read current time offset */
+ offset = gpbr_readl(rtc);
+
+ /* store the new base time in a battery backup register */
+ secs += 1;
+ gpbr_writel(rtc, secs);
+
+ /* adjust the alarm time for the new base */
+ alarm = rtt_readl(rtc, AR);
+ if (alarm != ALARM_DISABLED) {
+ if (offset > secs) {
+ /* time jumped backwards, increase time until alarm */
+ alarm += (offset - secs);
+ } else if ((alarm + offset) > secs) {
+ /* time jumped forwards, decrease time until alarm */
+ alarm -= (secs - offset);
+ } else {
+ /* time jumped past the alarm, disable alarm */
+ alarm = ALARM_DISABLED;
+ mr &= ~AT91_RTT_ALMIEN;
+ }
+ rtt_writel(rtc, AR, alarm);
+ }
+
+ /* reset the timer, and re-enable interrupts */
+ rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
+
+ return 0;
+}
+
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ u32 alarm = rtt_readl(rtc, AR);
+ u32 offset;
+
+ offset = gpbr_readl(rtc);
+ if (offset == 0)
+ return -EILSEQ;
+
+ memset(alrm, 0, sizeof(alrm));
+ if (alarm != ALARM_DISABLED && offset != 0) {
+ rtc_time_to_tm(offset + alarm, tm);
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm",
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN)
+ alrm->enabled = 1;
+ }
+
+ return 0;
+}
+
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ unsigned long secs;
+ u32 offset;
+ u32 mr;
+ int err;
+
+ err = rtc_tm_to_time(tm, &secs);
+ if (err != 0)
+ return err;
+
+ offset = gpbr_readl(rtc);
+ if (offset == 0) {
+ /* time is not set */
+ return -EILSEQ;
+ }
+ mr = rtt_readl(rtc, MR);
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+
+ /* alarm in the past? finish and leave disabled */
+ if (secs <= offset) {
+ rtt_writel(rtc, AR, ALARM_DISABLED);
+ return 0;
+ }
+
+ /* else set alarm and maybe enable it */
+ rtt_writel(rtc, AR, secs - offset);
+ if (alrm->enabled)
+ rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+
+ dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ int ret = 0;
+ u32 mr = rtt_readl(rtc, MR);
+
+ dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
+
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+ break;
+ case RTC_UIE_OFF: /* update off */
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+ break;
+ case RTC_UIE_ON: /* update on */
+ rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
+ u32 mr = mr = rtt_readl(rtc, MR);
+
+ seq_printf(seq, "update_IRQ\t: %s\n",
+ (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
+ return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+ struct sam9_rtc *rtc = _rtc;
+ u32 sr, mr;
+ unsigned long events = 0;
+
+ /* Shared interrupt may be for another device. Note: reading
+ * SR clears it, so we must only read it in this irq handler!
+ */
+ mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ sr = rtt_readl(rtc, SR) & mr;
+ if (!sr)
+ return IRQ_NONE;
+
+ /* alarm status */
+ if (sr & AT91_RTT_ALMS)
+ events |= (RTC_AF | RTC_IRQF);
+
+ /* timer update/increment */
+ if (sr & AT91_RTT_RTTINC)
+ events |= (RTC_UF | RTC_IRQF);
+
+ rtc_update_irq(rtc->rtcdev, 1, events);
+
+ pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__,
+ events >> 8, events & 0x000000FF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops at91_rtc_ops = {
+ .ioctl = at91_rtc_ioctl,
+ .read_time = at91_rtc_readtime,
+ .set_time = at91_rtc_settime,
+ .read_alarm = at91_rtc_readalarm,
+ .set_alarm = at91_rtc_setalarm,
+ .proc = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct sam9_rtc *rtc;
+ int ret;
+ u32 mr;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, rtc);
+ rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
+ rtc->rtt += r->start;
+
+ mr = rtt_readl(rtc, MR);
+
+ /* unless RTT is counting at 1 Hz, re-initialize it */
+ if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
+ mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
+ gpbr_writel(rtc, 0);
+ }
+
+ /* disable all interrupts (same as on shutdown path) */
+ mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ rtt_writel(rtc, MR, mr);
+
+ rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
+ &at91_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtcdev)) {
+ ret = PTR_ERR(rtc->rtcdev);
+ goto fail;
+ }
+
+ /* register irq handler after we know what name we'll use */
+ ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+ IRQF_DISABLED | IRQF_SHARED,
+ rtc->rtcdev->dev.bus_id, rtc);
+ if (ret) {
+ dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
+ rtc_device_unregister(rtc->rtcdev);
+ goto fail;
+ }
+
+ /* NOTE: sam9260 rev A silicon has a ROM bug which resets the
+ * RTT on at least some reboots. If you have that chip, you must
+ * initialize the time from some external source like a GPS, wall
+ * clock, discrete RTC, etc
+ */
+
+ if (gpbr_readl(rtc) == 0)
+ dev_warn(&pdev->dev, "%s: SET TIME!\n",
+ rtc->rtcdev->dev.bus_id);
+
+ return 0;
+
+fail:
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc);
+ return ret;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __exit at91_rtc_remove(struct platform_device *pdev)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr = rtt_readl(rtc, MR);
+
+ /* disable all interrupts */
+ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+ free_irq(AT91_ID_SYS, rtc);
+
+ rtc_device_unregister(rtc->rtcdev);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc);
+ return 0;
+}
+
+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr = rtt_readl(rtc, MR);
+
+ rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ rtt_writel(rtc, MR, mr & ~rtc->imr);
+}
+
+#ifdef CONFIG_PM
+
+/* AT91SAM9 RTC Power management control */
+
+static int at91_rtc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr = rtt_readl(rtc, MR);
+
+ /*
+ * This IRQ is shared with DBGU and other hardware which isn't
+ * necessarily a wakeup event source.
+ */
+ rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+ if (rtc->imr) {
+ if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
+ enable_irq_wake(AT91_ID_SYS);
+ /* don't let RTTINC cause wakeups */
+ if (mr & AT91_RTT_RTTINCIEN)
+ rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+ } else
+ rtt_writel(rtc, MR, mr & ~rtc->imr);
+ }
+
+ return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+ struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ u32 mr;
+
+ if (rtc->imr) {
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(AT91_ID_SYS);
+ mr = rtt_readl(rtc, MR);
+ rtt_writel(rtc, MR, mr | rtc->imr);
+ }
+
+ return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+ .driver.name = "rtc-at91sam9",
+ .driver.owner = THIS_MODULE,
+ .remove = __exit_p(at91_rtc_remove),
+ .shutdown = at91_rtc_shutdown,
+ .suspend = at91_rtc_suspend,
+ .resume = at91_rtc_resume,
+};
+
+/* Chips can have more than one RTT module, and they can be used for more
+ * than just RTCs. So we can't just register as "the" RTT driver.
+ *
+ * A normal approach in such cases is to create a library to allocate and
+ * free the modules. Here we just use bus_find_device() as like such a
+ * library, binding directly ... no runtime "library" footprint is needed.
+ */
+static int __init at91_rtc_match(struct device *dev, void *v)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+
+ /* continue searching if this isn't the RTT we need */
+ if (strcmp("at91_rtt", pdev->name) != 0
+ || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
+ goto fail;
+
+ /* else we found it ... but fail unless we can bind to the RTC driver */
+ if (dev->driver) {
+ dev_dbg(dev, "busy, can't use as RTC!\n");
+ goto fail;
+ }
+ dev->driver = &at91_rtc_driver.driver;
+ if (device_attach(dev) == 0) {
+ dev_dbg(dev, "can't attach RTC!\n");
+ goto fail;
+ }
+ ret = at91_rtc_probe(pdev);
+ if (ret == 0)
+ return true;
+
+ dev_dbg(dev, "RTC probe err %d!\n", ret);
+fail:
+ return false;
+}
+
+static int __init at91_rtc_init(void)
+{
+ int status;
+ struct device *rtc;
+
+ status = platform_driver_register(&at91_rtc_driver);
+ if (status)
+ return status;
+ rtc = bus_find_device(&platform_bus_type, NULL,
+ NULL, at91_rtc_match);
+ if (!rtc)
+ platform_driver_unregister(&at91_rtc_driver);
+ return rtc ? 0 : -ENODEV;
+}
+module_init(at91_rtc_init);
+
+static void __exit at91_rtc_exit(void)
+{
+ platform_driver_unregister(&at91_rtc_driver);
+}
+module_exit(at91_rtc_exit);
+
+
+MODULE_AUTHOR("Michel Benoit");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 1aa709d..d90ba86 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -1,6 +1,6 @@
/*
* Blackfin On-Chip Real Time Clock Driver
- * Supports BF53[123]/BF53[467]/BF54[2489]
+ * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
*
* Copyright 2004-2007 Analog Devices Inc.
*
@@ -32,26 +32,25 @@
* writes to clear status registers complete immediately.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
+#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/seq_file.h>
#include <asm/blackfin.h>
-#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
-#define stampit() stamp("here i am")
+#define dev_dbg_stamp(dev) dev_dbg(dev, "%s:%i: here i am\n", __func__, __LINE__)
struct bfin_rtc {
struct rtc_device *rtc_dev;
struct rtc_time rtc_alarm;
- spinlock_t lock;
+ u16 rtc_wrote_regs;
};
/* Bit values for the ISTAT / ICTL registers */
@@ -72,7 +71,7 @@
#define SEC_BITS_OFF 0
/* Some helper functions to convert between the common RTC notion of time
- * and the internal Blackfin notion that is stored in 32bits.
+ * and the internal Blackfin notion that is encoded in 32bits.
*/
static inline u32 rtc_time_to_bfin(unsigned long now)
{
@@ -97,7 +96,10 @@
rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
}
-/* Wait for the previous write to a RTC register to complete.
+/**
+ * bfin_rtc_sync_pending - make sure pending writes have complete
+ *
+ * Wait for the previous write to a RTC register to complete.
* Unfortunately, we can't sleep here as that introduces a race condition when
* turning on interrupt events. Consider this:
* - process sets alarm
@@ -112,188 +114,202 @@
* If anyone can point out the obvious solution here, i'm listening :). This
* shouldn't be an issue on an SMP or preempt system as this function should
* only be called with the rtc lock held.
+ *
+ * Other options:
+ * - disable PREN so the sync happens at 32.768kHZ ... but this changes the
+ * inc rate for all RTC registers from 1HZ to 32.768kHZ ...
+ * - use the write complete IRQ
*/
-static void rtc_bfin_sync_pending(void)
+/*
+static void bfin_rtc_sync_pending_polled(void)
{
- stampit();
- while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
+ while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE))
if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
break;
- }
bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
}
-
-static void rtc_bfin_reset(struct bfin_rtc *rtc)
+*/
+static DECLARE_COMPLETION(bfin_write_complete);
+static void bfin_rtc_sync_pending(struct device *dev)
{
- /* Initialize the RTC. Enable pre-scaler to scale RTC clock
- * to 1Hz and clear interrupt/status registers. */
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
+ dev_dbg_stamp(dev);
+ while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
+ wait_for_completion_timeout(&bfin_write_complete, HZ * 5);
+ dev_dbg_stamp(dev);
+}
+
+/**
+ * bfin_rtc_reset - set RTC to sane/known state
+ *
+ * Initialize the RTC. Enable pre-scaler to scale RTC clock
+ * to 1Hz and clear interrupt/status registers.
+ */
+static void bfin_rtc_reset(struct device *dev)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ dev_dbg_stamp(dev);
+ bfin_rtc_sync_pending(dev);
bfin_write_RTC_PREN(0x1);
- bfin_write_RTC_ICTL(0);
+ bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE);
bfin_write_RTC_SWCNT(0);
bfin_write_RTC_ALARM(0);
bfin_write_RTC_ISTAT(0xFFFF);
- spin_unlock_irq(&rtc->lock);
+ rtc->rtc_wrote_regs = 0;
}
+/**
+ * bfin_rtc_interrupt - handle interrupt from RTC
+ *
+ * Since we handle all RTC events here, we have to make sure the requested
+ * interrupt is enabled (in RTC_ICTL) as the event status register (RTC_ISTAT)
+ * always gets updated regardless of the interrupt being enabled. So when one
+ * even we care about (e.g. stopwatch) goes off, we don't want to turn around
+ * and say that other events have happened as well (e.g. second). We do not
+ * have to worry about pending writes to the RTC_ICTL register as interrupts
+ * only fire if they are enabled in the RTC_ICTL register.
+ */
static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
{
- struct platform_device *pdev = to_platform_device(dev_id);
- struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+ struct device *dev = dev_id;
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
unsigned long events = 0;
- u16 rtc_istat;
+ bool write_complete = false;
+ u16 rtc_istat, rtc_ictl;
- stampit();
-
- spin_lock_irq(&rtc->lock);
+ dev_dbg_stamp(dev);
rtc_istat = bfin_read_RTC_ISTAT();
+ rtc_ictl = bfin_read_RTC_ICTL();
- if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
- events |= RTC_AF | RTC_IRQF;
+ if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+ write_complete = true;
+ complete(&bfin_write_complete);
}
- if (rtc_istat & RTC_ISTAT_STOPWATCH) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
- events |= RTC_PF | RTC_IRQF;
- bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+ if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+ if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+ events |= RTC_AF | RTC_IRQF;
+ }
}
- if (rtc_istat & RTC_ISTAT_SEC) {
- bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
- events |= RTC_UF | RTC_IRQF;
+ if (rtc_ictl & RTC_ISTAT_STOPWATCH) {
+ if (rtc_istat & RTC_ISTAT_STOPWATCH) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+ events |= RTC_PF | RTC_IRQF;
+ bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+ }
}
- rtc_update_irq(rtc->rtc_dev, 1, events);
+ if (rtc_ictl & RTC_ISTAT_SEC) {
+ if (rtc_istat & RTC_ISTAT_SEC) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+ events |= RTC_UF | RTC_IRQF;
+ }
+ }
- spin_unlock_irq(&rtc->lock);
+ if (events)
+ rtc_update_irq(rtc->rtc_dev, 1, events);
- return IRQ_HANDLED;
+ if (write_complete || events)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
static int bfin_rtc_open(struct device *dev)
{
- struct bfin_rtc *rtc = dev_get_drvdata(dev);
int ret;
- stampit();
+ dev_dbg_stamp(dev);
- ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
- if (unlikely(ret)) {
- dev_err(dev, "request RTC IRQ failed with %d\n", ret);
- return ret;
- }
-
- rtc_bfin_reset(rtc);
+ ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev);
+ if (!ret)
+ bfin_rtc_reset(dev);
return ret;
}
static void bfin_rtc_release(struct device *dev)
{
- struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- rtc_bfin_reset(rtc);
+ dev_dbg_stamp(dev);
+ bfin_rtc_reset(dev);
free_irq(IRQ_RTC, dev);
}
+static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int)
+{
+ bfin_write_RTC_ISTAT(rtc_int);
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int);
+}
+static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int)
+{
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int);
+}
+static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc)
+{
+ /* Blackfin has different bits for whether the alarm is
+ * more than 24 hours away.
+ */
+ bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY));
+}
static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ int ret = 0;
- stampit();
+ dev_dbg_stamp(dev);
+
+ bfin_rtc_sync_pending(dev);
switch (cmd) {
case RTC_PIE_ON:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH);
bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ break;
case RTC_PIE_OFF:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_SWCNT(0);
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH);
+ break;
case RTC_UIE_ON:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_set(rtc, RTC_ISTAT_SEC);
+ break;
case RTC_UIE_OFF:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC);
+ break;
- case RTC_AIE_ON: {
- unsigned long rtc_alarm;
- u16 which_alarm;
- int ret = 0;
-
- stampit();
-
- spin_lock_irq(&rtc->lock);
-
- rtc_bfin_sync_pending();
- if (rtc->rtc_alarm.tm_yday == -1) {
- struct rtc_time now;
- rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
- now.tm_sec = rtc->rtc_alarm.tm_sec;
- now.tm_min = rtc->rtc_alarm.tm_min;
- now.tm_hour = rtc->rtc_alarm.tm_hour;
- ret = rtc_tm_to_time(&now, &rtc_alarm);
- which_alarm = RTC_ISTAT_ALARM;
- } else {
- ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
- which_alarm = RTC_ISTAT_ALARM_DAY;
- }
- if (ret == 0) {
- bfin_write_RTC_ISTAT(which_alarm);
- bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
- }
-
- spin_unlock_irq(&rtc->lock);
-
- return ret;
- }
+ case RTC_AIE_ON:
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_set_alarm(rtc);
+ break;
case RTC_AIE_OFF:
- stampit();
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
- bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
- spin_unlock_irq(&rtc->lock);
- return 0;
+ dev_dbg_stamp(dev);
+ bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+ break;
+
+ default:
+ dev_dbg_stamp(dev);
+ ret = -ENOIOCTLCMD;
}
- return -ENOIOCTLCMD;
+ return ret;
}
static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
+ dev_dbg_stamp(dev);
- spin_lock_irq(&rtc->lock);
- rtc_bfin_sync_pending();
+ if (rtc->rtc_wrote_regs & 0x1)
+ bfin_rtc_sync_pending(dev);
+
rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
- spin_unlock_irq(&rtc->lock);
return 0;
}
@@ -304,64 +320,79 @@
int ret;
unsigned long now;
- stampit();
-
- spin_lock_irq(&rtc->lock);
+ dev_dbg_stamp(dev);
ret = rtc_tm_to_time(tm, &now);
if (ret == 0) {
- rtc_bfin_sync_pending();
+ if (rtc->rtc_wrote_regs & 0x1)
+ bfin_rtc_sync_pending(dev);
bfin_write_RTC_STAT(rtc_time_to_bfin(now));
+ rtc->rtc_wrote_regs = 0x1;
}
- spin_unlock_irq(&rtc->lock);
-
return ret;
}
static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
- alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+ dev_dbg_stamp(dev);
+ alrm->time = rtc->rtc_alarm;
+ bfin_rtc_sync_pending(dev);
+ alrm->enabled = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
return 0;
}
static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+ unsigned long rtc_alarm;
+
+ dev_dbg_stamp(dev);
+
+ if (rtc_tm_to_time(&alrm->time, &rtc_alarm))
+ return -EINVAL;
+
+ rtc->rtc_alarm = alrm->time;
+
+ bfin_rtc_sync_pending(dev);
+ bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
+ if (alrm->enabled)
+ bfin_rtc_int_set_alarm(rtc);
+
return 0;
}
static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
{
-#define yesno(x) (x ? "yes" : "no")
+#define yesno(x) ((x) ? "yes" : "no")
u16 ictl = bfin_read_RTC_ICTL();
- stampit();
- seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
- seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
- seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
- seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
-#ifdef DEBUG
- seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
- seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
- seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
- seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
- seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
- seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
-#endif
+ dev_dbg_stamp(dev);
+ seq_printf(seq,
+ "alarm_IRQ\t: %s\n"
+ "wkalarm_IRQ\t: %s\n"
+ "seconds_IRQ\t: %s\n"
+ "periodic_IRQ\t: %s\n",
+ yesno(ictl & RTC_ISTAT_ALARM),
+ yesno(ictl & RTC_ISTAT_ALARM_DAY),
+ yesno(ictl & RTC_ISTAT_SEC),
+ yesno(ictl & RTC_ISTAT_STOPWATCH));
return 0;
+#undef yesno
}
+/**
+ * bfin_irq_set_freq - make sure hardware supports requested freq
+ * @dev: pointer to RTC device structure
+ * @freq: requested frequency rate
+ *
+ * The Blackfin RTC can only generate periodic events at 1 per
+ * second (1 Hz), so reject any attempt at changing it.
+ */
static int bfin_irq_set_freq(struct device *dev, int freq)
{
- struct bfin_rtc *rtc = dev_get_drvdata(dev);
- stampit();
- rtc->rtc_dev->irq_freq = freq;
- return 0;
+ dev_dbg_stamp(dev);
+ return -ENOTTY;
}
static struct rtc_class_ops bfin_rtc_ops = {
@@ -381,27 +412,24 @@
struct bfin_rtc *rtc;
int ret = 0;
- stampit();
+ dev_dbg_stamp(&pdev->dev);
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (unlikely(!rtc))
return -ENOMEM;
- spin_lock_init(&rtc->lock);
-
rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
if (unlikely(IS_ERR(rtc))) {
ret = PTR_ERR(rtc->rtc_dev);
goto err;
}
- rtc->rtc_dev->irq_freq = 0;
- rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
+ rtc->rtc_dev->irq_freq = 1;
platform_set_drvdata(pdev, rtc);
return 0;
-err:
+ err:
kfree(rtc);
return ret;
}
@@ -428,7 +456,6 @@
static int __init bfin_rtc_init(void)
{
- stampit();
return platform_driver_register(&bfin_rtc_driver);
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 29cf145..e059f94 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -36,9 +36,24 @@
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
+#ifdef CONFIG_HPET_EMULATE_RTC
+#include <asm/hpet.h>
+#endif
+
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include <asm-generic/rtc.h>
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled() 0
+#define hpet_set_alarm_time(hrs, min, sec) do { } while (0)
+#define hpet_set_periodic_freq(arg) 0
+#define hpet_mask_rtc_irq_bit(arg) do { } while (0)
+#define hpet_set_rtc_irq_bit(arg) do { } while (0)
+#define hpet_rtc_timer_init() do { } while (0)
+#define hpet_register_irq_handler(h) 0
+#define hpet_unregister_irq_handler(h) do { } while (0)
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+#endif
struct cmos_rtc {
struct rtc_device *rtc;
@@ -199,6 +214,7 @@
sec = t->time.tm_sec;
sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
+ hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
spin_lock_irq(&rtc_lock);
/* next rtc irq must not be from previous alarm setting */
@@ -252,7 +268,8 @@
f = 16 - f;
spin_lock_irqsave(&rtc_lock, flags);
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+ if (!hpet_set_periodic_freq(freq))
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
@@ -314,28 +331,37 @@
switch (cmd) {
case RTC_AIE_OFF: /* alarm off */
rtc_control &= ~RTC_AIE;
+ hpet_mask_rtc_irq_bit(RTC_AIE);
break;
case RTC_AIE_ON: /* alarm on */
rtc_control |= RTC_AIE;
+ hpet_set_rtc_irq_bit(RTC_AIE);
break;
case RTC_UIE_OFF: /* update off */
rtc_control &= ~RTC_UIE;
+ hpet_mask_rtc_irq_bit(RTC_UIE);
break;
case RTC_UIE_ON: /* update on */
rtc_control |= RTC_UIE;
+ hpet_set_rtc_irq_bit(RTC_UIE);
break;
case RTC_PIE_OFF: /* periodic off */
rtc_control &= ~RTC_PIE;
+ hpet_mask_rtc_irq_bit(RTC_PIE);
break;
case RTC_PIE_ON: /* periodic on */
rtc_control |= RTC_PIE;
+ hpet_set_rtc_irq_bit(RTC_PIE);
break;
}
- CMOS_WRITE(rtc_control, RTC_CONTROL);
+ if (!is_hpet_enabled())
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
@@ -393,15 +419,111 @@
/*----------------------------------------------------------------*/
+/*
+ * All these chips have at least 64 bytes of address space, shared by
+ * RTC registers and NVRAM. Most of those bytes of NVRAM are used
+ * by boot firmware. Modern chips have 128 or 256 bytes.
+ */
+
+#define NVRAM_OFFSET (RTC_REG_D + 1)
+
+static ssize_t
+cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ int retval;
+
+ if (unlikely(off >= attr->size))
+ return 0;
+ if ((off + count) > attr->size)
+ count = attr->size - off;
+
+ spin_lock_irq(&rtc_lock);
+ for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++)
+ *buf++ = CMOS_READ(off);
+ spin_unlock_irq(&rtc_lock);
+
+ return retval;
+}
+
+static ssize_t
+cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct cmos_rtc *cmos;
+ int retval;
+
+ cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ if (unlikely(off >= attr->size))
+ return -EFBIG;
+ if ((off + count) > attr->size)
+ count = attr->size - off;
+
+ /* NOTE: on at least PCs and Ataris, the boot firmware uses a
+ * checksum on part of the NVRAM data. That's currently ignored
+ * here. If userspace is smart enough to know what fields of
+ * NVRAM to update, updating checksums is also part of its job.
+ */
+ spin_lock_irq(&rtc_lock);
+ for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) {
+ /* don't trash RTC registers */
+ if (off == cmos->day_alrm
+ || off == cmos->mon_alrm
+ || off == cmos->century)
+ buf++;
+ else
+ CMOS_WRITE(*buf++, off);
+ }
+ spin_unlock_irq(&rtc_lock);
+
+ return retval;
+}
+
+static struct bin_attribute nvram = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+
+ .read = cmos_nvram_read,
+ .write = cmos_nvram_write,
+ /* size gets set up later */
+};
+
+/*----------------------------------------------------------------*/
+
static struct cmos_rtc cmos_rtc;
static irqreturn_t cmos_interrupt(int irq, void *p)
{
u8 irqstat;
+ u8 rtc_control;
spin_lock(&rtc_lock);
- irqstat = CMOS_READ(RTC_INTR_FLAGS);
- irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF;
+ /*
+ * In this case it is HPET RTC interrupt handler
+ * calling us, with the interrupt information
+ * passed as arg1, instead of irq.
+ */
+ if (is_hpet_enabled())
+ irqstat = (unsigned long)irq & 0xF0;
+ else {
+ irqstat = CMOS_READ(RTC_INTR_FLAGS);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ }
+
+ /* All Linux RTC alarms should be treated as if they were oneshot.
+ * Similar code may be needed in system wakeup paths, in case the
+ * alarm woke the system.
+ */
+ if (irqstat & RTC_AIE) {
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control &= ~RTC_AIE;
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+ }
spin_unlock(&rtc_lock);
if (is_intr(irqstat)) {
@@ -412,11 +534,9 @@
}
#ifdef CONFIG_PNP
-#define is_pnp() 1
#define INITSECTION
#else
-#define is_pnp() 0
#define INITSECTION __init
#endif
@@ -426,6 +546,7 @@
struct cmos_rtc_board_info *info = dev->platform_data;
int retval = 0;
unsigned char rtc_control;
+ unsigned address_space;
/* there can be only one ... */
if (cmos_rtc.dev)
@@ -450,15 +571,36 @@
cmos_rtc.irq = rtc_irq;
cmos_rtc.iomem = ports;
+ /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
+ * driver did, but don't reject unknown configs. Old hardware
+ * won't address 128 bytes, and for now we ignore the way newer
+ * chips can address 256 bytes (using two more i/o ports).
+ */
+#if defined(CONFIG_ATARI)
+ address_space = 64;
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+ address_space = 128;
+#else
+#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
+ address_space = 128;
+#endif
+
/* For ACPI systems extension info comes from the FADT. On others,
* board specific setup provides it as appropriate. Systems where
* the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
* some almost-clones) can provide hooks to make that behave.
+ *
+ * Note that ACPI doesn't preclude putting these registers into
+ * "extended" areas of the chip, including some that we won't yet
+ * expect CMOS_READ and friends to handle.
*/
if (info) {
- cmos_rtc.day_alrm = info->rtc_day_alarm;
- cmos_rtc.mon_alrm = info->rtc_mon_alarm;
- cmos_rtc.century = info->rtc_century;
+ if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
+ cmos_rtc.day_alrm = info->rtc_day_alarm;
+ if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
+ cmos_rtc.mon_alrm = info->rtc_mon_alarm;
+ if (info->rtc_century && info->rtc_century < 128)
+ cmos_rtc.century = info->rtc_century;
if (info->wake_on && info->wake_off) {
cmos_rtc.wake_on = info->wake_on;
@@ -485,8 +627,9 @@
* doesn't use 32KHz here ... for portability we might need to
* do something about other clock frequencies.
*/
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
cmos_rtc.rtc->irq_freq = 1024;
+ if (!hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq))
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
/* disable irqs.
*
@@ -509,19 +652,39 @@
goto cleanup1;
}
- if (is_valid_irq(rtc_irq))
- retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
- cmos_rtc.rtc->dev.bus_id,
- cmos_rtc.rtc);
- if (retval < 0) {
- dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
- goto cleanup1;
- }
+ if (is_valid_irq(rtc_irq)) {
+ irq_handler_t rtc_cmos_int_handler;
- /* REVISIT optionally make 50 or 114 bytes NVRAM available,
- * like rtc-ds1553, rtc-ds1742 ... this will often include
- * registers for century, and day/month alarm.
- */
+ if (is_hpet_enabled()) {
+ int err;
+
+ rtc_cmos_int_handler = hpet_rtc_interrupt;
+ err = hpet_register_irq_handler(cmos_interrupt);
+ if (err != 0) {
+ printk(KERN_WARNING "hpet_register_irq_handler "
+ " failed in rtc_init().");
+ goto cleanup1;
+ }
+ } else
+ rtc_cmos_int_handler = cmos_interrupt;
+
+ retval = request_irq(rtc_irq, rtc_cmos_int_handler,
+ IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id,
+ cmos_rtc.rtc);
+ if (retval < 0) {
+ dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
+ goto cleanup1;
+ }
+ }
+ hpet_rtc_timer_init();
+
+ /* export at least the first block of NVRAM */
+ nvram.size = address_space - NVRAM_OFFSET;
+ retval = sysfs_create_bin_file(&dev->kobj, &nvram);
+ if (retval < 0) {
+ dev_dbg(dev, "can't create nvram file? %d\n", retval);
+ goto cleanup2;
+ }
pr_info("%s: alarms up to one %s%s\n",
cmos_rtc.rtc->dev.bus_id,
@@ -536,6 +699,9 @@
return 0;
+cleanup2:
+ if (is_valid_irq(rtc_irq))
+ free_irq(rtc_irq, cmos_rtc.rtc);
cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
@@ -563,8 +729,12 @@
cmos_do_shutdown();
- if (is_valid_irq(cmos->irq))
+ sysfs_remove_bin_file(&dev->kobj, &nvram);
+
+ if (is_valid_irq(cmos->irq)) {
free_irq(cmos->irq, cmos->rtc);
+ hpet_unregister_irq_handler(cmos_interrupt);
+ }
rtc_device_unregister(cmos->rtc);
cmos->rtc = NULL;
@@ -659,9 +829,12 @@
/*----------------------------------------------------------------*/
-/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
- * the device node will always be created as a PNPACPI device. Plus
- * pre-ACPI PCs probably list it in the PNPBIOS tables.
+/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
+ * ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs
+ * probably list them in similar PNPBIOS tables; so PNP is more common.
+ *
+ * We don't use legacy "poke at the hardware" probing. Ancient PCs that
+ * predate even PNPBIOS should set up platform_bus devices.
*/
#ifdef CONFIG_PNP
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 025c60a..90dfa0d 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -246,6 +246,15 @@
/* if the driver does not provide the ioctl interface
* or if that particular ioctl was not implemented
* (-ENOIOCTLCMD), we will try to emulate here.
+ *
+ * Drivers *SHOULD NOT* provide ioctl implementations
+ * for these requests. Instead, provide methods to
+ * support the following code, so that the RTC's main
+ * features are accessible without using ioctls.
+ *
+ * RTC and alarm times will be in UTC, by preference,
+ * but dual-booting with MS-Windows implies RTCs must
+ * use the local wall clock time.
*/
switch (cmd) {
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
new file mode 100644
index 0000000..7b002ce
--- /dev/null
+++ b/drivers/rtc/rtc-ds1302.c
@@ -0,0 +1,262 @@
+/*
+ * Dallas DS1302 RTC Support
+ *
+ * Copyright (C) 2002 David McCullough
+ * Copyright (C) 2003 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2. See the file "COPYING" in the main directory of
+ * this archive for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/bcd.h>
+#include <asm/rtc.h>
+
+#define DRV_NAME "rtc-ds1302"
+#define DRV_VERSION "0.1.0"
+
+#define RTC_CMD_READ 0x81 /* Read command */
+#define RTC_CMD_WRITE 0x80 /* Write command */
+
+#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */
+#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */
+#define RTC_ADDR_YEAR 0x06 /* Address of year register */
+#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
+#define RTC_ADDR_MON 0x04 /* Address of month register */
+#define RTC_ADDR_DATE 0x03 /* Address of day of month register */
+#define RTC_ADDR_HOUR 0x02 /* Address of hour register */
+#define RTC_ADDR_MIN 0x01 /* Address of minute register */
+#define RTC_ADDR_SEC 0x00 /* Address of second register */
+
+#define RTC_RESET 0x1000
+#define RTC_IODATA 0x0800
+#define RTC_SCLK 0x0400
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/snapgear.h>
+#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
+#define get_dp() SECUREEDGE_READ_IOPORT()
+#else
+#error "Add support for your platform"
+#endif
+
+struct ds1302_rtc {
+ struct rtc_device *rtc_dev;
+ spinlock_t lock;
+};
+
+static void ds1302_sendbits(unsigned int val)
+{
+ int i;
+
+ for (i = 8; (i); i--, val >>= 1) {
+ set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
+ RTC_IODATA : 0));
+ set_dp(get_dp() | RTC_SCLK); /* clock high */
+ set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+ }
+}
+
+static unsigned int ds1302_recvbits(void)
+{
+ unsigned int val;
+ int i;
+
+ for (i = 0, val = 0; (i < 8); i++) {
+ val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
+ set_dp(get_dp() | RTC_SCLK); /* clock high */
+ set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+ }
+
+ return val;
+}
+
+static unsigned int ds1302_readbyte(unsigned int addr)
+{
+ unsigned int val;
+
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+ set_dp(get_dp() | RTC_RESET);
+ ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
+ val = ds1302_recvbits();
+ set_dp(get_dp() & ~RTC_RESET);
+
+ return val;
+}
+
+static void ds1302_writebyte(unsigned int addr, unsigned int val)
+{
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+ set_dp(get_dp() | RTC_RESET);
+ ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+ ds1302_sendbits(val);
+ set_dp(get_dp() & ~RTC_RESET);
+}
+
+static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+ spin_lock_irq(&rtc->lock);
+
+ tm->tm_sec = BCD2BIN(ds1302_readbyte(RTC_ADDR_SEC));
+ tm->tm_min = BCD2BIN(ds1302_readbyte(RTC_ADDR_MIN));
+ tm->tm_hour = BCD2BIN(ds1302_readbyte(RTC_ADDR_HOUR));
+ tm->tm_wday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DAY));
+ tm->tm_mday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DATE));
+ tm->tm_mon = BCD2BIN(ds1302_readbyte(RTC_ADDR_MON)) - 1;
+ tm->tm_year = BCD2BIN(ds1302_readbyte(RTC_ADDR_YEAR));
+
+ if (tm->tm_year < 70)
+ tm->tm_year += 100;
+
+ spin_unlock_irq(&rtc->lock);
+
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
+
+ if (rtc_valid_tm(tm) < 0)
+ dev_err(dev, "invalid date\n");
+
+ return 0;
+}
+
+static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+ spin_lock_irq(&rtc->lock);
+
+ /* Stop RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
+
+ ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec));
+ ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min));
+ ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour));
+ ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday));
+ ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday));
+ ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1));
+ ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year % 100));
+
+ /* Start RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+#ifdef RTC_SET_CHARGE
+ case RTC_SET_CHARGE:
+ {
+ struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+ int tcs_val;
+
+ if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ spin_lock_irq(&rtc->lock);
+ ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+ }
+#endif
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static struct rtc_class_ops ds1302_rtc_ops = {
+ .read_time = ds1302_rtc_read_time,
+ .set_time = ds1302_rtc_set_time,
+ .ioctl = ds1302_rtc_ioctl,
+};
+
+static int __devinit ds1302_rtc_probe(struct platform_device *pdev)
+{
+ struct ds1302_rtc *rtc;
+ int ret;
+
+ /* Reset */
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+ /* Write a magic value to the DS1302 RAM, and see if it sticks. */
+ ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
+ if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+ return -ENODEV;
+
+ rtc = kzalloc(sizeof(struct ds1302_rtc), GFP_KERNEL);
+ if (unlikely(!rtc))
+ return -ENOMEM;
+
+ spin_lock_init(&rtc->lock);
+ rtc->rtc_dev = rtc_device_register("ds1302", &pdev->dev,
+ &ds1302_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc_dev)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ return 0;
+out:
+ kfree(rtc);
+ return ret;
+}
+
+static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
+{
+ struct ds1302_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (likely(rtc->rtc_dev))
+ rtc_device_unregister(rtc->rtc_dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver ds1302_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1302_rtc_probe,
+ .remove = __devexit_p(ds1302_rtc_remove),
+};
+
+static int __init ds1302_rtc_init(void)
+{
+ return platform_driver_register(&ds1302_platform_driver);
+}
+
+static void __exit ds1302_rtc_exit(void)
+{
+ platform_driver_unregister(&ds1302_platform_driver);
+}
+
+module_init(ds1302_rtc_init);
+module_exit(ds1302_rtc_exit);
+
+MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Paul Mundt, David McCullough");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bc1c7fe..f389a28 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -256,7 +256,7 @@
struct i2c_msg msg[2];
int result;
- client = to_i2c_client(container_of(kobj, struct device, kobj));
+ client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);
if (unlikely(off >= NVRAM_SIZE))
@@ -294,7 +294,7 @@
u8 buffer[NVRAM_SIZE + 1];
int ret;
- client = to_i2c_client(container_of(kobj, struct device, kobj));
+ client = kobj_to_i2c_client(kobj);
if (unlikely(off >= NVRAM_SIZE))
return -EFBIG;
@@ -412,11 +412,6 @@
*/
tmp = ds1307->regs[DS1307_REG_SECS];
switch (ds1307->type) {
- case ds_1340:
- /* FIXME read register with DS1340_BIT_OSF, use that to
- * trigger the "set time" warning (*after* restarting the
- * oscillator!) instead of this weaker ds1307/m41t00 test.
- */
case ds_1307:
case m41t00:
/* clock halted? turn it on, so clock can tick. */
@@ -440,6 +435,24 @@
goto read_rtc;
}
break;
+ case ds_1340:
+ /* clock halted? turn it on, so clock can tick. */
+ if (tmp & DS1340_BIT_nEOSC)
+ i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+ tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
+ if (tmp < 0) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ /* oscillator fault? clear flag, and warn */
+ if (tmp & DS1340_BIT_OSF) {
+ i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
+ dev_warn(&client->dev, "SET TIME!\n");
+ }
+ break;
case ds_1337:
case ds_1339:
break;
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
new file mode 100644
index 0000000..d74b808
--- /dev/null
+++ b/drivers/rtc/rtc-ds1511.c
@@ -0,0 +1,656 @@
+/*
+ * An rtc driver for the Dallas DS1511
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Real time clock driver for the Dallas 1511 chip, which also
+ * contains a watchdog timer. There is a tiny amount of code that
+ * platform code could use to mess with the watchdog device a little
+ * bit, but not a full watchdog driver.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.6"
+
+enum ds1511reg {
+ DS1511_SEC = 0x0,
+ DS1511_MIN = 0x1,
+ DS1511_HOUR = 0x2,
+ DS1511_DOW = 0x3,
+ DS1511_DOM = 0x4,
+ DS1511_MONTH = 0x5,
+ DS1511_YEAR = 0x6,
+ DS1511_CENTURY = 0x7,
+ DS1511_AM1_SEC = 0x8,
+ DS1511_AM2_MIN = 0x9,
+ DS1511_AM3_HOUR = 0xa,
+ DS1511_AM4_DATE = 0xb,
+ DS1511_WD_MSEC = 0xc,
+ DS1511_WD_SEC = 0xd,
+ DS1511_CONTROL_A = 0xe,
+ DS1511_CONTROL_B = 0xf,
+ DS1511_RAMADDR_LSB = 0x10,
+ DS1511_RAMDATA = 0x13
+};
+
+#define DS1511_BLF1 0x80
+#define DS1511_BLF2 0x40
+#define DS1511_PRS 0x20
+#define DS1511_PAB 0x10
+#define DS1511_TDF 0x08
+#define DS1511_KSF 0x04
+#define DS1511_WDF 0x02
+#define DS1511_IRQF 0x01
+#define DS1511_TE 0x80
+#define DS1511_CS 0x40
+#define DS1511_BME 0x20
+#define DS1511_TPE 0x10
+#define DS1511_TIE 0x08
+#define DS1511_KIE 0x04
+#define DS1511_WDE 0x02
+#define DS1511_WDS 0x01
+#define DS1511_RAM_MAX 0xff
+
+#define RTC_CMD DS1511_CONTROL_B
+#define RTC_CMD1 DS1511_CONTROL_A
+
+#define RTC_ALARM_SEC DS1511_AM1_SEC
+#define RTC_ALARM_MIN DS1511_AM2_MIN
+#define RTC_ALARM_HOUR DS1511_AM3_HOUR
+#define RTC_ALARM_DATE DS1511_AM4_DATE
+
+#define RTC_SEC DS1511_SEC
+#define RTC_MIN DS1511_MIN
+#define RTC_HOUR DS1511_HOUR
+#define RTC_DOW DS1511_DOW
+#define RTC_DOM DS1511_DOM
+#define RTC_MON DS1511_MONTH
+#define RTC_YEAR DS1511_YEAR
+#define RTC_CENTURY DS1511_CENTURY
+
+#define RTC_TIE DS1511_TIE
+#define RTC_TE DS1511_TE
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr; /* virtual base address */
+ unsigned long baseaddr; /* physical base address */
+ int size; /* amount of memory mapped */
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static DEFINE_SPINLOCK(ds1511_lock);
+
+static __iomem char *ds1511_base;
+static u32 reg_spacing = 1;
+
+ static noinline void
+rtc_write(uint8_t val, uint32_t reg)
+{
+ writeb(val, ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_write_alarm(uint8_t val, enum ds1511reg reg)
+{
+ rtc_write((val | 0x80), reg);
+}
+
+ static noinline uint8_t
+rtc_read(enum ds1511reg reg)
+{
+ return readb(ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_disable_update(void)
+{
+ rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
+}
+
+ static void
+rtc_enable_update(void)
+{
+ rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
+}
+
+/*
+ * #define DS1511_WDOG_RESET_SUPPORT
+ *
+ * Uncomment this if you want to use these routines in
+ * some platform code.
+ */
+#ifdef DS1511_WDOG_RESET_SUPPORT
+/*
+ * just enough code to set the watchdog timer so that it
+ * will reboot the system
+ */
+ void
+ds1511_wdog_set(unsigned long deciseconds)
+{
+ /*
+ * the wdog timer can take 99.99 seconds
+ */
+ deciseconds %= 10000;
+ /*
+ * set the wdog values in the wdog registers
+ */
+ rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC);
+ rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC);
+ /*
+ * set wdog enable and wdog 'steering' bit to issue a reset
+ */
+ rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
+}
+
+ void
+ds1511_wdog_disable(void)
+{
+ /*
+ * clear wdog enable and wdog 'steering' bits
+ */
+ rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
+ /*
+ * clear the wdog counter
+ */
+ rtc_write(0, DS1511_WD_MSEC);
+ rtc_write(0, DS1511_WD_SEC);
+}
+#endif
+
+/*
+ * set the rtc chip's idea of the time.
+ * stupidly, some callers call with year unmolested;
+ * and some call with year = year - 1900. thanks.
+ */
+ int
+ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ u8 mon, day, dow, hrs, min, sec, yrs, cen;
+ unsigned int flags;
+
+ /*
+ * won't have to change this for a while
+ */
+ if (rtc_tm->tm_year < 1900) {
+ rtc_tm->tm_year += 1900;
+ }
+
+ if (rtc_tm->tm_year < 1970) {
+ return -EINVAL;
+ }
+ yrs = rtc_tm->tm_year % 100;
+ cen = rtc_tm->tm_year / 100;
+ mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
+ day = rtc_tm->tm_mday;
+ dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
+ hrs = rtc_tm->tm_hour;
+ min = rtc_tm->tm_min;
+ sec = rtc_tm->tm_sec;
+
+ if ((mon > 12) || (day == 0)) {
+ return -EINVAL;
+ }
+
+ if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) {
+ return -EINVAL;
+ }
+
+ if ((hrs >= 24) || (min >= 60) || (sec >= 60)) {
+ return -EINVAL;
+ }
+
+ /*
+ * each register is a different number of valid bits
+ */
+ sec = BIN2BCD(sec) & 0x7f;
+ min = BIN2BCD(min) & 0x7f;
+ hrs = BIN2BCD(hrs) & 0x3f;
+ day = BIN2BCD(day) & 0x3f;
+ mon = BIN2BCD(mon) & 0x1f;
+ yrs = BIN2BCD(yrs) & 0xff;
+ cen = BIN2BCD(cen) & 0xff;
+
+ spin_lock_irqsave(&ds1511_lock, flags);
+ rtc_disable_update();
+ rtc_write(cen, RTC_CENTURY);
+ rtc_write(yrs, RTC_YEAR);
+ rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
+ rtc_write(day, RTC_DOM);
+ rtc_write(hrs, RTC_HOUR);
+ rtc_write(min, RTC_MIN);
+ rtc_write(sec, RTC_SEC);
+ rtc_write(dow, RTC_DOW);
+ rtc_enable_update();
+ spin_unlock_irqrestore(&ds1511_lock, flags);
+
+ return 0;
+}
+
+ int
+ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ unsigned int century;
+ unsigned int flags;
+
+ spin_lock_irqsave(&ds1511_lock, flags);
+ rtc_disable_update();
+
+ rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
+ rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
+ rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
+ rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
+ rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
+ rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
+ rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
+ century = rtc_read(RTC_CENTURY);
+
+ rtc_enable_update();
+ spin_unlock_irqrestore(&ds1511_lock, flags);
+
+ rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
+ rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
+ rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
+ rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
+ rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday);
+ rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
+ rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
+ century = BCD2BIN(century) * 100;
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ century += rtc_tm->tm_year;
+ rtc_tm->tm_year = century - 1900;
+
+ rtc_tm->tm_mon--;
+
+ if (rtc_valid_tm(rtc_tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, rtc_tm);
+ }
+ return 0;
+}
+
+/*
+ * write the alarm register settings
+ *
+ * we only have the use to interrupt every second, otherwise
+ * known as the update interrupt, or the interrupt if the whole
+ * date/hours/mins/secs matches. the ds1511 has many more
+ * permutations, but the kernel doesn't.
+ */
+ static void
+ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+ rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f,
+ RTC_ALARM_DATE);
+ rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f,
+ RTC_ALARM_HOUR);
+ rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_min) & 0x7f,
+ RTC_ALARM_MIN);
+ rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f,
+ RTC_ALARM_SEC);
+ rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
+ rtc_read(RTC_CMD1); /* clear interrupts */
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+ static int
+ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0) {
+ return -EINVAL;
+ }
+ pdata->alrm_mday = alrm->time.tm_mday;
+ pdata->alrm_hour = alrm->time.tm_hour;
+ pdata->alrm_min = alrm->time.tm_min;
+ pdata->alrm_sec = alrm->time.tm_sec;
+ if (alrm->enabled) {
+ pdata->irqen |= RTC_AF;
+ }
+ ds1511_rtc_update_alarm(pdata);
+ return 0;
+}
+
+ static int
+ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0) {
+ return -EINVAL;
+ }
+ alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+ alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+ alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+ alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+ alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+ return 0;
+}
+
+ static irqreturn_t
+ds1511_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ unsigned long events = RTC_IRQF;
+
+ /*
+ * read and clear interrupt
+ */
+ if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) {
+ return IRQ_NONE;
+ }
+ if (rtc_read(RTC_ALARM_SEC) & 0x80) {
+ events |= RTC_UF;
+ } else {
+ events |= RTC_AF;
+ }
+ rtc_update_irq(pdata->rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+ static void
+ds1511_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq >= 0) {
+ pdata->irqen = 0;
+ ds1511_rtc_update_alarm(pdata);
+ }
+}
+
+ static int
+ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0) {
+ return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+ }
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ pdata->irqen &= ~RTC_AF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ case RTC_AIE_ON:
+ pdata->irqen |= RTC_AF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_OFF:
+ pdata->irqen &= ~RTC_UF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_ON:
+ pdata->irqen |= RTC_UF;
+ ds1511_rtc_update_alarm(pdata);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops ds1511_rtc_ops = {
+ .read_time = ds1511_rtc_read_time,
+ .set_time = ds1511_rtc_set_time,
+ .read_alarm = ds1511_rtc_read_alarm,
+ .set_alarm = ds1511_rtc_set_alarm,
+ .release = ds1511_rtc_release,
+ .ioctl = ds1511_rtc_ioctl,
+};
+
+ static ssize_t
+ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
+ char *buf, loff_t pos, size_t size)
+{
+ ssize_t count;
+
+ /*
+ * if count is more than one, turn on "burst" mode
+ * turn it off when you're done
+ */
+ if (size > 1) {
+ rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+ }
+ if (pos > DS1511_RAM_MAX) {
+ pos = DS1511_RAM_MAX;
+ }
+ if (size + pos > DS1511_RAM_MAX + 1) {
+ size = DS1511_RAM_MAX - pos + 1;
+ }
+ rtc_write(pos, DS1511_RAMADDR_LSB);
+ for (count = 0; size > 0; count++, size--) {
+ *buf++ = rtc_read(DS1511_RAMDATA);
+ }
+ if (count > 1) {
+ rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+ }
+ return count;
+}
+
+ static ssize_t
+ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
+{
+ ssize_t count;
+
+ /*
+ * if count is more than one, turn on "burst" mode
+ * turn it off when you're done
+ */
+ if (size > 1) {
+ rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+ }
+ if (pos > DS1511_RAM_MAX) {
+ pos = DS1511_RAM_MAX;
+ }
+ if (size + pos > DS1511_RAM_MAX + 1) {
+ size = DS1511_RAM_MAX - pos + 1;
+ }
+ rtc_write(pos, DS1511_RAMADDR_LSB);
+ for (count = 0; size > 0; count++, size--) {
+ rtc_write(*buf++, DS1511_RAMDATA);
+ }
+ if (count > 1) {
+ rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+ }
+ return count;
+}
+
+static struct bin_attribute ds1511_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = DS1511_RAM_MAX,
+ .read = ds1511_nvram_read,
+ .write = ds1511_nvram_write,
+};
+
+ static int __devinit
+ds1511_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ struct rtc_plat_data *pdata = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ return -ENODEV;
+ }
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ return -ENOMEM;
+ }
+ pdata->irq = -1;
+ pdata->size = res->end - res->start + 1;
+ if (!request_mem_region(res->start, pdata->size, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ pdata->size = pdata->size;
+ ds1511_base = ioremap(pdata->baseaddr, pdata->size);
+ if (!ds1511_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ds1511_base;
+ pdata->irq = platform_get_irq(pdev, 0);
+
+ /*
+ * turn on the clock and the crystal, etc.
+ */
+ rtc_write(0, RTC_CMD);
+ rtc_write(0, RTC_CMD1);
+ /*
+ * clear the wdog counter
+ */
+ rtc_write(0, DS1511_WD_MSEC);
+ rtc_write(0, DS1511_WD_SEC);
+ /*
+ * start the clock
+ */
+ rtc_enable_update();
+
+ /*
+ * check for a dying bat-tree
+ */
+ if (rtc_read(RTC_CMD1) & DS1511_BLF1) {
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+ }
+
+ /*
+ * if the platform has an interrupt in mind for this device,
+ * then by all means, set it
+ */
+ if (pdata->irq >= 0) {
+ rtc_read(RTC_CMD1);
+ if (request_irq(pdata->irq, ds1511_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ platform_set_drvdata(pdev, pdata);
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+ if (ret) {
+ goto out;
+ }
+ return 0;
+ out:
+ if (pdata->rtc) {
+ rtc_device_unregister(pdata->rtc);
+ }
+ if (pdata->irq >= 0) {
+ free_irq(pdata->irq, pdev);
+ }
+ if (ds1511_base) {
+ iounmap(ds1511_base);
+ ds1511_base = NULL;
+ }
+ if (pdata->baseaddr) {
+ release_mem_region(pdata->baseaddr, pdata->size);
+ }
+
+ kfree(pdata);
+ return ret;
+}
+
+ static int __devexit
+ds1511_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ pdata->rtc = NULL;
+ if (pdata->irq >= 0) {
+ /*
+ * disable the alarm interrupt
+ */
+ rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
+ rtc_read(RTC_CMD1);
+ free_irq(pdata->irq, pdev);
+ }
+ iounmap(pdata->ioaddr);
+ ds1511_base = NULL;
+ release_mem_region(pdata->baseaddr, pdata->size);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver ds1511_rtc_driver = {
+ .probe = ds1511_rtc_probe,
+ .remove = __devexit_p(ds1511_rtc_remove),
+ .driver = {
+ .name = "ds1511",
+ .owner = THIS_MODULE,
+ },
+};
+
+ static int __init
+ds1511_rtc_init(void)
+{
+ return platform_driver_register(&ds1511_rtc_driver);
+}
+
+ static void __exit
+ds1511_rtc_exit(void)
+{
+ return platform_driver_unregister(&ds1511_rtc_driver);
+}
+
+module_init(ds1511_rtc_init);
+module_exit(ds1511_rtc_exit);
+
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index c973ba9..8b39970 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -163,27 +163,17 @@
static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
{
- unsigned char addr[1];
- struct i2c_msg msgs[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = addr,
- }, {
- .addr = client->addr,
- .flags = I2C_M_NOSTART,
- .len = mem->nr,
- .buf = mem->data,
- }
- };
+ unsigned char buf[9];
+ int ret;
- if (mem->loc < 8)
+ if (mem->loc < 8 || mem->nr > 8)
return -EINVAL;
- addr[0] = mem->loc;
+ buf[0] = mem->loc;
+ memcpy(buf + 1, mem->data, mem->nr);
- return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+ ret = i2c_master_send(client, buf, mem->nr + 1);
+ return ret == mem->nr + 1 ? 0 : -EIO;
}
static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
new file mode 100644
index 0000000..a64626a
--- /dev/null
+++ b/drivers/rtc/rtc-r9701.c
@@ -0,0 +1,178 @@
+/*
+ * Driver for Epson RTC-9701JE
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on rtc-max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#define RSECCNT 0x00 /* Second Counter */
+#define RMINCNT 0x01 /* Minute Counter */
+#define RHRCNT 0x02 /* Hour Counter */
+#define RWKCNT 0x03 /* Week Counter */
+#define RDAYCNT 0x04 /* Day Counter */
+#define RMONCNT 0x05 /* Month Counter */
+#define RYRCNT 0x06 /* Year Counter */
+#define R100CNT 0x07 /* Y100 Counter */
+#define RMINAR 0x08 /* Minute Alarm */
+#define RHRAR 0x09 /* Hour Alarm */
+#define RWKAR 0x0a /* Week/Day Alarm */
+#define RTIMCNT 0x0c /* Interval Timer */
+#define REXT 0x0d /* Extension Register */
+#define RFLAG 0x0e /* RTC Flag Register */
+#define RCR 0x0f /* RTC Control Register */
+
+static int write_reg(struct device *dev, int address, unsigned char data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[2];
+
+ buf[0] = address & 0x7f;
+ buf[1] = data;
+
+ return spi_write(spi, buf, ARRAY_SIZE(buf));
+}
+
+static int read_regs(struct device *dev, unsigned char *regs, int no_regs)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u8 txbuf[1], rxbuf[1];
+ int k, ret;
+
+ ret = 0;
+
+ for (k = 0; ret == 0 && k < no_regs; k++) {
+ txbuf[0] = 0x80 | regs[k];
+ ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+ regs[k] = rxbuf[0];
+ }
+
+ return ret;
+}
+
+static int r9701_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+ unsigned long time;
+ int ret;
+ unsigned char buf[] = { RSECCNT, RMINCNT, RHRCNT,
+ RDAYCNT, RMONCNT, RYRCNT };
+
+ ret = read_regs(dev, buf, ARRAY_SIZE(buf));
+ if (ret)
+ return ret;
+
+ memset(dt, 0, sizeof(*dt));
+
+ dt->tm_sec = BCD2BIN(buf[0]); /* RSECCNT */
+ dt->tm_min = BCD2BIN(buf[1]); /* RMINCNT */
+ dt->tm_hour = BCD2BIN(buf[2]); /* RHRCNT */
+
+ dt->tm_mday = BCD2BIN(buf[3]); /* RDAYCNT */
+ dt->tm_mon = BCD2BIN(buf[4]) - 1; /* RMONCNT */
+ dt->tm_year = BCD2BIN(buf[5]) + 100; /* RYRCNT */
+
+ /* the rtc device may contain illegal values on power up
+ * according to the data sheet. make sure they are valid.
+ */
+
+ return rtc_valid_tm(dt);
+}
+
+static int r9701_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+ int ret, year;
+
+ year = dt->tm_year + 1900;
+ if (year >= 2100 || year < 2000)
+ return -EINVAL;
+
+ ret = write_reg(dev, RHRCNT, BIN2BCD(dt->tm_hour));
+ ret = ret ? ret : write_reg(dev, RMINCNT, BIN2BCD(dt->tm_min));
+ ret = ret ? ret : write_reg(dev, RSECCNT, BIN2BCD(dt->tm_sec));
+ ret = ret ? ret : write_reg(dev, RDAYCNT, BIN2BCD(dt->tm_mday));
+ ret = ret ? ret : write_reg(dev, RMONCNT, BIN2BCD(dt->tm_mon + 1));
+ ret = ret ? ret : write_reg(dev, RYRCNT, BIN2BCD(dt->tm_year - 100));
+ ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday);
+
+ return ret;
+}
+
+static const struct rtc_class_ops r9701_rtc_ops = {
+ .read_time = r9701_get_datetime,
+ .set_time = r9701_set_datetime,
+};
+
+static int __devinit r9701_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char tmp;
+ int res;
+
+ rtc = rtc_device_register("r9701",
+ &spi->dev, &r9701_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ dev_set_drvdata(&spi->dev, rtc);
+
+ tmp = R100CNT;
+ res = read_regs(&spi->dev, &tmp, 1);
+ if (res || tmp != 0x20) {
+ rtc_device_unregister(rtc);
+ return res;
+ }
+
+ return 0;
+}
+
+static int __devexit r9701_remove(struct spi_device *spi)
+{
+ struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
+
+ rtc_device_unregister(rtc);
+ return 0;
+}
+
+static struct spi_driver r9701_driver = {
+ .driver = {
+ .name = "rtc-r9701",
+ .owner = THIS_MODULE,
+ },
+ .probe = r9701_probe,
+ .remove = __devexit_p(r9701_remove),
+};
+
+static __init int r9701_init(void)
+{
+ return spi_register_driver(&r9701_driver);
+}
+module_init(r9701_init);
+
+static __exit void r9701_exit(void)
+{
+ spi_unregister_driver(&r9701_driver);
+}
+module_exit(r9701_exit);
+
+MODULE_DESCRIPTION("r9701 spi RTC driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e2041b4..86766f1 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -20,6 +20,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/clk.h>
+#include <linux/log2.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
@@ -309,9 +310,7 @@
break;
case RTC_IRQP_SET:
- /* check for power of 2 */
-
- if ((arg & (arg-1)) != 0 || arg < 1) {
+ if (!is_power_of_2(arg)) {
ret = -EINVAL;
goto exit;
}
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 2eb3852..ee253cc 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -357,23 +357,15 @@
#ifdef CONFIG_PM
static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (pdev->dev.power.power_state.event != state.event) {
- if (state.event == PM_EVENT_SUSPEND &&
- device_may_wakeup(&pdev->dev))
- enable_irq_wake(IRQ_RTCAlrm);
-
- pdev->dev.power.power_state = state;
- }
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(IRQ_RTCAlrm);
return 0;
}
static int sa1100_rtc_resume(struct platform_device *pdev)
{
- if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
- if (device_may_wakeup(&pdev->dev))
- disable_irq_wake(IRQ_RTCAlrm);
- pdev->dev.power.power_state = PMSG_ON;
- }
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(IRQ_RTCAlrm);
return 0;
}
#else
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 2ae0e83..4d27ccc 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -17,6 +17,13 @@
/* device attributes */
+/*
+ * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's
+ * ideally UTC. However, PCs that also boot to MS-Windows normally use
+ * the local time and change to match daylight savings time. That affects
+ * attributes including date, time, since_epoch, and wakealarm.
+ */
+
static ssize_t
rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -113,13 +120,13 @@
unsigned long alarm;
struct rtc_wkalrm alm;
- /* Don't show disabled alarms; but the RTC could leave the
- * alarm enabled after it's already triggered. Alarms are
- * conceptually one-shot, even though some common hardware
- * (PCs) doesn't actually work that way.
+ /* Don't show disabled alarms. For uniformity, RTC alarms are
+ * conceptually one-shot, even though some common RTCs (on PCs)
+ * don't actually work that way.
*
- * REVISIT maybe we should require RTC implementations to
- * disable the RTC alarm after it triggers, for uniformity.
+ * NOTE: RTC implementations where the alarm doesn't match an
+ * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
+ * alarms after they trigger, to ensure one-shot semantics.
*/
retval = rtc_read_alarm(to_rtc_device(dev), &alm);
if (retval == 0 && alm.enabled) {
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index d640427..d984e0f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1057,12 +1057,11 @@
if (device->features & DASD_FEATURE_ERPLOG) {
dasd_log_sense(cqr, irb);
}
- /* If we have no sense data, or we just don't want complex ERP
- * for this request, but if we have retries left, then just
- * reset this request and retry it in the fastpath
+ /*
+ * If we don't want complex ERP for this request, then just
+ * reset this and retry it in the fastpath
*/
- if (!(cqr->irb.esw.esw0.erw.cons &&
- test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
+ if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
cqr->retries > 0) {
DEV_MESSAGE(KERN_DEBUG, device,
"default ERP in fastpath (%i retries left)",
@@ -1707,7 +1706,7 @@
req = (struct request *) cqr->callback_data;
dasd_profile_end(cqr->block, cqr, req);
- status = cqr->memdev->discipline->free_cp(cqr, req);
+ status = cqr->block->base->discipline->free_cp(cqr, req);
if (status <= 0)
error = status ? status : -EIO;
dasd_end_request(req, error);
@@ -1742,12 +1741,8 @@
/* Process requests that may be recovered */
if (cqr->status == DASD_CQR_NEED_ERP) {
- if (cqr->irb.esw.esw0.erw.cons &&
- test_bit(DASD_CQR_FLAGS_USE_ERP,
- &cqr->flags)) {
- erp_fn = base->discipline->erp_action(cqr);
- erp_fn(cqr);
- }
+ erp_fn = base->discipline->erp_action(cqr);
+ erp_fn(cqr);
goto restart;
}
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index c361ab6..f69714a 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -164,7 +164,7 @@
/* reset status to submit the request again... */
erp->status = DASD_CQR_FILLED;
- erp->retries = 1;
+ erp->retries = 10;
} else {
DEV_MESSAGE(KERN_ERR, device,
"No alternate channel path left (lpum=%x / "
@@ -301,8 +301,7 @@
erp->function = dasd_3990_erp_action_4;
} else {
-
- if (sense[25] == 0x1D) { /* state change pending */
+ if (sense && (sense[25] == 0x1D)) { /* state change pending */
DEV_MESSAGE(KERN_INFO, device,
"waiting for state change pending "
@@ -311,7 +310,7 @@
dasd_3990_erp_block_queue(erp, 30*HZ);
- } else if (sense[25] == 0x1E) { /* busy */
+ } else if (sense && (sense[25] == 0x1E)) { /* busy */
DEV_MESSAGE(KERN_INFO, device,
"busy - redriving request later, "
"%d retries left",
@@ -2120,6 +2119,34 @@
*/
/*
+ * DASD_3990_ERP_CONTROL_CHECK
+ *
+ * DESCRIPTION
+ * Does a generic inspection if a control check occured and sets up
+ * the related error recovery procedure
+ *
+ * PARAMETER
+ * erp pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ * erp_filled pointer to the erp
+ */
+
+static struct dasd_ccw_req *
+dasd_3990_erp_control_check(struct dasd_ccw_req *erp)
+{
+ struct dasd_device *device = erp->startdev;
+
+ if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK
+ | SCHN_STAT_CHN_CTRL_CHK)) {
+ DEV_MESSAGE(KERN_DEBUG, device, "%s",
+ "channel or interface control check");
+ erp = dasd_3990_erp_action_4(erp, NULL);
+ }
+ return erp;
+}
+
+/*
* DASD_3990_ERP_INSPECT
*
* DESCRIPTION
@@ -2145,8 +2172,11 @@
if (erp_new)
return erp_new;
+ /* check if no concurrent sens is available */
+ if (!erp->refers->irb.esw.esw0.erw.cons)
+ erp_new = dasd_3990_erp_control_check(erp);
/* distinguish between 24 and 32 byte sense data */
- if (sense[27] & DASD_SENSE_BIT_0) {
+ else if (sense[27] & DASD_SENSE_BIT_0) {
/* inspect the 24 byte sense data */
erp_new = dasd_3990_erp_inspect_24(erp, sense);
@@ -2285,6 +2315,17 @@
// return 0; /* CCW doesn't match */
}
+ if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons)
+ return 0;
+
+ if ((cqr1->irb.esw.esw0.erw.cons == 0) &&
+ (cqr2->irb.esw.esw0.erw.cons == 0)) {
+ if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
+ SCHN_STAT_CHN_CTRL_CHK)) ==
+ (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
+ SCHN_STAT_CHN_CTRL_CHK)))
+ return 1; /* match with ifcc*/
+ }
/* check sense data; byte 0-2,25,27 */
if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) &&
(cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) &&
@@ -2560,17 +2601,6 @@
return cqr;
}
- /* check if sense data are available */
- if (!cqr->irb.ecw) {
- DEV_MESSAGE(KERN_DEBUG, device,
- "ERP called witout sense data avail ..."
- "request %p - NO ERP possible", cqr);
-
- cqr->status = DASD_CQR_FAILED;
-
- return cqr;
-
- }
/* check if error happened before */
erp = dasd_3990_erp_in_erp(cqr);
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 7779bfc..3faf053 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -415,6 +415,8 @@
dev_info->gd->queue = dev_info->dcssblk_queue;
dev_info->gd->private_data = dev_info;
dev_info->gd->driverfs_dev = &dev_info->dev;
+ blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
+ blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
/*
* load the segment
*/
@@ -472,9 +474,6 @@
if (rc)
goto unregister_dev;
- blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
- blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
-
add_disk(dev_info->gd);
switch (dev_info->segment_type) {
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index e3b3d39..2e616e3 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -332,7 +332,7 @@
if (sclp_ttybuf == NULL) {
while (list_empty(&sclp_tty_pages)) {
spin_unlock_irqrestore(&sclp_tty_lock, flags);
- if (in_interrupt())
+ if (in_atomic())
sclp_sync_wait();
else
wait_event(sclp_tty_waitq,
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 40cd21b..6807162 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -400,7 +400,7 @@
while (list_empty(&sclp_vt220_empty)) {
spin_unlock_irqrestore(&sclp_vt220_lock,
flags);
- if (in_interrupt())
+ if (in_atomic())
sclp_sync_wait();
else
wait_event(sclp_vt220_waitq,
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 3964056..03914fa 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -391,12 +391,24 @@
return 0;
}
+static void ccwgroup_shutdown(struct device *dev)
+{
+ struct ccwgroup_device *gdev;
+ struct ccwgroup_driver *gdrv;
+
+ gdev = to_ccwgroupdev(dev);
+ gdrv = to_ccwgroupdrv(dev->driver);
+ if (gdrv && gdrv->shutdown)
+ gdrv->shutdown(gdev);
+}
+
static struct bus_type ccwgroup_bus_type = {
.name = "ccwgroup",
.match = ccwgroup_bus_match,
.uevent = ccwgroup_uevent,
.probe = ccwgroup_probe,
.remove = ccwgroup_remove,
+ .shutdown = ccwgroup_shutdown,
};
/**
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index e7ba16a..007aaeb 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -26,6 +26,25 @@
static void *sei_page;
+static int chsc_error_from_response(int response)
+{
+ switch (response) {
+ case 0x0001:
+ return 0;
+ case 0x0002:
+ case 0x0003:
+ case 0x0006:
+ case 0x0007:
+ case 0x0008:
+ case 0x000a:
+ return -EINVAL;
+ case 0x0004:
+ return -EOPNOTSUPP;
+ default:
+ return -EIO;
+ }
+}
+
struct chsc_ssd_area {
struct chsc_header request;
u16 :10;
@@ -75,11 +94,11 @@
ret = (ccode == 3) ? -ENODEV : -EBUSY;
goto out_free;
}
- if (ssd_area->response.code != 0x0001) {
+ ret = chsc_error_from_response(ssd_area->response.code);
+ if (ret != 0) {
CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
schid.ssid, schid.sch_no,
ssd_area->response.code);
- ret = -EIO;
goto out_free;
}
if (!ssd_area->sch_valid) {
@@ -717,36 +736,15 @@
return (ccode == 3) ? -ENODEV : -EBUSY;
switch (secm_area->response.code) {
- case 0x0001: /* Success. */
- ret = 0;
- break;
- case 0x0003: /* Invalid block. */
- case 0x0007: /* Invalid format. */
- case 0x0008: /* Other invalid block. */
- CIO_CRW_EVENT(2, "Error in chsc request block!\n");
+ case 0x0102:
+ case 0x0103:
ret = -EINVAL;
- break;
- case 0x0004: /* Command not provided in model. */
- CIO_CRW_EVENT(2, "Model does not provide secm\n");
- ret = -EOPNOTSUPP;
- break;
- case 0x0102: /* cub adresses incorrect */
- CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n");
- ret = -EINVAL;
- break;
- case 0x0103: /* key error */
- CIO_CRW_EVENT(2, "Access key error in secm\n");
- ret = -EINVAL;
- break;
- case 0x0105: /* error while starting */
- CIO_CRW_EVENT(2, "Error while starting channel measurement\n");
- ret = -EIO;
- break;
default:
- CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
- secm_area->response.code);
- ret = -EIO;
+ ret = chsc_error_from_response(secm_area->response.code);
}
+ if (ret != 0)
+ CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
+ secm_area->response.code);
return ret;
}
@@ -827,27 +825,14 @@
goto out;
}
- switch (scpd_area->response.code) {
- case 0x0001: /* Success. */
+ ret = chsc_error_from_response(scpd_area->response.code);
+ if (ret == 0)
+ /* Success. */
memcpy(desc, &scpd_area->desc,
sizeof(struct channel_path_desc));
- ret = 0;
- break;
- case 0x0003: /* Invalid block. */
- case 0x0007: /* Invalid format. */
- case 0x0008: /* Other invalid block. */
- CIO_CRW_EVENT(2, "Error in chsc request block!\n");
- ret = -EINVAL;
- break;
- case 0x0004: /* Command not provided in model. */
- CIO_CRW_EVENT(2, "Model does not provide scpd\n");
- ret = -EOPNOTSUPP;
- break;
- default:
- CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+ else
+ CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
scpd_area->response.code);
- ret = -EIO;
- }
out:
free_page((unsigned long)scpd_area);
return ret;
@@ -923,8 +908,9 @@
goto out;
}
- switch (scmc_area->response.code) {
- case 0x0001: /* Success. */
+ ret = chsc_error_from_response(scmc_area->response.code);
+ if (ret == 0) {
+ /* Success. */
if (!scmc_area->not_valid) {
chp->cmg = scmc_area->cmg;
chp->shared = scmc_area->shared;
@@ -935,22 +921,9 @@
chp->cmg = -1;
chp->shared = -1;
}
- ret = 0;
- break;
- case 0x0003: /* Invalid block. */
- case 0x0007: /* Invalid format. */
- case 0x0008: /* Invalid bit combination. */
- CIO_CRW_EVENT(2, "Error in chsc request block!\n");
- ret = -EINVAL;
- break;
- case 0x0004: /* Command not provided. */
- CIO_CRW_EVENT(2, "Model does not provide scmc\n");
- ret = -EOPNOTSUPP;
- break;
- default:
- CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+ } else {
+ CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
scmc_area->response.code);
- ret = -EIO;
}
out:
free_page((unsigned long)scmc_area);
@@ -1002,21 +975,17 @@
ret = (ret == 3) ? -ENODEV : -EBUSY;
goto out;
}
+
switch (sda_area->response.code) {
- case 0x0001: /* everything ok */
- ret = 0;
- break;
- case 0x0003: /* invalid request block */
- case 0x0007:
- ret = -EINVAL;
- break;
- case 0x0004: /* command not provided */
- case 0x0101: /* facility not provided */
+ case 0x0101:
ret = -EOPNOTSUPP;
break;
- default: /* something went wrong */
- ret = -EIO;
+ default:
+ ret = chsc_error_from_response(sda_area->response.code);
}
+ if (ret != 0)
+ CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
+ operation_code, sda_area->response.code);
out:
free_page((unsigned long)sda_area);
return ret;
@@ -1041,33 +1010,27 @@
} __attribute__ ((packed)) *scsc_area;
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!scsc_area) {
- CIO_MSG_EVENT(0, "Was not able to determine available "
- "CHSCs due to no memory.\n");
+ if (!scsc_area)
return -ENOMEM;
- }
scsc_area->request.length = 0x0010;
scsc_area->request.code = 0x0010;
result = chsc(scsc_area);
if (result) {
- CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "
- "cc=%i.\n", result);
- result = -EIO;
+ result = (result == 3) ? -ENODEV : -EBUSY;
goto exit;
}
- if (scsc_area->response.code != 1) {
- CIO_MSG_EVENT(0, "Was not able to determine "
- "available CHSCs.\n");
- result = -EIO;
- goto exit;
- }
- memcpy(&css_general_characteristics, scsc_area->general_char,
- sizeof(css_general_characteristics));
- memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
- sizeof(css_chsc_characteristics));
+ result = chsc_error_from_response(scsc_area->response.code);
+ if (result == 0) {
+ memcpy(&css_general_characteristics, scsc_area->general_char,
+ sizeof(css_general_characteristics));
+ memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
+ sizeof(css_chsc_characteristics));
+ } else
+ CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
+ scsc_area->response.code);
exit:
free_page ((unsigned long) scsc_area);
return result;
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 918b8b8..dc4d87f 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -26,17 +26,18 @@
#include "ioasm.h"
#include "io_sch.h"
-/*
- * Input :
- * devno - device number
- * ps - pointer to sense ID data area
- * Output : none
+/**
+ * vm_vdev_to_cu_type - Convert vm virtual device into control unit type
+ * for certain devices.
+ * @class: virtual device class
+ * @type: virtual device type
+ *
+ * Returns control unit type if a match was made or %0xffff otherwise.
*/
-static void
-VM_virtual_device_info (__u16 devno, struct senseid *ps)
+static int vm_vdev_to_cu_type(int class, int type)
{
static struct {
- int vrdcvcla, vrdcvtyp, cu_type;
+ int class, type, cu_type;
} vm_devices[] = {
{ 0x08, 0x01, 0x3480 },
{ 0x08, 0x02, 0x3430 },
@@ -68,8 +69,26 @@
{ 0x40, 0xc0, 0x5080 },
{ 0x80, 0x00, 0x3215 },
};
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
+ if (class == vm_devices[i].class && type == vm_devices[i].type)
+ return vm_devices[i].cu_type;
+
+ return 0xffff;
+}
+
+/**
+ * diag_get_dev_info - retrieve device information via DIAG X'210'
+ * @devno: device number
+ * @ps: pointer to sense ID data area
+ *
+ * Returns zero on success, non-zero otherwise.
+ */
+static int diag_get_dev_info(u16 devno, struct senseid *ps)
+{
struct diag210 diag_data;
- int ccode, i;
+ int ccode;
CIO_TRACE_EVENT (4, "VMvdinf");
@@ -79,21 +98,21 @@
};
ccode = diag210 (&diag_data);
- ps->reserved = 0xff;
+ if ((ccode == 0) || (ccode == 2)) {
+ ps->reserved = 0xff;
- /* Special case for bloody osa devices. */
- if (diag_data.vrdcvcla == 0x02 &&
- diag_data.vrdcvtyp == 0x20) {
- ps->cu_type = 0x3088;
- ps->cu_model = 0x60;
- return;
- }
- for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
- if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla &&
- diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) {
- ps->cu_type = vm_devices[i].cu_type;
- return;
+ /* Special case for osa devices. */
+ if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) {
+ ps->cu_type = 0x3088;
+ ps->cu_model = 0x60;
+ return 0;
}
+ ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla,
+ diag_data.vrdcvtyp);
+ if (ps->cu_type != 0xffff)
+ return 0;
+ }
+
CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
"vdev class : %02X, vdev type : %04X \n ... "
"rdev class : %02X, rdev type : %04X, "
@@ -102,6 +121,8 @@
diag_data.vrdcvcla, diag_data.vrdcvtyp,
diag_data.vrdcrccl, diag_data.vrdccrty,
diag_data.vrdccrmd);
+
+ return -ENODEV;
}
/*
@@ -130,6 +151,7 @@
/* Try on every path. */
ret = -ENODEV;
while (cdev->private->imask != 0) {
+ cdev->private->senseid.cu_type = 0xFFFF;
if ((sch->opm & cdev->private->imask) != 0 &&
cdev->private->iretry > 0) {
cdev->private->iretry--;
@@ -153,7 +175,6 @@
int ret;
memset (&cdev->private->senseid, 0, sizeof (struct senseid));
- cdev->private->senseid.cu_type = 0xFFFF;
cdev->private->imask = 0x80;
cdev->private->iretry = 5;
ret = __ccw_device_sense_id_start(cdev);
@@ -173,13 +194,7 @@
sch = to_subchannel(cdev->dev.parent);
irb = &cdev->private->irb;
- /* Did we get a proper answer ? */
- if (cdev->private->senseid.cu_type != 0xFFFF &&
- cdev->private->senseid.reserved == 0xFF) {
- if (irb->scsw.count < sizeof (struct senseid) - 8)
- cdev->private->flags.esid = 1;
- return 0; /* Success */
- }
+
/* Check the error cases. */
if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
/* Retry Sense ID if requested. */
@@ -231,6 +246,15 @@
sch->schid.ssid, sch->schid.sch_no);
return -EACCES;
}
+
+ /* Did we get a proper answer ? */
+ if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
+ cdev->private->senseid.reserved == 0xFF) {
+ if (irb->scsw.count < sizeof(struct senseid) - 8)
+ cdev->private->flags.esid = 1;
+ return 0; /* Success */
+ }
+
/* Hmm, whatever happened, try again. */
CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
"subchannel 0.%x.%04x returns status %02X%02X\n",
@@ -283,20 +307,17 @@
break;
/* fall through. */
default: /* Sense ID failed. Try asking VM. */
- if (MACHINE_IS_VM) {
- VM_virtual_device_info (cdev->private->dev_id.devno,
+ if (MACHINE_IS_VM)
+ ret = diag_get_dev_info(cdev->private->dev_id.devno,
&cdev->private->senseid);
- if (cdev->private->senseid.cu_type != 0xFFFF) {
- /* Got the device information from VM. */
- ccw_device_sense_id_done(cdev, 0);
- return;
- }
- }
- /*
- * If we can't couldn't identify the device type we
- * consider the device "not operational".
- */
- ccw_device_sense_id_done(cdev, -ENODEV);
+ else
+ /*
+ * If we can't couldn't identify the device type we
+ * consider the device "not operational".
+ */
+ ret = -ENODEV;
+
+ ccw_device_sense_id_done(cdev, ret);
break;
}
}
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 19343f9..291ff62 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -422,7 +422,7 @@
/*
* calibrate the delay loop
*/
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
{
s390_adjust_jiffies();
/* Print the good old Bogomips line .. */
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index d85cb73..00a0ba0 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -1,6 +1,6 @@
/* NCR53C9x.c: Defines and structures for the NCR53C9x generic driver.
*
- * Originaly esp.h: Defines and structures for the Sparc ESP
+ * Originally esp.h: Defines and structures for the Sparc ESP
* (Enhanced SCSI Processor) driver under Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 23f27c9..5ac3a3e 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -46,8 +46,7 @@
struct Scsi_Host *instance = cmd->device->host;
/* don't allow DMA if the physical address is bad */
- if (addr & A2091_XFER_MASK ||
- (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+ if (addr & A2091_XFER_MASK)
{
HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index d7255c8..3aeec96 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -54,8 +54,7 @@
* end of a physical memory chunk, then allocate a bounce
* buffer
*/
- if (addr & A3000_XFER_MASK ||
- (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+ if (addr & A3000_XFER_MASK)
{
HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 0e8267c..fb08861 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -449,9 +449,6 @@
else if (depth < 2)
depth = 2;
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
- if (!(((struct aac_dev *)host->hostdata)->adapter_info.options &
- AAC_OPT_NEW_COMM))
- blk_queue_max_segment_size(sdev->request_queue, 65536);
} else
scsi_adjust_queue_depth(sdev, 0, 1);
@@ -1133,6 +1130,12 @@
if (error < 0)
goto out_deinit;
+ if (!(aac->adapter_info.options & AAC_OPT_NEW_COMM)) {
+ error = pci_set_dma_max_seg_size(pdev, 65536);
+ if (error)
+ goto out_deinit;
+ }
+
/*
* Lets override negotiations and drop the maximum SG limit to 34
*/
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 190568e..5a1471c 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -21,7 +21,7 @@
* Modified by Chris Faulhaber <jedgar@fxp.org>
* Added module command-line options
* 19-Jul-99
- * Modified by Adam Fritzler <mid@auk.cx>
+ * Modified by Adam Fritzler
* Added proper detection of the AHA-1640 (MCA version of AHA-1540)
*/
diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
index e4f70c5..4c54954 100644
--- a/drivers/scsi/aic7xxx/Makefile
+++ b/drivers/scsi/aic7xxx/Makefile
@@ -44,13 +44,8 @@
# Dependencies for generated files need to be listed explicitly
-$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
-$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h
-$(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
-$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h
-
-$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h
-$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h
+$(addprefix $(src)/,$(aic7xxx-y:.o=.c)): $(obj)/aic7xxx_seq.h $(obj)/aic7xxx_reg.h
+$(addprefix $(src)/,$(aic79xx-y:.o=.c)): $(obj)/aic79xx_seq.h $(obj)/aic79xx_reg.h
aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE) := $(obj)/aic7xxx_reg.h
aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += $(obj)/aic7xxx_reg_print.c
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
index 2ceb67f..45e5557 100644
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -417,7 +417,7 @@
- (uint8_t *)ahd->qoutfifo);
}
-/*********************** Miscelaneous Support Functions ***********************/
+/*********************** Miscellaneous Support Functions ***********************/
static __inline struct ahd_initiator_tinfo *
ahd_fetch_transinfo(struct ahd_softc *ahd,
char channel, u_int our_id,
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 0146547..72fccd9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -325,7 +325,7 @@
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
-" no_reset Supress initial bus resets\n"
+" no_reset Suppress initial bus resets\n"
" extended Enable extended geometry on all controllers\n"
" periodic_otag Send an ordered tagged transaction\n"
" periodically to prevent tag starvation.\n"
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index df85367..c9f79fd 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -979,7 +979,7 @@
| AHD_FAINT_LED_BUG;
/*
- * IO Cell paramter setup.
+ * IO Cell parameter setup.
*/
AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
@@ -1006,7 +1006,7 @@
ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG;
/*
- * IO Cell paramter setup.
+ * IO Cell parameter setup.
*/
AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
index 8e1954c..cba2f23 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
@@ -229,7 +229,7 @@
return (ahc->name);
}
-/*********************** Miscelaneous Support Functions ***********************/
+/*********************** Miscellaneous Support Functions ***********************/
static __inline void ahc_update_residual(struct ahc_softc *ahc,
struct scb *scb);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 99a3b33..282aff6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -347,7 +347,7 @@
" debug Bitmask of debug values to enable\n"
" no_probe Toggle EISA/VLB controller probing\n"
" probe_eisa_vl Toggle EISA/VLB controller probing\n"
-" no_reset Supress initial bus resets\n"
+" no_reset Suppress initial bus resets\n"
" extended Enable extended geometry on all controllers\n"
" periodic_otag Send an ordered tagged transaction\n"
" periodically to prevent tag starvation.\n"
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 3bfd929..93984c9 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -6472,7 +6472,7 @@
unsigned long cpu_flags;
struct aic7xxx_host *p;
- p = (struct aic7xxx_host *)dev_id;
+ p = dev_id;
if(!p)
return IRQ_NONE;
spin_lock_irqsave(p->host->host_lock, cpu_flags);
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 37741e9..91f8522 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -54,8 +54,7 @@
static int scsi_alloc_out_of_range = 0;
/* use bounce buffer if the physical address is bad */
- if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
- (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+ if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
{
HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
& ~0x1ff;
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index d63f11e95..bd62131 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -539,9 +539,9 @@
srp_iu_put(iue);
}
-static irqreturn_t ibmvstgt_interrupt(int irq, void *data)
+static irqreturn_t ibmvstgt_interrupt(int dummy, void *data)
{
- struct srp_target *target = (struct srp_target *) data;
+ struct srp_target *target = data;
struct vio_port *vport = target_to_port(target);
vio_disable_interrupts(vport->dma_dev);
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 5ed0006..68e5c632 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -287,7 +287,7 @@
static ide_startstop_t
idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
{
- if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
/* force an abort */
HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
@@ -423,7 +423,7 @@
}
/* Clear the interrupt */
- stat = drive->hwif->INB(IDE_STATUS_REG);
+ stat = ide_read_status(drive);
if ((stat & DRQ_STAT) == 0) {
/* No more interrupts */
@@ -588,19 +588,14 @@
hwif->sg_mapped = 0;
}
- SELECT_DRIVE(drive);
-
ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma);
if (dma)
set_bit(PC_DMA_OK, &pc->flags);
if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
- BUG_ON(HWGROUP(drive)->handler != NULL);
- ide_set_handler(drive, &idescsi_transfer_pc,
- get_timeout(pc), idescsi_expiry);
- /* Issue the packet command */
- HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+ ide_execute_command(drive, WIN_PACKETCMD, &idescsi_transfer_pc,
+ get_timeout(pc), idescsi_expiry);
return ide_started;
} else {
/* Issue the packet command */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 73270ff..2074701 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7053,7 +7053,7 @@
* where it can accept new commands.
* Return value:
- * 0 on sucess / -EIO on failure
+ * 0 on success / -EIO on failure
**/
static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
{
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 7505cca..bb152fb9 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1309,7 +1309,7 @@
cstatus.value = (*ha->func.statupd) (ha);
if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
- /* Spurious Interupt ? */
+ /* Spurious Interrupt ? */
continue;
}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index f26b953..83567b9 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -325,7 +325,7 @@
#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
#define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */
-#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timout */
+#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timeout */
#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 3205f74..6cfeba7 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1894,7 +1894,7 @@
uint16_t iotag;
int bars = pci_select_bars(pdev, IORESOURCE_MEM);
- if (pci_enable_device_bars(pdev, bars))
+ if (pci_enable_device_mem(pdev))
goto out;
if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
goto out_disable_device;
@@ -2296,10 +2296,9 @@
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
struct lpfc_sli *psli = &phba->sli;
- int bars = pci_select_bars(pdev, IORESOURCE_MEM);
dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
- if (pci_enable_device_bars(pdev, bars)) {
+ if (pci_enable_device_mem(pdev)) {
printk(KERN_ERR "lpfc: Cannot re-enable "
"PCI device after reset.\n");
return PCI_ERS_RESULT_DISCONNECT;
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index dfc63f6..7a9be4c 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -880,7 +880,7 @@
void
lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
{
- /* This function expects to be called from interupt context */
+ /* This function expects to be called from interrupt context */
spin_lock(&phba->hbalock);
list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
spin_unlock(&phba->hbalock);
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 6db77c0..9f04192 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -3464,12 +3464,12 @@
/*
* START: Interface for the common management module
*
- * This is the module, which interfaces with the common mangement module to
+ * This is the module, which interfaces with the common management module to
* provide support for ioctl and sysfs
*/
/**
- * megaraid_cmm_register - register with the mangement module
+ * megaraid_cmm_register - register with the management module
* @adapter : HBA soft state
*
* Register with the management module, which allows applications to issue
@@ -3557,7 +3557,7 @@
/**
- * megaraid_cmm_unregister - un-register with the mangement module
+ * megaraid_cmm_unregister - un-register with the management module
* @adapter : HBA soft state
*
* Un-register with the management module.
@@ -3579,7 +3579,7 @@
* @kioc : CMM interface packet
* @action : command action
*
- * This routine is invoked whenever the Common Mangement Module (CMM) has a
+ * This routine is invoked whenever the Common Management Module (CMM) has a
* command for us. The 'action' parameter specifies if this is a new command
* or otherwise.
*/
@@ -3944,7 +3944,7 @@
*
* This routine will be called whenever user reads the logical drive
* attributes, go get the current logical drive mapping table from the
- * firmware. We use the managment API's to issue commands to the controller.
+ * firmware. We use the management API's to issue commands to the controller.
*
* NOTE: The commands issuance functionality is not generalized and
* implemented in context of "get ld map" command only. If required, the
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 672c759..77a62a1 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -31,7 +31,6 @@
#include <linux/moduleparam.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/uio.h>
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 4b82b20..d8b9935 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -130,7 +130,7 @@
cisparse_t parse;
int i, last_ret, last_fn;
u_char tuple_data[64];
- char str[16];
+ char str[22];
struct Scsi_Host *host;
DEBUG(0, "fdomain_config(0x%p)\n", link);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 6f129da..b72c7f1 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2268,6 +2268,7 @@
spinlock_t hardware_lock ____cacheline_aligned;
int bars;
+ int mem_only;
device_reg_t __iomem *iobase; /* Base I/O address */
resource_size_t pio_address;
#define MIN_IOBASE_LEN 0x100
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index eb0784c..6226d88 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1094,7 +1094,7 @@
}
/**
- * qla2x00_mgmt_svr_login() - Login to fabric Managment Service.
+ * qla2x00_mgmt_svr_login() - Login to fabric Management Service.
* @ha: HA context
*
* Returns 0 on success.
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3954ed2..8f69caf 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1564,7 +1564,7 @@
char pci_info[30];
char fw_str[30];
struct scsi_host_template *sht;
- int bars;
+ int bars, mem_only = 0;
bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
sht = &qla2x00_driver_template;
@@ -1575,10 +1575,16 @@
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
sht = &qla24xx_driver_template;
+ mem_only = 1;
}
- if (pci_enable_device_bars(pdev, bars))
- goto probe_out;
+ if (mem_only) {
+ if (pci_enable_device_mem(pdev))
+ goto probe_out;
+ } else {
+ if (pci_enable_device(pdev))
+ goto probe_out;
+ }
if (pci_find_aer_capability(pdev))
if (pci_enable_pcie_error_reporting(pdev))
@@ -1601,6 +1607,7 @@
sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
ha->parent = NULL;
ha->bars = bars;
+ ha->mem_only = mem_only;
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
@@ -2875,8 +2882,14 @@
{
pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ int rc;
- if (pci_enable_device_bars(pdev, ha->bars)) {
+ if (ha->mem_only)
+ rc = pci_enable_device_mem(pdev);
+ else
+ rc = pci_enable_device(pdev);
+
+ if (rc) {
qla_printk(KERN_WARNING, ha,
"Can't re-enable PCI device after reset.\n");
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index accaf690..d6be076 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -121,7 +121,7 @@
#define MAX_REQS_SERVICED_PER_INTR 16
#define ISCSI_IPADDR_SIZE 4 /* IP address size */
-#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
+#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */
#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */
#define LSDW(x) ((u32)((u64)(x)))
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index cbe0a17c..49925f9 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -1098,7 +1098,7 @@
}
config_chip = 1;
- /* Reset clears the semaphore, so aquire again */
+ /* Reset clears the semaphore, so acquire again */
if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
return QLA_ERROR;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index b12fb31..f243fc30 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1569,6 +1569,7 @@
request_fn_proc *request_fn)
{
struct request_queue *q;
+ struct device *dev = shost->shost_gendev.parent;
q = blk_init_queue(request_fn, NULL);
if (!q)
@@ -1583,6 +1584,9 @@
blk_queue_max_sectors(q, shost->max_sectors);
blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
blk_queue_segment_boundary(q, shost->dma_boundary);
+ dma_set_seg_boundary(dev, shost->dma_boundary);
+
+ blk_queue_max_segment_size(q, dma_get_max_seg_size(dev));
if (!shost->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 91630ba..3677fbb 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -320,7 +320,7 @@
EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
/*
- * This is run from a interrpt handler normally and the unmap
+ * This is run from a interrupt handler normally and the unmap
* needs process context so we must queue
*/
static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index f2149d0b..43a964d 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -6,7 +6,7 @@
*
* The SAS transport class contains common code to deal with SAS HBAs,
* an aproximated representation of SAS topologies in the driver model,
- * and various sysfs attributes to expose these topologies and managment
+ * and various sysfs attributes to expose these topologies and management
* interfaces to userspace.
*
* In addition to the basic SCSI core objects this transport class
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index 6a48dfa..0276471 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -237,6 +237,12 @@
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
+ if (port->info && port->info->tty) {
+ struct tty_struct *tty = port->info->tty;
+ unsigned int b = port->uartclk / (16 * quot);
+ tty_encode_baud_rate(tty, b, b);
+ }
+
switch (termios->c_cflag & CSIZE) {
case CS5:
h_lcr = 0x00;
@@ -277,8 +283,6 @@
if (termios->c_iflag & INPCK)
port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
- tty_encode_baud_rate(tty, baud, baud);
-
/*
* Which character status flags should we ignore?
*/
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index f94109c..b8a4bd9 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2047,7 +2047,7 @@
* Oxford Semi 952 rev B workaround
*/
if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
- quot ++;
+ quot++;
if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
if (baud < 2400)
@@ -2662,16 +2662,17 @@
memset(&port, 0, sizeof(struct uart_port));
for (i = 0; p && p->flags != 0; p++, i++) {
- port.iobase = p->iobase;
- port.membase = p->membase;
- port.irq = p->irq;
- port.uartclk = p->uartclk;
- port.regshift = p->regshift;
- port.iotype = p->iotype;
- port.flags = p->flags;
- port.mapbase = p->mapbase;
- port.hub6 = p->hub6;
- port.dev = &dev->dev;
+ port.iobase = p->iobase;
+ port.membase = p->membase;
+ port.irq = p->irq;
+ port.uartclk = p->uartclk;
+ port.regshift = p->regshift;
+ port.iotype = p->iotype;
+ port.flags = p->flags;
+ port.mapbase = p->mapbase;
+ port.hub6 = p->hub6;
+ port.private_data = p->private_data;
+ port.dev = &dev->dev;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
ret = serial8250_register_port(&port);
@@ -2812,15 +2813,16 @@
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
- uart->port.iobase = port->iobase;
- uart->port.membase = port->membase;
- uart->port.irq = port->irq;
- uart->port.uartclk = port->uartclk;
- uart->port.fifosize = port->fifosize;
- uart->port.regshift = port->regshift;
- uart->port.iotype = port->iotype;
- uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
- uart->port.mapbase = port->mapbase;
+ uart->port.iobase = port->iobase;
+ uart->port.membase = port->membase;
+ uart->port.irq = port->irq;
+ uart->port.uartclk = port->uartclk;
+ uart->port.fifosize = port->fifosize;
+ uart->port.regshift = port->regshift;
+ uart->port.iotype = port->iotype;
+ uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
+ uart->port.mapbase = port->mapbase;
+ uart->port.private_data = port->private_data;
if (port->dev)
uart->port.dev = port->dev;
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index ceb03c9..0a4ac2b 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -106,6 +106,32 @@
}
/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+static int addidata_apci7800_setup(struct serial_private *priv,
+ struct pciserial_board *board,
+ struct uart_port *port, int idx)
+{
+ unsigned int bar = 0, offset = board->first_offset;
+ bar = FL_GET_BASE(board->flags);
+
+ if (idx < 2) {
+ offset += idx * board->uart_offset;
+ } else if ((idx >= 2) && (idx < 4)) {
+ bar += 1;
+ offset += ((idx - 2) * board->uart_offset);
+ } else if ((idx >= 4) && (idx < 6)) {
+ bar += 2;
+ offset += ((idx - 4) * board->uart_offset);
+ } else if (idx >= 6) {
+ bar += 3;
+ offset += ((idx - 6) * board->uart_offset);
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
* AFAVLAB uses a different mixture of BARs and offsets
* Not that ugly ;) -- HW
*/
@@ -752,6 +778,16 @@
*/
static struct pci_serial_quirk pci_serial_quirks[] = {
/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ADDIDATA_OLD,
+ .device = PCI_DEVICE_ID_ADDIDATA_APCI7800,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = addidata_apci7800_setup,
+ },
+ /*
* AFAVLAB cards - these may be called via parport_serial
* It is not clear whether this applies to all products.
*/
@@ -1179,6 +1215,12 @@
.base_baud = 115200,
.uart_offset = 8,
},
+ [pbn_b0_8_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
[pbn_b0_1_921600] = {
.flags = FL_BASE0,
@@ -2697,6 +2739,97 @@
pbn_pasemi_1682M },
/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA_OLD,
+ PCI_DEVICE_ID_ADDIDATA_APCI7800,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b1_8_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_8_115200 },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 1de098e..6f09cbd 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -414,8 +414,9 @@
*/
static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
{
- if (!(check_name(pnp_dev_name(dev)) || (dev->card && check_name(dev->card->name))))
- return -ENODEV;
+ if (!(check_name(pnp_dev_name(dev)) ||
+ (dev->card && check_name(dev->card->name))))
+ return -ENODEV;
if (check_resources(dev->independent))
return 0;
@@ -452,8 +453,9 @@
return -ENODEV;
#ifdef SERIAL_DEBUG_PNP
- printk("Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- port.iobase, port.mapbase, port.irq, port.iotype);
+ printk(KERN_DEBUG
+ "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
+ port.iobase, port.mapbase, port.irq, port.iotype);
#endif
port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8a053ea..6a44fb1 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -877,15 +877,15 @@
systems. Say Y if you want to be able to use this device.
config SERIAL_IP22_ZILOG
- tristate "IP22 Zilog8530 serial support"
- depends on SGI_IP22
+ tristate "SGI Zilog8530 serial support"
+ depends on SGI_HAS_ZILOG
select SERIAL_CORE
help
- This driver supports the Zilog8530 serial ports found on SGI IP22
+ This driver supports the Zilog8530 serial ports found on SGI
systems. Say Y or M if you want to be able to these serial ports.
config SERIAL_IP22_ZILOG_CONSOLE
- bool "Console on IP22 Zilog8530 serial port"
+ bool "Console on SGI Zilog8530 serial port"
depends on SERIAL_IP22_ZILOG=y
select SERIAL_CORE_CONSOLE
@@ -1295,8 +1295,8 @@
depends on SERIAL_NETX
select SERIAL_CORE_CONSOLE
help
- If you have enabled the serial port on the Motorola IMX
- CPU you can make it the console by answering Y to this option.
+ If you have enabled the serial port on the Hilscher NetX SoC
+ you can make it the console by answering Y to this option.
config SERIAL_OF_PLATFORM
tristate "Serial port on Open Firmware platform bus"
@@ -1318,4 +1318,19 @@
This driver supports the QE serial ports on Freescale embedded
PowerPC that contain a QUICC Engine.
+config SERIAL_SC26XX
+ tristate "SC2681/SC2692 serial port support"
+ depends on SNI_RM
+ select SERIAL_CORE
+ help
+ This is a driver for the onboard serial ports of
+ older RM400 machines.
+
+config SERIAL_SC26XX_CONSOLE
+ bool "Console on SC2681/SC2692 serial port"
+ depends on SERIAL_SC26XX
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for Console on SC2681/SC2692 serial ports.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 2dd41b4..640cfe4 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -55,6 +55,7 @@
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 111da57f..60f5290 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -34,6 +34,7 @@
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
#include <linux/atmel_pdc.h>
+#include <linux/atmel_serial.h>
#include <asm/io.h>
@@ -45,8 +46,6 @@
#include <asm/arch/gpio.h>
#endif
-#include "atmel_serial.h"
-
#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index b5e4478..236af9d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -380,7 +380,7 @@
static irqreturn_t cpm_uart_int(int irq, void *data)
{
u8 events;
- struct uart_port *port = (struct uart_port *)data;
+ struct uart_port *port = data;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
smc_t __iomem *smcp = pinfo->smcp;
scc_t __iomem *sccp = pinfo->sccp;
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index d31721f..bbae5a2 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -324,7 +324,7 @@
*/
static irqreturn_t dz_interrupt(int irq, void *dev)
{
- struct dz_port *dport = (struct dz_port *)dev;
+ struct dz_port *dport = dev;
unsigned short status;
/* get the reason why we just got an irq */
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
index 0274554..c8029e0 100644
--- a/drivers/serial/icom.h
+++ b/drivers/serial/icom.h
@@ -20,7 +20,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include<linux/serial_core.h>
+#include <linux/serial_core.h>
#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
static int icom_acfg_baud[] = {
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index dc19671..56af1f5 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -308,7 +308,7 @@
static irqreturn_t imx_rtsint(int irq, void *dev_id)
{
- struct imx_port *sport = (struct imx_port *)dev_id;
+ struct imx_port *sport = dev_id;
unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
unsigned long flags;
@@ -324,7 +324,7 @@
static irqreturn_t imx_txint(int irq, void *dev_id)
{
- struct imx_port *sport = (struct imx_port *)dev_id;
+ struct imx_port *sport = dev_id;
struct circ_buf *xmit = &sport->port.info->xmit;
unsigned long flags;
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
index 051fcc2..e76fc72 100644
--- a/drivers/serial/mcf.c
+++ b/drivers/serial/mcf.c
@@ -434,7 +434,7 @@
static struct mcf_uart mcf_ports[3];
-#define MCF_MAXPORTS (sizeof(mcf_ports) / sizeof(struct mcf_uart))
+#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)
/****************************************************************************/
#if defined(CONFIG_SERIAL_MCF_CONSOLE)
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 4d643c9..cb3a919 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -612,6 +612,7 @@
/* No preamble, 16x divider, low-latency, */
writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
+ mpsc_set_baudrate(pi, pi->default_baud);
if (pi->mirror_regs) {
pi->MPSC_CHR_1_m = 0;
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index 8321101..e940317 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -582,7 +582,7 @@
};
/**
- * mux_init - Serial MUX initalization procedure.
+ * mux_init - Serial MUX initialization procedure.
*
* Register the Serial MUX driver.
*/
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index e773c8e..45de193 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1527,7 +1527,7 @@
#define s3c2440_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#if defined(CONFIG_CPU_S3C2412)
static int s3c2412_serial_setsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk)
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
new file mode 100644
index 0000000..a350b6d
--- /dev/null
+++ b/drivers/serial/sc26xx.c
@@ -0,0 +1,755 @@
+/*
+ * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
+ *
+ * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SC26XX_MAJOR 204
+#define SC26XX_MINOR_START 205
+#define SC26XX_NR 2
+
+struct uart_sc26xx_port {
+ struct uart_port port[2];
+ u8 dsr_mask[2];
+ u8 cts_mask[2];
+ u8 dcd_mask[2];
+ u8 ri_mask[2];
+ u8 dtr_mask[2];
+ u8 rts_mask[2];
+ u8 imr;
+};
+
+/* register common to both ports */
+#define RD_ISR 0x14
+#define RD_IPR 0x34
+
+#define WR_ACR 0x10
+#define WR_IMR 0x14
+#define WR_OPCR 0x34
+#define WR_OPR_SET 0x38
+#define WR_OPR_CLR 0x3C
+
+/* access common register */
+#define READ_SC(p, r) readb((p)->membase + RD_##r)
+#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r)
+
+/* register per port */
+#define RD_PORT_MRx 0x00
+#define RD_PORT_SR 0x04
+#define RD_PORT_RHR 0x0c
+
+#define WR_PORT_MRx 0x00
+#define WR_PORT_CSR 0x04
+#define WR_PORT_CR 0x08
+#define WR_PORT_THR 0x0c
+
+/* SR bits */
+#define SR_BREAK (1 << 7)
+#define SR_FRAME (1 << 6)
+#define SR_PARITY (1 << 5)
+#define SR_OVERRUN (1 << 4)
+#define SR_TXRDY (1 << 2)
+#define SR_RXRDY (1 << 0)
+
+#define CR_RES_MR (1 << 4)
+#define CR_RES_RX (2 << 4)
+#define CR_RES_TX (3 << 4)
+#define CR_STRT_BRK (6 << 4)
+#define CR_STOP_BRK (7 << 4)
+#define CR_DIS_TX (1 << 3)
+#define CR_ENA_TX (1 << 2)
+#define CR_DIS_RX (1 << 1)
+#define CR_ENA_RX (1 << 0)
+
+/* ISR bits */
+#define ISR_RXRDYB (1 << 5)
+#define ISR_TXRDYB (1 << 4)
+#define ISR_RXRDYA (1 << 1)
+#define ISR_TXRDYA (1 << 0)
+
+/* IMR bits */
+#define IMR_RXRDY (1 << 1)
+#define IMR_TXRDY (1 << 0)
+
+/* access port register */
+static inline u8 read_sc_port(struct uart_port *p, u8 reg)
+{
+ return readb(p->membase + p->line * 0x20 + reg);
+}
+
+static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
+{
+ writeb(val, p->membase + p->line * 0x20 + reg);
+}
+
+#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r)
+#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
+
+static void sc26xx_enable_irq(struct uart_port *port, int mask)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+ up->imr |= mask << (line * 4);
+ WRITE_SC(port, IMR, up->imr);
+}
+
+static void sc26xx_disable_irq(struct uart_port *port, int mask)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+ up->imr &= ~(mask << (line * 4));
+ WRITE_SC(port, IMR, up->imr);
+}
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = NULL;
+ int limit = 10000;
+ unsigned char ch;
+ char flag;
+ u8 status;
+
+ if (port->info != NULL) /* Unopened serial console */
+ tty = port->info->tty;
+
+ while (limit-- > 0) {
+ status = READ_SC_PORT(port, SR);
+ if (!(status & SR_RXRDY))
+ break;
+ ch = READ_SC_PORT(port, RHR);
+
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (unlikely(status & (SR_BREAK | SR_FRAME |
+ SR_PARITY | SR_OVERRUN))) {
+ if (status & SR_BREAK) {
+ status &= ~(SR_PARITY | SR_FRAME);
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (status & SR_PARITY)
+ port->icount.parity++;
+ else if (status & SR_FRAME)
+ port->icount.frame++;
+ if (status & SR_OVERRUN)
+ port->icount.overrun++;
+
+ status &= port->read_status_mask;
+ if (status & SR_BREAK)
+ flag = TTY_BREAK;
+ else if (status & SR_PARITY)
+ flag = TTY_PARITY;
+ else if (status & SR_FRAME)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ if (status & port->ignore_status_mask)
+ continue;
+
+ tty_insert_flip_char(tty, ch, flag);
+ }
+ return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit;
+
+ if (!port->info)
+ return;
+
+ xmit = &port->info->xmit;
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ sc26xx_disable_irq(port, IMR_TXRDY);
+ return;
+ }
+ while (!uart_circ_empty(xmit)) {
+ if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
+ break;
+
+ WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
+{
+ struct uart_sc26xx_port *up = dev_id;
+ struct tty_struct *tty;
+ unsigned long flags;
+ u8 isr;
+
+ spin_lock_irqsave(&up->port[0].lock, flags);
+
+ tty = NULL;
+ isr = READ_SC(&up->port[0], ISR);
+ if (isr & ISR_TXRDYA)
+ transmit_chars(&up->port[0]);
+ if (isr & ISR_RXRDYA)
+ tty = receive_chars(&up->port[0]);
+
+ spin_unlock(&up->port[0].lock);
+
+ if (tty)
+ tty_flip_buffer_push(tty);
+
+ spin_lock(&up->port[1].lock);
+
+ tty = NULL;
+ if (isr & ISR_TXRDYB)
+ transmit_chars(&up->port[1]);
+ if (isr & ISR_RXRDYB)
+ tty = receive_chars(&up->port[1]);
+
+ spin_unlock_irqrestore(&up->port[1].lock, flags);
+
+ if (tty)
+ tty_flip_buffer_push(tty);
+
+ return IRQ_HANDLED;
+}
+
+/* port->lock is not held. */
+static unsigned int sc26xx_tx_empty(struct uart_port *port)
+{
+ return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
+}
+
+/* port->lock held by caller. */
+static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+ if (up->dtr_mask[line]) {
+ if (mctrl & TIOCM_DTR)
+ WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
+ else
+ WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
+ }
+ if (up->rts_mask[line]) {
+ if (mctrl & TIOCM_RTS)
+ WRITE_SC(port, OPR_SET, up->rts_mask[line]);
+ else
+ WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
+ }
+}
+
+/* port->lock is held by caller and interrupts are disabled. */
+static unsigned int sc26xx_get_mctrl(struct uart_port *port)
+{
+ struct uart_sc26xx_port *up;
+ int line = port->line;
+ unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+ u8 ipr;
+
+ port -= line;
+ up = container_of(port, struct uart_sc26xx_port, port[0]);
+ ipr = READ_SC(port, IPR) ^ 0xff;
+
+ if (up->dsr_mask[line]) {
+ mctrl &= ~TIOCM_DSR;
+ mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
+ }
+ if (up->cts_mask[line]) {
+ mctrl &= ~TIOCM_CTS;
+ mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
+ }
+ if (up->dcd_mask[line]) {
+ mctrl &= ~TIOCM_CAR;
+ mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
+ }
+ if (up->ri_mask[line]) {
+ mctrl &= ~TIOCM_RNG;
+ mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
+ }
+ return mctrl;
+}
+
+/* port->lock held by caller. */
+static void sc26xx_stop_tx(struct uart_port *port)
+{
+ return;
+}
+
+/* port->lock held by caller. */
+static void sc26xx_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ while (!uart_circ_empty(xmit)) {
+ if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
+ sc26xx_enable_irq(port, IMR_TXRDY);
+ break;
+ }
+ WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+}
+
+/* port->lock held by caller. */
+static void sc26xx_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller. */
+static void sc26xx_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held. */
+static void sc26xx_break_ctl(struct uart_port *port, int break_state)
+{
+ if (break_state == -1)
+ WRITE_SC_PORT(port, CR, CR_STRT_BRK);
+ else
+ WRITE_SC_PORT(port, CR, CR_STOP_BRK);
+}
+
+/* port->lock is not held. */
+static int sc26xx_startup(struct uart_port *port)
+{
+ sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+ WRITE_SC(port, OPCR, 0);
+
+ /* reset tx and rx */
+ WRITE_SC_PORT(port, CR, CR_RES_RX);
+ WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+ /* start rx/tx */
+ WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+
+ /* enable irqs */
+ sc26xx_enable_irq(port, IMR_RXRDY);
+ return 0;
+}
+
+/* port->lock is not held. */
+static void sc26xx_shutdown(struct uart_port *port)
+{
+ /* disable interrupst */
+ sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+ /* stop tx/rx */
+ WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+}
+
+/* port->lock is not held. */
+static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+ unsigned int quot = uart_get_divisor(port, baud);
+ unsigned int iflag, cflag;
+ unsigned long flags;
+ u8 mr1, mr2, csr;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+ udelay(2);
+
+ WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+
+ iflag = termios->c_iflag;
+ cflag = termios->c_cflag;
+
+ port->read_status_mask = SR_OVERRUN;
+ if (iflag & INPCK)
+ port->read_status_mask |= SR_PARITY | SR_FRAME;
+ if (iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SR_BREAK;
+
+ port->ignore_status_mask = 0;
+ if (iflag & IGNBRK)
+ port->ignore_status_mask |= SR_BREAK;
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= SR_BREAK | SR_FRAME |
+ SR_PARITY | SR_OVERRUN;
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ mr1 = 0x00;
+ break;
+ case CS6:
+ mr1 = 0x01;
+ break;
+ case CS7:
+ mr1 = 0x02;
+ break;
+ default:
+ case CS8:
+ mr1 = 0x03;
+ break;
+ }
+ mr2 = 0x07;
+ if (cflag & CSTOPB)
+ mr2 = 0x0f;
+ if (cflag & PARENB) {
+ if (cflag & PARODD)
+ mr1 |= (1 << 2);
+ } else
+ mr1 |= (2 << 3);
+
+ switch (baud) {
+ case 50:
+ csr = 0x00;
+ break;
+ case 110:
+ csr = 0x11;
+ break;
+ case 134:
+ csr = 0x22;
+ break;
+ case 200:
+ csr = 0x33;
+ break;
+ case 300:
+ csr = 0x44;
+ break;
+ case 600:
+ csr = 0x55;
+ break;
+ case 1200:
+ csr = 0x66;
+ break;
+ case 2400:
+ csr = 0x88;
+ break;
+ case 4800:
+ csr = 0x99;
+ break;
+ default:
+ case 9600:
+ csr = 0xbb;
+ break;
+ case 19200:
+ csr = 0xcc;
+ break;
+ }
+
+ WRITE_SC_PORT(port, CR, CR_RES_MR);
+ WRITE_SC_PORT(port, MRx, mr1);
+ WRITE_SC_PORT(port, MRx, mr2);
+
+ WRITE_SC(port, ACR, 0x80);
+ WRITE_SC_PORT(port, CSR, csr);
+
+ /* reset tx and rx */
+ WRITE_SC_PORT(port, CR, CR_RES_RX);
+ WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+ WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+ while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+ udelay(2);
+
+ /* XXX */
+ uart_update_timeout(port, cflag,
+ (port->uartclk / (16 * quot)));
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sc26xx_type(struct uart_port *port)
+{
+ return "SC26XX";
+}
+
+static void sc26xx_release_port(struct uart_port *port)
+{
+}
+
+static int sc26xx_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void sc26xx_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ return -EINVAL;
+}
+
+static struct uart_ops sc26xx_ops = {
+ .tx_empty = sc26xx_tx_empty,
+ .set_mctrl = sc26xx_set_mctrl,
+ .get_mctrl = sc26xx_get_mctrl,
+ .stop_tx = sc26xx_stop_tx,
+ .start_tx = sc26xx_start_tx,
+ .stop_rx = sc26xx_stop_rx,
+ .enable_ms = sc26xx_enable_ms,
+ .break_ctl = sc26xx_break_ctl,
+ .startup = sc26xx_startup,
+ .shutdown = sc26xx_shutdown,
+ .set_termios = sc26xx_set_termios,
+ .type = sc26xx_type,
+ .release_port = sc26xx_release_port,
+ .request_port = sc26xx_request_port,
+ .config_port = sc26xx_config_port,
+ .verify_port = sc26xx_verify_port,
+};
+
+static struct uart_port *sc26xx_port;
+
+#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
+static void sc26xx_console_putchar(struct uart_port *port, char c)
+{
+ unsigned long flags;
+ int limit = 1000000;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while (limit-- > 0) {
+ if (READ_SC_PORT(port, SR) & SR_TXRDY) {
+ WRITE_SC_PORT(port, THR, c);
+ break;
+ }
+ udelay(2);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
+{
+ struct uart_port *port = sc26xx_port;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (*s == '\n')
+ sc26xx_console_putchar(port, '\r');
+ sc26xx_console_putchar(port, *s++);
+ }
+}
+
+static int __init sc26xx_console_setup(struct console *con, char *options)
+{
+ struct uart_port *port = sc26xx_port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (port->type != PORT_SC26XX)
+ return -1;
+
+ printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver sc26xx_reg;
+static struct console sc26xx_console = {
+ .name = "ttySC",
+ .write = sc26xx_console_write,
+ .device = uart_console_device,
+ .setup = sc26xx_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &sc26xx_reg,
+};
+#define SC26XX_CONSOLE &sc26xx_console
+#else
+#define SC26XX_CONSOLE NULL
+#endif
+
+static struct uart_driver sc26xx_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "SC26xx",
+ .dev_name = "ttySC",
+ .major = SC26XX_MAJOR,
+ .minor = SC26XX_MINOR_START,
+ .nr = SC26XX_NR,
+ .cons = SC26XX_CONSOLE,
+};
+
+static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
+{
+ unsigned int bit = (flags >> bitpos) & 15;
+
+ return bit ? (1 << (bit - 1)) : 0;
+}
+
+static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+ int line, unsigned int data)
+{
+ up->dtr_mask[line] = sc26xx_flags2mask(data, 0);
+ up->rts_mask[line] = sc26xx_flags2mask(data, 4);
+ up->dsr_mask[line] = sc26xx_flags2mask(data, 8);
+ up->cts_mask[line] = sc26xx_flags2mask(data, 12);
+ up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
+ up->ri_mask[line] = sc26xx_flags2mask(data, 20);
+}
+
+static int __devinit sc26xx_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ struct uart_sc26xx_port *up;
+ unsigned int *sc26xx_data = dev->dev.platform_data;
+ int err;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ up = kzalloc(sizeof *up, GFP_KERNEL);
+ if (unlikely(!up))
+ return -ENOMEM;
+
+ up->port[0].line = 0;
+ up->port[0].ops = &sc26xx_ops;
+ up->port[0].type = PORT_SC26XX;
+ up->port[0].uartclk = (29491200 / 16); /* arbitrary */
+
+ up->port[0].mapbase = res->start;
+ up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
+ up->port[0].iotype = UPIO_MEM;
+ up->port[0].irq = platform_get_irq(dev, 0);
+
+ up->port[0].dev = &dev->dev;
+
+ sc26xx_init_masks(up, 0, sc26xx_data[0]);
+
+ sc26xx_port = &up->port[0];
+
+ up->port[1].line = 1;
+ up->port[1].ops = &sc26xx_ops;
+ up->port[1].type = PORT_SC26XX;
+ up->port[1].uartclk = (29491200 / 16); /* arbitrary */
+
+ up->port[1].mapbase = up->port[0].mapbase;
+ up->port[1].membase = up->port[0].membase;
+ up->port[1].iotype = UPIO_MEM;
+ up->port[1].irq = up->port[0].irq;
+
+ up->port[1].dev = &dev->dev;
+
+ sc26xx_init_masks(up, 1, sc26xx_data[1]);
+
+ err = uart_register_driver(&sc26xx_reg);
+ if (err)
+ goto out_free_port;
+
+ sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
+
+ err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
+ if (err)
+ goto out_unregister_driver;
+
+ err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
+ if (err)
+ goto out_remove_port0;
+
+ err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
+ if (err)
+ goto out_remove_ports;
+
+ dev_set_drvdata(&dev->dev, up);
+ return 0;
+
+out_remove_ports:
+ uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+out_remove_port0:
+ uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+
+out_unregister_driver:
+ uart_unregister_driver(&sc26xx_reg);
+
+out_free_port:
+ kfree(up);
+ sc26xx_port = NULL;
+ return err;
+}
+
+
+static int __exit sc26xx_driver_remove(struct platform_device *dev)
+{
+ struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+
+ free_irq(up->port[0].irq, up);
+
+ uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+ uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+
+ uart_unregister_driver(&sc26xx_reg);
+
+ kfree(up);
+ sc26xx_port = NULL;
+
+ dev_set_drvdata(&dev->dev, NULL);
+ return 0;
+}
+
+static struct platform_driver sc26xx_driver = {
+ .probe = sc26xx_probe,
+ .remove = __devexit_p(sc26xx_driver_remove),
+ .driver = {
+ .name = "SC26xx",
+ },
+};
+
+static int __init sc26xx_init(void)
+{
+ return platform_driver_register(&sc26xx_driver);
+}
+
+static void __exit sc26xx_exit(void)
+{
+ platform_driver_unregister(&sc26xx_driver);
+}
+
+module_init(sc26xx_init);
+module_exit(sc26xx_exit);
+
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SC681/SC2692 serial driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 3bb5d24..276da14 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -371,7 +371,8 @@
*/
termios->c_cflag &= ~CBAUD;
if (old) {
- termios->c_cflag |= old->c_cflag & CBAUD;
+ baud = tty_termios_baud_rate(old);
+ tty_termios_encode_baud_rate(termios, baud, baud);
old = NULL;
continue;
}
@@ -380,7 +381,7 @@
* As a last resort, if the quotient is zero,
* default to 9600 bps
*/
- termios->c_cflag |= B9600;
+ tty_termios_encode_baud_rate(termios, 9600, 9600);
}
return 0;
@@ -1977,6 +1978,7 @@
if (state->info && state->info->flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
+ int tries;
state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
| UIF_SUSPENDED;
@@ -1990,9 +1992,14 @@
/*
* Wait for the transmitter to empty.
*/
- while (!ops->tx_empty(port)) {
+ for (tries = 3; !ops->tx_empty(port) && tries; tries--) {
msleep(10);
}
+ if (!tries)
+ printk(KERN_ERR "%s%s%s%d: Unable to drain transmitter\n",
+ port->dev ? port->dev->bus_id : "",
+ port->dev ? ": " : "",
+ drv->dev_name, port->line);
ops->shutdown(port);
}
@@ -2029,8 +2036,6 @@
}
port->suspended = 0;
- uart_change_pm(state, 0);
-
/*
* Re-enable the console device after suspending.
*/
@@ -2049,6 +2054,7 @@
if (state->info && state->info->tty && termios.c_cflag == 0)
termios = *state->info->tty->termios;
+ uart_change_pm(state, 0);
port->ops->set_termios(port, &termios, NULL);
console_start(port->cons);
}
@@ -2057,6 +2063,7 @@
const struct uart_ops *ops = port->ops;
int ret;
+ uart_change_pm(state, 0);
ops->set_mctrl(port, 0);
ret = ops->startup(port);
if (ret == 0) {
@@ -2150,10 +2157,11 @@
/*
* Ensure that the modem control lines are de-activated.
+ * keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/
spin_lock_irqsave(&port->lock, flags);
- port->ops->set_mctrl(port, 0);
+ port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
spin_unlock_irqrestore(&port->lock, flags);
/*
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index d8b6600..164d2a4 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -389,7 +389,7 @@
/*====================================================================*/
static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
- kio_addr_t iobase, int irq)
+ unsigned int iobase, int irq)
{
struct uart_port port;
int line;
@@ -456,7 +456,7 @@
static int simple_config(struct pcmcia_device *link)
{
- static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+ static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
static const int size_table[2] = { 8, 16 };
struct serial_info *info = link->priv;
struct serial_cfg_mem *cfg_mem;
@@ -480,7 +480,7 @@
/* If the card is already configured, look up the port and irq */
i = pcmcia_get_configuration_info(link, &config);
if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
- kio_addr_t port = 0;
+ unsigned int port = 0;
if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
port = config.BasePort2;
info->slave = 1;
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index 8094340..bacf68d 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -142,7 +142,7 @@
static irqreturn_t ulite_isr(int irq, void *dev_id)
{
- struct uart_port *port = (struct uart_port *)dev_id;
+ struct uart_port *port = dev_id;
int busy;
do {
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index aaaea81..d810789 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -144,10 +144,10 @@
This hooks up to the MicroWire controller on OMAP1 chips.
config SPI_OMAP24XX
- tristate "McSPI driver for OMAP24xx"
- depends on SPI_MASTER && ARCH_OMAP24XX
+ tristate "McSPI driver for OMAP24xx/OMAP34xx"
+ depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX)
help
- SPI master controller for OMAP24xx Multichannel SPI
+ SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.
config SPI_PXA2XX
@@ -176,6 +176,13 @@
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
+config SPI_SH_SCI
+ tristate "SuperH SCI SPI controller"
+ depends on SPI_MASTER && SUPERH
+ select SPI_BITBANG
+ help
+ SPI driver for SuperH SCI blocks.
+
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 41fbac4..7fca043 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -27,6 +27,7 @@
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
+obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index ff10808..293b7ca 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -51,7 +51,9 @@
u8 stopping;
struct list_head queue;
struct spi_transfer *current_transfer;
- unsigned long remaining_bytes;
+ unsigned long current_remaining_bytes;
+ struct spi_transfer *next_transfer;
+ unsigned long next_remaining_bytes;
void *buffer;
dma_addr_t buffer_dma;
@@ -121,6 +123,48 @@
gpio_set_value(gpio, !active);
}
+static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+ struct spi_transfer *xfer)
+{
+ return msg->transfers.prev == &xfer->transfer_list;
+}
+
+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+{
+ return xfer->delay_usecs == 0 && !xfer->cs_change;
+}
+
+static void atmel_spi_next_xfer_data(struct spi_master *master,
+ struct spi_transfer *xfer,
+ dma_addr_t *tx_dma,
+ dma_addr_t *rx_dma,
+ u32 *plen)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ u32 len = *plen;
+
+ /* use scratch buffer only when rx or tx data is unspecified */
+ if (xfer->rx_buf)
+ *rx_dma = xfer->rx_dma + xfer->len - len;
+ else {
+ *rx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ }
+ if (xfer->tx_buf)
+ *tx_dma = xfer->tx_dma + xfer->len - len;
+ else {
+ *tx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ memset(as->buffer, 0, len);
+ dma_sync_single_for_device(&as->pdev->dev,
+ as->buffer_dma, len, DMA_TO_DEVICE);
+ }
+
+ *plen = len;
+}
+
/*
* Submit next transfer for DMA.
* lock is held, spi irq is blocked
@@ -130,53 +174,78 @@
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_transfer *xfer;
- u32 len;
+ u32 len, remaining, total;
dma_addr_t tx_dma, rx_dma;
- xfer = as->current_transfer;
- if (!xfer || as->remaining_bytes == 0) {
- if (xfer)
- xfer = list_entry(xfer->transfer_list.next,
- struct spi_transfer, transfer_list);
- else
- xfer = list_entry(msg->transfers.next,
- struct spi_transfer, transfer_list);
- as->remaining_bytes = xfer->len;
- as->current_transfer = xfer;
+ if (!as->current_transfer)
+ xfer = list_entry(msg->transfers.next,
+ struct spi_transfer, transfer_list);
+ else if (!as->next_transfer)
+ xfer = list_entry(as->current_transfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ else
+ xfer = NULL;
+
+ if (xfer) {
+ len = xfer->len;
+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ remaining = xfer->len - len;
+
+ spi_writel(as, RPR, rx_dma);
+ spi_writel(as, TPR, tx_dma);
+
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+ spi_writel(as, RCR, len);
+ spi_writel(as, TCR, len);
+
+ dev_dbg(&msg->spi->dev,
+ " start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ } else {
+ xfer = as->next_transfer;
+ remaining = as->next_remaining_bytes;
}
- len = as->remaining_bytes;
+ as->current_transfer = xfer;
+ as->current_remaining_bytes = remaining;
- tx_dma = xfer->tx_dma + xfer->len - len;
- rx_dma = xfer->rx_dma + xfer->len - len;
+ if (remaining > 0)
+ len = remaining;
+ else if (!atmel_spi_xfer_is_last(msg, xfer)
+ && atmel_spi_xfer_can_be_chained(xfer)) {
+ xfer = list_entry(xfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ len = xfer->len;
+ } else
+ xfer = NULL;
- /* use scratch buffer only when rx or tx data is unspecified */
- if (!xfer->rx_buf) {
- rx_dma = as->buffer_dma;
- if (len > BUFFER_SIZE)
- len = BUFFER_SIZE;
- }
- if (!xfer->tx_buf) {
- tx_dma = as->buffer_dma;
- if (len > BUFFER_SIZE)
- len = BUFFER_SIZE;
- memset(as->buffer, 0, len);
- dma_sync_single_for_device(&as->pdev->dev,
- as->buffer_dma, len, DMA_TO_DEVICE);
+ as->next_transfer = xfer;
+
+ if (xfer) {
+ total = len;
+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ as->next_remaining_bytes = total - len;
+
+ spi_writel(as, RNPR, rx_dma);
+ spi_writel(as, TNPR, tx_dma);
+
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+ spi_writel(as, RNCR, len);
+ spi_writel(as, TNCR, len);
+
+ dev_dbg(&msg->spi->dev,
+ " next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ } else {
+ spi_writel(as, RNCR, 0);
+ spi_writel(as, TNCR, 0);
}
- spi_writel(as, RPR, rx_dma);
- spi_writel(as, TPR, tx_dma);
-
- as->remaining_bytes -= len;
- if (msg->spi->bits_per_word > 8)
- len >>= 1;
-
- /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
- * mechanism might help avoid the IRQ latency between transfers
- * (and improve the nCS0 errata handling on at91rm9200 chips)
- *
- * We're also waiting for ENDRX before we start the next
+ /* REVISIT: We're waiting for ENDRX before we start the next
* transfer because we need to handle some difficult timing
* issues otherwise. If we wait for ENDTX in one transfer and
* then starts waiting for ENDRX in the next, it's difficult
@@ -186,17 +255,7 @@
*
* It should be doable, though. Just not now...
*/
- spi_writel(as, TNCR, 0);
- spi_writel(as, RNCR, 0);
spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
-
- dev_dbg(&msg->spi->dev,
- " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
-
- spi_writel(as, RCR, len);
- spi_writel(as, TCR, len);
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
@@ -294,6 +353,7 @@
spin_lock(&as->lock);
as->current_transfer = NULL;
+ as->next_transfer = NULL;
/* continue if needed */
if (list_empty(&as->queue) || as->stopping)
@@ -377,7 +437,7 @@
spi_writel(as, IDR, pending);
- if (as->remaining_bytes == 0) {
+ if (as->current_remaining_bytes == 0) {
msg->actual_length += xfer->len;
if (!msg->is_dma_mapped)
@@ -387,7 +447,7 @@
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
- if (msg->transfers.prev == &xfer->transfer_list) {
+ if (atmel_spi_xfer_is_last(msg, xfer)) {
/* report completed message */
atmel_spi_msg_done(master, as, msg, 0,
xfer->cs_change);
@@ -490,9 +550,14 @@
if (!(spi->mode & SPI_CPHA))
csr |= SPI_BIT(NCPHA);
- /* TODO: DLYBS and DLYBCT */
- csr |= SPI_BF(DLYBS, 10);
- csr |= SPI_BF(DLYBCT, 10);
+ /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
+ *
+ * DLYBCT would add delays between words, slowing down transfers.
+ * It could potentially be useful to cope with DMA bottlenecks, but
+ * in those cases it's probably best to just use a lower bitrate.
+ */
+ csr |= SPI_BF(DLYBS, 0);
+ csr |= SPI_BF(DLYBCT, 0);
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned int)spi->controller_data;
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index ea61724..a6ba11a 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -915,6 +915,28 @@
OMAP24XX_DMA_SPI2_TX1,
};
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+static u8 __initdata spi3_rxdma_id[] = {
+ OMAP24XX_DMA_SPI3_RX0,
+ OMAP24XX_DMA_SPI3_RX1,
+};
+
+static u8 __initdata spi3_txdma_id[] = {
+ OMAP24XX_DMA_SPI3_TX0,
+ OMAP24XX_DMA_SPI3_TX1,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static u8 __initdata spi4_rxdma_id[] = {
+ OMAP34XX_DMA_SPI4_RX0,
+};
+
+static u8 __initdata spi4_txdma_id[] = {
+ OMAP34XX_DMA_SPI4_TX0,
+};
+#endif
+
static int __init omap2_mcspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -935,7 +957,20 @@
txdma_id = spi2_txdma_id;
num_chipselect = 2;
break;
- /* REVISIT omap2430 has a third McSPI ... */
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+ case 3:
+ rxdma_id = spi3_rxdma_id;
+ txdma_id = spi3_txdma_id;
+ num_chipselect = 2;
+ break;
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+ case 4:
+ rxdma_id = spi4_rxdma_id;
+ txdma_id = spi4_txdma_id;
+ num_chipselect = 1;
+ break;
+#endif
default:
return -EINVAL;
}
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index eb817b8..365e0e3 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1526,17 +1526,6 @@
}
#ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
- pm_message_t *state = pm_message;
-
- if (dev->power.power_state.event != state->event) {
- dev_warn(dev, "pm state does not match request\n");
- return -1;
- }
-
- return 0;
-}
static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
{
@@ -1544,12 +1533,6 @@
struct ssp_device *ssp = drv_data->ssp;
int status = 0;
- /* Check all childern for current power state */
- if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
- dev_warn(&pdev->dev, "suspend aborted\n");
- return -1;
- }
-
status = stop_queue(drv_data);
if (status != 0)
return status;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 682a6a4..1ad12af 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
@@ -77,39 +76,33 @@
#ifdef CONFIG_PM
-/*
- * NOTE: the suspend() method for an spi_master controller driver
- * should verify that all its child devices are marked as suspended;
- * suspend requests delivered through sysfs power/state files don't
- * enforce such constraints.
- */
static int spi_suspend(struct device *dev, pm_message_t message)
{
- int value;
+ int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
- if (!drv || !drv->suspend)
- return 0;
-
/* suspend will stop irqs and dma; no more i/o */
- value = drv->suspend(to_spi_device(dev), message);
- if (value == 0)
- dev->power.power_state = message;
+ if (drv) {
+ if (drv->suspend)
+ value = drv->suspend(to_spi_device(dev), message);
+ else
+ dev_dbg(dev, "... can't suspend\n");
+ }
return value;
}
static int spi_resume(struct device *dev)
{
- int value;
+ int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
- if (!drv || !drv->resume)
- return 0;
-
/* resume may restart the i/o queue */
- value = drv->resume(to_spi_device(dev));
- if (value == 0)
- dev->power.power_state = PMSG_ON;
+ if (drv) {
+ if (drv->resume)
+ value = drv->resume(to_spi_device(dev));
+ else
+ dev_dbg(dev, "... can't resume\n");
+ }
return value;
}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 7ef39a6..d853fceb 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1,37 +1,11 @@
/*
- * File: drivers/spi/bfin5xx_spi.c
- * Maintainer:
- * Bryan Wu <bryan.wu@analog.com>
- * Original Author:
- * Luke Yang (Analog Devices Inc.)
- *
- * Created: March. 10th 2006
- * Description: SPI controller driver for Blackfin BF5xx
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * Modified:
- * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
- * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
- * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu)
- * July 30, 2007 add platfrom_resource interface to support multi-port
- * SPI controller (Bryan Wu)
+ * Blackfin On-Chip SPI Driver
*
* Copyright 2004-2007 Analog Devices Inc.
*
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ; either version 2, or (at your option)
- * any later version.
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program ; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/init.h>
@@ -223,10 +197,9 @@
#define MAX_SPI_SSEL 7
/* stop controller and re-config current chip*/
-static int restore_state(struct driver_data *drv_data)
+static void restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- int ret = 0;
/* Clear status and disable clock */
write_STAT(drv_data, BIT_STAT_CLR);
@@ -239,13 +212,6 @@
bfin_spi_enable(drv_data);
cs_active(drv_data, chip);
-
- if (ret)
- dev_dbg(&drv_data->pdev->dev,
- ": request chip select number %d failed\n",
- chip->chip_select_num);
-
- return ret;
}
/* used to kick off transfer in rx mode */
@@ -286,32 +252,30 @@
dev_dbg(&drv_data->pdev->dev,
"cr8-s is 0x%x\n", read_STAT(drv_data));
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
cpu_relax();
++drv_data->tx;
}
+
+ /* poll for SPI completion before return */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
}
static void u8_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
cs_deactive(drv_data, chip);
@@ -350,43 +314,28 @@
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
- /* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(drv_data, 0xFFFF);
-
- cs_active(drv_data, chip);
- dummy_read(drv_data);
-
- while (drv_data->rx < drv_data->rx_end - 1) {
- cs_deactive(drv_data, chip);
+ while (drv_data->rx < drv_data->rx_end) {
+ cs_active(drv_data, chip);
+ read_RDBR(drv_data); /* kick off */
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
- cs_active(drv_data, chip);
- *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
+
+ *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
+ cs_deactive(drv_data, chip);
+
++drv_data->rx;
}
- cs_deactive(drv_data, chip);
-
- while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- cpu_relax();
- *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
- ++drv_data->rx;
}
static void u8_duplex(struct driver_data *drv_data)
{
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -400,15 +349,12 @@
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->rx < drv_data->rx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -426,32 +372,30 @@
dev_dbg(&drv_data->pdev->dev,
"cr16 is 0x%x\n", read_STAT(drv_data));
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while ((read_STAT(drv_data) & BIT_STAT_TXS))
cpu_relax();
drv_data->tx += 2;
}
+
+ /* poll for SPI completion before return */
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
}
static void u16_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while ((read_STAT(drv_data) & BIT_STAT_TXS))
cpu_relax();
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+ cpu_relax();
cs_deactive(drv_data, chip);
@@ -519,14 +463,10 @@
static void u16_duplex(struct driver_data *drv_data)
{
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -540,15 +480,11 @@
{
struct chip_data *chip = drv_data->cur_chip;
- /* poll for SPI completion before start */
- while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- cpu_relax();
-
while (drv_data->tx < drv_data->tx_end) {
cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
- while (read_STAT(drv_data) & BIT_STAT_TXS)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
@@ -616,7 +552,7 @@
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
- struct driver_data *drv_data = (struct driver_data *)dev_id;
+ struct driver_data *drv_data = dev_id;
struct chip_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg;
@@ -978,10 +914,7 @@
/* Setup the SSP using the per chip configuration */
drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
- if (restore_state(drv_data)) {
- spin_unlock_irqrestore(&drv_data->lock, flags);
- return;
- };
+ restore_state(drv_data);
list_del_init(&drv_data->cur_msg->queue);
@@ -1187,7 +1120,7 @@
if ((chip->chip_select_num > 0)
&& (chip->chip_select_num <= spi->master->num_chipselect))
peripheral_request(ssel[spi->master->bus_num]
- [chip->chip_select_num-1], DRV_NAME);
+ [chip->chip_select_num-1], spi->modalias);
cs_deactive(drv_data, chip);
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 2cd8573..1b06471 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -157,7 +157,7 @@
#define SPI_FIFO_BYTE_WIDTH (2)
#define SPI_FIFO_OVERFLOW_MARGIN (2)
-/* DMA burst lenght for half full/empty request trigger */
+/* DMA burst length for half full/empty request trigger */
#define SPI_DMA_BLR (SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)
/* Dummy char output to achieve reads.
@@ -1686,17 +1686,6 @@
}
#ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
- pm_message_t *state = pm_message;
-
- if (dev->power.power_state.event != state->event) {
- dev_warn(dev, "pm state does not match request\n");
- return -1;
- }
-
- return 0;
-}
static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
{
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 89d6685..6e834b8b 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -237,10 +237,8 @@
{
struct s3c24xx_spi *hw;
struct spi_master *master;
- struct spi_board_info *bi;
struct resource *res;
int err = 0;
- int i;
master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
if (master == NULL) {
@@ -348,16 +346,6 @@
goto err_register;
}
- /* register all the devices associated */
-
- bi = &hw->pdata->board_info[0];
- for (i = 0; i < hw->pdata->board_size; i++, bi++) {
- dev_info(hw->dev, "registering %s\n", bi->modalias);
-
- bi->controller_data = hw;
- spi_new_device(master, bi);
- }
-
return 0;
err_register:
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index 109d82c..82ae7d7 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -100,7 +100,6 @@
struct spi_master *master;
struct s3c2410_spigpio *sp;
int ret;
- int i;
master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
if (master == NULL) {
@@ -143,17 +142,6 @@
if (ret)
goto err_no_bitbang;
- /* register the chips to go with the board */
-
- for (i = 0; i < sp->info->board_size; i++) {
- dev_info(&dev->dev, "registering %p: %s\n",
- &sp->info->board_info[i],
- sp->info->board_info[i].modalias);
-
- sp->info->board_info[i].controller_data = sp;
- spi_new_device(master, sp->info->board_info + i);
- }
-
return 0;
err_no_bitbang:
diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c
new file mode 100644
index 0000000..3dbe71b
--- /dev/null
+++ b/drivers/spi/spi_sh_sci.c
@@ -0,0 +1,205 @@
+/*
+ * SH SCI SPI interface
+ *
+ * Copyright (c) 2008 Magnus Damm
+ *
+ * Based on S3C24XX GPIO based SPI driver, which is:
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/spi.h>
+#include <asm/io.h>
+
+struct sh_sci_spi {
+ struct spi_bitbang bitbang;
+
+ void __iomem *membase;
+ unsigned char val;
+ struct sh_spi_info *info;
+ struct platform_device *dev;
+};
+
+#define SCSPTR(sp) (sp->membase + 0x1c)
+#define PIN_SCK (1 << 2)
+#define PIN_TXD (1 << 0)
+#define PIN_RXD PIN_TXD
+#define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
+
+static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
+{
+ /*
+ * We are the only user of SCSPTR so no locking is required.
+ * Reading bit 2 and 0 in SCSPTR gives pin state as input.
+ * Writing the same bits sets the output value.
+ * This makes regular read-modify-write difficult so we
+ * use sp->val to keep track of the latest register value.
+ */
+
+ if (on)
+ sp->val |= bits;
+ else
+ sp->val &= ~bits;
+
+ iowrite8(sp->val, SCSPTR(sp));
+}
+
+static inline void setsck(struct spi_device *dev, int on)
+{
+ setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+ setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+ struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+ return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
+{
+ struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+ if (sp->info && sp->info->chip_select)
+ (sp->info->chip_select)(sp->info, dev->chip_select, value);
+}
+
+static int sh_sci_spi_probe(struct platform_device *dev)
+{
+ struct resource *r;
+ struct spi_master *master;
+ struct sh_sci_spi *sp;
+ int ret;
+
+ master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
+ if (master == NULL) {
+ dev_err(&dev->dev, "failed to allocate spi master\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ sp = spi_master_get_devdata(master);
+
+ platform_set_drvdata(dev, sp);
+ sp->info = dev->dev.platform_data;
+
+ /* setup spi bitbang adaptor */
+ sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.master->bus_num = sp->info->bus_num;
+ sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
+ sp->bitbang.chipselect = sh_sci_spi_chipselect;
+
+ sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
+ sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
+ sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
+ sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENOENT;
+ goto err1;
+ }
+ sp->membase = ioremap(r->start, r->end - r->start + 1);
+ if (!sp->membase) {
+ ret = -ENXIO;
+ goto err1;
+ }
+ sp->val = ioread8(SCSPTR(sp));
+ setbits(sp, PIN_INIT, 1);
+
+ ret = spi_bitbang_start(&sp->bitbang);
+ if (!ret)
+ return 0;
+
+ setbits(sp, PIN_INIT, 0);
+ iounmap(sp->membase);
+ err1:
+ spi_master_put(sp->bitbang.master);
+ err0:
+ return ret;
+}
+
+static int sh_sci_spi_remove(struct platform_device *dev)
+{
+ struct sh_sci_spi *sp = platform_get_drvdata(dev);
+
+ iounmap(sp->membase);
+ setbits(sp, PIN_INIT, 0);
+ spi_bitbang_stop(&sp->bitbang);
+ spi_master_put(sp->bitbang.master);
+ return 0;
+}
+
+static struct platform_driver sh_sci_spi_drv = {
+ .probe = sh_sci_spi_probe,
+ .remove = sh_sci_spi_remove,
+ .driver = {
+ .name = "spi_sh_sci",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_sci_spi_init(void)
+{
+ return platform_driver_register(&sh_sci_spi_drv);
+}
+module_init(sh_sci_spi_init);
+
+static void __exit sh_sci_spi_exit(void)
+{
+ platform_driver_unregister(&sh_sci_spi_drv);
+}
+module_exit(sh_sci_spi_exit);
+
+MODULE_DESCRIPTION("SH SCI SPI Driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
index 1a31f7a..2d27d6d 100644
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -1,7 +1,7 @@
/*
* Broadcom 43xx PCI-SSB bridge module
*
- * This technically is a seperate PCI driver module, but
+ * This technically is a separate PCI driver module, but
* because of its small size we include it in the SSB core
* instead of creating a standalone module.
*
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index cc246fa..2a77e9d 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -417,30 +417,28 @@
idev->vma_count--;
}
-static struct page *uio_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_device *idev = vma->vm_private_data;
- struct page* page = NOPAGE_SIGBUS;
+ struct page *page;
int mi = uio_find_mem_index(vma);
if (mi < 0)
- return page;
+ return VM_FAULT_SIGBUS;
if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
page = virt_to_page(idev->info->mem[mi].addr);
else
page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = page;
+ return 0;
}
static struct vm_operations_struct uio_vm_ops = {
.open = uio_vma_open,
.close = uio_vma_close,
- .nopage = uio_vma_nopage,
+ .fault = uio_vma_fault,
};
static int uio_mmap_physical(struct vm_area_struct *vma)
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7a64990..755823c 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -42,6 +42,10 @@
default y if PPC_MPC52xx
# MIPS:
default y if SOC_AU1X00
+ # SH:
+ default y if CPU_SUBTYPE_SH7720
+ default y if CPU_SUBTYPE_SH7721
+ default y if CPU_SUBTYPE_SH7763
# more:
default PCI
@@ -50,6 +54,7 @@
boolean
default y if PPC_83xx
default y if SOC_AU1200
+ default y if ARCH_IXP4XX
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index b450cba..86e6403 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -2,10 +2,7 @@
# USB/ATM DSL configuration
#
-menu "USB DSL modem support"
- depends on USB
-
-config USB_ATM
+menuconfig USB_ATM
tristate "USB DSL modem support"
depends on USB && ATM
select CRC32
@@ -18,6 +15,8 @@
To compile this driver as a module, choose M here: the
module will be called usbatm.
+if USB_ATM
+
config USB_SPEEDTOUCH
tristate "Speedtouch USB support"
depends on USB_ATM
@@ -70,4 +69,4 @@
To compile this driver as a module, choose M here: the
module will be called xusbatm.
-endmenu
+endif # USB_ATM
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 389c5b1..c5ec1a5 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -999,7 +999,7 @@
bi.dwAddress = swab32(blockidx->PageAddress);
uea_dbg(INS_TO_USBDEV(sc),
- "sending block %u for DSP page %u size %u adress %x\n",
+ "sending block %u for DSP page %u size %u address %x\n",
blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
/* send block info through the IDMA pipe */
@@ -1990,7 +1990,7 @@
return;
bad2:
- uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
"Function : %d, Subfunction : %d\n",
E1_FUNCTION_TYPE(cmv->bFunction),
E1_FUNCTION_SUBTYPE(cmv->bFunction));
@@ -2038,7 +2038,7 @@
return;
bad2:
- uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
"Function : %d, Subfunction : %d\n",
E4_FUNCTION_TYPE(cmv->wFunction),
E4_FUNCTION_SUBTYPE(cmv->wFunction));
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 912d97a..bcc4213 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -496,10 +496,19 @@
otherwise it is scheduled, and with high data rates data can get lost. */
tty->low_latency = 1;
+ if (usb_autopm_get_interface(acm->control)) {
+ mutex_unlock(&open_mutex);
+ return -EIO;
+ }
+
+ mutex_lock(&acm->mutex);
+ mutex_unlock(&open_mutex);
if (acm->used++) {
+ usb_autopm_put_interface(acm->control);
goto done;
}
+
acm->ctrlurb->dev = acm->dev;
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
dbg("usb_submit_urb(ctrl irq) failed");
@@ -526,14 +535,15 @@
done:
err_out:
- mutex_unlock(&open_mutex);
+ mutex_unlock(&acm->mutex);
return rv;
full_bailout:
usb_kill_urb(acm->ctrlurb);
bail_out:
+ usb_autopm_put_interface(acm->control);
acm->used--;
- mutex_unlock(&open_mutex);
+ mutex_unlock(&acm->mutex);
return -EIO;
}
@@ -570,6 +580,7 @@
usb_kill_urb(acm->writeurb);
for (i = 0; i < nr; i++)
usb_kill_urb(acm->ru[i].urb);
+ usb_autopm_put_interface(acm->control);
} else
acm_tty_unregister(acm);
}
@@ -904,7 +915,7 @@
}
if (data_interface_num != call_interface_num)
- dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
+ dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
skip_normal_probe:
@@ -980,6 +991,7 @@
spin_lock_init(&acm->throttle_lock);
spin_lock_init(&acm->write_lock);
spin_lock_init(&acm->read_lock);
+ mutex_init(&acm->mutex);
acm->write_ready = 1;
acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
@@ -1096,6 +1108,25 @@
return -ENOMEM;
}
+static void stop_data_traffic(struct acm *acm)
+{
+ int i;
+
+ tasklet_disable(&acm->urb_task);
+
+ usb_kill_urb(acm->ctrlurb);
+ usb_kill_urb(acm->writeurb);
+ for (i = 0; i < acm->rx_buflimit; i++)
+ usb_kill_urb(acm->ru[i].urb);
+
+ INIT_LIST_HEAD(&acm->filled_read_bufs);
+ INIT_LIST_HEAD(&acm->spare_read_bufs);
+
+ tasklet_enable(&acm->urb_task);
+
+ cancel_work_sync(&acm->work);
+}
+
static void acm_disconnect(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
@@ -1123,19 +1154,7 @@
usb_set_intfdata(acm->control, NULL);
usb_set_intfdata(acm->data, NULL);
- tasklet_disable(&acm->urb_task);
-
- usb_kill_urb(acm->ctrlurb);
- usb_kill_urb(acm->writeurb);
- for (i = 0; i < acm->rx_buflimit; i++)
- usb_kill_urb(acm->ru[i].urb);
-
- INIT_LIST_HEAD(&acm->filled_read_bufs);
- INIT_LIST_HEAD(&acm->spare_read_bufs);
-
- tasklet_enable(&acm->urb_task);
-
- flush_scheduled_work(); /* wait for acm_softint */
+ stop_data_traffic(acm);
acm_write_buffers_free(acm);
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
@@ -1156,6 +1175,46 @@
tty_hangup(acm->tty);
}
+static int acm_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct acm *acm = usb_get_intfdata(intf);
+
+ if (acm->susp_count++)
+ return 0;
+ /*
+ we treat opened interfaces differently,
+ we must guard against open
+ */
+ mutex_lock(&acm->mutex);
+
+ if (acm->used)
+ stop_data_traffic(acm);
+
+ mutex_unlock(&acm->mutex);
+ return 0;
+}
+
+static int acm_resume(struct usb_interface *intf)
+{
+ struct acm *acm = usb_get_intfdata(intf);
+ int rv = 0;
+
+ if (--acm->susp_count)
+ return 0;
+
+ mutex_lock(&acm->mutex);
+ if (acm->used) {
+ rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
+ if (rv < 0)
+ goto err_out;
+
+ tasklet_schedule(&acm->urb_task);
+ }
+
+err_out:
+ mutex_unlock(&acm->mutex);
+ return rv;
+}
/*
* USB driver structure.
*/
@@ -1208,7 +1267,10 @@
.name = "cdc_acm",
.probe = acm_probe,
.disconnect = acm_disconnect,
+ .suspend = acm_suspend,
+ .resume = acm_resume,
.id_table = acm_ids,
+ .supports_autosuspend = 1,
};
/*
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 09f7765..8df6a57 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -107,6 +107,7 @@
int write_used; /* number of non-empty write buffers */
int write_ready; /* write urb is not running */
spinlock_t write_lock;
+ struct mutex mutex;
struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct urb_task; /* rx processing */
@@ -120,6 +121,7 @@
unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
unsigned int ctrl_caps; /* control capabilities from the class specific header */
+ unsigned int susp_count; /* number of suspended interfaces */
};
#define CDC_DATA_INTERFACE_TYPE 0x0a
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 97b09f28..5c33cdb 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -9,6 +9,21 @@
of debug messages to the system log. Select this if you are having a
problem with USB support and want to see more of what is going on.
+config USB_ANNOUNCE_NEW_DEVICES
+ bool "USB announce new devices"
+ depends on USB
+ default N
+ help
+ Say Y here if you want the USB core to always announce the
+ idVendor, idProduct, Manufacturer, Product, and SerialNumber
+ strings for every new USB device to the syslog. This option is
+ usually used by distro vendors to help with debugging and to
+ let users know what specific device was added to the machine
+ in what location.
+
+ If you do not want this kind of information sent to the system
+ log, or have any doubts about this, say N here.
+
comment "Miscellaneous USB options"
depends on USB
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 28d4972..cadb2dc 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -53,11 +53,13 @@
char name[16];
int i, size;
- if (!hcd->self.controller->dma_mask)
+ if (!hcd->self.controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM))
return 0;
- for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- if (!(size = pool_max [i]))
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ size = pool_max[i];
+ if (!size)
continue;
snprintf(name, sizeof name, "buffer-%d", size);
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
@@ -80,10 +82,10 @@
*/
void hcd_buffer_destroy(struct usb_hcd *hcd)
{
- int i;
+ int i;
- for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- struct dma_pool *pool = hcd->pool[i];
+ for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+ struct dma_pool *pool = hcd->pool[i];
if (pool) {
dma_pool_destroy(pool);
hcd->pool[i] = NULL;
@@ -107,7 +109,8 @@
int i;
/* some USB hosts just use PIO */
- if (!bus->controller->dma_mask) {
+ if (!bus->controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM)) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
@@ -132,7 +135,8 @@
if (!addr)
return;
- if (!bus->controller->dma_mask) {
+ if (!bus->controller->dma_mask &&
+ !(hcd->driver->flags & HCD_LOCAL_MEM)) {
kfree(addr);
return;
}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 1a8edce..a92122a 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -238,7 +238,7 @@
/* Allocate space for the right(?) number of endpoints */
num_ep = num_ep_orig = alt->desc.bNumEndpoints;
- alt->desc.bNumEndpoints = 0; // Use as a counter
+ alt->desc.bNumEndpoints = 0; /* Use as a counter */
if (num_ep > USB_MAXENDPOINTS) {
dev_warn(ddev, "too many endpoints for config %d interface %d "
"altsetting %d: %d, using maximum allowed: %d\n",
@@ -246,7 +246,8 @@
num_ep = USB_MAXENDPOINTS;
}
- if (num_ep > 0) { /* Can't allocate 0 bytes */
+ if (num_ep > 0) {
+ /* Can't allocate 0 bytes */
len = sizeof(struct usb_host_endpoint) * num_ep;
alt->endpoint = kzalloc(len, GFP_KERNEL);
if (!alt->endpoint)
@@ -475,8 +476,9 @@
return 0;
}
-// hub-only!! ... and only exported for reset/reinit path.
-// otherwise used internally on disconnect/destroy path
+/* hub-only!! ... and only exported for reset/reinit path.
+ * otherwise used internally on disconnect/destroy path
+ */
void usb_destroy_configuration(struct usb_device *dev)
{
int c, i;
@@ -498,7 +500,7 @@
kfree(cf->string);
for (i = 0; i < cf->desc.bNumInterfaces; i++) {
if (cf->intf_cache[i])
- kref_put(&cf->intf_cache[i]->ref,
+ kref_put(&cf->intf_cache[i]->ref,
usb_release_interface_cache);
}
}
@@ -525,7 +527,7 @@
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
- struct usb_config_descriptor *desc;
+ struct usb_config_descriptor *desc;
cfgno = 0;
if (dev->authorized == 0) /* Not really an error */
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 87c794d6..83d9dc3 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -89,7 +89,7 @@
static const char *format_bandwidth =
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
"B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
-
+
static const char *format_device1 =
/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
"D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
@@ -101,7 +101,7 @@
static const char *format_config =
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
-
+
static const char *format_iad =
/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
"A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
@@ -122,7 +122,7 @@
*/
static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
-static unsigned int conndiscevcnt = 0;
+static unsigned int conndiscevcnt;
/* this struct stores the poll state for <mountpoint>/devices pollers */
struct usb_device_status {
@@ -172,12 +172,8 @@
return clas_info[ix].class_name;
}
-static char *usb_dump_endpoint_descriptor(
- int speed,
- char *start,
- char *end,
- const struct usb_endpoint_descriptor *desc
-)
+static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
+ const struct usb_endpoint_descriptor *desc)
{
char dir, unit, *type;
unsigned interval, bandwidth = 1;
@@ -235,22 +231,24 @@
start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
desc->bmAttributes, type,
- (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * bandwidth,
+ (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
+ bandwidth,
interval, unit);
return start;
}
static char *usb_dump_interface_descriptor(char *start, char *end,
- const struct usb_interface_cache *intfc,
- const struct usb_interface *iface,
- int setno)
+ const struct usb_interface_cache *intfc,
+ const struct usb_interface *iface,
+ int setno)
{
- const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
+ const struct usb_interface_descriptor *desc;
const char *driver_name = "";
int active = 0;
if (start > end)
return start;
+ desc = &intfc->altsetting[setno].desc;
if (iface) {
driver_name = (iface->dev.driver
? iface->dev.driver->name
@@ -270,14 +268,10 @@
return start;
}
-static char *usb_dump_interface(
- int speed,
- char *start,
- char *end,
- const struct usb_interface_cache *intfc,
- const struct usb_interface *iface,
- int setno
-) {
+static char *usb_dump_interface(int speed, char *start, char *end,
+ const struct usb_interface_cache *intfc,
+ const struct usb_interface *iface, int setno)
+{
const struct usb_host_interface *desc = &intfc->altsetting[setno];
int i;
@@ -292,7 +286,7 @@
}
static char *usb_dump_iad_descriptor(char *start, char *end,
- const struct usb_interface_assoc_descriptor *iad)
+ const struct usb_interface_assoc_descriptor *iad)
{
if (start > end)
return start;
@@ -311,13 +305,15 @@
* 1. marking active interface altsettings (code lists all, but should mark
* which ones are active, if any)
*/
-
-static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
+static char *usb_dump_config_descriptor(char *start, char *end,
+ const struct usb_config_descriptor *desc,
+ int active)
{
if (start > end)
return start;
start += sprintf(start, format_config,
- active ? '*' : ' ', /* mark active/actual/current cfg. */
+ /* mark active/actual/current cfg. */
+ active ? '*' : ' ',
desc->bNumInterfaces,
desc->bConfigurationValue,
desc->bmAttributes,
@@ -325,13 +321,8 @@
return start;
}
-static char *usb_dump_config (
- int speed,
- char *start,
- char *end,
- const struct usb_host_config *config,
- int active
-)
+static char *usb_dump_config(int speed, char *start, char *end,
+ const struct usb_host_config *config, int active)
{
int i, j;
struct usb_interface_cache *intfc;
@@ -339,7 +330,8 @@
if (start > end)
return start;
- if (!config) /* getting these some in 2.3.7; none in 2.3.6 */
+ if (!config)
+ /* getting these some in 2.3.7; none in 2.3.6 */
return start + sprintf(start, "(null Cfg. desc.)\n");
start = usb_dump_config_descriptor(start, end, &config->desc, active);
for (i = 0; i < USB_MAXIADS; i++) {
@@ -364,7 +356,8 @@
/*
* Dump the different USB descriptors.
*/
-static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
+static char *usb_dump_device_descriptor(char *start, char *end,
+ const struct usb_device_descriptor *desc)
{
u16 bcdUSB = le16_to_cpu(desc->bcdUSB);
u16 bcdDevice = le16_to_cpu(desc->bcdDevice);
@@ -374,7 +367,7 @@
start += sprintf(start, format_device1,
bcdUSB >> 8, bcdUSB & 0xff,
desc->bDeviceClass,
- class_decode (desc->bDeviceClass),
+ class_decode(desc->bDeviceClass),
desc->bDeviceSubClass,
desc->bDeviceProtocol,
desc->bMaxPacketSize0,
@@ -391,12 +384,14 @@
/*
* Dump the different strings that this device holds.
*/
-static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end,
+ struct usb_device *dev)
{
if (start > end)
return start;
if (dev->manufacturer)
- start += sprintf(start, format_string_manufacturer, dev->manufacturer);
+ start += sprintf(start, format_string_manufacturer,
+ dev->manufacturer);
if (start > end)
goto out;
if (dev->product)
@@ -405,7 +400,8 @@
goto out;
#ifdef ALLOW_SERIAL_NUMBER
if (dev->serial)
- start += sprintf(start, format_string_serialnumber, dev->serial);
+ start += sprintf(start, format_string_serialnumber,
+ dev->serial);
#endif
out:
return start;
@@ -417,12 +413,12 @@
if (start > end)
return start;
-
+
start = usb_dump_device_descriptor(start, end, &dev->descriptor);
if (start > end)
return start;
-
+
start = usb_dump_device_strings(start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
@@ -439,7 +435,8 @@
#ifdef PROC_EXTRA /* TBD: may want to add this code later */
-static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
+static char *usb_dump_hub_descriptor(char *start, char *end,
+ const struct usb_hub_descriptor *desc)
{
int leng = USB_DT_HUB_NONVAR_SIZE;
unsigned char *ptr = (unsigned char *)desc;
@@ -455,13 +452,16 @@
return start;
}
-static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
+static char *usb_dump_string(char *start, char *end,
+ const struct usb_device *dev, char *id, int index)
{
if (start > end)
return start;
start += sprintf(start, "Interface:");
- if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
- start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]);
+ if (index <= dev->maxstring && dev->stringindex &&
+ dev->stringindex[index])
+ start += sprintf(start, "%s: %.100s ", id,
+ dev->stringindex[index]);
return start;
}
@@ -476,8 +476,10 @@
* file_offset - the offset into the devices file on completion
* The caller must own the device lock.
*/
-static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
- struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
+static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
+ loff_t *skip_bytes, loff_t *file_offset,
+ struct usb_device *usbdev, struct usb_bus *bus,
+ int level, int index, int count)
{
int chix;
int ret, cnt = 0;
@@ -485,17 +487,19 @@
char *pages_start, *data_end, *speed;
unsigned int length;
ssize_t total_written = 0;
-
+
/* don't bother with anything else if we're not writing any data */
if (*nbytes <= 0)
return 0;
-
+
if (level > MAX_TOPO_LEVEL)
return 0;
- /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
- if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
- return -ENOMEM;
-
+ /* allocate 2^1 pages = 8K (on i386);
+ * should be more than enough for one device */
+ pages_start = (char *)__get_free_pages(GFP_KERNEL, 1);
+ if (!pages_start)
+ return -ENOMEM;
+
if (usbdev->parent && usbdev->parent->devnum != -1)
parent_devnum = usbdev->parent->devnum;
/*
@@ -541,15 +545,16 @@
bus->bandwidth_allocated, max,
(100 * bus->bandwidth_allocated + max / 2)
/ max,
- bus->bandwidth_int_reqs,
- bus->bandwidth_isoc_reqs);
-
+ bus->bandwidth_int_reqs,
+ bus->bandwidth_isoc_reqs);
+
}
- data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
-
+ data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256,
+ usbdev);
+
if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
data_end += sprintf(data_end, "(truncated)\n");
-
+
length = data_end - pages_start;
/* if we can start copying some data to the user */
if (length > *skip_bytes) {
@@ -567,17 +572,18 @@
*skip_bytes = 0;
} else
*skip_bytes -= length;
-
+
free_pages((unsigned long)pages_start, 1);
-
+
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
struct usb_device *childdev = usbdev->children[chix];
if (childdev) {
usb_lock_device(childdev);
- ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
- bus, level + 1, chix, ++cnt);
+ ret = usb_device_dump(buffer, nbytes, skip_bytes,
+ file_offset, childdev, bus,
+ level + 1, chix, ++cnt);
usb_unlock_device(childdev);
if (ret == -EFAULT)
return total_written;
@@ -587,7 +593,8 @@
return total_written;
}
-static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t usb_device_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
{
struct usb_bus *bus;
ssize_t ret, total_written = 0;
@@ -607,7 +614,8 @@
if (!bus->root_hub)
continue;
usb_lock_device(bus->root_hub);
- ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
+ ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
+ bus->root_hub, bus, 0, 0, 0);
usb_unlock_device(bus->root_hub);
if (ret < 0) {
mutex_unlock(&usb_bus_list_lock);
@@ -620,7 +628,8 @@
}
/* Kernel lock for "lastev" protection */
-static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int usb_device_poll(struct file *file,
+ struct poll_table_struct *wait)
{
struct usb_device_status *st = file->private_data;
unsigned int mask = 0;
@@ -629,7 +638,8 @@
if (!st) {
st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
- /* we may have dropped BKL - need to check for having lost the race */
+ /* we may have dropped BKL -
+ * need to check for having lost the race */
if (file->private_data) {
kfree(st);
st = file->private_data;
@@ -652,7 +662,7 @@
}
lost_race:
if (file->f_mode & FMODE_READ)
- poll_wait(file, &deviceconndiscwq, wait);
+ poll_wait(file, &deviceconndiscwq, wait);
if (st->lastev != conndiscevcnt)
mask |= POLLIN;
st->lastev = conndiscevcnt;
@@ -662,18 +672,18 @@
static int usb_device_open(struct inode *inode, struct file *file)
{
- file->private_data = NULL;
- return 0;
+ file->private_data = NULL;
+ return 0;
}
static int usb_device_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
file->private_data = NULL;
- return 0;
+ return 0;
}
-static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
+static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 1f4f6d0..ae94176 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -75,14 +75,14 @@
u32 secid;
};
-static int usbfs_snoop = 0;
-module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
+static int usbfs_snoop;
+module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
#define snoop(dev, format, arg...) \
do { \
if (usbfs_snoop) \
- dev_info( dev , format , ## arg); \
+ dev_info(dev , format , ## arg); \
} while (0)
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
@@ -90,7 +90,7 @@
#define MAX_USBFS_BUFFER_SIZE 16384
-static inline int connected (struct dev_state *ps)
+static inline int connected(struct dev_state *ps)
{
return (!list_empty(&ps->list) &&
ps->dev->state != USB_STATE_NOTATTACHED);
@@ -120,7 +120,8 @@
return ret;
}
-static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
+ loff_t *ppos)
{
struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
@@ -140,7 +141,8 @@
}
if (pos < sizeof(struct usb_device_descriptor)) {
- struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
+ /* 18 bytes - fits on the stack */
+ struct usb_device_descriptor temp_desc;
memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
le16_to_cpus(&temp_desc.bcdUSB);
@@ -210,17 +212,17 @@
static struct async *alloc_async(unsigned int numisoframes)
{
- unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
- struct async *as = kzalloc(assize, GFP_KERNEL);
+ struct async *as;
- if (!as)
- return NULL;
+ as = kzalloc(sizeof(struct async), GFP_KERNEL);
+ if (!as)
+ return NULL;
as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
if (!as->urb) {
kfree(as);
return NULL;
}
- return as;
+ return as;
}
static void free_async(struct async *as)
@@ -234,52 +236,54 @@
static inline void async_newpending(struct async *as)
{
- struct dev_state *ps = as->ps;
- unsigned long flags;
-
- spin_lock_irqsave(&ps->lock, flags);
- list_add_tail(&as->asynclist, &ps->async_pending);
- spin_unlock_irqrestore(&ps->lock, flags);
+ struct dev_state *ps = as->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_add_tail(&as->asynclist, &ps->async_pending);
+ spin_unlock_irqrestore(&ps->lock, flags);
}
static inline void async_removepending(struct async *as)
{
- struct dev_state *ps = as->ps;
- unsigned long flags;
-
- spin_lock_irqsave(&ps->lock, flags);
- list_del_init(&as->asynclist);
- spin_unlock_irqrestore(&ps->lock, flags);
+ struct dev_state *ps = as->ps;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->lock, flags);
+ list_del_init(&as->asynclist);
+ spin_unlock_irqrestore(&ps->lock, flags);
}
static inline struct async *async_getcompleted(struct dev_state *ps)
{
- unsigned long flags;
- struct async *as = NULL;
+ unsigned long flags;
+ struct async *as = NULL;
- spin_lock_irqsave(&ps->lock, flags);
- if (!list_empty(&ps->async_completed)) {
- as = list_entry(ps->async_completed.next, struct async, asynclist);
- list_del_init(&as->asynclist);
- }
- spin_unlock_irqrestore(&ps->lock, flags);
- return as;
+ spin_lock_irqsave(&ps->lock, flags);
+ if (!list_empty(&ps->async_completed)) {
+ as = list_entry(ps->async_completed.next, struct async,
+ asynclist);
+ list_del_init(&as->asynclist);
+ }
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return as;
}
-static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb)
+static inline struct async *async_getpending(struct dev_state *ps,
+ void __user *userurb)
{
- unsigned long flags;
- struct async *as;
+ unsigned long flags;
+ struct async *as;
- spin_lock_irqsave(&ps->lock, flags);
+ spin_lock_irqsave(&ps->lock, flags);
list_for_each_entry(as, &ps->async_pending, asynclist)
if (as->userurb == userurb) {
list_del_init(&as->asynclist);
spin_unlock_irqrestore(&ps->lock, flags);
return as;
}
- spin_unlock_irqrestore(&ps->lock, flags);
- return NULL;
+ spin_unlock_irqrestore(&ps->lock, flags);
+ return NULL;
}
static void snoop_urb(struct urb *urb, void __user *userurb)
@@ -298,19 +302,19 @@
dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length);
dev_info(&urb->dev->dev, "data: ");
for (j = 0; j < urb->transfer_buffer_length; ++j)
- printk ("%02x ", data[j]);
+ printk("%02x ", data[j]);
printk("\n");
}
static void async_completed(struct urb *urb)
{
- struct async *as = urb->context;
- struct dev_state *ps = as->ps;
+ struct async *as = urb->context;
+ struct dev_state *ps = as->ps;
struct siginfo sinfo;
- spin_lock(&ps->lock);
- list_move_tail(&as->asynclist, &ps->async_completed);
- spin_unlock(&ps->lock);
+ spin_lock(&ps->lock);
+ list_move_tail(&as->asynclist, &ps->async_completed);
+ spin_unlock(&ps->lock);
as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
@@ -325,7 +329,7 @@
wake_up(&ps->wait);
}
-static void destroy_async (struct dev_state *ps, struct list_head *list)
+static void destroy_async(struct dev_state *ps, struct list_head *list)
{
struct async *as;
unsigned long flags;
@@ -348,7 +352,8 @@
}
}
-static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum)
+static void destroy_async_on_interface(struct dev_state *ps,
+ unsigned int ifnum)
{
struct list_head *p, *q, hitlist;
unsigned long flags;
@@ -364,7 +369,7 @@
static inline void destroy_all_async(struct dev_state *ps)
{
- destroy_async(ps, &ps->async_pending);
+ destroy_async(ps, &ps->async_pending);
}
/*
@@ -373,15 +378,15 @@
* they're also undone when devices disconnect.
*/
-static int driver_probe (struct usb_interface *intf,
- const struct usb_device_id *id)
+static int driver_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
return -ENODEV;
}
static void driver_disconnect(struct usb_interface *intf)
{
- struct dev_state *ps = usb_get_intfdata (intf);
+ struct dev_state *ps = usb_get_intfdata(intf);
unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
if (!ps)
@@ -396,16 +401,31 @@
else
warn("interface number %u out of range", ifnum);
- usb_set_intfdata (intf, NULL);
+ usb_set_intfdata(intf, NULL);
/* force async requests to complete */
destroy_async_on_interface(ps, ifnum);
}
+/* The following routines are merely placeholders. There is no way
+ * to inform a user task about suspend or resumes.
+ */
+static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+ return 0;
+}
+
+static int driver_resume(struct usb_interface *intf)
+{
+ return 0;
+}
+
struct usb_driver usbfs_driver = {
.name = "usbfs",
.probe = driver_probe,
.disconnect = driver_disconnect,
+ .suspend = driver_suspend,
+ .resume = driver_resume,
};
static int claimintf(struct dev_state *ps, unsigned int ifnum)
@@ -459,15 +479,16 @@
if (test_bit(ifnum, &ps->ifclaimed))
return 0;
/* if not yet claimed, claim it for the driver */
- dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n",
- task_pid_nr(current), current->comm, ifnum);
+ dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
+ "interface %u before use\n", task_pid_nr(current),
+ current->comm, ifnum);
return claimintf(ps, ifnum);
}
static int findintfep(struct usb_device *dev, unsigned int ep)
{
unsigned int i, j, e;
- struct usb_interface *intf;
+ struct usb_interface *intf;
struct usb_host_interface *alts;
struct usb_endpoint_descriptor *endpt;
@@ -478,7 +499,7 @@
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
intf = dev->actconfig->interface[i];
for (j = 0; j < intf->num_altsetting; j++) {
- alts = &intf->altsetting[j];
+ alts = &intf->altsetting[j];
for (e = 0; e < alts->desc.bNumEndpoints; e++) {
endpt = &alts->endpoint[e].desc;
if (endpt->bEndpointAddress == ep)
@@ -486,10 +507,11 @@
}
}
}
- return -ENOENT;
+ return -ENOENT;
}
-static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
+static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
+ unsigned int index)
{
int ret = 0;
@@ -502,7 +524,8 @@
index &= 0xff;
switch (requesttype & USB_RECIP_MASK) {
case USB_RECIP_ENDPOINT:
- if ((ret = findintfep(ps->dev, index)) >= 0)
+ ret = findintfep(ps->dev, index);
+ if (ret >= 0)
ret = checkintf(ps, ret);
break;
@@ -546,7 +569,8 @@
mutex_lock(&usbfs_mutex);
ret = -ENOMEM;
- if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
+ ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
+ if (!ps)
goto out;
ret = -ENOENT;
@@ -627,15 +651,18 @@
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
- if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
+ ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
+ if (ret)
return ret;
if (ctrl.wLength > PAGE_SIZE)
return -EINVAL;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+ if (!tbuf)
return -ENOMEM;
tmo = ctrl.timeout;
if (ctrl.bRequestType & 0x80) {
- if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
+ if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
+ ctrl.wLength)) {
free_page((unsigned long)tbuf);
return -EINVAL;
}
@@ -646,14 +673,15 @@
ctrl.wIndex, ctrl.wLength);
usb_unlock_device(dev);
- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
- ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
+ i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest,
+ ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+ tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
if ((i > 0) && ctrl.wLength) {
if (usbfs_snoop) {
dev_info(&dev->dev, "control read: data ");
for (j = 0; j < i; ++j)
- printk("%02x ", (unsigned char)(tbuf)[j]);
+ printk("%02x ", (u8)(tbuf)[j]);
printk("\n");
}
if (copy_to_user(ctrl.data, tbuf, i)) {
@@ -680,12 +708,13 @@
printk("\n");
}
usb_unlock_device(dev);
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
- ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
+ i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
+ ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+ tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
}
free_page((unsigned long)tbuf);
- if (i<0 && i != -EPIPE) {
+ if (i < 0 && i != -EPIPE) {
dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
"failed cmd %s rqt %u rq %u len %u ret %d\n",
current->comm, ctrl.bRequestType, ctrl.bRequest,
@@ -705,9 +734,11 @@
if (copy_from_user(&bulk, arg, sizeof(bulk)))
return -EFAULT;
- if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
+ ret = findintfep(ps->dev, bulk.ep);
+ if (ret < 0)
return ret;
- if ((ret = checkintf(ps, ret)))
+ ret = checkintf(ps, ret);
+ if (ret)
return ret;
if (bulk.ep & USB_DIR_IN)
pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
@@ -735,7 +766,7 @@
if (usbfs_snoop) {
dev_info(&dev->dev, "bulk read: data ");
for (j = 0; j < len2; ++j)
- printk("%02x ", (unsigned char)(tbuf)[j]);
+ printk("%02x ", (u8)(tbuf)[j]);
printk("\n");
}
if (copy_to_user(bulk.data, tbuf, len2)) {
@@ -775,9 +806,11 @@
if (get_user(ep, (unsigned int __user *)arg))
return -EFAULT;
- if ((ret = findintfep(ps->dev, ep)) < 0)
+ ret = findintfep(ps->dev, ep);
+ if (ret < 0)
return ret;
- if ((ret = checkintf(ps, ret)))
+ ret = checkintf(ps, ret);
+ if (ret)
return ret;
usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
return 0;
@@ -791,18 +824,19 @@
if (get_user(ep, (unsigned int __user *)arg))
return -EFAULT;
- if ((ret = findintfep(ps->dev, ep)) < 0)
+ ret = findintfep(ps->dev, ep);
+ if (ret < 0)
return ret;
- if ((ret = checkintf(ps, ret)))
+ ret = checkintf(ps, ret);
+ if (ret)
return ret;
if (ep & USB_DIR_IN)
- pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
- else
- pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+ pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
return usb_clear_halt(ps->dev, pipe);
}
-
static int proc_getdriver(struct dev_state *ps, void __user *arg)
{
@@ -856,23 +890,23 @@
{
int u;
int status = 0;
- struct usb_host_config *actconfig;
+ struct usb_host_config *actconfig;
if (get_user(u, (int __user *)arg))
return -EFAULT;
- actconfig = ps->dev->actconfig;
-
- /* Don't touch the device if any interfaces are claimed.
- * It could interfere with other drivers' operations, and if
+ actconfig = ps->dev->actconfig;
+
+ /* Don't touch the device if any interfaces are claimed.
+ * It could interfere with other drivers' operations, and if
* an interface is claimed by usbfs it could easily deadlock.
*/
- if (actconfig) {
- int i;
-
- for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
- if (usb_interface_claimed(actconfig->interface[i])) {
- dev_warn (&ps->dev->dev,
+ if (actconfig) {
+ int i;
+
+ for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
+ if (usb_interface_claimed(actconfig->interface[i])) {
+ dev_warn(&ps->dev->dev,
"usbfs: interface %d claimed by %s "
"while '%s' sets config #%d\n",
actconfig->interface[i]
@@ -881,11 +915,11 @@
actconfig->interface[i]
->dev.driver->name,
current->comm, u);
- status = -EBUSY;
+ status = -EBUSY;
break;
}
- }
- }
+ }
+ }
/* SET_CONFIGURATION is often abused as a "cheap" driver reset,
* so avoid usb_set_configuration()'s kick to sysfs
@@ -901,8 +935,8 @@
}
static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
- struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
- void __user *arg)
+ struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
+ void __user *arg)
{
struct usbdevfs_iso_packet_desc *isopkt = NULL;
struct usb_host_endpoint *ep;
@@ -917,12 +951,16 @@
return -EINVAL;
if (!uurb->buffer)
return -EINVAL;
- if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX))
+ if (uurb->signr != 0 && (uurb->signr < SIGRTMIN ||
+ uurb->signr > SIGRTMAX))
return -EINVAL;
- if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
- if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0)
+ if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
+ (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+ ifnum = findintfep(ps->dev, uurb->endpoint);
+ if (ifnum < 0)
return ifnum;
- if ((ret = checkintf(ps, ifnum)))
+ ret = checkintf(ps, ifnum);
+ if (ret)
return ret;
}
if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
@@ -938,10 +976,13 @@
case USBDEVFS_URB_TYPE_CONTROL:
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
- /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
- if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
+ /* min 8 byte setup packet,
+ * max 8 byte setup plus an arbitrary data stage */
+ if (uurb->buffer_length < 8 ||
+ uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
return -EINVAL;
- if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr)
return -ENOMEM;
if (copy_from_user(dr, uurb->buffer, 8)) {
kfree(dr);
@@ -951,7 +992,9 @@
kfree(dr);
return -EINVAL;
}
- if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
+ ret = check_ctrlrecip(ps, dr->bRequestType,
+ le16_to_cpup(&dr->wIndex));
+ if (ret) {
kfree(dr);
return ret;
}
@@ -997,11 +1040,13 @@
case USBDEVFS_URB_TYPE_ISO:
/* arbitrary limit */
- if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
+ if (uurb->number_of_packets < 1 ||
+ uurb->number_of_packets > 128)
return -EINVAL;
if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
- isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
+ isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
+ uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
return -ENOMEM;
if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
@@ -1009,7 +1054,8 @@
return -EFAULT;
}
for (totlen = u = 0; u < uurb->number_of_packets; u++) {
- /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */
+ /* arbitrary limit,
+ * sufficient for USB 2.0 high-bandwidth iso */
if (isopkt[u].length > 8192) {
kfree(isopkt);
return -EINVAL;
@@ -1039,25 +1085,27 @@
default:
return -EINVAL;
}
- if (!(as = alloc_async(uurb->number_of_packets))) {
+ as = alloc_async(uurb->number_of_packets);
+ if (!as) {
kfree(isopkt);
kfree(dr);
return -ENOMEM;
}
- if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) {
+ as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL);
+ if (!as->urb->transfer_buffer) {
kfree(isopkt);
kfree(dr);
free_async(as);
return -ENOMEM;
}
- as->urb->dev = ps->dev;
- as->urb->pipe = (uurb->type << 30) |
+ as->urb->dev = ps->dev;
+ as->urb->pipe = (uurb->type << 30) |
__create_pipe(ps->dev, uurb->endpoint & 0xf) |
(uurb->endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb->flags |
+ as->urb->transfer_flags = uurb->flags |
(is_in ? URB_DIR_IN : URB_DIR_OUT);
as->urb->transfer_buffer_length = uurb->buffer_length;
- as->urb->setup_packet = (unsigned char*)dr;
+ as->urb->setup_packet = (unsigned char *)dr;
as->urb->start_frame = uurb->start_frame;
as->urb->number_of_packets = uurb->number_of_packets;
if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
@@ -1065,8 +1113,8 @@
as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
else
as->urb->interval = ep->desc.bInterval;
- as->urb->context = as;
- as->urb->complete = async_completed;
+ as->urb->context = as;
+ as->urb->complete = async_completed;
for (totlen = u = 0; u < uurb->number_of_packets; u++) {
as->urb->iso_frame_desc[u].offset = totlen;
as->urb->iso_frame_desc[u].length = isopkt[u].length;
@@ -1074,7 +1122,7 @@
}
kfree(isopkt);
as->ps = ps;
- as->userurb = arg;
+ as->userurb = arg;
if (uurb->endpoint & USB_DIR_IN)
as->userbuffer = uurb->buffer;
else
@@ -1093,14 +1141,15 @@
}
}
snoop_urb(as->urb, as->userurb);
- async_newpending(as);
- if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
- dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
- async_removepending(as);
- free_async(as);
- return ret;
- }
- return 0;
+ async_newpending(as);
+ if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
+ dev_printk(KERN_DEBUG, &ps->dev->dev,
+ "usbfs: usb_submit_urb returned %d\n", ret);
+ async_removepending(as);
+ free_async(as);
+ return ret;
+ }
+ return 0;
}
static int proc_submiturb(struct dev_state *ps, void __user *arg)
@@ -1110,7 +1159,9 @@
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
+ return proc_do_submiturb(ps, &uurb,
+ (((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
+ arg);
}
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
@@ -1132,7 +1183,8 @@
unsigned int i;
if (as->userbuffer)
- if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer,
+ urb->transfer_buffer_length))
return -EFAULT;
if (put_user(as->status, &userurb->status))
return -EFAULT;
@@ -1159,16 +1211,17 @@
return 0;
}
-static struct async* reap_as(struct dev_state *ps)
+static struct async *reap_as(struct dev_state *ps)
{
- DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAITQUEUE(wait, current);
struct async *as = NULL;
struct usb_device *dev = ps->dev;
add_wait_queue(&ps->wait, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
- if ((as = async_getcompleted(ps)))
+ as = async_getcompleted(ps);
+ if (as)
break;
if (signal_pending(current))
break;
@@ -1232,10 +1285,12 @@
{
struct usbdevfs_urb uurb;
- if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg))
+ if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
+ return proc_do_submiturb(ps, &uurb,
+ ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
+ arg);
}
static int processcompl_compat(struct async *as, void __user * __user *arg)
@@ -1246,7 +1301,8 @@
unsigned int i;
if (as->userbuffer)
- if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer,
+ urb->transfer_buffer_length))
return -EFAULT;
if (put_user(as->status, &userurb->status))
return -EFAULT;
@@ -1337,16 +1393,16 @@
struct usb_driver *driver = NULL;
/* alloc buffer */
- if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) {
- if ((buf = kmalloc (size, GFP_KERNEL)) == NULL)
+ if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
+ if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
return -ENOMEM;
if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
- if (copy_from_user (buf, ctl->data, size)) {
+ if (copy_from_user(buf, ctl->data, size)) {
kfree(buf);
return -EFAULT;
}
} else {
- memset (buf, 0, size);
+ memset(buf, 0, size);
}
}
@@ -1357,15 +1413,15 @@
if (ps->dev->state != USB_STATE_CONFIGURED)
retval = -EHOSTUNREACH;
- else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno)))
- retval = -EINVAL;
+ else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
+ retval = -EINVAL;
else switch (ctl->ioctl_code) {
/* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT:
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
- dev_dbg (&intf->dev, "disconnect by usbfs\n");
+ dev_dbg(&intf->dev, "disconnect by usbfs\n");
usb_driver_release_interface(driver, intf);
} else
retval = -ENODATA;
@@ -1373,9 +1429,10 @@
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
- usb_unlock_device(ps->dev);
- retval = bus_rescan_devices(intf->dev.bus);
- usb_lock_device(ps->dev);
+ if (!intf->dev.driver)
+ retval = device_attach(&intf->dev);
+ else
+ retval = -EBUSY;
break;
/* talk directly to the interface's driver */
@@ -1385,7 +1442,7 @@
if (driver == NULL || driver->ioctl == NULL) {
retval = -ENOTTY;
} else {
- retval = driver->ioctl (intf, ctl->ioctl_code, buf);
+ retval = driver->ioctl(intf, ctl->ioctl_code, buf);
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
}
@@ -1393,9 +1450,9 @@
/* cleanup and return */
if (retval >= 0
- && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0
+ && (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
&& size > 0
- && copy_to_user (ctl->data, buf, size) != 0)
+ && copy_to_user(ctl->data, buf, size) != 0)
retval = -EFAULT;
kfree(buf);
@@ -1406,7 +1463,7 @@
{
struct usbdevfs_ioctl ctrl;
- if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
+ if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
return proc_ioctl(ps, &ctrl);
}
@@ -1434,7 +1491,8 @@
* are assuming that somehow the configuration has been prevented from
* changing. But there's no mechanism to ensure that...
*/
-static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int usbdev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
@@ -1577,7 +1635,8 @@
}
/* No kernel lock - fine */
-static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int usbdev_poll(struct file *file,
+ struct poll_table_struct *wait)
{
struct dev_state *ps = file->private_data;
unsigned int mask = 0;
@@ -1648,7 +1707,7 @@
int retval;
retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
- "usb_device");
+ "usb_device");
if (retval) {
err("unable to register minors for usb_device");
goto out;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 7c3aaa9..801b6f1 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -202,10 +202,10 @@
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
- if (udev->authorized == 0) {
- dev_err(&intf->dev, "Device is not authorized for usage\n");
- return -ENODEV;
- }
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+ return -ENODEV;
+ }
id = usb_match_id(intf, driver->id_table);
if (!id)
@@ -299,7 +299,7 @@
* lock.
*/
int usb_driver_claim_interface(struct usb_driver *driver,
- struct usb_interface *iface, void* priv)
+ struct usb_interface *iface, void *priv)
{
struct device *dev = &iface->dev;
struct usb_device *udev = interface_to_usbdev(iface);
@@ -325,7 +325,7 @@
return retval;
}
-EXPORT_SYMBOL(usb_driver_claim_interface);
+EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
/**
* usb_driver_release_interface - unbind a driver from an interface
@@ -370,7 +370,7 @@
iface->needs_remote_wakeup = 0;
usb_pm_unlock(udev);
}
-EXPORT_SYMBOL(usb_driver_release_interface);
+EXPORT_SYMBOL_GPL(usb_driver_release_interface);
/* returns 0 if no match, 1 if match */
int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
@@ -398,7 +398,7 @@
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
- (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
@@ -534,15 +534,15 @@
id->driver_info is the way to create an entry that
indicates that the driver want to examine every
device and interface. */
- for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
- id->driver_info; id++) {
+ for (; id->idVendor || id->idProduct || id->bDeviceClass ||
+ id->bInterfaceClass || id->driver_info; id++) {
if (usb_match_one_id(interface, id))
return id;
}
return NULL;
}
-EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
+EXPORT_SYMBOL_GPL(usb_match_id);
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
@@ -586,7 +586,7 @@
struct usb_device *usb_dev;
/* driver is often null here; dev_dbg() would oops */
- pr_debug ("usb %s: uevent\n", dev->bus_id);
+ pr_debug("usb %s: uevent\n", dev->bus_id);
if (is_usb_device(dev))
usb_dev = to_usb_device(dev);
@@ -596,11 +596,11 @@
}
if (usb_dev->devnum < 0) {
- pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+ pr_debug("usb %s: already deleted?\n", dev->bus_id);
return -ENODEV;
}
if (!usb_dev->bus) {
- pr_debug ("usb %s: bus removed?\n", dev->bus_id);
+ pr_debug("usb %s: bus removed?\n", dev->bus_id);
return -ENODEV;
}
@@ -745,7 +745,7 @@
return retval;
}
-EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
+EXPORT_SYMBOL_GPL(usb_register_driver);
/**
* usb_deregister - unregister a USB interface driver
@@ -769,7 +769,7 @@
usbfs_update_special();
}
-EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
+EXPORT_SYMBOL_GPL(usb_deregister);
#ifdef CONFIG_PM
@@ -854,8 +854,10 @@
dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
} else {
- // FIXME else if there's no suspend method, disconnect...
- // Not possible if auto_pm is set...
+ /*
+ * FIXME else if there's no suspend method, disconnect...
+ * Not possible if auto_pm is set...
+ */
dev_warn(&intf->dev, "no suspend for driver %s?\n",
driver->name);
mark_quiesced(intf);
@@ -894,7 +896,7 @@
dev_err(&intf->dev, "%s error %d\n",
"reset_resume", status);
} else {
- // status = -EOPNOTSUPP;
+ /* status = -EOPNOTSUPP; */
dev_warn(&intf->dev, "no %s for driver %s?\n",
"reset_resume", driver->name);
}
@@ -905,7 +907,7 @@
dev_err(&intf->dev, "%s error %d\n",
"resume", status);
} else {
- // status = -EOPNOTSUPP;
+ /* status = -EOPNOTSUPP; */
dev_warn(&intf->dev, "no %s for driver %s?\n",
"resume", driver->name);
}
@@ -1175,7 +1177,7 @@
* so if a root hub's controller is suspended
* then we're stuck. */
status = usb_resume_device(udev);
- }
+ }
} else {
/* Needed for setting udev->dev.power.power_state.event,
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 5d860bc..8133c99 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -204,7 +204,7 @@
exit:
return retval;
}
-EXPORT_SYMBOL(usb_register_dev);
+EXPORT_SYMBOL_GPL(usb_register_dev);
/**
* usb_deregister_dev - deregister a USB device's dynamic minor.
@@ -245,4 +245,4 @@
intf->minor = -1;
destroy_usb_class();
}
-EXPORT_SYMBOL(usb_deregister_dev);
+EXPORT_SYMBOL_GPL(usb_deregister_dev);
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 3fb9af8..84760dd 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -1,6 +1,6 @@
/*
* (C) Copyright David Brownell 2000-2002
- *
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -55,7 +55,7 @@
*
* Store this function in the HCD's struct pci_driver as probe().
*/
-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct hc_driver *driver;
struct usb_hcd *hcd;
@@ -64,66 +64,71 @@
if (usb_disabled())
return -ENODEV;
- if (!id || !(driver = (struct hc_driver *) id->driver_data))
+ if (!id)
+ return -EINVAL;
+ driver = (struct hc_driver *)id->driver_data;
+ if (!driver)
return -EINVAL;
- if (pci_enable_device (dev) < 0)
+ if (pci_enable_device(dev) < 0)
return -ENODEV;
dev->current_state = PCI_D0;
dev->dev.power.power_state = PMSG_ON;
-
- if (!dev->irq) {
- dev_err (&dev->dev,
+
+ if (!dev->irq) {
+ dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
- retval = -ENODEV;
+ retval = -ENODEV;
goto err1;
- }
+ }
- hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev));
+ hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
if (!hcd) {
retval = -ENOMEM;
goto err1;
}
- if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
- hcd->rsrc_start = pci_resource_start (dev, 0);
- hcd->rsrc_len = pci_resource_len (dev, 0);
- if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,
+ if (driver->flags & HCD_MEMORY) {
+ /* EHCI, OHCI */
+ hcd->rsrc_start = pci_resource_start(dev, 0);
+ hcd->rsrc_len = pci_resource_len(dev, 0);
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
- dev_dbg (&dev->dev, "controller already in use\n");
+ dev_dbg(&dev->dev, "controller already in use\n");
retval = -EBUSY;
goto err2;
}
- hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
- dev_dbg (&dev->dev, "error mapping memory\n");
+ dev_dbg(&dev->dev, "error mapping memory\n");
retval = -EFAULT;
goto err3;
}
- } else { // UHCI
+ } else {
+ /* UHCI */
int region;
for (region = 0; region < PCI_ROM_RESOURCE; region++) {
- if (!(pci_resource_flags (dev, region) &
+ if (!(pci_resource_flags(dev, region) &
IORESOURCE_IO))
continue;
- hcd->rsrc_start = pci_resource_start (dev, region);
- hcd->rsrc_len = pci_resource_len (dev, region);
- if (request_region (hcd->rsrc_start, hcd->rsrc_len,
+ hcd->rsrc_start = pci_resource_start(dev, region);
+ hcd->rsrc_len = pci_resource_len(dev, region);
+ if (request_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description))
break;
}
if (region == PCI_ROM_RESOURCE) {
- dev_dbg (&dev->dev, "no i/o regions available\n");
+ dev_dbg(&dev->dev, "no i/o regions available\n");
retval = -EBUSY;
goto err1;
}
}
- pci_set_master (dev);
+ pci_set_master(dev);
retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
@@ -132,19 +137,19 @@
err4:
if (driver->flags & HCD_MEMORY) {
- iounmap (hcd->regs);
+ iounmap(hcd->regs);
err3:
- release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else
- release_region (hcd->rsrc_start, hcd->rsrc_len);
+ release_region(hcd->rsrc_start, hcd->rsrc_len);
err2:
- usb_put_hcd (hcd);
+ usb_put_hcd(hcd);
err1:
- pci_disable_device (dev);
- dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
+ pci_disable_device(dev);
+ dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_probe);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
/* may be called without controller electrically present */
@@ -161,7 +166,7 @@
*
* Store this function in the HCD's struct pci_driver as remove().
*/
-void usb_hcd_pci_remove (struct pci_dev *dev)
+void usb_hcd_pci_remove(struct pci_dev *dev)
{
struct usb_hcd *hcd;
@@ -169,17 +174,17 @@
if (!hcd)
return;
- usb_remove_hcd (hcd);
+ usb_remove_hcd(hcd);
if (hcd->driver->flags & HCD_MEMORY) {
- iounmap (hcd->regs);
- release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else {
- release_region (hcd->rsrc_start, hcd->rsrc_len);
+ release_region(hcd->rsrc_start, hcd->rsrc_len);
}
- usb_put_hcd (hcd);
+ usb_put_hcd(hcd);
pci_disable_device(dev);
}
-EXPORT_SYMBOL (usb_hcd_pci_remove);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
#ifdef CONFIG_PM
@@ -191,7 +196,7 @@
*
* Store this function in the HCD's struct pci_driver as suspend().
*/
-int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
+int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
{
struct usb_hcd *hcd;
int retval = 0;
@@ -246,12 +251,18 @@
/* no DMA or IRQs except when HC is active */
if (dev->current_state == PCI_D0) {
- pci_save_state (dev);
- pci_disable_device (dev);
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ }
+
+ if (message.event == PM_EVENT_FREEZE ||
+ message.event == PM_EVENT_PRETHAW) {
+ dev_dbg(hcd->self.controller, "--> no state change\n");
+ goto done;
}
if (!has_pci_pm) {
- dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
+ dev_dbg(hcd->self.controller, "--> PCI D0/legacy\n");
goto done;
}
@@ -260,30 +271,30 @@
* PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
* some device state (e.g. as part of clock reinit).
*/
- retval = pci_set_power_state (dev, PCI_D3hot);
+ retval = pci_set_power_state(dev, PCI_D3hot);
suspend_report_result(pci_set_power_state, retval);
if (retval == 0) {
int wake = device_can_wakeup(&hcd->self.root_hub->dev);
wake = wake && device_may_wakeup(hcd->self.controller);
- dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
+ dev_dbg(hcd->self.controller, "--> PCI D3%s\n",
wake ? "/wakeup" : "");
/* Ignore these return values. We rely on pci code to
* reject requests the hardware can't implement, rather
* than coding the same thing.
*/
- (void) pci_enable_wake (dev, PCI_D3hot, wake);
- (void) pci_enable_wake (dev, PCI_D3cold, wake);
+ (void) pci_enable_wake(dev, PCI_D3hot, wake);
+ (void) pci_enable_wake(dev, PCI_D3cold, wake);
} else {
- dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
+ dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
retval);
- (void) usb_hcd_pci_resume (dev);
+ (void) usb_hcd_pci_resume(dev);
}
} else if (hcd->state != HC_STATE_HALT) {
- dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
+ dev_dbg(hcd->self.controller, "hcd state %d; not suspended\n",
hcd->state);
WARN_ON(1);
retval = -EINVAL;
@@ -298,7 +309,7 @@
if (machine_is(powermac)) {
struct device_node *of_node;
- of_node = pci_device_to_OF_node (dev);
+ of_node = pci_device_to_OF_node(dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 0);
@@ -308,7 +319,7 @@
return retval;
}
-EXPORT_SYMBOL (usb_hcd_pci_suspend);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
/**
* usb_hcd_pci_resume - power management resume of a PCI-based HCD
@@ -316,14 +327,14 @@
*
* Store this function in the HCD's struct pci_driver as resume().
*/
-int usb_hcd_pci_resume (struct pci_dev *dev)
+int usb_hcd_pci_resume(struct pci_dev *dev)
{
struct usb_hcd *hcd;
int retval;
hcd = pci_get_drvdata(dev);
if (hcd->state != HC_STATE_SUSPENDED) {
- dev_dbg (hcd->self.controller,
+ dev_dbg(hcd->self.controller,
"can't resume, not suspended!\n");
return 0;
}
@@ -333,9 +344,9 @@
if (machine_is(powermac)) {
struct device_node *of_node;
- of_node = pci_device_to_OF_node (dev);
+ of_node = pci_device_to_OF_node(dev);
if (of_node)
- pmac_call_feature (PMAC_FTR_USB_ENABLE,
+ pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 1);
}
#endif
@@ -374,8 +385,8 @@
}
#endif
/* yes, ignore these results too... */
- (void) pci_enable_wake (dev, dev->current_state, 0);
- (void) pci_enable_wake (dev, PCI_D3cold, 0);
+ (void) pci_enable_wake(dev, dev->current_state, 0);
+ (void) pci_enable_wake(dev, PCI_D3cold, 0);
} else {
/* Same basic cases: clean (powered/not), dirty */
dev_dbg(hcd->self.controller, "PCI legacy resume\n");
@@ -386,14 +397,14 @@
* but that won't re-enable bus mastering. Yet pci_disable_device()
* explicitly disables bus mastering...
*/
- retval = pci_enable_device (dev);
+ retval = pci_enable_device(dev);
if (retval < 0) {
- dev_err (hcd->self.controller,
+ dev_err(hcd->self.controller,
"can't re-enable after resume, %d!\n", retval);
return retval;
}
- pci_set_master (dev);
- pci_restore_state (dev);
+ pci_set_master(dev);
+ pci_restore_state(dev);
dev->dev.power.power_state = PMSG_ON;
@@ -402,15 +413,15 @@
if (hcd->driver->resume) {
retval = hcd->driver->resume(hcd);
if (retval) {
- dev_err (hcd->self.controller,
+ dev_err(hcd->self.controller,
"PCI post-resume error %d!\n", retval);
- usb_hc_died (hcd);
+ usb_hc_died(hcd);
}
}
return retval;
}
-EXPORT_SYMBOL (usb_hcd_pci_resume);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
#endif /* CONFIG_PM */
@@ -418,7 +429,7 @@
* usb_hcd_pci_shutdown - shutdown host controller
* @dev: USB Host Controller being shutdown
*/
-void usb_hcd_pci_shutdown (struct pci_dev *dev)
+void usb_hcd_pci_shutdown(struct pci_dev *dev)
{
struct usb_hcd *hcd;
@@ -429,5 +440,5 @@
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
-EXPORT_SYMBOL (usb_hcd_pci_shutdown);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index d5ed3fa..e52ed16 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -35,6 +35,7 @@
#include <linux/mutex.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
@@ -131,8 +132,8 @@
0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
- 0x00, 0x00, /* __le16 idVendor; */
- 0x00, 0x00, /* __le16 idProduct; */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x02, 0x00, /* __le16 idProduct; device 0x0002 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
@@ -154,8 +155,8 @@
0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
- 0x00, 0x00, /* __le16 idVendor; */
- 0x00, 0x00, /* __le16 idProduct; */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x01, 0x00, /* __le16 idProduct; device 0x0001 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
@@ -807,13 +808,13 @@
}
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
- bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
- bus->controller, "usb_host%d",
- busnum);
- result = PTR_ERR(bus->class_dev);
- if (IS_ERR(bus->class_dev))
+
+ bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
+ "usb_host%d", busnum);
+ result = PTR_ERR(bus->dev);
+ if (IS_ERR(bus->dev))
goto error_create_class_dev;
- class_set_devdata(bus->class_dev, bus);
+ dev_set_drvdata(bus->dev, bus);
/* Add it to the local list of buses */
list_add (&bus->bus_list, &usb_bus_list);
@@ -857,7 +858,7 @@
clear_bit (bus->busnum, busmap.busmap);
- class_device_unregister(bus->class_dev);
+ device_unregister(bus->dev);
}
/**
@@ -970,7 +971,7 @@
return -1;
}
}
-EXPORT_SYMBOL (usb_calc_bus_time);
+EXPORT_SYMBOL_GPL(usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
@@ -1112,48 +1113,177 @@
}
EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
-static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+/*
+ * Some usb host controllers can only perform dma using a small SRAM area.
+ * The usb core itself is however optimized for host controllers that can dma
+ * using regular system memory - like pci devices doing bus mastering.
+ *
+ * To support host controllers with limited dma capabilites we provide dma
+ * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
+ * For this to work properly the host controller code must first use the
+ * function dma_declare_coherent_memory() to point out which memory area
+ * that should be used for dma allocations.
+ *
+ * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
+ * dma using dma_alloc_coherent() which in turn allocates from the memory
+ * area pointed out with dma_declare_coherent_memory().
+ *
+ * So, to summarize...
+ *
+ * - We need "local" memory, canonical example being
+ * a small SRAM on a discrete controller being the
+ * only memory that the controller can read ...
+ * (a) "normal" kernel memory is no good, and
+ * (b) there's not enough to share
+ *
+ * - The only *portable* hook for such stuff in the
+ * DMA framework is dma_declare_coherent_memory()
+ *
+ * - So we use that, even though the primary requirement
+ * is that the memory be "local" (hence addressible
+ * by that device), not "coherent".
+ *
+ */
+
+static int hcd_alloc_coherent(struct usb_bus *bus,
+ gfp_t mem_flags, dma_addr_t *dma_handle,
+ void **vaddr_handle, size_t size,
+ enum dma_data_direction dir)
{
+ unsigned char *vaddr;
+
+ vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
+ mem_flags, dma_handle);
+ if (!vaddr)
+ return -ENOMEM;
+
+ /*
+ * Store the virtual address of the buffer at the end
+ * of the allocated dma buffer. The size of the buffer
+ * may be uneven so use unaligned functions instead
+ * of just rounding up. It makes sense to optimize for
+ * memory footprint over access speed since the amount
+ * of memory available for dma may be limited.
+ */
+ put_unaligned((unsigned long)*vaddr_handle,
+ (unsigned long *)(vaddr + size));
+
+ if (dir == DMA_TO_DEVICE)
+ memcpy(vaddr, *vaddr_handle, size);
+
+ *vaddr_handle = vaddr;
+ return 0;
+}
+
+static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
+ void **vaddr_handle, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned char *vaddr = *vaddr_handle;
+
+ vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size));
+
+ if (dir == DMA_FROM_DEVICE)
+ memcpy(vaddr, *vaddr_handle, size);
+
+ hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle);
+
+ *vaddr_handle = vaddr;
+ *dma_handle = 0;
+}
+
+static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ enum dma_data_direction dir;
+ int ret = 0;
+
/* Map the URB's buffers for DMA access.
* Lower level HCD code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
- if (usb_endpoint_xfer_control(&urb->ep->desc)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- urb->setup_dma = dma_map_single (
+ if (is_root_hub(urb->dev))
+ return 0;
+
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
+ if (hcd->self.uses_dma)
+ urb->setup_dma = dma_map_single(
hcd->self.controller,
urb->setup_packet,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ else if (hcd->driver->flags & HCD_LOCAL_MEM)
+ ret = hcd_alloc_coherent(
+ urb->dev->bus, mem_flags,
+ &urb->setup_dma,
+ (void **)&urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ }
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ if (ret == 0 && urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+ if (hcd->self.uses_dma)
urb->transfer_dma = dma_map_single (
hcd->self.controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
- usb_urb_dir_in(urb)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
+ dir);
+ else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+ ret = hcd_alloc_coherent(
+ urb->dev->bus, mem_flags,
+ &urb->transfer_dma,
+ &urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
+
+ if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ hcd_free_coherent(urb->dev->bus,
+ &urb->setup_dma,
+ (void **)&urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ }
}
+ return ret;
}
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
- if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
- if (usb_endpoint_xfer_control(&urb->ep->desc)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ enum dma_data_direction dir;
+
+ if (is_root_hub(urb->dev))
+ return;
+
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
+ if (hcd->self.uses_dma)
dma_unmap_single(hcd->self.controller, urb->setup_dma,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ else if (hcd->driver->flags & HCD_LOCAL_MEM)
+ hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
+ (void **)&urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ }
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ if (urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+ if (hcd->self.uses_dma)
dma_unmap_single(hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
- usb_urb_dir_in(urb)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
+ dir);
+ else if (hcd->driver->flags & HCD_LOCAL_MEM)
+ hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
+ &urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ dir);
}
}
@@ -1185,7 +1315,12 @@
* URBs must be submitted in process context with interrupts
* enabled.
*/
- map_urb_for_dma(hcd, urb);
+ status = map_urb_for_dma(hcd, urb, mem_flags);
+ if (unlikely(status)) {
+ usbmon_urb_submit_error(&hcd->self, urb, status);
+ goto error;
+ }
+
if (is_root_hub(urb->dev))
status = rh_urb_enqueue(hcd, urb);
else
@@ -1194,6 +1329,7 @@
if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
unmap_urb_for_dma(hcd, urb);
+ error:
urb->hcpriv = NULL;
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
@@ -1291,7 +1427,7 @@
wake_up (&usb_kill_urb_queue);
usb_put_urb (urb);
}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
+EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/
@@ -1531,7 +1667,7 @@
mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10));
return status;
}
-EXPORT_SYMBOL (usb_bus_start_enum);
+EXPORT_SYMBOL_GPL(usb_bus_start_enum);
#endif
@@ -1638,7 +1774,7 @@
"USB Host Controller";
return hcd;
}
-EXPORT_SYMBOL (usb_create_hcd);
+EXPORT_SYMBOL_GPL(usb_create_hcd);
static void hcd_release (struct kref *kref)
{
@@ -1653,14 +1789,14 @@
kref_get (&hcd->kref);
return hcd;
}
-EXPORT_SYMBOL (usb_get_hcd);
+EXPORT_SYMBOL_GPL(usb_get_hcd);
void usb_put_hcd (struct usb_hcd *hcd)
{
if (hcd)
kref_put (&hcd->kref, hcd_release);
}
-EXPORT_SYMBOL (usb_put_hcd);
+EXPORT_SYMBOL_GPL(usb_put_hcd);
/**
* usb_add_hcd - finish generic HCD structure initialization and register
@@ -1786,7 +1922,7 @@
hcd_buffer_destroy(hcd);
return retval;
}
-EXPORT_SYMBOL (usb_add_hcd);
+EXPORT_SYMBOL_GPL(usb_add_hcd);
/**
* usb_remove_hcd - shutdown processing for generic HCDs
@@ -1828,7 +1964,7 @@
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
}
-EXPORT_SYMBOL (usb_remove_hcd);
+EXPORT_SYMBOL_GPL(usb_remove_hcd);
void
usb_hcd_platform_shutdown(struct platform_device* dev)
@@ -1838,7 +1974,7 @@
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
-EXPORT_SYMBOL (usb_hcd_platform_shutdown);
+EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 98e2419..2d1c3d5e 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -125,7 +125,7 @@
/* more shared queuing code would be good; it should support
* smarter scheduling, handle transaction translators, etc;
- * input size of periodic table to an interrupt scheduler.
+ * input size of periodic table to an interrupt scheduler.
* (ohci 32, uhci 1024, ehci 256/512/1024).
*/
@@ -133,16 +133,16 @@
* this structure.
*/
unsigned long hcd_priv[0]
- __attribute__ ((aligned (sizeof(unsigned long))));
+ __attribute__ ((aligned(sizeof(unsigned long))));
};
/* 2.4 does this a bit differently ... */
-static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
{
return &hcd->self;
}
-static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
+static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
{
return container_of(bus, struct usb_hcd, self);
}
@@ -165,6 +165,7 @@
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
+#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
@@ -201,15 +202,18 @@
struct usb_host_endpoint *ep);
/* root hub support */
- int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
- int (*hub_control) (struct usb_hcd *hcd,
+ int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
+ int (*hub_control) (struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
- int (*bus_suspend)(struct usb_hcd *);
- int (*bus_resume)(struct usb_hcd *);
- int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
- void (*hub_irq_enable)(struct usb_hcd *);
+ int (*bus_suspend)(struct usb_hcd *);
+ int (*bus_resume)(struct usb_hcd *);
+ int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
+ void (*hub_irq_enable)(struct usb_hcd *);
/* Needed only if port-change IRQs are level-triggered */
+
+ /* force handover of high-speed port to full-speed companion */
+ void (*relinquish_port)(struct usb_hcd *, int);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -217,56 +221,56 @@
int status);
extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
-extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
-extern int usb_hcd_unlink_urb (struct urb *urb, int status);
+extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags);
+extern int usb_hcd_unlink_urb(struct urb *urb, int status);
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
extern void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
-extern int usb_hcd_get_frame_number (struct usb_device *udev);
+extern int usb_hcd_get_frame_number(struct usb_device *udev);
-extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
struct device *dev, char *bus_name);
-extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
-extern void usb_put_hcd (struct usb_hcd *hcd);
+extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd);
+extern void usb_put_hcd(struct usb_hcd *hcd);
extern int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags);
extern void usb_remove_hcd(struct usb_hcd *hcd);
struct platform_device;
-extern void usb_hcd_platform_shutdown(struct platform_device* dev);
+extern void usb_hcd_platform_shutdown(struct platform_device *dev);
#ifdef CONFIG_PCI
struct pci_dev;
struct pci_device_id;
-extern int usb_hcd_pci_probe (struct pci_dev *dev,
+extern int usb_hcd_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id);
-extern void usb_hcd_pci_remove (struct pci_dev *dev);
+extern void usb_hcd_pci_remove(struct pci_dev *dev);
#ifdef CONFIG_PM
-extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
-extern int usb_hcd_pci_resume (struct pci_dev *dev);
+extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t state);
+extern int usb_hcd_pci_resume(struct pci_dev *dev);
#endif /* CONFIG_PM */
-extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
+extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
#endif /* CONFIG_PCI */
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
-int hcd_buffer_create (struct usb_hcd *hcd);
-void hcd_buffer_destroy (struct usb_hcd *hcd);
+int hcd_buffer_create(struct usb_hcd *hcd);
+void hcd_buffer_destroy(struct usb_hcd *hcd);
-void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,
+void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
gfp_t mem_flags, dma_addr_t *dma);
-void hcd_buffer_free (struct usb_bus *bus, size_t size,
+void hcd_buffer_free(struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
/* generic bus glue, needed for host controllers that don't use PCI */
-extern irqreturn_t usb_hcd_irq (int irq, void *__hcd);
+extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
-extern void usb_hc_died (struct usb_hcd *hcd);
+extern void usb_hc_died(struct usb_hcd *hcd);
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */
@@ -319,9 +323,9 @@
* Generic bandwidth allocation constants/support
*/
#define FRAME_TIME_USECS 1000L
-#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
+#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
/* Trying not to use worst-case bit-stuffing
- of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+ * of (7/6 * 8 * bytecount) = 9.33 * bytecount */
/* bytecount = data payload byte count */
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
@@ -333,9 +337,9 @@
*/
#define BW_HOST_DELAY 1000L /* nanoseconds */
#define BW_HUB_LS_SETUP 333L /* nanoseconds */
- /* 4 full-speed bit times (est.) */
+ /* 4 full-speed bit times (est.) */
-#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */
+#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
@@ -345,16 +349,16 @@
* to preallocate bandwidth)
*/
#define USB2_HOST_DELAY 5 /* nsec, guess */
-#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \
+#define HS_NSECS(bytes) (((55 * 8 * 2083) \
+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ USB2_HOST_DELAY)
-#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \
+#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ USB2_HOST_DELAY)
#define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
#define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))
-extern long usb_calc_bus_time (int speed, int is_input,
+extern long usb_calc_bus_time(int speed, int is_input,
int isoc, int bytecount);
/*-------------------------------------------------------------------------*/
@@ -370,16 +374,16 @@
extern struct mutex usb_bus_list_lock;
extern wait_queue_head_t usb_kill_urb_queue;
-extern void usb_enable_root_hub_irq (struct usb_bus *bus);
+extern void usb_enable_root_hub_irq(struct usb_bus *bus);
-extern int usb_find_interface_driver (struct usb_device *dev,
+extern int usb_find_interface_driver(struct usb_device *dev,
struct usb_interface *interface);
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
-extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
-extern void usb_root_hub_lost_power (struct usb_device *rhdev);
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
+extern void usb_root_hub_lost_power(struct usb_device *rhdev);
extern int hcd_bus_suspend(struct usb_device *rhdev);
extern int hcd_bus_resume(struct usb_device *rhdev);
#else
@@ -399,13 +403,13 @@
* these are expected to be called from the USB core/hub thread
* with the kernel lock held
*/
-extern void usbfs_update_special (void);
+extern void usbfs_update_special(void);
extern int usbfs_init(void);
extern void usbfs_cleanup(void);
#else /* CONFIG_USB_DEVICEFS */
-static inline void usbfs_update_special (void) {}
+static inline void usbfs_update_special(void) {}
static inline int usbfs_init(void) { return 0; }
static inline void usbfs_cleanup(void) { }
@@ -460,7 +464,7 @@
/*-------------------------------------------------------------------------*/
/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
-// bleech -- resurfaced in 2.4.11 or 2.4.12
+/* bleech -- resurfaced in 2.4.11 or 2.4.12 */
#define bitmap DeviceRemovable
@@ -468,8 +472,8 @@
/* random stuff */
-#define RUN_CONTEXT (in_irq () ? "in_irq" \
- : (in_interrupt () ? "in_interrupt" : "can sleep"))
+#define RUN_CONTEXT (in_irq() ? "in_irq" \
+ : (in_interrupt() ? "in_interrupt" : "can sleep"))
/* This rwsem is for use only by the hub driver and ehci-hcd.
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b04d232..68fc521 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -37,6 +37,13 @@
#define USB_PERSIST 0
#endif
+/* if we are in debug mode, always announce new devices */
+#ifdef DEBUG
+#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#define CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#endif
+#endif
+
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
@@ -487,6 +494,7 @@
schedule_work (&tt->kevent);
spin_unlock_irqrestore (&tt->lock, flags);
}
+EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
static void hub_power_on(struct usb_hub *hub)
{
@@ -1027,8 +1035,10 @@
if (udev->children[i])
recursively_mark_NOTATTACHED(udev->children[i]);
}
- if (udev->state == USB_STATE_SUSPENDED)
+ if (udev->state == USB_STATE_SUSPENDED) {
udev->discon_suspended = 1;
+ udev->active_duration -= jiffies;
+ }
udev->state = USB_STATE_NOTATTACHED;
}
@@ -1077,6 +1087,12 @@
else
device_init_wakeup(&udev->dev, 0);
}
+ if (udev->state == USB_STATE_SUSPENDED &&
+ new_state != USB_STATE_SUSPENDED)
+ udev->active_duration -= jiffies;
+ else if (new_state == USB_STATE_SUSPENDED &&
+ udev->state != USB_STATE_SUSPENDED)
+ udev->active_duration += jiffies;
udev->state = new_state;
} else
recursively_mark_NOTATTACHED(udev);
@@ -1207,7 +1223,7 @@
put_device(&udev->dev);
}
-#ifdef DEBUG
+#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
static void show_string(struct usb_device *udev, char *id, char *string)
{
if (!string)
@@ -1215,12 +1231,24 @@
dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
}
+static void announce_device(struct usb_device *udev)
+{
+ dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+ dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, "
+ "SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
+}
#else
-static inline void show_string(struct usb_device *udev, char *id, char *string)
-{}
+static inline void announce_device(struct usb_device *udev) { }
#endif
-
#ifdef CONFIG_USB_OTG
#include "otg_whitelist.h"
#endif
@@ -1390,14 +1418,7 @@
}
/* Tell the world! */
- dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
- "SerialNumber=%d\n",
- udev->descriptor.iManufacturer,
- udev->descriptor.iProduct,
- udev->descriptor.iSerialNumber);
- show_string(udev, "Product", udev->product);
- show_string(udev, "Manufacturer", udev->manufacturer);
- show_string(udev, "SerialNumber", udev->serial);
+ announce_device(udev);
return err;
fail:
@@ -2482,6 +2503,7 @@
{
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
int status, i;
@@ -2645,6 +2667,8 @@
done:
hub_port_disable(hub, port1, 1);
+ if (hcd->driver->relinquish_port && !hub->hdev->parent)
+ hcd->driver->relinquish_port(hcd, port1);
}
static void hub_events(void)
@@ -2946,7 +2970,7 @@
if (len < le16_to_cpu(udev->config[index].desc.wTotalLength))
len = le16_to_cpu(udev->config[index].desc.wTotalLength);
}
- buf = kmalloc (len, GFP_KERNEL);
+ buf = kmalloc(len, GFP_NOIO);
if (buf == NULL) {
dev_err(&udev->dev, "no mem to re-read configs after reset\n");
/* assume the worst */
@@ -3093,7 +3117,7 @@
hub_port_logical_disconnect(parent_hub, port1);
return -ENODEV;
}
-EXPORT_SYMBOL(usb_reset_device);
+EXPORT_SYMBOL_GPL(usb_reset_device);
/**
* usb_reset_composite_device - warn interface drivers and perform a USB port reset
@@ -3110,16 +3134,12 @@
* this from a driver probe() routine after downloading new firmware.
* For calls that might not occur during probe(), drivers should lock
* the device using usb_lock_device_for_reset().
- *
- * The interface locks are acquired during the pre_reset stage and released
- * during the post_reset stage. However if iface is not NULL and is
- * currently being probed, we assume that the caller already owns its
- * lock.
*/
int usb_reset_composite_device(struct usb_device *udev,
struct usb_interface *iface)
{
int ret;
+ int i;
struct usb_host_config *config = udev->actconfig;
if (udev->state == USB_STATE_NOTATTACHED ||
@@ -3136,16 +3156,11 @@
iface = NULL;
if (config) {
- int i;
- struct usb_interface *cintf;
- struct usb_driver *drv;
-
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
- cintf = config->interface[i];
- if (cintf != iface)
- down(&cintf->dev.sem);
- if (device_is_registered(&cintf->dev) &&
- cintf->dev.driver) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
+
+ if (cintf->dev.driver) {
drv = to_usb_driver(cintf->dev.driver);
if (drv->pre_reset)
(drv->pre_reset)(cintf);
@@ -3157,25 +3172,20 @@
ret = usb_reset_device(udev);
if (config) {
- int i;
- struct usb_interface *cintf;
- struct usb_driver *drv;
-
for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
- cintf = config->interface[i];
- if (device_is_registered(&cintf->dev) &&
- cintf->dev.driver) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
+
+ if (cintf->dev.driver) {
drv = to_usb_driver(cintf->dev.driver);
if (drv->post_reset)
(drv->post_reset)(cintf);
/* FIXME: Unbind if post_reset returns an error or isn't defined */
}
- if (cintf != iface)
- up(&cintf->dev.sem);
}
}
usb_autosuspend_device(udev);
return ret;
}
-EXPORT_SYMBOL(usb_reset_composite_device);
+EXPORT_SYMBOL_GPL(usb_reset_composite_device);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index cf9559c..1551aed 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -55,16 +55,16 @@
#define USB_PORT_FEAT_TEST 21
#define USB_PORT_FEAT_INDICATOR 22
-/*
+/*
* Hub Status and Hub Change results
* See USB 2.0 spec Table 11-19 and Table 11-20
*/
struct usb_port_status {
__le16 wPortStatus;
- __le16 wPortChange;
+ __le16 wPortChange;
} __attribute__ ((packed));
-/*
+/*
* wPortStatus bit field
* See USB 2.0 spec Table 11-21
*/
@@ -81,7 +81,7 @@
#define USB_PORT_STAT_INDICATOR 0x1000
/* bits 13 to 15 are reserved */
-/*
+/*
* wPortChange bit field
* See USB 2.0 spec Table 11-22
* Bits 0 to 4 shown, bits 5 to 15 are reserved
@@ -93,7 +93,7 @@
#define USB_PORT_STAT_C_RESET 0x0010
/*
- * wHubCharacteristics (masks)
+ * wHubCharacteristics (masks)
* See USB 2.0 spec Table 11-13, offset 3
*/
#define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */
@@ -119,8 +119,8 @@
#define HUB_CHANGE_OVERCURRENT 0x0002
-/*
- * Hub descriptor
+/*
+ * Hub descriptor
* See USB 2.0 spec Table 11-13
*/
@@ -134,7 +134,7 @@
__le16 wHubCharacteristics;
__u8 bPwrOn2PwrGood;
__u8 bHubContrCurrent;
- /* add 1 bit for hub status change; round to bytes */
+ /* add 1 bit for hub status change; round to bytes */
__u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
__u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
} __attribute__ ((packed));
@@ -190,6 +190,6 @@
u16 devinfo;
};
-extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
+extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
#endif /* __LINUX_HUB_H */
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index cd4f111..83a373e 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -38,10 +38,15 @@
#include <linux/usbdevice_fs.h>
#include <linux/parser.h>
#include <linux/notifier.h>
+#include <linux/seq_file.h>
#include <asm/byteorder.h>
#include "usb.h"
#include "hcd.h"
+#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
+#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
+#define USBFS_DEFAULT_LISTMODE S_IRUGO
+
static struct super_operations usbfs_ops;
static const struct file_operations default_file_operations;
static struct vfsmount *usbfs_mount;
@@ -57,9 +62,33 @@
static gid_t devgid; /* = 0 */
static gid_t busgid; /* = 0 */
static gid_t listgid; /* = 0 */
-static umode_t devmode = S_IWUSR | S_IRUGO;
-static umode_t busmode = S_IXUGO | S_IRUGO;
-static umode_t listmode = S_IRUGO;
+static umode_t devmode = USBFS_DEFAULT_DEVMODE;
+static umode_t busmode = USBFS_DEFAULT_BUSMODE;
+static umode_t listmode = USBFS_DEFAULT_LISTMODE;
+
+static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+ if (devuid != 0)
+ seq_printf(seq, ",devuid=%u", devuid);
+ if (devgid != 0)
+ seq_printf(seq, ",devgid=%u", devgid);
+ if (devmode != USBFS_DEFAULT_DEVMODE)
+ seq_printf(seq, ",devmode=%o", devmode);
+ if (busuid != 0)
+ seq_printf(seq, ",busuid=%u", busuid);
+ if (busgid != 0)
+ seq_printf(seq, ",busgid=%u", busgid);
+ if (busmode != USBFS_DEFAULT_BUSMODE)
+ seq_printf(seq, ",busmode=%o", busmode);
+ if (listuid != 0)
+ seq_printf(seq, ",listuid=%u", listuid);
+ if (listgid != 0)
+ seq_printf(seq, ",listgid=%u", listgid);
+ if (listmode != USBFS_DEFAULT_LISTMODE)
+ seq_printf(seq, ",listmode=%o", listmode);
+
+ return 0;
+}
enum {
Opt_devuid, Opt_devgid, Opt_devmode,
@@ -93,9 +122,9 @@
devgid = 0;
busgid = 0;
listgid = 0;
- devmode = S_IWUSR | S_IRUGO;
- busmode = S_IXUGO | S_IRUGO;
- listmode = S_IRUGO;
+ devmode = USBFS_DEFAULT_DEVMODE;
+ busmode = USBFS_DEFAULT_BUSMODE;
+ listmode = USBFS_DEFAULT_LISTMODE;
while ((p = strsep(&data, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
@@ -418,6 +447,7 @@
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
.remount_fs = remount,
+ .show_options = usbfs_show_options,
};
static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index fcd40ec..fefb922 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -39,7 +39,7 @@
* own interruptible routines.
*/
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
-{
+{
struct api_context ctx;
unsigned long expire;
int retval;
@@ -74,9 +74,9 @@
}
/*-------------------------------------------------------------------*/
-// returns status (negative) or length (positive)
+/* returns status (negative) or length (positive) */
static int usb_internal_control_msg(struct usb_device *usb_dev,
- unsigned int pipe,
+ unsigned int pipe,
struct usb_ctrlrequest *cmd,
void *data, int len, int timeout)
{
@@ -87,7 +87,7 @@
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
-
+
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
@@ -99,47 +99,51 @@
}
/**
- * usb_control_msg - Builds a control urb, sends it off and waits for completion
- * @dev: pointer to the usb device to send the message to
- * @pipe: endpoint "pipe" to send the message to
- * @request: USB message request value
- * @requesttype: USB message request type value
- * @value: USB message value
- * @index: USB message index value
- * @data: pointer to the data to send
- * @size: length in bytes of the data to send
- * @timeout: time in msecs to wait for the message to complete before
- * timing out (if 0 the wait is forever)
- * Context: !in_interrupt ()
+ * usb_control_msg - Builds a control urb, sends it off and waits for completion
+ * @dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @request: USB message request value
+ * @requesttype: USB message request type value
+ * @value: USB message value
+ * @index: USB message index value
+ * @data: pointer to the data to send
+ * @size: length in bytes of the data to send
+ * @timeout: time in msecs to wait for the message to complete before timing
+ * out (if 0 the wait is forever)
*
- * This function sends a simple control message to a specified endpoint
- * and waits for the message to complete, or timeout.
- *
- * If successful, it returns the number of bytes transferred, otherwise a negative error number.
+ * Context: !in_interrupt ()
*
- * Don't use this function from within an interrupt context, like a
- * bottom half handler. If you need an asynchronous message, or need to send
- * a message from within interrupt context, use usb_submit_urb()
- * If a thread in your driver uses this call, make sure your disconnect()
- * method can wait for it to complete. Since you don't have a handle on
- * the URB used, you can't cancel the request.
+ * This function sends a simple control message to a specified endpoint and
+ * waits for the message to complete, or timeout.
+ *
+ * If successful, it returns the number of bytes transferred, otherwise a
+ * negative error number.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler. If you need an asynchronous message, or need to send a message
+ * from within interrupt context, use usb_submit_urb().
+ * If a thread in your driver uses this call, make sure your disconnect()
+ * method can wait for it to complete. Since you don't have a handle on the
+ * URB used, you can't cancel the request.
*/
-int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
- __u16 value, __u16 index, void *data, __u16 size, int timeout)
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
+ __u8 requesttype, __u16 value, __u16 index, void *data,
+ __u16 size, int timeout)
{
- struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+ struct usb_ctrlrequest *dr;
int ret;
-
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
- dr->bRequestType= requesttype;
+ dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
dr->wIndex = cpu_to_le16p(&index);
dr->wLength = cpu_to_le16p(&size);
- //dbg("usb_control_msg");
+ /* dbg("usb_control_msg"); */
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
@@ -147,7 +151,7 @@
return ret;
}
-
+EXPORT_SYMBOL_GPL(usb_control_msg);
/**
* usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion
@@ -155,9 +159,11 @@
* @pipe: endpoint "pipe" to send the message to
* @data: pointer to the data to send
* @len: length in bytes of the data to send
- * @actual_length: pointer to a location to put the actual length transferred in bytes
+ * @actual_length: pointer to a location to put the actual length transferred
+ * in bytes
* @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
+ *
* Context: !in_interrupt ()
*
* This function sends a simple interrupt message to a specified endpoint and
@@ -181,38 +187,38 @@
EXPORT_SYMBOL_GPL(usb_interrupt_msg);
/**
- * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
- * @usb_dev: pointer to the usb device to send the message to
- * @pipe: endpoint "pipe" to send the message to
- * @data: pointer to the data to send
- * @len: length in bytes of the data to send
- * @actual_length: pointer to a location to put the actual length transferred in bytes
- * @timeout: time in msecs to wait for the message to complete before
- * timing out (if 0 the wait is forever)
- * Context: !in_interrupt ()
+ * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred
+ * in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ * timing out (if 0 the wait is forever)
*
- * This function sends a simple bulk message to a specified endpoint
- * and waits for the message to complete, or timeout.
- *
- * If successful, it returns 0, otherwise a negative error number.
- * The number of actual bytes transferred will be stored in the
- * actual_length paramater.
+ * Context: !in_interrupt ()
*
- * Don't use this function from within an interrupt context, like a
- * bottom half handler. If you need an asynchronous message, or need to
- * send a message from within interrupt context, use usb_submit_urb()
- * If a thread in your driver uses this call, make sure your disconnect()
- * method can wait for it to complete. Since you don't have a handle on
- * the URB used, you can't cancel the request.
+ * This function sends a simple bulk message to a specified endpoint
+ * and waits for the message to complete, or timeout.
*
- * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT
- * ioctl, users are forced to abuse this routine by using it to submit
- * URBs for interrupt endpoints. We will take the liberty of creating
- * an interrupt URB (with the default interval) if the target is an
- * interrupt endpoint.
+ * If successful, it returns 0, otherwise a negative error number. The number
+ * of actual bytes transferred will be stored in the actual_length paramater.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler. If you need an asynchronous message, or need to send a message
+ * from within interrupt context, use usb_submit_urb() If a thread in your
+ * driver uses this call, make sure your disconnect() method can wait for it to
+ * complete. Since you don't have a handle on the URB used, you can't cancel
+ * the request.
+ *
+ * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl,
+ * users are forced to abuse this routine by using it to submit URBs for
+ * interrupt endpoints. We will take the liberty of creating an interrupt URB
+ * (with the default interval) if the target is an interrupt endpoint.
*/
-int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
- void *data, int len, int *actual_length, int timeout)
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
struct usb_host_endpoint *ep;
@@ -238,29 +244,30 @@
return usb_start_wait_urb(urb, timeout, actual_length);
}
+EXPORT_SYMBOL_GPL(usb_bulk_msg);
/*-------------------------------------------------------------------*/
-static void sg_clean (struct usb_sg_request *io)
+static void sg_clean(struct usb_sg_request *io)
{
if (io->urbs) {
while (io->entries--)
- usb_free_urb (io->urbs [io->entries]);
- kfree (io->urbs);
+ usb_free_urb(io->urbs [io->entries]);
+ kfree(io->urbs);
io->urbs = NULL;
}
if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
- io->sg, io->nents);
+ usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
+ io->sg, io->nents);
io->dev = NULL;
}
-static void sg_complete (struct urb *urb)
+static void sg_complete(struct urb *urb)
{
- struct usb_sg_request *io = urb->context;
+ struct usb_sg_request *io = urb->context;
int status = urb->status;
- spin_lock (&io->lock);
+ spin_lock(&io->lock);
/* In 2.5 we require hcds' endpoint queues not to progress after fault
* reports, until the completion callback (this!) returns. That lets
@@ -276,13 +283,13 @@
&& (io->status != -ECONNRESET
|| status != -ECONNRESET)
&& urb->actual_length) {
- dev_err (io->dev->bus->controller,
+ dev_err(io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
status, io->status);
- // BUG ();
+ /* BUG (); */
}
if (io->status == 0 && status && status != -ECONNRESET) {
@@ -294,22 +301,22 @@
* unlink pending urbs so they won't rx/tx bad data.
* careful: unlink can sometimes be synchronous...
*/
- spin_unlock (&io->lock);
+ spin_unlock(&io->lock);
for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs [i] || !io->urbs [i]->dev)
continue;
if (found) {
- retval = usb_unlink_urb (io->urbs [i]);
+ retval = usb_unlink_urb(io->urbs [i]);
if (retval != -EINPROGRESS &&
retval != -ENODEV &&
retval != -EBUSY)
- dev_err (&io->dev->dev,
+ dev_err(&io->dev->dev,
"%s, unlink --> %d\n",
__FUNCTION__, retval);
} else if (urb == io->urbs [i])
found = 1;
}
- spin_lock (&io->lock);
+ spin_lock(&io->lock);
}
urb->dev = NULL;
@@ -317,9 +324,9 @@
io->bytes += urb->actual_length;
io->count--;
if (!io->count)
- complete (&io->complete);
+ complete(&io->complete);
- spin_unlock (&io->lock);
+ spin_unlock(&io->lock);
}
@@ -348,28 +355,21 @@
* The request may be canceled with usb_sg_cancel(), either before or after
* usb_sg_wait() is called.
*/
-int usb_sg_init (
- struct usb_sg_request *io,
- struct usb_device *dev,
- unsigned pipe,
- unsigned period,
- struct scatterlist *sg,
- int nents,
- size_t length,
- gfp_t mem_flags
-)
+int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
+ unsigned pipe, unsigned period, struct scatterlist *sg,
+ int nents, size_t length, gfp_t mem_flags)
{
- int i;
- int urb_flags;
- int dma;
+ int i;
+ int urb_flags;
+ int dma;
if (!io || !dev || !sg
- || usb_pipecontrol (pipe)
- || usb_pipeisoc (pipe)
+ || usb_pipecontrol(pipe)
+ || usb_pipeisoc(pipe)
|| nents <= 0)
return -EINVAL;
- spin_lock_init (&io->lock);
+ spin_lock_init(&io->lock);
io->dev = dev;
io->pipe = pipe;
io->sg = sg;
@@ -381,7 +381,7 @@
dma = (dev->dev.dma_mask != NULL);
if (dma)
io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
- sg, nents);
+ sg, nents);
else
io->entries = nents;
@@ -390,30 +390,30 @@
return io->entries;
io->count = io->entries;
- io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
+ io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
if (!io->urbs)
goto nomem;
urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
- if (usb_pipein (pipe))
+ if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
for (i = 0; i < io->entries; i++) {
- unsigned len;
+ unsigned len;
- io->urbs [i] = usb_alloc_urb (0, mem_flags);
- if (!io->urbs [i]) {
+ io->urbs[i] = usb_alloc_urb(0, mem_flags);
+ if (!io->urbs[i]) {
io->entries = i;
goto nomem;
}
- io->urbs [i]->dev = NULL;
- io->urbs [i]->pipe = pipe;
- io->urbs [i]->interval = period;
- io->urbs [i]->transfer_flags = urb_flags;
+ io->urbs[i]->dev = NULL;
+ io->urbs[i]->pipe = pipe;
+ io->urbs[i]->interval = period;
+ io->urbs[i]->transfer_flags = urb_flags;
- io->urbs [i]->complete = sg_complete;
- io->urbs [i]->context = io;
+ io->urbs[i]->complete = sg_complete;
+ io->urbs[i]->context = io;
/*
* Some systems need to revert to PIO when DMA is temporarily
@@ -432,8 +432,8 @@
* to prevent stale pointers and to help spot bugs.
*/
if (dma) {
- io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
- len = sg_dma_len (sg + i);
+ io->urbs[i]->transfer_dma = sg_dma_address(sg + i);
+ len = sg_dma_len(sg + i);
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
io->urbs[i]->transfer_buffer = NULL;
#else
@@ -441,31 +441,31 @@
#endif
} else {
/* hc may use _only_ transfer_buffer */
- io->urbs [i]->transfer_buffer = sg_virt(&sg[i]);
- len = sg [i].length;
+ io->urbs[i]->transfer_buffer = sg_virt(&sg[i]);
+ len = sg[i].length;
}
if (length) {
- len = min_t (unsigned, len, length);
+ len = min_t(unsigned, len, length);
length -= len;
if (length == 0)
io->entries = i + 1;
}
- io->urbs [i]->transfer_buffer_length = len;
+ io->urbs[i]->transfer_buffer_length = len;
}
- io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
+ io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
/* transaction state */
io->status = 0;
io->bytes = 0;
- init_completion (&io->complete);
+ init_completion(&io->complete);
return 0;
nomem:
- sg_clean (io);
+ sg_clean(io);
return -ENOMEM;
}
-
+EXPORT_SYMBOL_GPL(usb_sg_init);
/**
* usb_sg_wait - synchronously execute scatter/gather request
@@ -506,31 +506,32 @@
* speed interrupt endpoints, which allow at most one packet per millisecond,
* of at most 8 or 64 bytes (respectively).
*/
-void usb_sg_wait (struct usb_sg_request *io)
+void usb_sg_wait(struct usb_sg_request *io)
{
- int i, entries = io->entries;
+ int i;
+ int entries = io->entries;
/* queue the urbs. */
- spin_lock_irq (&io->lock);
+ spin_lock_irq(&io->lock);
i = 0;
while (i < entries && !io->status) {
- int retval;
+ int retval;
- io->urbs [i]->dev = io->dev;
- retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC);
+ io->urbs[i]->dev = io->dev;
+ retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC);
/* after we submit, let completions or cancelations fire;
* we handshake using io->status.
*/
- spin_unlock_irq (&io->lock);
+ spin_unlock_irq(&io->lock);
switch (retval) {
/* maybe we retrying will recover */
- case -ENXIO: // hc didn't queue this one
+ case -ENXIO: /* hc didn't queue this one */
case -EAGAIN:
case -ENOMEM:
io->urbs[i]->dev = NULL;
retval = 0;
- yield ();
+ yield();
break;
/* no error? continue immediately.
@@ -541,34 +542,35 @@
*/
case 0:
++i;
- cpu_relax ();
+ cpu_relax();
break;
/* fail any uncompleted urbs */
default:
- io->urbs [i]->dev = NULL;
- io->urbs [i]->status = retval;
- dev_dbg (&io->dev->dev, "%s, submit --> %d\n",
+ io->urbs[i]->dev = NULL;
+ io->urbs[i]->status = retval;
+ dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
__FUNCTION__, retval);
- usb_sg_cancel (io);
+ usb_sg_cancel(io);
}
- spin_lock_irq (&io->lock);
+ spin_lock_irq(&io->lock);
if (retval && (io->status == 0 || io->status == -ECONNRESET))
io->status = retval;
}
io->count -= entries - i;
if (io->count == 0)
- complete (&io->complete);
- spin_unlock_irq (&io->lock);
+ complete(&io->complete);
+ spin_unlock_irq(&io->lock);
/* OK, yes, this could be packaged as non-blocking.
* So could the submit loop above ... but it's easier to
* solve neither problem than to solve both!
*/
- wait_for_completion (&io->complete);
+ wait_for_completion(&io->complete);
- sg_clean (io);
+ sg_clean(io);
}
+EXPORT_SYMBOL_GPL(usb_sg_wait);
/**
* usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
@@ -578,32 +580,33 @@
* It can also prevents one initialized by usb_sg_init() from starting,
* so that call just frees resources allocated to the request.
*/
-void usb_sg_cancel (struct usb_sg_request *io)
+void usb_sg_cancel(struct usb_sg_request *io)
{
- unsigned long flags;
+ unsigned long flags;
- spin_lock_irqsave (&io->lock, flags);
+ spin_lock_irqsave(&io->lock, flags);
/* shut everything down, if it didn't already */
if (!io->status) {
- int i;
+ int i;
io->status = -ECONNRESET;
- spin_unlock (&io->lock);
+ spin_unlock(&io->lock);
for (i = 0; i < io->entries; i++) {
- int retval;
+ int retval;
if (!io->urbs [i]->dev)
continue;
- retval = usb_unlink_urb (io->urbs [i]);
+ retval = usb_unlink_urb(io->urbs [i]);
if (retval != -EINPROGRESS && retval != -EBUSY)
- dev_warn (&io->dev->dev, "%s, unlink --> %d\n",
+ dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__FUNCTION__, retval);
}
- spin_lock (&io->lock);
+ spin_lock(&io->lock);
}
- spin_unlock_irqrestore (&io->lock, flags);
+ spin_unlock_irqrestore(&io->lock, flags);
}
+EXPORT_SYMBOL_GPL(usb_sg_cancel);
/*-------------------------------------------------------------------*/
@@ -629,12 +632,13 @@
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
-int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+int usb_get_descriptor(struct usb_device *dev, unsigned char type,
+ unsigned char index, void *buf, int size)
{
int i;
int result;
-
- memset(buf,0,size); // Make sure we parse really received data
+
+ memset(buf, 0, size); /* Make sure we parse really received data */
for (i = 0; i < 3; ++i) {
/* retry on length 0 or error; some devices are flakey */
@@ -652,6 +656,7 @@
}
return result;
}
+EXPORT_SYMBOL_GPL(usb_get_descriptor);
/**
* usb_get_string - gets a string descriptor
@@ -708,7 +713,7 @@
}
static int usb_string_sub(struct usb_device *dev, unsigned int langid,
- unsigned int index, unsigned char *buf)
+ unsigned int index, unsigned char *buf)
{
int rc;
@@ -751,7 +756,7 @@
* @buf: where to put the string
* @size: how big is "buf"?
* Context: !in_interrupt ()
- *
+ *
* This converts the UTF-16LE encoded strings returned by devices, from
* usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
* that are more usable in most kernel contexts. Note that all characters
@@ -787,23 +792,23 @@
if (!dev->have_langid) {
err = usb_string_sub(dev, 0, 0, tbuf);
if (err < 0) {
- dev_err (&dev->dev,
+ dev_err(&dev->dev,
"string descriptor 0 read error: %d\n",
err);
goto errout;
} else if (err < 4) {
- dev_err (&dev->dev, "string descriptor 0 too short\n");
+ dev_err(&dev->dev, "string descriptor 0 too short\n");
err = -EINVAL;
goto errout;
} else {
dev->have_langid = 1;
- dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
- /* always use the first langid listed */
- dev_dbg (&dev->dev, "default language 0x%04x\n",
+ dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+ /* always use the first langid listed */
+ dev_dbg(&dev->dev, "default language 0x%04x\n",
dev->string_langid);
}
}
-
+
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
if (err < 0)
goto errout;
@@ -821,12 +826,15 @@
err = idx;
if (tbuf[1] != USB_DT_STRING)
- dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf);
+ dev_dbg(&dev->dev,
+ "wrong descriptor type %02x for string %d (\"%s\")\n",
+ tbuf[1], index, buf);
errout:
kfree(tbuf);
return err;
}
+EXPORT_SYMBOL_GPL(usb_string);
/**
* usb_cache_string - read a string descriptor and cache it for later use
@@ -842,9 +850,15 @@
char *smallbuf = NULL;
int len;
- if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) {
- if ((len = usb_string(udev, index, buf, 256)) > 0) {
- if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL)
+ if (index <= 0)
+ return NULL;
+
+ buf = kmalloc(256, GFP_KERNEL);
+ if (buf) {
+ len = usb_string(udev, index, buf, 256);
+ if (len > 0) {
+ smallbuf = kmalloc(++len, GFP_KERNEL);
+ if (!smallbuf)
return buf;
memcpy(smallbuf, buf, len);
}
@@ -883,7 +897,7 @@
return -ENOMEM;
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
- if (ret >= 0)
+ if (ret >= 0)
memcpy(&dev->descriptor, desc, size);
kfree(desc);
return ret;
@@ -927,6 +941,7 @@
kfree(status);
return ret;
}
+EXPORT_SYMBOL_GPL(usb_get_status);
/**
* usb_clear_halt - tells device to clear endpoint halt/stall condition
@@ -955,8 +970,8 @@
{
int result;
int endp = usb_pipeendpoint(pipe);
-
- if (usb_pipein (pipe))
+
+ if (usb_pipein(pipe))
endp |= USB_DIR_IN;
/* we don't care if it wasn't halted first. in fact some devices
@@ -985,6 +1000,7 @@
return 0;
}
+EXPORT_SYMBOL_GPL(usb_clear_halt);
/**
* usb_disable_endpoint -- Disable an endpoint by address
@@ -1038,7 +1054,7 @@
}
}
-/*
+/**
* usb_disable_device - Disable all the endpoints for a USB device
* @dev: the device whose endpoints are being disabled
* @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
@@ -1053,7 +1069,7 @@
int i;
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__,
- skip_ep0 ? "non-ep0" : "all");
+ skip_ep0 ? "non-ep0" : "all");
for (i = skip_ep0; i < 16; ++i) {
usb_disable_endpoint(dev, i);
usb_disable_endpoint(dev, i + USB_DIR_IN);
@@ -1071,17 +1087,17 @@
interface = dev->actconfig->interface[i];
if (!device_is_registered(&interface->dev))
continue;
- dev_dbg (&dev->dev, "unregistering interface %s\n",
+ dev_dbg(&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
usb_remove_sysfs_intf_files(interface);
- device_del (&interface->dev);
+ device_del(&interface->dev);
}
/* Now that the interfaces are unbound, nobody should
* try to access them.
*/
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
- put_device (&dev->actconfig->interface[i]->dev);
+ put_device(&dev->actconfig->interface[i]->dev);
dev->actconfig->interface[i] = NULL;
}
dev->actconfig = NULL;
@@ -1090,8 +1106,7 @@
}
}
-
-/*
+/**
* usb_enable_endpoint - Enable an endpoint for USB communications
* @dev: the device whose interface is being enabled
* @ep: the endpoint
@@ -1116,7 +1131,7 @@
ep->enabled = 1;
}
-/*
+/**
* usb_enable_interface - Enable all the endpoints for an interface
* @dev: the device whose interface is being enabled
* @intf: pointer to the interface descriptor
@@ -1172,6 +1187,8 @@
struct usb_host_interface *alt;
int ret;
int manual = 0;
+ unsigned int epaddr;
+ unsigned int pipe;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@@ -1226,11 +1243,11 @@
int i;
for (i = 0; i < alt->desc.bNumEndpoints; i++) {
- unsigned int epaddr =
- alt->endpoint[i].desc.bEndpointAddress;
- unsigned int pipe =
- __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr)
- | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN);
+ epaddr = alt->endpoint[i].desc.bEndpointAddress;
+ pipe = __create_pipe(dev,
+ USB_ENDPOINT_NUMBER_MASK & epaddr) |
+ (usb_endpoint_out(epaddr) ?
+ USB_DIR_OUT : USB_DIR_IN);
usb_clear_halt(dev, pipe);
}
@@ -1253,6 +1270,7 @@
return 0;
}
+EXPORT_SYMBOL_GPL(usb_set_interface);
/**
* usb_reset_configuration - lightweight device reset
@@ -1328,6 +1346,7 @@
}
return 0;
}
+EXPORT_SYMBOL_GPL(usb_reset_configuration);
static void usb_release_interface(struct device *dev)
{
@@ -1357,7 +1376,8 @@
return -ENOMEM;
if (add_uevent_var(env,
- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+ "MODALIAS=usb:"
+ "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice),
@@ -1387,8 +1407,8 @@
};
static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
- struct usb_host_config *config,
- u8 inum)
+ struct usb_host_config *config,
+ u8 inum)
{
struct usb_interface_assoc_descriptor *retval = NULL;
struct usb_interface_assoc_descriptor *intf_assoc;
@@ -1415,7 +1435,6 @@
return retval;
}
-
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@@ -1533,12 +1552,12 @@
* getting rid of old interfaces means unbinding their drivers.
*/
if (dev->state != USB_STATE_ADDRESS)
- usb_disable_device (dev, 1); // Skip ep0
+ usb_disable_device(dev, 1); /* Skip ep0 */
- if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
- NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
-
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (ret < 0) {
/* All the old state is gone, so what else can we do?
* The device is probably useless now anyway.
*/
@@ -1585,11 +1604,11 @@
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.dma_mask = dev->dev.dma_mask;
- device_initialize (&intf->dev);
+ device_initialize(&intf->dev);
mark_quiesced(intf);
- sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
- dev->bus->busnum, dev->devpath,
- configuration, alt->desc.bInterfaceNumber);
+ sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",
+ dev->bus->busnum, dev->devpath,
+ configuration, alt->desc.bInterfaceNumber);
}
kfree(new_interfaces);
@@ -1605,11 +1624,11 @@
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
- dev_dbg (&dev->dev,
+ dev_dbg(&dev->dev,
"adding %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
- ret = device_add (&intf->dev);
+ ret = device_add(&intf->dev);
if (ret != 0) {
dev_err(&dev->dev, "device_add(%s) --> %d\n",
intf->dev.bus_id, ret);
@@ -1677,22 +1696,3 @@
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
-
-// synchronous request completion model
-EXPORT_SYMBOL(usb_control_msg);
-EXPORT_SYMBOL(usb_bulk_msg);
-
-EXPORT_SYMBOL(usb_sg_init);
-EXPORT_SYMBOL(usb_sg_cancel);
-EXPORT_SYMBOL(usb_sg_wait);
-
-// synchronous control message convenience routines
-EXPORT_SYMBOL(usb_get_descriptor);
-EXPORT_SYMBOL(usb_get_status);
-EXPORT_SYMBOL(usb_string);
-
-// synchronous calls that also maintain usbcore state
-EXPORT_SYMBOL(usb_clear_halt);
-EXPORT_SYMBOL(usb_reset_configuration);
-EXPORT_SYMBOL(usb_set_interface);
-
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index 6b36897..7542dce 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -33,7 +33,7 @@
* usb_unregister_notify - unregister a notifier callback
* @nb: pointer to the notifier block for the callback events.
*
- * usb_register_notifier() must have been previously called for this function
+ * usb_register_notify() must have been previously called for this function
* to work properly.
*/
void usb_unregister_notify(struct notifier_block *nb)
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index 7f31a49..e8cdce5 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -14,7 +14,7 @@
* mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
*
* YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
- */
+ */
static struct usb_device_id whitelist_table [] = {
@@ -55,7 +55,7 @@
return 1;
/* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
- if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
return 0;
@@ -86,7 +86,7 @@
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
- (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
continue;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 32bd130..a37ccbd 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -72,7 +72,7 @@
return (value < 0) ? value : count;
}
-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
show_bConfigurationValue, set_bConfigurationValue);
/* String fields */
@@ -249,6 +249,41 @@
#ifdef CONFIG_USB_SUSPEND
static ssize_t
+show_connected_duration(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ return sprintf(buf, "%u\n",
+ jiffies_to_msecs(jiffies - udev->connect_time));
+}
+
+static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL);
+
+/*
+ * If the device is resumed, the last time the device was suspended has
+ * been pre-subtracted from active_duration. We add the current time to
+ * get the duration that the device was actually active.
+ *
+ * If the device is suspended, the active_duration is up-to-date.
+ */
+static ssize_t
+show_active_duration(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int duration;
+
+ if (udev->state != USB_STATE_SUSPENDED)
+ duration = jiffies_to_msecs(jiffies + udev->active_duration);
+ else
+ duration = jiffies_to_msecs(udev->active_duration);
+ return sprintf(buf, "%u\n", duration);
+}
+
+static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
+
+static ssize_t
show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
@@ -365,6 +400,14 @@
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_level.attr,
power_group);
+ if (rc == 0)
+ rc = sysfs_add_file_to_group(&dev->kobj,
+ &dev_attr_connected_duration.attr,
+ power_group);
+ if (rc == 0)
+ rc = sysfs_add_file_to_group(&dev->kobj,
+ &dev_attr_active_duration.attr,
+ power_group);
}
return rc;
}
@@ -372,6 +415,12 @@
static void remove_power_attributes(struct device *dev)
{
sysfs_remove_file_from_group(&dev->kobj,
+ &dev_attr_active_duration.attr,
+ power_group);
+ sysfs_remove_file_from_group(&dev->kobj,
+ &dev_attr_connected_duration.attr,
+ power_group);
+ sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_level.attr,
power_group);
sysfs_remove_file_from_group(&dev->kobj,
@@ -601,21 +650,21 @@
/* Interface Accociation Descriptor fields */
#define usb_intf_assoc_attr(field, format_string) \
static ssize_t \
-show_iad_##field (struct device *dev, struct device_attribute *attr, \
+show_iad_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface (dev); \
+ struct usb_interface *intf = to_usb_interface(dev); \
\
- return sprintf (buf, format_string, \
- intf->intf_assoc->field); \
+ return sprintf(buf, format_string, \
+ intf->intf_assoc->field); \
} \
static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
-usb_intf_assoc_attr (bFirstInterface, "%02x\n")
-usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
-usb_intf_assoc_attr (bFunctionClass, "%02x\n")
-usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
-usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
+usb_intf_assoc_attr(bFirstInterface, "%02x\n")
+usb_intf_assoc_attr(bInterfaceCount, "%02d\n")
+usb_intf_assoc_attr(bFunctionClass, "%02x\n")
+usb_intf_assoc_attr(bFunctionSubClass, "%02x\n")
+usb_intf_assoc_attr(bFunctionProtocol, "%02x\n")
/* Interface fields */
#define usb_intf_attr(field, format_string) \
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index d05ead2..9d7e632 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -42,6 +42,7 @@
INIT_LIST_HEAD(&urb->anchor_list);
}
}
+EXPORT_SYMBOL_GPL(usb_init_urb);
/**
* usb_alloc_urb - creates a new urb for a USB driver to use
@@ -73,6 +74,7 @@
usb_init_urb(urb);
return urb;
}
+EXPORT_SYMBOL_GPL(usb_alloc_urb);
/**
* usb_free_urb - frees the memory used by a urb when all users of it are finished
@@ -89,6 +91,7 @@
if (urb)
kref_put(&urb->kref, urb_destroy);
}
+EXPORT_SYMBOL_GPL(usb_free_urb);
/**
* usb_get_urb - increments the reference count of the urb
@@ -100,12 +103,13 @@
*
* A pointer to the urb with the incremented reference counter is returned.
*/
-struct urb * usb_get_urb(struct urb *urb)
+struct urb *usb_get_urb(struct urb *urb)
{
if (urb)
kref_get(&urb->kref);
return urb;
}
+EXPORT_SYMBOL_GPL(usb_get_urb);
/**
* usb_anchor_urb - anchors an URB while it is processed
@@ -172,7 +176,7 @@
* describing that request to the USB subsystem. Request completion will
* be indicated later, asynchronously, by calling the completion handler.
* The three types of completion are success, error, and unlink
- * (a software-induced fault, also called "request cancellation").
+ * (a software-induced fault, also called "request cancellation").
*
* URBs may be submitted in interrupt context.
*
@@ -255,7 +259,7 @@
* semaphores), or
* (c) current->state != TASK_RUNNING, this is the case only after
* you've changed it.
- *
+ *
* GFP_NOIO is used in the block io path and error handling of storage
* devices.
*
@@ -284,7 +288,8 @@
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
- if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
+ dev = urb->dev;
+ if ((!dev) || (dev->state < USB_STATE_DEFAULT))
return -ENODEV;
/* For now, get the endpoint from the pipe. Eventually drivers
@@ -347,11 +352,11 @@
max *= mult;
}
- if (urb->number_of_packets <= 0)
+ if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
len = urb->iso_frame_desc[n].length;
- if (len < 0 || len > max)
+ if (len < 0 || len > max)
return -EMSGSIZE;
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
@@ -416,7 +421,7 @@
/* too big? */
switch (dev->speed) {
case USB_SPEED_HIGH: /* units are microframes */
- // NOTE usb handles 2^15
+ /* NOTE usb handles 2^15 */
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
max = 1024 * 8;
@@ -426,12 +431,12 @@
if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
- // NOTE ohci only handles up to 32
+ /* NOTE ohci only handles up to 32 */
max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
- // NOTE usb and ohci handle up to 2^15
+ /* NOTE usb and ohci handle up to 2^15 */
max = 1024;
}
break;
@@ -444,6 +449,7 @@
return usb_hcd_submit_urb(urb, mem_flags);
}
+EXPORT_SYMBOL_GPL(usb_submit_urb);
/*-------------------------------------------------------------------*/
@@ -514,6 +520,7 @@
return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
+EXPORT_SYMBOL_GPL(usb_unlink_urb);
/**
* usb_kill_urb - cancel a transfer request and wait for it to finish
@@ -553,6 +560,7 @@
--urb->reject;
mutex_unlock(&reject_mutex);
}
+EXPORT_SYMBOL_GPL(usb_kill_urb);
/**
* usb_kill_anchored_urbs - cancel transfer requests en masse
@@ -567,7 +575,8 @@
spin_lock_irq(&anchor->lock);
while (!list_empty(&anchor->urb_list)) {
- victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
/* we must make sure the URB isn't freed before we kill it*/
usb_get_urb(victim);
spin_unlock_irq(&anchor->lock);
@@ -595,11 +604,3 @@
msecs_to_jiffies(timeout));
}
EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
-
-EXPORT_SYMBOL(usb_init_urb);
-EXPORT_SYMBOL(usb_alloc_urb);
-EXPORT_SYMBOL(usb_free_urb);
-EXPORT_SYMBOL(usb_get_urb);
-EXPORT_SYMBOL(usb_submit_urb);
-EXPORT_SYMBOL(usb_unlink_urb);
-EXPORT_SYMBOL(usb_kill_urb);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 8f14237..4e98406 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -96,6 +96,7 @@
return NULL;
}
+EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
/**
* usb_altnum_to_altsetting - get the altsetting structure with a given
@@ -115,8 +116,9 @@
* Don't call this function unless you are bound to the intf interface
* or you have locked the device!
*/
-struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
- unsigned int altnum)
+struct usb_host_interface *usb_altnum_to_altsetting(
+ const struct usb_interface *intf,
+ unsigned int altnum)
{
int i;
@@ -126,13 +128,14 @@
}
return NULL;
}
+EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting);
struct find_interface_arg {
int minor;
struct usb_interface *interface;
};
-static int __find_interface(struct device * dev, void * data)
+static int __find_interface(struct device *dev, void *data)
{
struct find_interface_arg *arg = data;
struct usb_interface *intf;
@@ -154,7 +157,7 @@
* @drv: the driver whose current configuration is considered
* @minor: the minor number of the desired device
*
- * This walks the driver device list and returns a pointer to the interface
+ * This walks the driver device list and returns a pointer to the interface
* with the matching minor. Note, this only works for devices that share the
* USB major number.
*/
@@ -170,6 +173,7 @@
__find_interface);
return argb.interface;
}
+EXPORT_SYMBOL_GPL(usb_find_interface);
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
@@ -230,7 +234,7 @@
* singlethreaded. Its job doesn't justify running on more
* than one CPU.
*/
- ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
+ ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
if (!ksuspend_usb_wq)
return -ENOMEM;
return 0;
@@ -269,8 +273,8 @@
*
* This call may not be used in a non-sleeping context.
*/
-struct usb_device *
-usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
+struct usb_device *usb_alloc_dev(struct usb_device *parent,
+ struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
@@ -339,6 +343,8 @@
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
+ dev->connect_time = jiffies;
+ dev->active_duration = -jiffies;
#endif
if (root_hub) /* Root hub always ok [and always wired] */
dev->authorized = 1;
@@ -367,6 +373,7 @@
get_device(&dev->dev);
return dev;
}
+EXPORT_SYMBOL_GPL(usb_get_dev);
/**
* usb_put_dev - release a use of the usb device structure
@@ -380,6 +387,7 @@
if (dev)
put_device(&dev->dev);
}
+EXPORT_SYMBOL_GPL(usb_put_dev);
/**
* usb_get_intf - increments the reference count of the usb interface structure
@@ -400,6 +408,7 @@
get_device(&intf->dev);
return intf;
}
+EXPORT_SYMBOL_GPL(usb_get_intf);
/**
* usb_put_intf - release a use of the usb interface structure
@@ -414,7 +423,7 @@
if (intf)
put_device(&intf->dev);
}
-
+EXPORT_SYMBOL_GPL(usb_put_intf);
/* USB device locking
*
@@ -461,11 +470,11 @@
return -EHOSTUNREACH;
if (iface) {
switch (iface->condition) {
- case USB_INTERFACE_BINDING:
+ case USB_INTERFACE_BINDING:
return 0;
- case USB_INTERFACE_BOUND:
+ case USB_INTERFACE_BOUND:
break;
- default:
+ default:
return -EINTR;
}
}
@@ -487,7 +496,7 @@
}
return 1;
}
-
+EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
static struct usb_device *match_device(struct usb_device *dev,
u16 vendor_id, u16 product_id)
@@ -540,10 +549,10 @@
struct list_head *buslist;
struct usb_bus *bus;
struct usb_device *dev = NULL;
-
+
mutex_lock(&usb_bus_list_lock);
for (buslist = usb_bus_list.next;
- buslist != &usb_bus_list;
+ buslist != &usb_bus_list;
buslist = buslist->next) {
bus = container_of(buslist, struct usb_bus, bus_list);
if (!bus->root_hub)
@@ -576,6 +585,7 @@
{
return usb_hcd_get_frame_number(dev);
}
+EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
/*-------------------------------------------------------------------*/
/*
@@ -584,7 +594,7 @@
*/
int __usb_get_extra_descriptor(char *buffer, unsigned size,
- unsigned char type, void **ptr)
+ unsigned char type, void **ptr)
{
struct usb_descriptor_header *header;
@@ -595,7 +605,7 @@
printk(KERN_ERR
"%s: bogus descriptor, type %d length %d\n",
usbcore_name,
- header->bDescriptorType,
+ header->bDescriptorType,
header->bLength);
return -1;
}
@@ -610,6 +620,7 @@
}
return -1;
}
+EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
/**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
@@ -633,17 +644,14 @@
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
-void *usb_buffer_alloc(
- struct usb_device *dev,
- size_t size,
- gfp_t mem_flags,
- dma_addr_t *dma
-)
+void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags,
+ dma_addr_t *dma)
{
if (!dev || !dev->bus)
return NULL;
return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
}
+EXPORT_SYMBOL_GPL(usb_buffer_alloc);
/**
* usb_buffer_free - free memory allocated with usb_buffer_alloc()
@@ -656,12 +664,8 @@
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
-void usb_buffer_free(
- struct usb_device *dev,
- size_t size,
- void *addr,
- dma_addr_t dma
-)
+void usb_buffer_free(struct usb_device *dev, size_t size, void *addr,
+ dma_addr_t dma)
{
if (!dev || !dev->bus)
return;
@@ -669,6 +673,7 @@
return;
hcd_buffer_free(dev->bus, size, addr, dma);
}
+EXPORT_SYMBOL_GPL(usb_buffer_free);
/**
* usb_buffer_map - create DMA mapping(s) for an urb
@@ -708,14 +713,15 @@
urb->setup_packet,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
- // FIXME generic api broken like pci, can't report errors
- // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
+ /* FIXME generic api broken like pci, can't report errors */
+ /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP);
return urb;
}
+EXPORT_SYMBOL_GPL(usb_buffer_map);
#endif /* 0 */
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -753,6 +759,7 @@
DMA_TO_DEVICE);
}
}
+EXPORT_SYMBOL_GPL(usb_buffer_dmasync);
#endif
/**
@@ -788,6 +795,7 @@
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP);
}
+EXPORT_SYMBOL_GPL(usb_buffer_unmap);
#endif /* 0 */
/**
@@ -828,10 +836,11 @@
|| !controller->dma_mask)
return -1;
- // FIXME generic api broken like pci, can't report errors
+ /* FIXME generic api broken like pci, can't report errors */
return dma_map_sg(controller, sg, nents,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
+EXPORT_SYMBOL_GPL(usb_buffer_map_sg);
/* XXX DISABLED, no users currently. If you wish to re-enable this
* XXX please determine whether the sync is to transfer ownership of
@@ -865,6 +874,7 @@
dma_sync_sg(controller, sg, n_hw_ents,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
+EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
#endif
/**
@@ -891,6 +901,7 @@
dma_unmap_sg(controller, sg, n_hw_ents,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
+EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
/* format to disable USB on kernel command line is: nousb */
__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
@@ -902,6 +913,7 @@
{
return nousb;
}
+EXPORT_SYMBOL_GPL(usb_disabled);
/*
* Init
@@ -918,7 +930,7 @@
if (retval)
goto out;
retval = bus_register(&usb_bus_type);
- if (retval)
+ if (retval)
goto bus_register_failed;
retval = usb_host_init();
if (retval)
@@ -983,45 +995,4 @@
subsys_initcall(usb_init);
module_exit(usb_exit);
-
-/*
- * USB may be built into the kernel or be built as modules.
- * These symbols are exported for device (or host controller)
- * driver modules to use.
- */
-
-EXPORT_SYMBOL(usb_disabled);
-
-EXPORT_SYMBOL_GPL(usb_get_intf);
-EXPORT_SYMBOL_GPL(usb_put_intf);
-
-EXPORT_SYMBOL(usb_put_dev);
-EXPORT_SYMBOL(usb_get_dev);
-EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
-
-EXPORT_SYMBOL(usb_lock_device_for_reset);
-
-EXPORT_SYMBOL(usb_find_interface);
-EXPORT_SYMBOL(usb_ifnum_to_if);
-EXPORT_SYMBOL(usb_altnum_to_altsetting);
-
-EXPORT_SYMBOL(__usb_get_extra_descriptor);
-
-EXPORT_SYMBOL(usb_get_current_frame_number);
-
-EXPORT_SYMBOL(usb_buffer_alloc);
-EXPORT_SYMBOL(usb_buffer_free);
-
-#if 0
-EXPORT_SYMBOL(usb_buffer_map);
-EXPORT_SYMBOL(usb_buffer_dmasync);
-EXPORT_SYMBOL(usb_buffer_unmap);
-#endif
-
-EXPORT_SYMBOL(usb_buffer_map_sg);
-#if 0
-EXPORT_SYMBOL(usb_buffer_dmasync_sg);
-#endif
-EXPORT_SYMBOL(usb_buffer_unmap_sg);
-
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index c52626c..2375194 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -1,22 +1,23 @@
/* Functions local to drivers/usb/core/ */
-extern int usb_create_sysfs_dev_files (struct usb_device *dev);
-extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
-extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
-extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
-extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
+extern int usb_create_sysfs_dev_files(struct usb_device *dev);
+extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
+extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
+extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
+extern int usb_create_ep_files(struct device *parent,
+ struct usb_host_endpoint *endpoint,
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
extern void usb_enable_endpoint(struct usb_device *dev,
struct usb_host_endpoint *ep);
-extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
-extern void usb_disable_interface (struct usb_device *dev,
+extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr);
+extern void usb_disable_interface(struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
-extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
-extern int usb_deauthorize_device (struct usb_device *);
-extern int usb_authorize_device (struct usb_device *);
+extern void usb_disable_device(struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device(struct usb_device *);
+extern int usb_authorize_device(struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 77a3759..c139551 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -12,10 +12,9 @@
# With help from a special transceiver and a "Mini-AB" jack, systems with
# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
#
-menu "USB Gadget Support"
-config USB_GADGET
- tristate "Support for USB Gadgets"
+menuconfig USB_GADGET
+ tristate "USB Gadget Support"
help
USB is a master/slave protocol, organized with one master
host (such as a PC) controlling up to 127 peripheral devices.
@@ -42,6 +41,8 @@
For more information, see <http://www.linux-usb.org/gadget> and
the kernel DocBook documentation for this API.
+if USB_GADGET
+
config USB_GADGET_DEBUG
boolean "Debugging messages"
depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
@@ -220,6 +221,16 @@
default USB_GADGET
select USB_GADGET_SELECTED
+config SUPERH_BUILT_IN_M66592
+ boolean "Enable SuperH built-in USB like the M66592"
+ depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
+ help
+ SH7722 has USB like the M66592.
+
+ The transfer rate is very slow when use "Ethernet Gadget".
+ However, this problem is improved if change a value of
+ NET_IP_ALIGN to 4.
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
@@ -538,6 +549,20 @@
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_midi".
+config USB_G_PRINTER
+ tristate "Printer Gadget"
+ help
+ The Printer Gadget channels data between the USB host and a
+ userspace program driving the print engine. The user space
+ program reads and writes the device file /dev/g_printer to
+ receive or send printer data. It can use ioctl calls to
+ the device file to get or set printer status.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_printer".
+
+ For more information, see Documentation/usb/gadget_printer.txt
+ which includes sample code for accessing the device file.
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.
@@ -546,4 +571,4 @@
endchoice
-endmenu
+endif # USB_GADGET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 904e57b..c3aab80 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -28,6 +28,8 @@
gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o usbstring.o config.o \
epautoconf.o
+g_printer-objs := printer.o usbstring.o config.o \
+ epautoconf.o
ifeq ($(CONFIG_USB_ETH_RNDIS),y)
g_ether-objs += rndis.o
@@ -38,5 +40,6 @@
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index c72e962..b663f23 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1244,7 +1244,7 @@
/* stop OUT naking */
if (!ep->in) {
if (!use_dma && udc_rxfifo_pending) {
- DBG(dev, "udc_queue(): pending bytes in"
+ DBG(dev, "udc_queue(): pending bytes in "
"rxfifo after nyet\n");
/*
* read pending bytes afer nyet:
@@ -2038,6 +2038,7 @@
spin_unlock_irqrestore(&dev->lock, flags);
driver->unbind(&dev->gadget);
+ dev->gadget.dev.driver = NULL;
dev->driver = NULL;
/* set SD */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index cd62b02..a83e8b7 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -21,8 +21,7 @@
* Boston, MA 02111-1307, USA.
*/
-#undef DEBUG
-#undef VERBOSE
+#undef VERBOSE_DEBUG
#undef PACKET_TRACE
#include <linux/kernel.h>
@@ -46,8 +45,8 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach-types.h>
+#include <asm/gpio.h>
-#include <asm/arch/gpio.h>
#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
#include <asm/arch/at91sam9261_matrix.h>
@@ -580,7 +579,7 @@
*/
static struct usb_request *
-at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
+at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
{
struct at91_request *req;
@@ -881,6 +880,8 @@
*/
static void pullup(struct at91_udc *udc, int is_on)
{
+ int active = !udc->board.pullup_active_low;
+
if (!udc->enabled || !udc->vbus)
is_on = 0;
DBG("%sactive\n", is_on ? "" : "in");
@@ -890,7 +891,7 @@
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
at91_udp_write(udc, AT91_UDP_TXVC, 0);
if (cpu_is_at91rm9200())
- at91_set_gpio_value(udc->board.pullup_pin, 1);
+ gpio_set_value(udc->board.pullup_pin, active);
else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
@@ -908,7 +909,7 @@
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
if (cpu_is_at91rm9200())
- at91_set_gpio_value(udc->board.pullup_pin, 0);
+ gpio_set_value(udc->board.pullup_pin, !active);
else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
@@ -1153,7 +1154,7 @@
| USB_REQ_GET_STATUS:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
- if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc))
+ if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
goto stall;
if (tmp) {
@@ -1176,7 +1177,7 @@
| USB_REQ_SET_FEATURE:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
- if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+ if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
goto stall;
if (!ep->desc || ep->is_iso)
goto stall;
@@ -1195,7 +1196,7 @@
| USB_REQ_CLEAR_FEATURE:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
- if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+ if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
goto stall;
if (tmp == 0)
goto succeed;
@@ -1551,7 +1552,7 @@
/* vbus needs at least brief debouncing */
udelay(10);
- value = at91_get_gpio_value(udc->board.vbus_pin);
+ value = gpio_get_value(udc->board.vbus_pin);
if (value != udc->vbus)
at91_vbus_session(&udc->gadget, value);
@@ -1616,6 +1617,8 @@
local_irq_enable();
driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->gadget.dev.driver_data = NULL;
udc->driver = NULL;
DBG("unbound from %s\n", driver->driver.name);
@@ -1645,12 +1648,12 @@
}
if (pdev->num_resources != 2) {
- DBG("invalid num_resources");
+ DBG("invalid num_resources\n");
return -ENODEV;
}
if ((pdev->resource[0].flags != IORESOURCE_MEM)
|| (pdev->resource[1].flags != IORESOURCE_IRQ)) {
- DBG("invalid resource type");
+ DBG("invalid resource type\n");
return -ENODEV;
}
@@ -1672,10 +1675,26 @@
udc->pdev = pdev;
udc->enabled = 0;
+ /* rm9200 needs manual D+ pullup; off by default */
+ if (cpu_is_at91rm9200()) {
+ if (udc->board.pullup_pin <= 0) {
+ DBG("no D+ pullup?\n");
+ retval = -ENODEV;
+ goto fail0;
+ }
+ retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
+ if (retval) {
+ DBG("D+ pullup is busy\n");
+ goto fail0;
+ }
+ gpio_direction_output(udc->board.pullup_pin,
+ udc->board.pullup_active_low);
+ }
+
udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
if (!udc->udp_baseaddr) {
- release_mem_region(res->start, res->end - res->start + 1);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto fail0a;
}
udc_reinit(udc);
@@ -1686,12 +1705,13 @@
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
DBG("clocks missing\n");
retval = -ENODEV;
- goto fail0;
+ /* NOTE: we "know" here that refcounts on these are NOPs */
+ goto fail0b;
}
retval = device_register(&udc->gadget.dev);
if (retval < 0)
- goto fail0;
+ goto fail0b;
/* don't do anything until we have both gadget driver and VBUS */
clk_enable(udc->iclk);
@@ -1703,25 +1723,32 @@
/* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0);
- if (request_irq(udc->udp_irq, at91_udc_irq,
- IRQF_DISABLED, driver_name, udc)) {
+ retval = request_irq(udc->udp_irq, at91_udc_irq,
+ IRQF_DISABLED, driver_name, udc);
+ if (retval < 0) {
DBG("request irq %d failed\n", udc->udp_irq);
- retval = -EBUSY;
goto fail1;
}
if (udc->board.vbus_pin > 0) {
+ retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
+ if (retval < 0) {
+ DBG("request vbus pin failed\n");
+ goto fail2;
+ }
+ gpio_direction_input(udc->board.vbus_pin);
+
/*
* Get the initial state of VBUS - we cannot expect
* a pending interrupt.
*/
- udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
+ udc->vbus = gpio_get_value(udc->board.vbus_pin);
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
IRQF_DISABLED, driver_name, udc)) {
DBG("request vbus irq %d failed\n",
udc->board.vbus_pin);
free_irq(udc->udp_irq, udc);
retval = -EBUSY;
- goto fail1;
+ goto fail3;
}
} else {
DBG("no VBUS detection, assuming always-on\n");
@@ -1734,8 +1761,18 @@
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
return 0;
+fail3:
+ if (udc->board.vbus_pin > 0)
+ gpio_free(udc->board.vbus_pin);
+fail2:
+ free_irq(udc->udp_irq, udc);
fail1:
device_unregister(&udc->gadget.dev);
+fail0b:
+ iounmap(udc->udp_baseaddr);
+fail0a:
+ if (cpu_is_at91rm9200())
+ gpio_free(udc->board.pullup_pin);
fail0:
release_mem_region(res->start, res->end - res->start + 1);
DBG("%s probe failed, %d\n", driver_name, retval);
@@ -1756,12 +1793,18 @@
device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
- if (udc->board.vbus_pin > 0)
+ if (udc->board.vbus_pin > 0) {
free_irq(udc->board.vbus_pin, udc);
+ gpio_free(udc->board.vbus_pin);
+ }
free_irq(udc->udp_irq, udc);
device_unregister(&udc->gadget.dev);
iounmap(udc->udp_baseaddr);
+
+ if (cpu_is_at91rm9200())
+ gpio_free(udc->board.pullup_pin);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 7e34e2f..a973f2a 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -53,7 +53,7 @@
#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */
#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */
#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */
-#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */
+#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrupt Status */
#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */
#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */
@@ -158,13 +158,7 @@
/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
-#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff)
-#else
-#define DBG(stuff...) do{}while(0)
-#endif
-
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
# define VDBG DBG
#else
# define VDBG(stuff...) do{}while(0)
@@ -176,9 +170,10 @@
# define PACKET(stuff...) do{}while(0)
#endif
-#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...) pr_err("udc: " stuff)
+#define WARN(stuff...) pr_warning("udc: " stuff)
+#define INFO(stuff...) pr_info("udc: " stuff)
+#define DBG(stuff...) pr_debug("udc: " stuff)
#endif
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 4fb5ff4..af8b2a3 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1384,8 +1384,7 @@
return retval;
stall:
- printk(KERN_ERR
- "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+ pr_err("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
"halting endpoint...\n",
ep->ep.name, crq->bRequestType, crq->bRequest,
le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
@@ -1456,8 +1455,7 @@
set_protocol_stall(udc, ep);
break;
default:
- printk(KERN_ERR
- "udc: %s: TXCOMP: Invalid endpoint state %d, "
+ pr_err("udc: %s: TXCOMP: Invalid endpoint state %d, "
"halting endpoint...\n",
ep->ep.name, ep->state);
set_protocol_stall(udc, ep);
@@ -1486,8 +1484,7 @@
default:
usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
- printk(KERN_ERR
- "udc: %s: RXRDY: Invalid endpoint state %d, "
+ pr_err("udc: %s: RXRDY: Invalid endpoint state %d, "
"halting endpoint...\n",
ep->ep.name, ep->state);
set_protocol_stall(udc, ep);
@@ -1532,7 +1529,7 @@
pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
DBG(DBG_HW, "Packet length: %u\n", pkt_len);
if (pkt_len != sizeof(crq)) {
- printk(KERN_WARNING "udc: Invalid packet length %u "
+ pr_warning("udc: Invalid packet length %u "
"(expected %lu)\n", pkt_len, sizeof(crq));
set_protocol_stall(udc, ep);
return;
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index a68304e..08bf6f9 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -216,7 +216,6 @@
#define FIFO_IOMEM_ID 0
#define CTRL_IOMEM_ID 1
-#ifdef DEBUG
#define DBG_ERR 0x0001 /* report all error returns */
#define DBG_HW 0x0002 /* debug hardware initialization */
#define DBG_GADGET 0x0004 /* calls to/from gadget driver */
@@ -230,14 +229,12 @@
#define DBG_NONE 0x0000
#define DEBUG_LEVEL (DBG_ERR)
+
#define DBG(level, fmt, ...) \
do { \
if ((level) & DEBUG_LEVEL) \
- printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+ pr_debug("udc: " fmt, ## __VA_ARGS__); \
} while (0)
-#else
-#define DBG(level, fmt...)
-#endif
enum usba_ctrl_state {
WAIT_FOR_SETUP,
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 9db2482..cbe4453 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -61,6 +61,8 @@
#define DRIVER_DESC "USB Host+Gadget Emulator"
#define DRIVER_VERSION "02 May 2005"
+#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
+
static const char driver_name [] = "dummy_hcd";
static const char driver_desc [] = "USB Host+Gadget Emulator";
@@ -772,18 +774,17 @@
list_del_init (&dum->ep [0].ep.ep_list);
INIT_LIST_HEAD(&dum->fifo_req.queue);
+ driver->driver.bus = NULL;
dum->driver = driver;
dum->gadget.dev.driver = &driver->driver;
dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
- if ((retval = driver->bind (&dum->gadget)) != 0)
- goto err_bind_gadget;
-
- driver->driver.bus = dum->gadget.dev.parent->bus;
- if ((retval = driver_register (&driver->driver)) != 0)
- goto err_register;
- if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
- goto err_bind_driver;
+ retval = driver->bind(&dum->gadget);
+ if (retval) {
+ dum->driver = NULL;
+ dum->gadget.dev.driver = NULL;
+ return retval;
+ }
/* khubd will enumerate this in a while */
spin_lock_irq (&dum->lock);
@@ -793,20 +794,6 @@
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
-
-err_bind_driver:
- driver_unregister (&driver->driver);
-err_register:
- if (driver->unbind)
- driver->unbind (&dum->gadget);
- spin_lock_irq (&dum->lock);
- dum->pullup = 0;
- set_link_state (dum);
- spin_unlock_irq (&dum->lock);
-err_bind_gadget:
- dum->driver = NULL;
- dum->gadget.dev.driver = NULL;
- return retval;
}
EXPORT_SYMBOL (usb_gadget_register_driver);
@@ -830,11 +817,9 @@
spin_unlock_irqrestore (&dum->lock, flags);
driver->unbind (&dum->gadget);
+ dum->gadget.dev.driver = NULL;
dum->driver = NULL;
- device_release_driver (&dum->gadget.dev);
- driver_unregister (&driver->driver);
-
spin_lock_irqsave (&dum->lock, flags);
dum->pullup = 0;
set_link_state (dum);
@@ -1827,8 +1812,7 @@
INIT_LIST_HEAD (&dum->urbp_list);
- /* only show a low-power port: just 8mA */
- hcd->power_budget = 8;
+ hcd->power_budget = POWER_BUDGET;
hcd->state = HC_STATE_RUNNING;
hcd->uses_new_polling = 1;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 9e732bf..a70e255 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -1067,19 +1067,19 @@
/* on error, disable any endpoints */
if (result < 0) {
- if (!subset_active(dev))
+ if (!subset_active(dev) && dev->status_ep)
(void) usb_ep_disable (dev->status_ep);
dev->status = NULL;
(void) usb_ep_disable (dev->in_ep);
(void) usb_ep_disable (dev->out_ep);
dev->in = NULL;
dev->out = NULL;
- } else
+ }
/* activate non-CDC configs right away
* this isn't strictly according to the RNDIS spec
*/
- if (!cdc_active (dev)) {
+ else if (!cdc_active (dev)) {
netif_carrier_on (dev->net);
if (netif_running (dev->net)) {
spin_unlock (&dev->lock);
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 1d174dc..3301167 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -275,19 +275,15 @@
/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
#define LDBG(lun,fmt,args...) \
dev_dbg(&(lun)->dev , fmt , ## args)
#define MDBG(fmt,args...) \
- printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
-#else
-#define LDBG(lun,fmt,args...) \
- do { } while (0)
-#define MDBG(fmt,args...) \
- do { } while (0)
+ pr_debug(DRIVER_NAME ": " fmt , ## args)
+
+#ifndef DEBUG
#undef VERBOSE_DEBUG
#undef DUMP_MSGS
-#endif /* DEBUG */
+#endif /* !DEBUG */
#ifdef VERBOSE_DEBUG
#define VLDBG LDBG
@@ -304,7 +300,7 @@
dev_info(&(lun)->dev , fmt , ## args)
#define MINFO(fmt,args...) \
- printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
+ pr_info(DRIVER_NAME ": " fmt , ## args)
#define DBG(d, fmt, args...) \
dev_dbg(&(d)->gadget->dev , fmt , ## args)
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 038e7d7..63e8fa3 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -776,7 +776,7 @@
VDBG("%s, bad params\n", __FUNCTION__);
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep_index(ep))) {
+ if (unlikely(!_ep || !ep->desc)) {
VDBG("%s, bad ep\n", __FUNCTION__);
return -EINVAL;
}
@@ -1896,7 +1896,7 @@
spin_lock_irqsave(&udc->lock, flags);
- /* ------basic driver infomation ---- */
+ /* ------basic driver information ---- */
t = scnprintf(next, size,
DRIVER_DESC "\n"
"%s version: %s\n"
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 832ab82..9fb0b1e 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -551,9 +551,9 @@
#define VDBG(stuff...) do{}while(0)
#endif
-#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...) pr_err("udc: " stuff)
+#define WARN(stuff...) pr_warning("udc: " stuff)
+#define INFO(stuff...) pr_info("udc: " stuff)
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 7da7fcb..5b42ccd 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -1158,7 +1158,7 @@
/* support optional vendor/distro customization */
if (idVendor) {
if (!idProduct) {
- printk(KERN_ERR "idVendor needs idProduct!\n");
+ pr_err("idVendor needs idProduct!\n");
return -ENODEV;
}
device_desc.idVendor = cpu_to_le16(idVendor);
@@ -1190,7 +1190,7 @@
in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
if (!in_ep) {
autoconf_fail:
- printk(KERN_ERR "%s: can't autoconfigure on %s\n",
+ pr_err("%s: can't autoconfigure on %s\n",
shortname, gadget->name);
return -ENODEV;
}
@@ -1212,7 +1212,7 @@
* it SHOULD NOT have problems with bulk-capable hardware.
* so warn about unrecognized controllers, don't panic.
*/
- printk(KERN_WARNING "%s: controller '%s' not recognized\n",
+ pr_warning("%s: controller '%s' not recognized\n",
shortname, gadget->name);
device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
}
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 2ec9d19..d3e7025 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1422,6 +1422,7 @@
spin_unlock_irqrestore(&dev->lock, flags);
driver->unbind(&dev->gadget);
+ dev->gadget.dev.driver = NULL;
DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
return 0;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 47ef8bd..805602a 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1699,7 +1699,7 @@
if (!dev)
return -ESRCH;
if (0 != strcmp (CHIP, gadget->name)) {
- printk (KERN_ERR "%s expected %s controller not %s\n",
+ pr_err("%s expected %s controller not %s\n",
shortname, CHIP, gadget->name);
return -ENODEV;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 367b75c..37243ef 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -474,6 +474,7 @@
spin_unlock_irqrestore(&dev->lock, flags);
driver->unbind(&dev->gadget);
+ dev->gadget.dev.driver = NULL;
device_del(&dev->gadget.dev);
udc_disable(dev);
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index ebc5536a..835948f 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -36,9 +36,14 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
-#define DRIVER_VERSION "29 May 2007"
+#define DRIVER_VERSION "18 Oct 2007"
/* module parameters */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+static unsigned short endian = M66592_LITTLE;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)");
+#else
static unsigned short clock = M66592_XTAL24;
module_param(clock, ushort, 0644);
MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
@@ -56,6 +61,7 @@
module_param(irq_sense, ushort, 0644);
MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
"(default=2)");
+#endif
static const char udc_name[] = "m66592_udc";
static const char *m66592_ep_name[] = {
@@ -141,7 +147,7 @@
offset = get_pipectr_addr(pipenum);
pid = m66592_read(m66592, offset) & M66592_PID;
} else
- printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+ pr_err("unexpect pipe num (%d)\n", pipenum);
return pid;
}
@@ -157,7 +163,7 @@
offset = get_pipectr_addr(pipenum);
m66592_mdfy(m66592, pid, M66592_PID, offset);
} else
- printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+ pr_err("unexpect pipe num (%d)\n", pipenum);
}
static inline void pipe_start(struct m66592 *m66592, u16 pipenum)
@@ -186,7 +192,7 @@
offset = get_pipectr_addr(pipenum);
ret = m66592_read(m66592, offset);
} else
- printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+ pr_err("unexpect pipe num (%d)\n", pipenum);
return ret;
}
@@ -203,7 +209,7 @@
offset = get_pipectr_addr(pipenum);
m66592_bset(m66592, M66592_SQCLR, offset);
} else
- printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+ pr_err("unexpect pipe num(%d)\n", pipenum);
}
static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
@@ -285,7 +291,7 @@
break;
}
if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
- printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
+ pr_err("m66592 pipe memory is insufficient(%d)\n",
m66592->bi_bufnum);
return -ENOMEM;
}
@@ -326,7 +332,7 @@
if (info->type == M66592_BULK)
m66592->bulk--;
} else
- printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
+ pr_err("ep_release: unexpect pipenum (%d)\n",
info->pipe);
}
@@ -360,6 +366,7 @@
ep->fifosel = M66592_D0FIFOSEL;
ep->fifoctr = M66592_D0FIFOCTR;
ep->fifotrn = M66592_D0FIFOTRN;
+#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
} else if (m66592->num_dma == 1) {
m66592->num_dma++;
ep->use_dma = 1;
@@ -367,6 +374,7 @@
ep->fifosel = M66592_D1FIFOSEL;
ep->fifoctr = M66592_D1FIFOCTR;
ep->fifotrn = M66592_D1FIFOTRN;
+#endif
} else {
ep->use_dma = 0;
ep->fifoaddr = M66592_CFIFO;
@@ -422,7 +430,7 @@
case USB_ENDPOINT_XFER_BULK:
if (m66592->bulk >= M66592_MAX_NUM_BULK) {
if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
- printk(KERN_ERR "bulk pipe is insufficient\n");
+ pr_err("bulk pipe is insufficient\n");
return -ENODEV;
} else {
info.pipe = M66592_BASE_PIPENUM_ISOC
@@ -438,7 +446,7 @@
break;
case USB_ENDPOINT_XFER_INT:
if (m66592->interrupt >= M66592_MAX_NUM_INT) {
- printk(KERN_ERR "interrupt pipe is insufficient\n");
+ pr_err("interrupt pipe is insufficient\n");
return -ENODEV;
}
info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt;
@@ -447,7 +455,7 @@
break;
case USB_ENDPOINT_XFER_ISOC:
if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
- printk(KERN_ERR "isochronous pipe is insufficient\n");
+ pr_err("isochronous pipe is insufficient\n");
return -ENODEV;
}
info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous;
@@ -455,7 +463,7 @@
counter = &m66592->isochronous;
break;
default:
- printk(KERN_ERR "unexpect xfer type\n");
+ pr_err("unexpect xfer type\n");
return -EINVAL;
}
ep->type = info.type;
@@ -470,7 +478,7 @@
ret = pipe_buffer_setting(m66592, &info);
if (ret < 0) {
- printk(KERN_ERR "pipe_buffer_setting fail\n");
+ pr_err("pipe_buffer_setting fail\n");
return ret;
}
@@ -606,11 +614,33 @@
control_end(ep->m66592, 0);
break;
default:
- printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+ pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq);
break;
}
}
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+static void init_controller(struct m66592 *m66592)
+{
+ usbf_start_clock();
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+ /* This is a workaound for SH7722 2nd cut */
+ m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
+ m66592_bset(m66592, 0x1000, M66592_TESTMODE);
+ m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
+
+ m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
+
+ m66592_write(m66592, 0, M66592_CFBCFG);
+ m66592_write(m66592, 0, M66592_D0FBCFG);
+ m66592_bset(m66592, endian, M66592_CFBCFG);
+ m66592_bset(m66592, endian, M66592_D0FBCFG);
+}
+#else /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
static void init_controller(struct m66592 *m66592)
{
m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
@@ -636,9 +666,13 @@
m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
M66592_DMA0CFG);
}
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
static void disable_controller(struct m66592 *m66592)
{
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+ usbf_stop_clock();
+#else
m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
udelay(1);
m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
@@ -646,15 +680,20 @@
m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
udelay(1);
m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+#endif
}
static void m66592_start_xclock(struct m66592 *m66592)
{
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+ usbf_start_clock();
+#else
u16 tmp;
tmp = m66592_read(m66592, M66592_SYSCFG);
if (!(tmp & M66592_XCKE))
m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+#endif
}
/*-------------------------------------------------------------------------*/
@@ -709,7 +748,7 @@
do {
tmp = m66592_read(m66592, ep->fifoctr);
if (i++ > 100000) {
- printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+ pr_err("pipe0 is busy. maybe cpu i/o bus "
"conflict. please power off this controller.");
return;
}
@@ -759,7 +798,7 @@
if (unlikely((tmp & M66592_FRDY) == 0)) {
pipe_stop(m66592, pipenum);
pipe_irq_disable(m66592, pipenum);
- printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+ pr_err("write fifo not ready. pipnum=%d\n", pipenum);
return;
}
@@ -808,7 +847,7 @@
req->req.status = -EPIPE;
pipe_stop(m66592, pipenum);
pipe_irq_disable(m66592, pipenum);
- printk(KERN_ERR "read fifo not ready");
+ pr_err("read fifo not ready");
return;
}
@@ -1063,7 +1102,7 @@
break;
default:
m66592->gadget.speed = USB_SPEED_UNKNOWN;
- printk(KERN_ERR "USB speed unknown\n");
+ pr_err("USB speed unknown\n");
}
}
@@ -1122,7 +1161,7 @@
control_end(m66592, 0);
break;
default:
- printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+ pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq);
break;
}
}
@@ -1142,6 +1181,19 @@
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+ if (!intsts0 && !intenb0) {
+ /*
+ * When USB clock stops, it cannot read register. Even if a
+ * clock stops, the interrupt occurs. So this driver turn on
+ * a clock by this timing and do re-reading of register.
+ */
+ m66592_start_xclock(m66592);
+ intsts0 = m66592_read(m66592, M66592_INTSTS0);
+ intenb0 = m66592_read(m66592, M66592_INTENB0);
+ }
+#endif
+
savepipe = m66592_read(m66592, M66592_CFIFOSEL);
mask0 = intsts0 & intenb0;
@@ -1409,13 +1461,13 @@
retval = device_add(&m66592->gadget.dev);
if (retval) {
- printk(KERN_ERR "device_add error (%d)\n", retval);
+ pr_err("device_add error (%d)\n", retval);
goto error;
}
retval = driver->bind (&m66592->gadget);
if (retval) {
- printk(KERN_ERR "bind to driver error (%d)\n", retval);
+ pr_err("bind to driver error (%d)\n", retval);
device_del(&m66592->gadget.dev);
goto error;
}
@@ -1456,6 +1508,7 @@
m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
driver->unbind(&m66592->gadget);
+ m66592->gadget.dev.driver = NULL;
init_controller(m66592);
disable_controller(m66592);
@@ -1485,6 +1538,7 @@
iounmap(m66592->reg);
free_irq(platform_get_irq(pdev, 0), m66592);
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+ usbf_stop_clock();
kfree(m66592);
return 0;
}
@@ -1508,28 +1562,28 @@
(char *)udc_name);
if (!res) {
ret = -ENODEV;
- printk(KERN_ERR "platform_get_resource_byname error.\n");
+ pr_err("platform_get_resource_byname error.\n");
goto clean_up;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENODEV;
- printk(KERN_ERR "platform_get_irq error.\n");
+ pr_err("platform_get_irq error.\n");
goto clean_up;
}
reg = ioremap(res->start, resource_len(res));
if (reg == NULL) {
ret = -ENOMEM;
- printk(KERN_ERR "ioremap error.\n");
+ pr_err("ioremap error.\n");
goto clean_up;
}
/* initialize ucd */
m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
if (m66592 == NULL) {
- printk(KERN_ERR "kzalloc error\n");
+ pr_err("kzalloc error\n");
goto clean_up;
}
@@ -1555,7 +1609,7 @@
ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
udc_name, m66592);
if (ret < 0) {
- printk(KERN_ERR "request_irq error (%d)\n", ret);
+ pr_err("request_irq error (%d)\n", ret);
goto clean_up;
}
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index bfa0c64..17b792b 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -72,6 +72,11 @@
#define M66592_P_TST_J 0x0001 /* PERI TEST J */
#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#define M66592_CFBCFG 0x0A
+#define M66592_D0FBCFG 0x0C
+#define M66592_LITTLE 0x0100 /* b8: Little endian mode */
+#else
#define M66592_PINCFG 0x0A
#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
@@ -91,6 +96,7 @@
#define M66592_PKTM 0x0020 /* b5: Packet mode */
#define M66592_DENDE 0x0010 /* b4: Dend enable */
#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
#define M66592_CFIFO 0x10
#define M66592_D0FIFO 0x14
@@ -103,9 +109,13 @@
#define M66592_REW 0x4000 /* b14: Buffer rewind */
#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#define M66592_MBW 0x0800 /* b11: Maximum bit width for FIFO */
+#else
#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
#define M66592_MBW_8 0x0000 /* 8bit */
#define M66592_MBW_16 0x0400 /* 16bit */
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */
@@ -530,8 +540,13 @@
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+ len = (len + 3) / 4;
+ insl(fifoaddr, buf, len);
+#else
len = (len + 1) / 2;
insw(fifoaddr, buf, len);
+#endif
}
static inline void m66592_write(struct m66592 *m66592, u16 val,
@@ -545,6 +560,24 @@
void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+ unsigned long count;
+ unsigned char *pb;
+ int i;
+
+ count = len / 4;
+ outsl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ pb = buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (m66592_read(m66592, M66592_CFBCFG)) /* little */
+ outb(pb[i], fifoaddr + (3 - i));
+ else
+ outb(pb[i], fifoaddr + i);
+ }
+ }
+#else
unsigned long odd = len & 0x0001;
len = len / 2;
@@ -553,6 +586,7 @@
unsigned char *p = buf + len*2;
outb(*p, fifoaddr);
}
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
}
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
@@ -570,6 +604,26 @@
#define m66592_bset(m66592, val, offset) \
m66592_mdfy(m66592, val, 0, offset)
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#include <asm/io.h>
+#define MSTPCR2 0xA4150038 /* for SH7722 */
+#define MSTPCR2_USB 0x00000800
+
+static inline void usbf_start_clock(void)
+{
+ ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2);
+}
+
+static inline void usbf_stop_clock(void)
+{
+ ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2);
+}
+
+#else
+#define usbf_start_clock(x)
+#define usbf_stop_clock(x)
+#endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+
#endif /* ifndef __M66592_UDC_H__ */
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index d5d473f..33469cf 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2435,7 +2435,7 @@
break;
default:
delegate:
- VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
+ VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x "
"ep_cfg %08x\n",
u.r.bRequestType, u.r.bRequest,
w_value, w_index, w_length,
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index d377154..e6d68bd 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -4,6 +4,8 @@
* Copyright (C) 2004 Texas Instruments, Inc.
* Copyright (C) 2004-2005 David Brownell
*
+ * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -60,11 +62,6 @@
/* bulk DMA seems to be behaving for both IN and OUT */
#define USE_DMA
-/* FIXME: OMAP2 currently has some problem in DMA mode */
-#ifdef CONFIG_ARCH_OMAP2
-#undef USE_DMA
-#endif
-
/* ISO too */
#define USE_ISO
@@ -73,6 +70,8 @@
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define OMAP2_DMA_CH(ch) (((ch) - 1) << 1)
+#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch))
/*
* The OMAP UDC needs _very_ early endpoint setup: before enabling the
@@ -571,20 +570,25 @@
const int sync_mode = cpu_is_omap15xx()
? OMAP_DMA_SYNC_FRAME
: OMAP_DMA_SYNC_ELEMENT;
+ int dma_trigger = 0;
+
+ if (cpu_is_omap24xx())
+ dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel);
/* measure length in either bytes or packets */
if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
+ || (cpu_is_omap24xx() && length < ep->maxpacket)
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, sync_mode, 0, 0);
+ length, 1, sync_mode, dma_trigger, 0);
} else {
length = min(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1);
txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, length, sync_mode,
- 0, 0);
+ dma_trigger, 0);
length *= ep->maxpacket;
}
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
@@ -622,20 +626,31 @@
static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
{
- unsigned packets;
+ unsigned packets = req->req.length - req->req.actual;
+ int dma_trigger = 0;
+
+ if (cpu_is_omap24xx())
+ dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
/* NOTE: we filtered out "short reads" before, so we know
* the buffer has only whole numbers of packets.
+ * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode
*/
-
- /* set up this DMA transfer, enable the fifo, start */
- packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
- packets = min(packets, (unsigned)UDC_RXN_TC + 1);
- req->dma_bytes = packets * ep->ep.maxpacket;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
- ep->ep.maxpacket >> 1, packets,
- OMAP_DMA_SYNC_ELEMENT,
- 0, 0);
+ if (cpu_is_omap24xx() && packets < ep->maxpacket) {
+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
+ packets, 1, OMAP_DMA_SYNC_ELEMENT,
+ dma_trigger, 0);
+ req->dma_bytes = packets;
+ } else {
+ /* set up this DMA transfer, enable the fifo, start */
+ packets /= ep->ep.maxpacket;
+ packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+ req->dma_bytes = packets * ep->ep.maxpacket;
+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+ ep->ep.maxpacket >> 1, packets,
+ OMAP_DMA_SYNC_ELEMENT,
+ dma_trigger, 0);
+ }
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
0, 0);
@@ -743,6 +758,7 @@
{
u16 reg;
int status, restart, is_in;
+ int dma_channel;
is_in = ep->bEndpointAddress & USB_DIR_IN;
if (is_in)
@@ -769,11 +785,15 @@
ep->dma_channel = channel;
if (is_in) {
- status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel,
+ if (cpu_is_omap24xx())
+ dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel);
+ else
+ dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
+ status = omap_request_dma(dma_channel,
ep->ep.name, dma_error, ep, &ep->lch);
if (status == 0) {
UDC_TXDMA_CFG_REG = reg;
- /* EMIFF */
+ /* EMIFF or SDRC */
omap_set_dma_src_burst_mode(ep->lch,
OMAP_DMA_DATA_BURST_4);
omap_set_dma_src_data_pack(ep->lch, 1);
@@ -785,7 +805,12 @@
0, 0);
}
} else {
- status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
+ if (cpu_is_omap24xx())
+ dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel);
+ else
+ dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
+
+ status = omap_request_dma(dma_channel,
ep->ep.name, dma_error, ep, &ep->lch);
if (status == 0) {
UDC_RXDMA_CFG_REG = reg;
@@ -795,7 +820,7 @@
OMAP_DMA_AMODE_CONSTANT,
(unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
0, 0);
- /* EMIFF */
+ /* EMIFF or SDRC */
omap_set_dma_dest_burst_mode(ep->lch,
OMAP_DMA_DATA_BURST_4);
omap_set_dma_dest_data_pack(ep->lch, 1);
@@ -808,7 +833,7 @@
omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
/* channel type P: hw synch (fifo) */
- if (!cpu_is_omap15xx())
+ if (cpu_class_is_omap1() && !cpu_is_omap15xx())
OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
}
@@ -926,11 +951,13 @@
/* this isn't bogus, but OMAP DMA isn't the only hardware to
* have a hard time with partial packet reads... reject it.
+ * Except OMAP2 can handle the small packets.
*/
if (use_dma
&& ep->has_dma
&& ep->bEndpointAddress != 0
&& (ep->bEndpointAddress & USB_DIR_IN) == 0
+ && !cpu_class_is_omap2()
&& (req->req.length % ep->ep.maxpacket) != 0) {
DBG("%s, no partial packet OUT reads\n", __FUNCTION__);
return -EMSGSIZE;
@@ -1001,7 +1028,7 @@
/* STATUS for zero length DATA stages is
* always an IN ... even for IN transfers,
- * a wierd case which seem to stall OMAP.
+ * a weird case which seem to stall OMAP.
*/
UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
UDC_CTRL_REG = UDC_CLR_EP;
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 1dc398b..c6b9cbc 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -182,21 +182,16 @@
/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
-#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff)
-#else
-#define DBG(stuff...) do{}while(0)
-#endif
-
#ifdef VERBOSE
# define VDBG DBG
#else
# define VDBG(stuff...) do{}while(0)
#endif
-#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...) pr_err("udc: " stuff)
+#define WARN(stuff...) pr_warning("udc: " stuff)
+#define INFO(stuff...) pr_info("udc: " stuff)
+#define DBG(stuff...) pr_debug("udc: " stuff)
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
new file mode 100644
index 0000000..9fdabc8
--- /dev/null
+++ b/drivers/usb/gadget/printer.c
@@ -0,0 +1,1592 @@
+/*
+ * printer.c -- Printer gadget driver
+ *
+ * Copyright (C) 2003-2005 David Brownell
+ * Copyright (C) 2006 Craig W. Nadler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/cdev.h>
+
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/g_printer.h>
+
+#include "gadget_chips.h"
+
+#define DRIVER_DESC "Printer Gadget"
+#define DRIVER_VERSION "2007 OCT 06"
+
+static const char shortname [] = "printer";
+static const char driver_desc [] = DRIVER_DESC;
+
+static dev_t g_printer_devno;
+
+static struct class *usb_gadget_class;
+
+/*-------------------------------------------------------------------------*/
+
+struct printer_dev {
+ spinlock_t lock; /* lock this structure */
+ /* lock buffer lists during read/write calls */
+ spinlock_t lock_printer_io;
+ struct usb_gadget *gadget;
+ struct usb_request *req; /* for control responses */
+ u8 config;
+ s8 interface;
+ struct usb_ep *in_ep, *out_ep;
+ const struct usb_endpoint_descriptor
+ *in, *out;
+ struct list_head rx_reqs; /* List of free RX structs */
+ struct list_head rx_reqs_active; /* List of Active RX xfers */
+ struct list_head rx_buffers; /* List of completed xfers */
+ /* wait until there is data to be read. */
+ wait_queue_head_t rx_wait;
+ struct list_head tx_reqs; /* List of free TX structs */
+ struct list_head tx_reqs_active; /* List of Active TX xfers */
+ /* Wait until there are write buffers available to use. */
+ wait_queue_head_t tx_wait;
+ /* Wait until all write buffers have been sent. */
+ wait_queue_head_t tx_flush_wait;
+ struct usb_request *current_rx_req;
+ size_t current_rx_bytes;
+ u8 *current_rx_buf;
+ u8 printer_status;
+ u8 reset_printer;
+ struct class_device *printer_class_dev;
+ struct cdev printer_cdev;
+ struct device *pdev;
+ u8 printer_cdev_open;
+ wait_queue_head_t wait;
+};
+
+static struct printer_dev usb_printer_gadget;
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ */
+#define PRINTER_VENDOR_NUM 0x0525 /* NetChip */
+#define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */
+
+/* Some systems will want different product identifers published in the
+ * device descriptor, either numbers or strings or both. These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort __initdata idVendor;
+module_param(idVendor, ushort, S_IRUGO);
+MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+
+static ushort __initdata idProduct;
+module_param(idProduct, ushort, S_IRUGO);
+MODULE_PARM_DESC(idProduct, "USB Product ID");
+
+static ushort __initdata bcdDevice;
+module_param(bcdDevice, ushort, S_IRUGO);
+MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+
+static char *__initdata iManufacturer;
+module_param(iManufacturer, charp, S_IRUGO);
+MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+
+static char *__initdata iProduct;
+module_param(iProduct, charp, S_IRUGO);
+MODULE_PARM_DESC(iProduct, "USB Product string");
+
+static char *__initdata iSerialNum;
+module_param(iSerialNum, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNum, "1");
+
+static char *__initdata iPNPstring;
+module_param(iPNPstring, charp, S_IRUGO);
+MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
+
+/* Number of requests to allocate per endpoint, not used for ep0. */
+static unsigned qlen = 10;
+module_param(qlen, uint, S_IRUGO|S_IWUSR);
+
+#define QLEN qlen
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+#define DEVSPEED USB_SPEED_HIGH
+#else /* full speed (low speed doesn't do bulk) */
+#define DEVSPEED USB_SPEED_FULL
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(d, level, fmt, args...) \
+ printk(level "%s: " fmt, DRIVER_DESC, ## args)
+
+#ifdef DEBUG
+#define DBG(dev, fmt, args...) \
+ xprintk(dev, KERN_DEBUG, fmt, ## args)
+#else
+#define DBG(dev, fmt, args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG(dev, fmt, args...) \
+ xprintk(dev, KERN_DEBUG, fmt, ## args)
+#else
+#define VDBG(dev, fmt, args...) \
+ do { } while (0)
+#endif /* VERBOSE */
+
+#define ERROR(dev, fmt, args...) \
+ xprintk(dev, KERN_ERR, fmt, ## args)
+#define WARN(dev, fmt, args...) \
+ xprintk(dev, KERN_WARNING, fmt, ## args)
+#define INFO(dev, fmt, args...) \
+ xprintk(dev, KERN_INFO, fmt, ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+ * ep0 implementation: descriptors, config management, setup().
+ * also optional class-specific notification interrupt transfer.
+ */
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand.
+ */
+
+#define STRING_MANUFACTURER 1
+#define STRING_PRODUCT 2
+#define STRING_SERIALNUM 3
+
+/* holds our biggest descriptor */
+#define USB_DESC_BUFSIZE 256
+#define USB_BUFSIZE 8192
+
+/* This device advertises one configuration. */
+#define DEV_CONFIG_VALUE 1
+#define PRINTER_INTERFACE 0
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .idVendor = __constant_cpu_to_le16(PRINTER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(PRINTER_PRODUCT_NUM),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIALNUM,
+ .bNumConfigurations = 1
+};
+
+static struct usb_otg_descriptor otg_desc = {
+ .bLength = sizeof otg_desc,
+ .bDescriptorType = USB_DT_OTG,
+ .bmAttributes = USB_OTG_SRP
+};
+
+static struct usb_config_descriptor config_desc = {
+ .bLength = sizeof config_desc,
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = 1,
+ .bConfigurationValue = DEV_CONFIG_VALUE,
+ .iConfiguration = 0,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 1 /* Self-Powered */
+};
+
+static struct usb_interface_descriptor intf_desc = {
+ .bLength = sizeof intf_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = PRINTER_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_PRINTER,
+ .bInterfaceSubClass = 1, /* Printer Sub-Class */
+ .bInterfaceProtocol = 2, /* Bi-Directional */
+ .iInterface = 0
+};
+
+static struct usb_endpoint_descriptor fs_ep_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK
+};
+
+static struct usb_endpoint_descriptor fs_ep_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK
+};
+
+static const struct usb_descriptor_header *fs_printer_function [11] = {
+ (struct usb_descriptor_header *) &otg_desc,
+ (struct usb_descriptor_header *) &intf_desc,
+ (struct usb_descriptor_header *) &fs_ep_in_desc,
+ (struct usb_descriptor_header *) &fs_ep_out_desc,
+ NULL
+};
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+static struct usb_endpoint_descriptor hs_ep_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512)
+};
+
+static struct usb_endpoint_descriptor hs_ep_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = __constant_cpu_to_le16(512)
+};
+
+static struct usb_qualifier_descriptor dev_qualifier = {
+ .bLength = sizeof dev_qualifier,
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PRINTER,
+ .bNumConfigurations = 1
+};
+
+static const struct usb_descriptor_header *hs_printer_function [11] = {
+ (struct usb_descriptor_header *) &otg_desc,
+ (struct usb_descriptor_header *) &intf_desc,
+ (struct usb_descriptor_header *) &hs_ep_in_desc,
+ (struct usb_descriptor_header *) &hs_ep_out_desc,
+ NULL
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g, hs, fs) (((void)(g)), (fs))
+
+#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+
+/*-------------------------------------------------------------------------*/
+
+/* descriptors that are built on-demand */
+
+static char manufacturer [50];
+static char product_desc [40] = DRIVER_DESC;
+static char serial_num [40] = "1";
+static char pnp_string [1024] =
+ "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";
+
+/* static strings, in UTF-8 */
+static struct usb_string strings [] = {
+ { STRING_MANUFACTURER, manufacturer, },
+ { STRING_PRODUCT, product_desc, },
+ { STRING_SERIALNUM, serial_num, },
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, gfp_flags);
+
+ if (req != NULL) {
+ req->length = len;
+ req->buf = kmalloc(len, gfp_flags);
+ if (req->buf == NULL) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+ }
+
+ return req;
+}
+
+static void
+printer_req_free(struct usb_ep *ep, struct usb_request *req)
+{
+ if (ep != NULL && req != NULL) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct printer_dev *dev = ep->driver_data;
+ int status = req->status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ list_del_init(&req->list); /* Remode from Active List */
+
+ switch (status) {
+
+ /* normal completion */
+ case 0:
+ list_add_tail(&req->list, &dev->rx_buffers);
+ wake_up_interruptible(&dev->rx_wait);
+ DBG(dev, "G_Printer : rx length %d\n", req->actual);
+ break;
+
+ /* software-driven interface shutdown */
+ case -ECONNRESET: /* unlink */
+ case -ESHUTDOWN: /* disconnect etc */
+ VDBG(dev, "rx shutdown, code %d\n", status);
+ list_add(&req->list, &dev->rx_reqs);
+ break;
+
+ /* for hardware automagic (such as pxa) */
+ case -ECONNABORTED: /* endpoint reset */
+ DBG(dev, "rx %s reset\n", ep->name);
+ list_add(&req->list, &dev->rx_reqs);
+ break;
+
+ /* data overrun */
+ case -EOVERFLOW:
+ /* FALLTHROUGH */
+
+ default:
+ DBG(dev, "rx status %d\n", status);
+ list_add(&req->list, &dev->rx_reqs);
+ break;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct printer_dev *dev = ep->driver_data;
+
+ switch (req->status) {
+ default:
+ VDBG(dev, "tx err %d\n", req->status);
+ /* FALLTHROUGH */
+ case -ECONNRESET: /* unlink */
+ case -ESHUTDOWN: /* disconnect etc */
+ break;
+ case 0:
+ break;
+ }
+
+ spin_lock(&dev->lock);
+ /* Take the request struct off the active list and put it on the
+ * free list.
+ */
+ list_del_init(&req->list);
+ list_add(&req->list, &dev->tx_reqs);
+ wake_up_interruptible(&dev->tx_wait);
+ if (likely(list_empty(&dev->tx_reqs_active)))
+ wake_up_interruptible(&dev->tx_flush_wait);
+
+ spin_unlock(&dev->lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+printer_open(struct inode *inode, struct file *fd)
+{
+ struct printer_dev *dev;
+ unsigned long flags;
+ int ret = -EBUSY;
+
+ dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ if (!dev->printer_cdev_open) {
+ dev->printer_cdev_open = 1;
+ fd->private_data = dev;
+ ret = 0;
+ /* Change the printer status to show that it's on-line. */
+ dev->printer_status |= PRINTER_SELECTED;
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ DBG(dev, "printer_open returned %x\n", ret);
+
+ return ret;
+}
+
+static int
+printer_close(struct inode *inode, struct file *fd)
+{
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ dev->printer_cdev_open = 0;
+ fd->private_data = NULL;
+ /* Change printer status to show that the printer is off-line. */
+ dev->printer_status &= ~PRINTER_SELECTED;
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ DBG(dev, "printer_close\n");
+
+ return 0;
+}
+
+static ssize_t
+printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+{
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+ size_t size;
+ size_t bytes_copied;
+ struct usb_request *req;
+ /* This is a pointer to the current USB rx request. */
+ struct usb_request *current_rx_req;
+ /* This is the number of bytes in the current rx buffer. */
+ size_t current_rx_bytes;
+ /* This is a pointer to the current rx buffer. */
+ u8 *current_rx_buf;
+
+ if (len == 0)
+ return -EINVAL;
+
+ DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
+
+ spin_lock(&dev->lock_printer_io);
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* We will use this flag later to check if a printer reset happened
+ * after we turn interrupts back on.
+ */
+ dev->reset_printer = 0;
+
+ while (likely(!list_empty(&dev->rx_reqs))) {
+ int error;
+
+ req = container_of(dev->rx_reqs.next,
+ struct usb_request, list);
+ list_del_init(&req->list);
+
+ /* The USB Host sends us whatever amount of data it wants to
+ * so we always set the length field to the full USB_BUFSIZE.
+ * If the amount of data is more than the read() caller asked
+ * for it will be stored in the request buffer until it is
+ * asked for by read().
+ */
+ req->length = USB_BUFSIZE;
+ req->complete = rx_complete;
+
+ error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+ if (error) {
+ DBG(dev, "rx submit --> %d\n", error);
+ list_add(&req->list, &dev->rx_reqs);
+ break;
+ } else {
+ list_add(&req->list, &dev->rx_reqs_active);
+ }
+ }
+
+ bytes_copied = 0;
+ current_rx_req = dev->current_rx_req;
+ current_rx_bytes = dev->current_rx_bytes;
+ current_rx_buf = dev->current_rx_buf;
+ dev->current_rx_req = NULL;
+ dev->current_rx_bytes = 0;
+ dev->current_rx_buf = NULL;
+
+ /* Check if there is any data in the read buffers. Please note that
+ * current_rx_bytes is the number of bytes in the current rx buffer.
+ * If it is zero then check if there are any other rx_buffers that
+ * are on the completed list. We are only out of data if all rx
+ * buffers are empty.
+ */
+ if ((current_rx_bytes == 0) &&
+ (likely(list_empty(&dev->rx_buffers)))) {
+ /* Turn interrupts back on before sleeping. */
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /*
+ * If no data is available check if this is a NON-Blocking
+ * call or not.
+ */
+ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
+ spin_unlock(&dev->lock_printer_io);
+ return -EAGAIN;
+ }
+
+ /* Sleep until data is available */
+ wait_event_interruptible(dev->rx_wait,
+ (likely(!list_empty(&dev->rx_buffers))));
+ spin_lock_irqsave(&dev->lock, flags);
+ }
+
+ /* We have data to return then copy it to the caller's buffer.*/
+ while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
+ && len) {
+ if (current_rx_bytes == 0) {
+ req = container_of(dev->rx_buffers.next,
+ struct usb_request, list);
+ list_del_init(&req->list);
+
+ if (req->actual && req->buf) {
+ current_rx_req = req;
+ current_rx_bytes = req->actual;
+ current_rx_buf = req->buf;
+ } else {
+ list_add(&req->list, &dev->rx_reqs);
+ continue;
+ }
+ }
+
+ /* Don't leave irqs off while doing memory copies */
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (len > current_rx_bytes)
+ size = current_rx_bytes;
+ else
+ size = len;
+
+ size -= copy_to_user(buf, current_rx_buf, size);
+ bytes_copied += size;
+ len -= size;
+ buf += size;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* We've disconnected or reset free the req and buffer */
+ if (dev->reset_printer) {
+ printer_req_free(dev->out_ep, current_rx_req);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+ return -EAGAIN;
+ }
+
+ /* If we not returning all the data left in this RX request
+ * buffer then adjust the amount of data left in the buffer.
+ * Othewise if we are done with this RX request buffer then
+ * requeue it to get any incoming data from the USB host.
+ */
+ if (size < current_rx_bytes) {
+ current_rx_bytes -= size;
+ current_rx_buf += size;
+ } else {
+ list_add(¤t_rx_req->list, &dev->rx_reqs);
+ current_rx_bytes = 0;
+ current_rx_buf = NULL;
+ current_rx_req = NULL;
+ }
+ }
+
+ dev->current_rx_req = current_rx_req;
+ dev->current_rx_bytes = current_rx_bytes;
+ dev->current_rx_buf = current_rx_buf;
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+
+ DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
+
+ if (bytes_copied)
+ return bytes_copied;
+ else
+ return -EAGAIN;
+}
+
+static ssize_t
+printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+ size_t size; /* Amount of data in a TX request. */
+ size_t bytes_copied = 0;
+ struct usb_request *req;
+
+ DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
+
+ if (len == 0)
+ return -EINVAL;
+
+ spin_lock(&dev->lock_printer_io);
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* Check if a printer reset happens while we have interrupts on */
+ dev->reset_printer = 0;
+
+ /* Check if there is any available write buffers */
+ if (likely(list_empty(&dev->tx_reqs))) {
+ /* Turn interrupts back on before sleeping. */
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /*
+ * If write buffers are available check if this is
+ * a NON-Blocking call or not.
+ */
+ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
+ spin_unlock(&dev->lock_printer_io);
+ return -EAGAIN;
+ }
+
+ /* Sleep until a write buffer is available */
+ wait_event_interruptible(dev->tx_wait,
+ (likely(!list_empty(&dev->tx_reqs))));
+ spin_lock_irqsave(&dev->lock, flags);
+ }
+
+ while (likely(!list_empty(&dev->tx_reqs)) && len) {
+
+ if (len > USB_BUFSIZE)
+ size = USB_BUFSIZE;
+ else
+ size = len;
+
+ req = container_of(dev->tx_reqs.next, struct usb_request,
+ list);
+ list_del_init(&req->list);
+
+ req->complete = tx_complete;
+ req->length = size;
+
+ /* Check if we need to send a zero length packet. */
+ if (len > size)
+ /* They will be more TX requests so no yet. */
+ req->zero = 0;
+ else
+ /* If the data amount is not a multple of the
+ * maxpacket size then send a zero length packet.
+ */
+ req->zero = ((len % dev->in_ep->maxpacket) == 0);
+
+ /* Don't leave irqs off while doing memory copies */
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (copy_from_user(req->buf, buf, size)) {
+ list_add(&req->list, &dev->tx_reqs);
+ spin_unlock(&dev->lock_printer_io);
+ return bytes_copied;
+ }
+
+ bytes_copied += size;
+ len -= size;
+ buf += size;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* We've disconnected or reset so free the req and buffer */
+ if (dev->reset_printer) {
+ printer_req_free(dev->in_ep, req);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+ return -EAGAIN;
+ }
+
+ if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
+ list_add(&req->list, &dev->tx_reqs);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+ return -EAGAIN;
+ }
+
+ list_add(&req->list, &dev->tx_reqs_active);
+
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock(&dev->lock_printer_io);
+
+ DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
+
+ if (bytes_copied) {
+ return bytes_copied;
+ } else {
+ return -EAGAIN;
+ }
+}
+
+static int
+printer_fsync(struct file *fd, struct dentry *dentry, int datasync)
+{
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+ int tx_list_empty;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (!tx_list_empty) {
+ /* Sleep until all data has been sent */
+ wait_event_interruptible(dev->tx_flush_wait,
+ (likely(list_empty(&dev->tx_reqs_active))));
+ }
+
+ return 0;
+}
+
+static unsigned int
+printer_poll(struct file *fd, poll_table *wait)
+{
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+ int status = 0;
+
+ poll_wait(fd, &dev->rx_wait, wait);
+ poll_wait(fd, &dev->tx_wait, wait);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (likely(!list_empty(&dev->tx_reqs)))
+ status |= POLLOUT | POLLWRNORM;
+
+ if (likely(!list_empty(&dev->rx_buffers)))
+ status |= POLLIN | POLLRDNORM;
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return status;
+}
+
+static int
+printer_ioctl(struct inode *inode, struct file *fd, unsigned int code,
+ unsigned long arg)
+{
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+ int status = 0;
+
+ DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
+
+ /* handle ioctls */
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ switch (code) {
+ case GADGET_GET_PRINTER_STATUS:
+ status = (int)dev->printer_status;
+ break;
+ case GADGET_SET_PRINTER_STATUS:
+ dev->printer_status = (u8)arg;
+ break;
+ default:
+ /* could not handle ioctl */
+ DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
+ code);
+ status = -ENOTTY;
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return status;
+}
+
+/* used after endpoint configuration */
+static struct file_operations printer_io_operations = {
+ .owner = THIS_MODULE,
+ .open = printer_open,
+ .read = printer_read,
+ .write = printer_write,
+ .fsync = printer_fsync,
+ .poll = printer_poll,
+ .ioctl = printer_ioctl,
+ .release = printer_close
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+set_printer_interface(struct printer_dev *dev)
+{
+ int result = 0;
+
+ dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+ dev->in_ep->driver_data = dev;
+
+ dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+ dev->out_ep->driver_data = dev;
+
+ result = usb_ep_enable(dev->in_ep, dev->in);
+ if (result != 0) {
+ DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+ goto done;
+ }
+
+ result = usb_ep_enable(dev->out_ep, dev->out);
+ if (result != 0) {
+ DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+ goto done;
+ }
+
+done:
+ /* on error, disable any endpoints */
+ if (result != 0) {
+ (void) usb_ep_disable(dev->in_ep);
+ (void) usb_ep_disable(dev->out_ep);
+ dev->in = NULL;
+ dev->out = NULL;
+ }
+
+ /* caller is responsible for cleanup on error */
+ return result;
+}
+
+static void printer_reset_interface(struct printer_dev *dev)
+{
+ if (dev->interface < 0)
+ return;
+
+ DBG(dev, "%s\n", __FUNCTION__);
+
+ if (dev->in)
+ usb_ep_disable(dev->in_ep);
+
+ if (dev->out)
+ usb_ep_disable(dev->out_ep);
+
+ dev->interface = -1;
+}
+
+/* change our operational config. must agree with the code
+ * that returns config descriptors, and altsetting code.
+ */
+static int
+printer_set_config(struct printer_dev *dev, unsigned number)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+ if (gadget_is_sa1100(gadget) && dev->config) {
+ /* tx fifo is full, but we can't clear it...*/
+ INFO(dev, "can't change configurations\n");
+ return -ESPIPE;
+ }
+
+ switch (number) {
+ case DEV_CONFIG_VALUE:
+ result = 0;
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ case 0:
+ break;
+ }
+
+ if (result) {
+ usb_gadget_vbus_draw(dev->gadget,
+ dev->gadget->is_otg ? 8 : 100);
+ } else {
+ char *speed;
+ unsigned power;
+
+ power = 2 * config_desc.bMaxPower;
+ usb_gadget_vbus_draw(dev->gadget, power);
+
+ switch (gadget->speed) {
+ case USB_SPEED_FULL: speed = "full"; break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ case USB_SPEED_HIGH: speed = "high"; break;
+#endif
+ default: speed = "?"; break;
+ }
+
+ dev->config = number;
+ INFO(dev, "%s speed config #%d: %d mA, %s\n",
+ speed, number, power, driver_desc);
+ }
+ return result;
+}
+
+static int
+config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
+ int is_otg)
+{
+ int len;
+ const struct usb_descriptor_header **function;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ int hs = (speed == USB_SPEED_HIGH);
+
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+
+ if (hs) {
+ function = hs_printer_function;
+ } else {
+ function = fs_printer_function;
+ }
+#else
+ function = fs_printer_function;
+#endif
+
+ if (index >= device_desc.bNumConfigurations)
+ return -EINVAL;
+
+ /* for now, don't advertise srp-only devices */
+ if (!is_otg)
+ function++;
+
+ len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
+ function);
+ if (len < 0)
+ return len;
+ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+ return len;
+}
+
+/* Change our operational Interface. */
+static int
+set_interface(struct printer_dev *dev, unsigned number)
+{
+ int result = 0;
+
+ if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) {
+ /* tx fifo is full, but we can't clear it...*/
+ INFO(dev, "can't change interfaces\n");
+ return -ESPIPE;
+ }
+
+ /* Free the current interface */
+ switch (dev->interface) {
+ case PRINTER_INTERFACE:
+ printer_reset_interface(dev);
+ break;
+ }
+
+ switch (number) {
+ case PRINTER_INTERFACE:
+ result = set_printer_interface(dev);
+ if (result) {
+ printer_reset_interface(dev);
+ } else {
+ dev->interface = PRINTER_INTERFACE;
+ }
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ }
+
+ if (!result)
+ INFO(dev, "Using interface %x\n", number);
+
+ return result;
+}
+
+static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->status || req->actual != req->length)
+ DBG((struct printer_dev *) ep->driver_data,
+ "setup complete --> %d, %d/%d\n",
+ req->status, req->actual, req->length);
+}
+
+static void printer_soft_reset(struct printer_dev *dev)
+{
+ struct usb_request *req;
+
+ INFO(dev, "Received Printer Reset Request\n");
+
+ if (usb_ep_disable(dev->in_ep))
+ DBG(dev, "Failed to disable USB in_ep\n");
+ if (usb_ep_disable(dev->out_ep))
+ DBG(dev, "Failed to disable USB out_ep\n");
+
+ if (dev->current_rx_req != NULL) {
+ list_add(&dev->current_rx_req->list, &dev->rx_reqs);
+ dev->current_rx_req = NULL;
+ }
+ dev->current_rx_bytes = 0;
+ dev->current_rx_buf = NULL;
+ dev->reset_printer = 1;
+
+ while (likely(!(list_empty(&dev->rx_buffers)))) {
+ req = container_of(dev->rx_buffers.next, struct usb_request,
+ list);
+ list_del_init(&req->list);
+ list_add(&req->list, &dev->rx_reqs);
+ }
+
+ while (likely(!(list_empty(&dev->rx_reqs_active)))) {
+ req = container_of(dev->rx_buffers.next, struct usb_request,
+ list);
+ list_del_init(&req->list);
+ list_add(&req->list, &dev->rx_reqs);
+ }
+
+ while (likely(!(list_empty(&dev->tx_reqs_active)))) {
+ req = container_of(dev->tx_reqs_active.next,
+ struct usb_request, list);
+ list_del_init(&req->list);
+ list_add(&req->list, &dev->tx_reqs);
+ }
+
+ if (usb_ep_enable(dev->in_ep, dev->in))
+ DBG(dev, "Failed to enable USB in_ep\n");
+ if (usb_ep_enable(dev->out_ep, dev->out))
+ DBG(dev, "Failed to enable USB out_ep\n");
+
+ wake_up_interruptible(&dev->tx_wait);
+ wake_up_interruptible(&dev->tx_flush_wait);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down.
+ */
+static int
+printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+ struct printer_dev *dev = get_gadget_data(gadget);
+ struct usb_request *req = dev->req;
+ int value = -EOPNOTSUPP;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
+
+ DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
+
+ req->complete = printer_setup_complete;
+
+ switch (ctrl->bRequestType&USB_TYPE_MASK) {
+
+ case USB_TYPE_STANDARD:
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ switch (wValue >> 8) {
+
+ case USB_DT_DEVICE:
+ value = min(wLength, (u16) sizeof device_desc);
+ memcpy(req->buf, &device_desc, value);
+ break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ case USB_DT_DEVICE_QUALIFIER:
+ if (!gadget->is_dualspeed)
+ break;
+ value = min(wLength,
+ (u16) sizeof dev_qualifier);
+ memcpy(req->buf, &dev_qualifier, value);
+ break;
+
+ case USB_DT_OTHER_SPEED_CONFIG:
+ if (!gadget->is_dualspeed)
+ break;
+ /* FALLTHROUGH */
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ case USB_DT_CONFIG:
+ value = config_buf(gadget->speed, req->buf,
+ wValue >> 8,
+ wValue & 0xff,
+ gadget->is_otg);
+ if (value >= 0)
+ value = min(wLength, (u16) value);
+ break;
+
+ case USB_DT_STRING:
+ value = usb_gadget_get_string(&stringtab,
+ wValue & 0xff, req->buf);
+ if (value >= 0)
+ value = min(wLength, (u16) value);
+ break;
+ }
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl->bRequestType != 0)
+ break;
+ if (gadget->a_hnp_support)
+ DBG(dev, "HNP available\n");
+ else if (gadget->a_alt_hnp_support)
+ DBG(dev, "HNP needs a different root port\n");
+ value = printer_set_config(dev, wValue);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ *(u8 *)req->buf = dev->config;
+ value = min(wLength, (u16) 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE ||
+ !dev->config)
+ break;
+
+ value = set_interface(dev, PRINTER_INTERFACE);
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (ctrl->bRequestType !=
+ (USB_DIR_IN|USB_RECIP_INTERFACE)
+ || !dev->config)
+ break;
+
+ *(u8 *)req->buf = dev->interface;
+ value = min(wLength, (u16) 1);
+ break;
+
+ default:
+ goto unknown;
+ }
+ break;
+
+ case USB_TYPE_CLASS:
+ switch (ctrl->bRequest) {
+ case 0: /* Get the IEEE-1284 PNP String */
+ /* Only one printer interface is supported. */
+ if ((wIndex>>8) != PRINTER_INTERFACE)
+ break;
+
+ value = (pnp_string[0]<<8)|pnp_string[1];
+ memcpy(req->buf, pnp_string, value);
+ DBG(dev, "1284 PNP String: %x %s\n", value,
+ &pnp_string[2]);
+ break;
+
+ case 1: /* Get Port Status */
+ /* Only one printer interface is supported. */
+ if (wIndex != PRINTER_INTERFACE)
+ break;
+
+ *(u8 *)req->buf = dev->printer_status;
+ value = min(wLength, (u16) 1);
+ break;
+
+ case 2: /* Soft Reset */
+ /* Only one printer interface is supported. */
+ if (wIndex != PRINTER_INTERFACE)
+ break;
+
+ printer_soft_reset(dev);
+
+ value = 0;
+ break;
+
+ default:
+ goto unknown;
+ }
+ break;
+
+ default:
+unknown:
+ VDBG(dev,
+ "unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ wValue, wIndex, wLength);
+ break;
+ }
+
+ /* respond with data transfer before status phase? */
+ if (value >= 0) {
+ req->length = value;
+ req->zero = value < wLength
+ && (value % gadget->ep0->maxpacket) == 0;
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ DBG(dev, "ep_queue --> %d\n", value);
+ req->status = 0;
+ printer_setup_complete(gadget->ep0, req);
+ }
+ }
+
+ /* host either stalls (value < 0) or reports success */
+ return value;
+}
+
+static void
+printer_disconnect(struct usb_gadget *gadget)
+{
+ struct printer_dev *dev = get_gadget_data(gadget);
+ unsigned long flags;
+
+ DBG(dev, "%s\n", __FUNCTION__);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ printer_reset_interface(dev);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void
+printer_unbind(struct usb_gadget *gadget)
+{
+ struct printer_dev *dev = get_gadget_data(gadget);
+ struct usb_request *req;
+
+
+ DBG(dev, "%s\n", __FUNCTION__);
+
+ /* Remove sysfs files */
+ device_destroy(usb_gadget_class, g_printer_devno);
+
+ /* Remove Character Device */
+ cdev_del(&dev->printer_cdev);
+
+ /* we must already have been disconnected ... no i/o may be active */
+ WARN_ON(!list_empty(&dev->tx_reqs_active));
+ WARN_ON(!list_empty(&dev->rx_reqs_active));
+
+ /* Free all memory for this driver. */
+ while (!list_empty(&dev->tx_reqs)) {
+ req = container_of(dev->tx_reqs.next, struct usb_request,
+ list);
+ list_del(&req->list);
+ printer_req_free(dev->in_ep, req);
+ }
+
+ if (dev->current_rx_req != NULL);
+ printer_req_free(dev->out_ep, dev->current_rx_req);
+
+ while (!list_empty(&dev->rx_reqs)) {
+ req = container_of(dev->rx_reqs.next,
+ struct usb_request, list);
+ list_del(&req->list);
+ printer_req_free(dev->out_ep, req);
+ }
+
+ while (!list_empty(&dev->rx_buffers)) {
+ req = container_of(dev->rx_buffers.next,
+ struct usb_request, list);
+ list_del(&req->list);
+ printer_req_free(dev->out_ep, req);
+ }
+
+ if (dev->req) {
+ printer_req_free(gadget->ep0, dev->req);
+ dev->req = NULL;
+ }
+
+ set_gadget_data(gadget, NULL);
+}
+
+static int __init
+printer_bind(struct usb_gadget *gadget)
+{
+ struct printer_dev *dev;
+ struct usb_ep *in_ep, *out_ep;
+ int status = -ENOMEM;
+ int gcnum;
+ size_t len;
+ u32 i;
+ struct usb_request *req;
+
+ dev = &usb_printer_gadget;
+
+
+ /* Setup the sysfs files for the printer gadget. */
+ dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
+ "g_printer");
+ if (IS_ERR(dev->pdev)) {
+ ERROR(dev, "Failed to create device: g_printer\n");
+ goto fail;
+ }
+
+ /*
+ * Register a character device as an interface to a user mode
+ * program that handles the printer specific functionality.
+ */
+ cdev_init(&dev->printer_cdev, &printer_io_operations);
+ dev->printer_cdev.owner = THIS_MODULE;
+ status = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
+ if (status) {
+ ERROR(dev, "Failed to open char device\n");
+ goto fail;
+ }
+
+ if (gadget_is_sa1100(gadget)) {
+ /* hardware can't write zero length packets. */
+ ERROR(dev, "SA1100 controller is unsupport by this driver\n");
+ goto fail;
+ }
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0) {
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+ } else {
+ dev_warn(&gadget->dev, "controller '%s' not recognized\n",
+ gadget->name);
+ /* unrecognized, but safe unless bulk is REALLY quirky */
+ device_desc.bcdDevice =
+ __constant_cpu_to_le16(0xFFFF);
+ }
+ snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+ device_desc.idVendor =
+ __constant_cpu_to_le16(PRINTER_VENDOR_NUM);
+ device_desc.idProduct =
+ __constant_cpu_to_le16(PRINTER_PRODUCT_NUM);
+
+ /* support optional vendor/distro customization */
+ if (idVendor) {
+ if (!idProduct) {
+ dev_err(&gadget->dev, "idVendor needs idProduct!\n");
+ return -ENODEV;
+ }
+ device_desc.idVendor = cpu_to_le16(idVendor);
+ device_desc.idProduct = cpu_to_le16(idProduct);
+ if (bcdDevice)
+ device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+ }
+
+ if (iManufacturer)
+ strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
+
+ if (iProduct)
+ strlcpy(product_desc, iProduct, sizeof product_desc);
+
+ if (iSerialNum)
+ strlcpy(serial_num, iSerialNum, sizeof serial_num);
+
+ if (iPNPstring)
+ strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
+
+ len = strlen(pnp_string);
+ pnp_string[0] = (len >> 8) & 0xFF;
+ pnp_string[1] = len & 0xFF;
+
+ /* all we really need is bulk IN/OUT */
+ usb_ep_autoconfig_reset(gadget);
+ in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc);
+ if (!in_ep) {
+autoconf_fail:
+ dev_err(&gadget->dev, "can't autoconfigure on %s\n",
+ gadget->name);
+ return -ENODEV;
+ }
+ in_ep->driver_data = in_ep; /* claim */
+
+ out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc);
+ if (!out_ep)
+ goto autoconf_fail;
+ out_ep->driver_data = out_ep; /* claim */
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ /* assumes ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+
+ /* and that all endpoints are dual-speed */
+ hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
+ hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+#endif /* DUALSPEED */
+
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+ usb_gadget_set_selfpowered(gadget);
+
+ if (gadget->is_otg) {
+ otg_desc.bmAttributes |= USB_OTG_HNP,
+ config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ config_desc.bMaxPower = 4;
+ }
+
+ spin_lock_init(&dev->lock);
+ spin_lock_init(&dev->lock_printer_io);
+ INIT_LIST_HEAD(&dev->tx_reqs);
+ INIT_LIST_HEAD(&dev->tx_reqs_active);
+ INIT_LIST_HEAD(&dev->rx_reqs);
+ INIT_LIST_HEAD(&dev->rx_reqs_active);
+ INIT_LIST_HEAD(&dev->rx_buffers);
+ init_waitqueue_head(&dev->rx_wait);
+ init_waitqueue_head(&dev->tx_wait);
+ init_waitqueue_head(&dev->tx_flush_wait);
+
+ dev->config = 0;
+ dev->interface = -1;
+ dev->printer_cdev_open = 0;
+ dev->printer_status = PRINTER_NOT_ERROR;
+ dev->current_rx_req = NULL;
+ dev->current_rx_bytes = 0;
+ dev->current_rx_buf = NULL;
+
+ dev->in_ep = in_ep;
+ dev->out_ep = out_ep;
+
+ /* preallocate control message data and buffer */
+ dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE,
+ GFP_KERNEL);
+ if (!dev->req) {
+ status = -ENOMEM;
+ goto fail;
+ }
+
+ for (i = 0; i < QLEN; i++) {
+ req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
+ if (!req) {
+ while (!list_empty(&dev->tx_reqs)) {
+ req = container_of(dev->tx_reqs.next,
+ struct usb_request, list);
+ list_del(&req->list);
+ printer_req_free(dev->in_ep, req);
+ }
+ return -ENOMEM;
+ }
+ list_add(&req->list, &dev->tx_reqs);
+ }
+
+ for (i = 0; i < QLEN; i++) {
+ req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
+ if (!req) {
+ while (!list_empty(&dev->rx_reqs)) {
+ req = container_of(dev->rx_reqs.next,
+ struct usb_request, list);
+ list_del(&req->list);
+ printer_req_free(dev->out_ep, req);
+ }
+ return -ENOMEM;
+ }
+ list_add(&req->list, &dev->rx_reqs);
+ }
+
+ dev->req->complete = printer_setup_complete;
+
+ /* finish hookup to lower layer ... */
+ dev->gadget = gadget;
+ set_gadget_data(gadget, dev);
+ gadget->ep0->driver_data = dev;
+
+ INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
+ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
+ in_ep->name);
+
+ return 0;
+
+fail:
+ printer_unbind(gadget);
+ return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver printer_driver = {
+ .speed = DEVSPEED,
+
+ .function = (char *) driver_desc,
+ .bind = printer_bind,
+ .unbind = printer_unbind,
+
+ .setup = printer_setup,
+ .disconnect = printer_disconnect,
+
+ .driver = {
+ .name = (char *) shortname,
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Craig Nadler");
+MODULE_LICENSE("GPL");
+
+static int __init
+init(void)
+{
+ int status;
+
+ usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
+ if (IS_ERR(usb_gadget_class)) {
+ status = PTR_ERR(usb_gadget_class);
+ ERROR(dev, "unable to create usb_gadget class %d\n", status);
+ return status;
+ }
+
+ status = alloc_chrdev_region(&g_printer_devno, 0, 1,
+ "USB printer gadget");
+ if (status) {
+ ERROR(dev, "alloc_chrdev_region %d\n", status);
+ class_destroy(usb_gadget_class);
+ return status;
+ }
+
+ status = usb_gadget_register_driver(&printer_driver);
+ if (status) {
+ class_destroy(usb_gadget_class);
+ unregister_chrdev_region(g_printer_devno, 1);
+ DBG(dev, "usb_gadget_register_driver %x\n", status);
+ }
+
+ return status;
+}
+module_init(init);
+
+static void __exit
+cleanup(void)
+{
+ int status;
+
+ spin_lock(&usb_printer_gadget.lock_printer_io);
+ class_destroy(usb_gadget_class);
+ unregister_chrdev_region(g_printer_devno, 2);
+
+ status = usb_gadget_unregister_driver(&printer_driver);
+ if (status)
+ ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
+
+ spin_unlock(&usb_printer_gadget.lock_printer_io);
+}
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 3173b39..4402d6f0 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -24,7 +24,7 @@
*
*/
-// #define VERBOSE DBG_VERBOSE
+/* #define VERBOSE_DEBUG */
#include <linux/device.h>
#include <linux/module.h>
@@ -38,13 +38,14 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
@@ -127,8 +128,10 @@
{
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
- if (mach->gpio_vbus)
- return gpio_get_value(mach->gpio_vbus);
+ if (mach->gpio_vbus) {
+ int value = gpio_get_value(mach->gpio_vbus);
+ return mach->gpio_vbus_inverted ? !value : value;
+ }
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@@ -677,7 +680,7 @@
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped) {
- if (ep->desc == 0 /* ep0 */) {
+ if (ep->desc == NULL/* ep0 */) {
unsigned length = _req->length;
switch (dev->ep0state) {
@@ -731,7 +734,7 @@
}
/* pio or dma irq handler advances the queue. */
- if (likely (req != 0))
+ if (likely(req != NULL))
list_add_tail(&req->queue, &ep->queue);
local_irq_restore(flags);
@@ -991,45 +994,32 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static const char proc_node_name [] = "driver/udc";
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
static int
-udc_proc_read(char *page, char **start, off_t off, int count,
- int *eof, void *_dev)
+udc_seq_show(struct seq_file *m, void *d)
{
- char *buf = page;
- struct pxa2xx_udc *dev = _dev;
- char *next = buf;
- unsigned size = count;
+ struct pxa2xx_udc *dev = m->private;
unsigned long flags;
- int i, t;
+ int i;
u32 tmp;
- if (off != 0)
- return 0;
-
local_irq_save(flags);
/* basic device status */
- t = scnprintf(next, size, DRIVER_DESC "\n"
+ seq_printf(m, DRIVER_DESC "\n"
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
driver_name, DRIVER_VERSION SIZE_STR "(pio)",
dev->driver ? dev->driver->driver.name : "(none)",
is_vbus_present() ? "full speed" : "disconnected");
- size -= t;
- next += t;
/* registers for device and ep0 */
- t = scnprintf(next, size,
+ seq_printf(m,
"uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
- size -= t;
- next += t;
tmp = UDCCR;
- t = scnprintf(next, size,
+ seq_printf(m,
"udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
(tmp & UDCCR_REM) ? " rem" : "",
(tmp & UDCCR_RSTIR) ? " rstir" : "",
@@ -1039,11 +1029,9 @@
(tmp & UDCCR_RSM) ? " rsm" : "",
(tmp & UDCCR_UDA) ? " uda" : "",
(tmp & UDCCR_UDE) ? " ude" : "");
- size -= t;
- next += t;
tmp = UDCCS0;
- t = scnprintf(next, size,
+ seq_printf(m,
"udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
(tmp & UDCCS0_SA) ? " sa" : "",
(tmp & UDCCS0_RNE) ? " rne" : "",
@@ -1053,28 +1041,22 @@
(tmp & UDCCS0_FTF) ? " ftf" : "",
(tmp & UDCCS0_IPR) ? " ipr" : "",
(tmp & UDCCS0_OPR) ? " opr" : "");
- size -= t;
- next += t;
if (dev->has_cfr) {
tmp = UDCCFR;
- t = scnprintf(next, size,
+ seq_printf(m,
"udccfr %02X =%s%s\n", tmp,
(tmp & UDCCFR_AREN) ? " aren" : "",
(tmp & UDCCFR_ACM) ? " acm" : "");
- size -= t;
- next += t;
}
if (!is_vbus_present() || !dev->driver)
goto done;
- t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
+ seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
dev->stats.write.bytes, dev->stats.write.ops,
dev->stats.read.bytes, dev->stats.read.ops,
dev->stats.irqs);
- size -= t;
- next += t;
/* dump endpoint queues */
for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
@@ -1082,61 +1064,68 @@
struct pxa2xx_request *req;
if (i != 0) {
- const struct usb_endpoint_descriptor *d;
+ const struct usb_endpoint_descriptor *desc;
- d = ep->desc;
- if (!d)
+ desc = ep->desc;
+ if (!desc)
continue;
tmp = *dev->ep [i].reg_udccs;
- t = scnprintf(next, size,
+ seq_printf(m,
"%s max %d %s udccs %02x irqs %lu\n",
- ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
+ ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
"pio", tmp, ep->pio_irqs);
/* TODO translate all five groups of udccs bits! */
} else /* ep0 should only have one transfer queued */
- t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n",
+ seq_printf(m, "ep0 max 16 pio irqs %lu\n",
ep->pio_irqs);
- if (t <= 0 || t > size)
- goto done;
- size -= t;
- next += t;
if (list_empty(&ep->queue)) {
- t = scnprintf(next, size, "\t(nothing queued)\n");
- if (t <= 0 || t > size)
- goto done;
- size -= t;
- next += t;
+ seq_printf(m, "\t(nothing queued)\n");
continue;
}
list_for_each_entry(req, &ep->queue, queue) {
- t = scnprintf(next, size,
+ seq_printf(m,
"\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
- if (t <= 0 || t > size)
- goto done;
- size -= t;
- next += t;
}
}
done:
local_irq_restore(flags);
- *eof = 1;
- return count - size;
+ return 0;
}
-#define create_proc_files() \
- create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
-#define remove_proc_files() \
- remove_proc_entry(proc_node_name, NULL)
+static int
+udc_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, udc_seq_show, inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+ .open = udc_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+#define create_debug_files(dev) \
+ do { \
+ dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
+ S_IRUGO, NULL, dev, &debug_fops); \
+ } while (0)
+#define remove_debug_files(dev) \
+ do { \
+ if (dev->debugfs_udc) \
+ debugfs_remove(dev->debugfs_udc); \
+ } while (0)
#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
-#define create_proc_files() do {} while (0)
-#define remove_proc_files() do {} while (0)
+#define create_debug_files(dev) do {} while (0)
+#define remove_debug_files(dev) do {} while (0)
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
@@ -1345,6 +1334,7 @@
local_irq_enable();
driver->unbind(&dev->gadget);
+ dev->gadget.dev.driver = NULL;
dev->driver = NULL;
device_del (&dev->gadget.dev);
@@ -1397,6 +1387,9 @@
struct pxa2xx_udc *dev = _dev;
int vbus = gpio_get_value(dev->mach->gpio_vbus);
+ if (dev->mach->gpio_vbus_inverted)
+ vbus = !vbus;
+
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
}
@@ -2099,7 +2092,7 @@
/* insist on Intel/ARM/XScale */
asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
- printk(KERN_ERR "%s: not XScale!\n", driver_name);
+ pr_err("%s: not XScale!\n", driver_name);
return -ENODEV;
}
@@ -2128,7 +2121,7 @@
break;
#endif
default:
- printk(KERN_ERR "%s: unrecognized processor: %08x\n",
+ pr_err("%s: unrecognized processor: %08x\n",
driver_name, chiprev);
/* iop3xx, ixp4xx, ... */
return -ENODEV;
@@ -2199,7 +2192,7 @@
retval = request_irq(irq, pxa2xx_udc_irq,
IRQF_DISABLED, driver_name, dev);
if (retval != 0) {
- printk(KERN_ERR "%s: can't get irq %d, err %d\n",
+ pr_err("%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
goto err_irq1;
}
@@ -2212,7 +2205,7 @@
IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
- printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+ pr_err("%s: can't get irq %i, err %d\n",
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
lubbock_fail0:
goto err_irq_lub;
@@ -2222,7 +2215,7 @@
IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
- printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+ pr_err("%s: can't get irq %i, err %d\n",
driver_name, LUBBOCK_USB_IRQ, retval);
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
goto lubbock_fail0;
@@ -2235,12 +2228,12 @@
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
driver_name, dev);
if (retval != 0) {
- printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+ pr_err("%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
goto err_vbus_irq;
}
}
- create_proc_files();
+ create_debug_files(dev);
return 0;
@@ -2277,7 +2270,7 @@
return -EBUSY;
udc_disable(dev);
- remove_proc_files();
+ remove_debug_files(dev);
if (dev->got_irq) {
free_irq(platform_get_irq(pdev, 0), dev);
@@ -2361,7 +2354,7 @@
static int __init udc_init(void)
{
- printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
+ pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);
}
module_init(udc_init);
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 1db46d7..b67e3ff 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -129,6 +129,10 @@
struct pxa2xx_udc_mach_info *mach;
u64 dma_mask;
struct pxa2xx_ep ep [PXA_UDC_NUM_ENDPOINTS];
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_udc;
+#endif
};
/*-------------------------------------------------------------------------*/
@@ -151,17 +155,19 @@
#define DBG_NOISY 3 /* ... even more: request level */
#define DBG_VERY_NOISY 4 /* ... even more: packet level */
+#define DMSG(stuff...) pr_debug("udc: " stuff)
+
#ifdef DEBUG
+static int is_vbus_present(void);
+
static const char *state_name[] = {
"EP0_IDLE",
"EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
"EP0_END_XFER", "EP0_STALL"
};
-#define DMSG(stuff...) printk(KERN_DEBUG "udc: " stuff)
-
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
# define UDC_DEBUG DBG_VERBOSE
#else
# define UDC_DEBUG DBG_NORMAL
@@ -207,7 +213,7 @@
unsigned i;
DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
- is_usb_connected() ? "host " : "disconnected",
+ is_vbus_present() ? "host " : "disconnected",
state_name[dev->ep0state],
UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
dump_udccr("udccr");
@@ -224,7 +230,7 @@
} else
DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
- if (!is_usb_connected())
+ if (!is_vbus_present())
return;
dump_udccs0 ("udccs0");
@@ -233,7 +239,7 @@
dev->stats.read.bytes, dev->stats.read.ops);
for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
- if (dev->ep [i].desc == 0)
+ if (dev->ep [i].desc == NULL)
continue;
DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
}
@@ -241,8 +247,6 @@
#else
-#define DMSG(stuff...) do{}while(0)
-
#define dump_udccr(x) do{}while(0)
#define dump_udccs0(x) do{}while(0)
#define dump_state(x) do{}while(0)
@@ -253,8 +257,9 @@
#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...) pr_err("udc: " stuff)
+#define WARN(stuff...) pr_warning("udc: " stuff)
+#define INFO(stuff...) pr_info("udc: " stuff)
#endif /* __LINUX_USB_GADGET_PXA2XX_H */
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index db1b2bf..3d03664 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -53,21 +53,18 @@
*/
#if 0
-#define DBG(str,args...) do { \
- if (rndis_debug) \
- printk(KERN_DEBUG str , ## args ); \
- } while (0)
static int rndis_debug = 0;
-
module_param (rndis_debug, int, 0);
MODULE_PARM_DESC (rndis_debug, "enable debugging");
-
#else
-
#define rndis_debug 0
-#define DBG(str,args...) do{}while(0)
#endif
+#define DBG(str,args...) do { \
+ if (rndis_debug) \
+ pr_debug(str , ## args); \
+ } while (0)
+
#define RNDIS_MAX_CONFIGS 1
@@ -679,7 +676,7 @@
#endif
default:
- printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
+ pr_warning("%s: query unknown OID 0x%08X\n",
__FUNCTION__, OID);
}
if (retval < 0)
@@ -804,7 +801,7 @@
#endif /* RNDIS_PM */
default:
- printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
+ pr_warning("%s: set unknown OID 0x%08X, size %d\n",
__FUNCTION__, OID, buf_len);
}
@@ -1126,8 +1123,7 @@
* In one case those messages seemed to relate to the host
* suspending itself.
*/
- printk (KERN_WARNING
- "%s: unknown RNDIS message 0x%08X len %d\n",
+ pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
__FUNCTION__ , MsgType, MsgLength);
{
unsigned i;
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 4ce050c..aadc420 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -893,7 +893,7 @@
/*
* s3c2410_udc_irq - interrupt handler
*/
-static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
+static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
{
struct s3c2410_udc *dev = _dev;
int usb_status;
@@ -1016,7 +1016,7 @@
}
}
- dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);
+ dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
/* Restore old index */
udc_write(idx, S3C2410_UDC_INDEX_REG);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f5738eb..f5c3896 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -89,9 +89,9 @@
#endif
#define gs_debug(format, arg...) \
- do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
+ do { if (debug) pr_debug(format, ## arg); } while (0)
#define gs_debug_level(level, format, arg...) \
- do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
+ do { if (debug >= level) pr_debug(format, ## arg); } while (0)
/* Thanks to NetChip Technologies for donating this product ID.
@@ -553,7 +553,8 @@
retval = usb_gadget_register_driver(&gs_gadget_driver);
if (retval) {
- printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval);
+ pr_err("gs_module_init: cannot register gadget driver, "
+ "ret=%d\n", retval);
return retval;
}
@@ -579,11 +580,13 @@
if (retval) {
usb_gadget_unregister_driver(&gs_gadget_driver);
put_tty_driver(gs_tty_driver);
- printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval);
+ pr_err("gs_module_init: cannot register tty driver, "
+ "ret=%d\n", retval);
return retval;
}
- printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR);
+ pr_info("gs_module_init: %s %s loaded\n",
+ GS_LONG_NAME, GS_VERSION_STR);
return 0;
}
@@ -598,7 +601,8 @@
put_tty_driver(gs_tty_driver);
usb_gadget_unregister_driver(&gs_gadget_driver);
- printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR);
+ pr_info("gs_module_exit: %s %s unloaded\n",
+ GS_LONG_NAME, GS_VERSION_STR);
}
/* TTY Driver */
@@ -621,7 +625,7 @@
gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
if (port_num < 0 || port_num >= GS_NUM_PORTS) {
- printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n",
+ pr_err("gs_open: (%d,%p,%p) invalid port number\n",
port_num, tty, file);
return -ENODEV;
}
@@ -629,15 +633,14 @@
dev = gs_device;
if (dev == NULL) {
- printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n",
+ pr_err("gs_open: (%d,%p,%p) NULL device pointer\n",
port_num, tty, file);
return -ENODEV;
}
mtx = &gs_open_close_lock[port_num];
if (mutex_lock_interruptible(mtx)) {
- printk(KERN_ERR
- "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
+ pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
port_num, tty, file);
return -ERESTARTSYS;
}
@@ -645,8 +648,7 @@
spin_lock_irqsave(&dev->dev_lock, flags);
if (dev->dev_config == GS_NO_CONFIG_ID) {
- printk(KERN_ERR
- "gs_open: (%d,%p,%p) device is not connected\n",
+ pr_err("gs_open: (%d,%p,%p) device is not connected\n",
port_num, tty, file);
ret = -ENODEV;
goto exit_unlock_dev;
@@ -655,7 +657,7 @@
port = dev->dev_port[port_num];
if (port == NULL) {
- printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
+ pr_err("gs_open: (%d,%p,%p) NULL port pointer\n",
port_num, tty, file);
ret = -ENODEV;
goto exit_unlock_dev;
@@ -665,7 +667,7 @@
spin_unlock(&dev->dev_lock);
if (port->port_dev == NULL) {
- printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
+ pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n",
port_num, tty, file);
ret = -EIO;
goto exit_unlock_port;
@@ -692,8 +694,7 @@
/* might have been disconnected while asleep, check */
if (port->port_dev == NULL) {
- printk(KERN_ERR
- "gs_open: (%d,%p,%p) port disconnected (2)\n",
+ pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n",
port_num, tty, file);
port->port_in_use = 0;
ret = -EIO;
@@ -701,7 +702,8 @@
}
if ((port->port_write_buf=buf) == NULL) {
- printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n",
+ pr_err("gs_open: (%d,%p,%p) cannot allocate "
+ "port write buffer\n",
port_num, tty, file);
port->port_in_use = 0;
ret = -ENOMEM;
@@ -714,7 +716,7 @@
/* might have been disconnected while asleep, check */
if (port->port_dev == NULL) {
- printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
+ pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n",
port_num, tty, file);
port->port_in_use = 0;
ret = -EIO;
@@ -762,7 +764,7 @@
struct mutex *mtx;
if (port == NULL) {
- printk(KERN_ERR "gs_close: NULL port pointer\n");
+ pr_err("gs_close: NULL port pointer\n");
return;
}
@@ -774,8 +776,7 @@
spin_lock_irq(&port->port_lock);
if (port->port_open_count == 0) {
- printk(KERN_ERR
- "gs_close: (%d,%p,%p) port is already closed\n",
+ pr_err("gs_close: (%d,%p,%p) port is already closed\n",
port->port_num, tty, file);
goto exit;
}
@@ -837,7 +838,7 @@
int ret;
if (port == NULL) {
- printk(KERN_ERR "gs_write: NULL port pointer\n");
+ pr_err("gs_write: NULL port pointer\n");
return -EIO;
}
@@ -850,14 +851,14 @@
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_dev == NULL) {
- printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n",
+ pr_err("gs_write: (%d,%p) port is not connected\n",
port->port_num, tty);
ret = -EIO;
goto exit;
}
if (port->port_open_count == 0) {
- printk(KERN_ERR "gs_write: (%d,%p) port is closed\n",
+ pr_err("gs_write: (%d,%p) port is closed\n",
port->port_num, tty);
ret = -EBADF;
goto exit;
@@ -888,7 +889,7 @@
struct gs_port *port = tty->driver_data;
if (port == NULL) {
- printk(KERN_ERR "gs_put_char: NULL port pointer\n");
+ pr_err("gs_put_char: NULL port pointer\n");
return;
}
@@ -898,13 +899,13 @@
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_dev == NULL) {
- printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n",
+ pr_err("gs_put_char: (%d,%p) port is not connected\n",
port->port_num, tty);
goto exit;
}
if (port->port_open_count == 0) {
- printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n",
+ pr_err("gs_put_char: (%d,%p) port is closed\n",
port->port_num, tty);
goto exit;
}
@@ -924,7 +925,7 @@
struct gs_port *port = tty->driver_data;
if (port == NULL) {
- printk(KERN_ERR "gs_flush_chars: NULL port pointer\n");
+ pr_err("gs_flush_chars: NULL port pointer\n");
return;
}
@@ -933,14 +934,13 @@
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_dev == NULL) {
- printk(KERN_ERR
- "gs_flush_chars: (%d,%p) port is not connected\n",
+ pr_err("gs_flush_chars: (%d,%p) port is not connected\n",
port->port_num, tty);
goto exit;
}
if (port->port_open_count == 0) {
- printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n",
+ pr_err("gs_flush_chars: (%d,%p) port is closed\n",
port->port_num, tty);
goto exit;
}
@@ -1038,7 +1038,7 @@
struct gs_port *port = tty->driver_data;
if (port == NULL) {
- printk(KERN_ERR "gs_ioctl: NULL port pointer\n");
+ pr_err("gs_ioctl: NULL port pointer\n");
return -EIO;
}
@@ -1076,7 +1076,7 @@
struct gs_req_entry *req_entry;
if (dev == NULL) {
- printk(KERN_ERR "gs_send: NULL device pointer\n");
+ pr_err("gs_send: NULL device pointer\n");
return -ENODEV;
}
@@ -1103,7 +1103,7 @@
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
- printk(KERN_ERR
+ pr_err(
"gs_send: cannot queue read request, ret=%d\n",
ret);
spin_lock_irqsave(&dev->dev_lock, flags);
@@ -1144,9 +1144,7 @@
port = dev->dev_port[0];
if (port == NULL) {
- printk(KERN_ERR
- "gs_send_packet: port=%d, NULL port pointer\n",
- 0);
+ pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0);
return -EIO;
}
@@ -1193,7 +1191,7 @@
port = dev->dev_port[0];
if (port == NULL) {
- printk(KERN_ERR "gs_recv_packet: port=%d, NULL port pointer\n",
+ pr_err("gs_recv_packet: port=%d, NULL port pointer\n",
port->port_num);
return -EIO;
}
@@ -1201,7 +1199,7 @@
spin_lock(&port->port_lock);
if (port->port_open_count == 0) {
- printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n",
+ pr_err("gs_recv_packet: port=%d, port is closed\n",
port->port_num);
ret = -EIO;
goto exit;
@@ -1211,14 +1209,14 @@
tty = port->port_tty;
if (tty == NULL) {
- printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n",
+ pr_err("gs_recv_packet: port=%d, NULL tty pointer\n",
port->port_num);
ret = -EIO;
goto exit;
}
if (port->port_tty->magic != TTY_MAGIC) {
- printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n",
+ pr_err("gs_recv_packet: port=%d, bad tty magic\n",
port->port_num);
ret = -EIO;
goto exit;
@@ -1245,7 +1243,7 @@
struct gs_dev *dev = ep->driver_data;
if (dev == NULL) {
- printk(KERN_ERR "gs_read_complete: NULL device pointer\n");
+ pr_err("gs_read_complete: NULL device pointer\n");
return;
}
@@ -1256,7 +1254,7 @@
requeue:
req->length = ep->maxpacket;
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
- printk(KERN_ERR
+ pr_err(
"gs_read_complete: cannot queue read request, ret=%d\n",
ret);
}
@@ -1270,7 +1268,7 @@
default:
/* unexpected */
- printk(KERN_ERR
+ pr_err(
"gs_read_complete: unexpected status error, status=%d\n",
req->status);
goto requeue;
@@ -1287,7 +1285,7 @@
struct gs_req_entry *gs_req = req->context;
if (dev == NULL) {
- printk(KERN_ERR "gs_write_complete: NULL device pointer\n");
+ pr_err("gs_write_complete: NULL device pointer\n");
return;
}
@@ -1296,8 +1294,7 @@
/* normal completion */
requeue:
if (gs_req == NULL) {
- printk(KERN_ERR
- "gs_write_complete: NULL request pointer\n");
+ pr_err("gs_write_complete: NULL request pointer\n");
return;
}
@@ -1316,7 +1313,7 @@
break;
default:
- printk(KERN_ERR
+ pr_err(
"gs_write_complete: unexpected status error, status=%d\n",
req->status);
goto requeue;
@@ -1351,7 +1348,7 @@
gs_device_desc.bcdDevice =
cpu_to_le16(GS_VERSION_NUM | gcnum);
else {
- printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
+ pr_warning("gs_bind: controller '%s' not recognized\n",
gadget->name);
/* unrecognized, but safe unless bulk is REALLY quirky */
gs_device_desc.bcdDevice =
@@ -1375,7 +1372,7 @@
if (use_acm) {
ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
if (!ep) {
- printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name);
+ pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
goto autoconf_fail;
}
gs_device_desc.idProduct = __constant_cpu_to_le16(
@@ -1425,7 +1422,7 @@
set_gadget_data(gadget, dev);
if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) {
- printk(KERN_ERR "gs_bind: cannot allocate ports\n");
+ pr_err("gs_bind: cannot allocate ports\n");
gs_unbind(gadget);
return ret;
}
@@ -1441,13 +1438,13 @@
gadget->ep0->driver_data = dev;
- printk(KERN_INFO "gs_bind: %s %s bound\n",
+ pr_info("gs_bind: %s %s bound\n",
GS_LONG_NAME, GS_VERSION_STR);
return 0;
autoconf_fail:
- printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name);
+ pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
return -ENODEV;
}
@@ -1480,7 +1477,7 @@
set_gadget_data(gadget, NULL);
}
- printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+ pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
GS_VERSION_STR);
}
@@ -1513,7 +1510,8 @@
break;
default:
- printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+ pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+ "value=%04x, index=%04x, length=%d\n",
ctrl->bRequestType, ctrl->bRequest,
wValue, wIndex, wLength);
break;
@@ -1526,7 +1524,7 @@
&& (ret % gadget->ep0->maxpacket) == 0;
ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (ret < 0) {
- printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n",
+ pr_err("gs_setup: cannot queue response, ret=%d\n",
ret);
req->status = 0;
gs_setup_complete(gadget->ep0, req);
@@ -1656,7 +1654,8 @@
break;
default:
- printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+ pr_err("gs_setup: unknown standard request, type=%02x, "
+ "request=%02x, value=%04x, index=%04x, length=%d\n",
ctrl->bRequestType, ctrl->bRequest,
wValue, wIndex, wLength);
break;
@@ -1682,7 +1681,7 @@
* handler copy that data to port->port_line_coding (iff
* it's valid) and maybe pass it on. Until then, fail.
*/
- printk(KERN_WARNING "gs_setup: set_line_coding "
+ pr_warning("gs_setup: set_line_coding "
"unuspported\n");
break;
@@ -1702,12 +1701,12 @@
* handler use that to set the state (iff it's valid) and
* maybe pass it on. Until then, fail.
*/
- printk(KERN_WARNING "gs_setup: set_control_line_state "
+ pr_warning("gs_setup: set_control_line_state "
"unuspported\n");
break;
default:
- printk(KERN_ERR "gs_setup: unknown class request, "
+ pr_err("gs_setup: unknown class request, "
"type=%02x, request=%02x, value=%04x, "
"index=%04x, length=%d\n",
ctrl->bRequestType, ctrl->bRequest,
@@ -1724,7 +1723,8 @@
static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length) {
- printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n",
+ pr_err("gs_setup_complete: status error, status=%d, "
+ "actual=%d, length=%d\n",
req->status, req->actual, req->length);
}
}
@@ -1751,11 +1751,11 @@
/* re-allocate ports for the next connection */
if (gs_alloc_ports(dev, GFP_ATOMIC) != 0)
- printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n");
+ pr_err("gs_disconnect: cannot re-allocate ports\n");
spin_unlock_irqrestore(&dev->dev_lock, flags);
- printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME);
+ pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
}
/*
@@ -1778,7 +1778,7 @@
struct gs_req_entry *req_entry;
if (dev == NULL) {
- printk(KERN_ERR "gs_set_config: NULL device pointer\n");
+ pr_err("gs_set_config: NULL device pointer\n");
return 0;
}
@@ -1823,7 +1823,8 @@
dev->dev_notify_ep = ep;
dev->dev_notify_ep_desc = ep_desc;
} else {
- printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n",
+ pr_err("gs_set_config: cannot enable NOTIFY "
+ "endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
@@ -1839,7 +1840,8 @@
dev->dev_in_ep = ep;
dev->dev_in_ep_desc = ep_desc;
} else {
- printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n",
+ pr_err("gs_set_config: cannot enable IN "
+ "endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
@@ -1855,7 +1857,8 @@
dev->dev_out_ep = ep;
dev->dev_out_ep_desc = ep_desc;
} else {
- printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n",
+ pr_err("gs_set_config: cannot enable OUT "
+ "endpoint %s, ret=%d\n",
ep->name, ret);
goto exit_reset_config;
}
@@ -1865,7 +1868,7 @@
if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
|| (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
- printk(KERN_ERR "gs_set_config: cannot find endpoints\n");
+ pr_err("gs_set_config: cannot find endpoints\n");
ret = -ENODEV;
goto exit_reset_config;
}
@@ -1876,11 +1879,12 @@
if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) {
req->complete = gs_read_complete;
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
- printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n",
- ret);
+ pr_err("gs_set_config: cannot queue read "
+ "request, ret=%d\n", ret);
}
} else {
- printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
+ pr_err("gs_set_config: cannot allocate "
+ "read requests\n");
ret = -ENOMEM;
goto exit_reset_config;
}
@@ -1893,13 +1897,14 @@
req_entry->re_req->complete = gs_write_complete;
list_add(&req_entry->re_entry, &dev->dev_req_list);
} else {
- printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
+ pr_err("gs_set_config: cannot allocate "
+ "write requests\n");
ret = -ENOMEM;
goto exit_reset_config;
}
}
- printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
+ pr_info("gs_set_config: %s configured, %s speed %s config\n",
GS_LONG_NAME,
gadget->speed == USB_SPEED_HIGH ? "high" : "full",
config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
@@ -1926,7 +1931,7 @@
struct gs_req_entry *req_entry;
if (dev == NULL) {
- printk(KERN_ERR "gs_reset_config: NULL device pointer\n");
+ pr_err("gs_reset_config: NULL device pointer\n");
return;
}
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index fcde5d9..d3d4f40 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1115,7 +1115,7 @@
ep = usb_ep_autoconfig (gadget, &fs_source_desc);
if (!ep) {
autoconf_fail:
- printk (KERN_ERR "%s: can't autoconfigure on %s\n",
+ pr_err("%s: can't autoconfigure on %s\n",
shortname, gadget->name);
return -ENODEV;
}
@@ -1139,7 +1139,7 @@
* things like configuration and altsetting numbering
* can need hardware-specific attention though.
*/
- printk (KERN_WARNING "%s: controller '%s' not recognized\n",
+ pr_warning("%s: controller '%s' not recognized\n",
shortname, gadget->name);
device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 49a91c5e..d97b16b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -29,15 +29,6 @@
To compile this driver as a module, choose M here: the
module will be called ehci-hcd.
-config USB_EHCI_SPLIT_ISO
- bool "Full speed ISO transactions (EXPERIMENTAL)"
- depends on USB_EHCI_HCD && EXPERIMENTAL
- default n
- ---help---
- This code is new and hasn't been used with many different
- EHCI or USB 2.0 transaction translator implementations.
- It should work for ISO-OUT transfers, like audio.
-
config USB_EHCI_ROOT_HUB_TT
bool "Root Hub Transaction Translators (EXPERIMENTAL)"
depends on USB_EHCI_HCD && EXPERIMENTAL
@@ -69,21 +60,30 @@
config USB_EHCI_BIG_ENDIAN_MMIO
bool
- depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX)
+ depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX)
default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
- depends on USB_EHCI_HCD && 440EPX
+ depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX)
default y
config USB_EHCI_FSL
bool
+ depends on USB_EHCI_HCD
select USB_EHCI_ROOT_HUB_TT
default y if MPC834x || PPC_MPC831x
---help---
Variation of ARC USB block used in some Freescale chips.
+config USB_EHCI_HCD_PPC_OF
+ bool "EHCI support for PPC USB controller on OF platform bus"
+ depends on USB_EHCI_HCD && PPC_OF
+ default y
+ ---help---
+ Enables support for the USB controller present on the PowerPC
+ OpenFirmware platform bus.
+
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 766ef68..da7532d 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -222,6 +222,7 @@
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index c9cc441..64ebfc5 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -323,7 +323,43 @@
#else
-/* troubleshooting help: expose state in sysfs */
+/* troubleshooting help: expose state in debugfs */
+
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_async_open,
+ .read = debug_output,
+ .release = debug_close,
+};
+static const struct file_operations debug_periodic_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_periodic_open,
+ .read = debug_output,
+ .release = debug_close,
+};
+static const struct file_operations debug_registers_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_registers_open,
+ .read = debug_output,
+ .release = debug_close,
+};
+
+static struct dentry *ehci_debug_root;
+
+struct debug_buffer {
+ ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
+ struct usb_bus *bus;
+ struct mutex mutex; /* protect filling of buffer */
+ size_t count; /* number of characters filled into buffer */
+ char *page;
+};
#define speed_char(info1) ({ char tmp; \
switch (info1 & (3 << 12)) { \
@@ -441,10 +477,8 @@
*nextp = next;
}
-static ssize_t
-show_async (struct class_device *class_dev, char *buf)
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
{
- struct usb_bus *bus;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
unsigned long flags;
@@ -452,14 +486,13 @@
char *next;
struct ehci_qh *qh;
- *buf = 0;
-
- bus = class_get_devdata(class_dev);
- hcd = bus_to_hcd(bus);
+ hcd = bus_to_hcd(buf->bus);
ehci = hcd_to_ehci (hcd);
- next = buf;
+ next = buf->page;
size = PAGE_SIZE;
+ *next = 0;
+
/* dumps a snapshot of the async schedule.
* usually empty except for long-term bulk reads, or head.
* one QH per line, and TDs we know about
@@ -477,16 +510,12 @@
}
spin_unlock_irqrestore (&ehci->lock, flags);
- return strlen (buf);
+ return strlen(buf->page);
}
-static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
#define DBG_SCHED_LIMIT 64
-
-static ssize_t
-show_periodic (struct class_device *class_dev, char *buf)
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
{
- struct usb_bus *bus;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
unsigned long flags;
@@ -500,10 +529,9 @@
return 0;
seen_count = 0;
- bus = class_get_devdata(class_dev);
- hcd = bus_to_hcd(bus);
+ hcd = bus_to_hcd(buf->bus);
ehci = hcd_to_ehci (hcd);
- next = buf;
+ next = buf->page;
size = PAGE_SIZE;
temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
@@ -623,14 +651,10 @@
return PAGE_SIZE - size;
}
-static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
-
#undef DBG_SCHED_LIMIT
-static ssize_t
-show_registers (struct class_device *class_dev, char *buf)
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
{
- struct usb_bus *bus;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
unsigned long flags;
@@ -639,15 +663,14 @@
static char fmt [] = "%*s\n";
static char label [] = "";
- bus = class_get_devdata(class_dev);
- hcd = bus_to_hcd(bus);
+ hcd = bus_to_hcd(buf->bus);
ehci = hcd_to_ehci (hcd);
- next = buf;
+ next = buf->page;
size = PAGE_SIZE;
spin_lock_irqsave (&ehci->lock, flags);
- if (bus->controller->power.power_state.event) {
+ if (buf->bus->controller->power.power_state.event) {
size = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
@@ -763,9 +786,7 @@
}
if (ehci->reclaim) {
- temp = scnprintf (next, size, "reclaim qh %p%s\n",
- ehci->reclaim,
- ehci->reclaim_ready ? " ready" : "");
+ temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
size -= temp;
next += temp;
}
@@ -789,26 +810,150 @@
return PAGE_SIZE - size;
}
-static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
+ ssize_t (*fill_func)(struct debug_buffer *))
+{
+ struct debug_buffer *buf;
+
+ buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+
+ if (buf) {
+ buf->bus = bus;
+ buf->fill_func = fill_func;
+ mutex_init(&buf->mutex);
+ }
+
+ return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+ int ret = 0;
+
+ if (!buf->page)
+ buf->page = (char *)get_zeroed_page(GFP_KERNEL);
+
+ if (!buf->page) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = buf->fill_func(buf);
+
+ if (ret >= 0) {
+ buf->count = ret;
+ ret = 0;
+ }
+
+out:
+ return ret;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+ size_t len, loff_t *offset)
+{
+ struct debug_buffer *buf = file->private_data;
+ int ret = 0;
+
+ mutex_lock(&buf->mutex);
+ if (buf->count == 0) {
+ ret = fill_buffer(buf);
+ if (ret != 0) {
+ mutex_unlock(&buf->mutex);
+ goto out;
+ }
+ }
+ mutex_unlock(&buf->mutex);
+
+ ret = simple_read_from_buffer(user_buf, len, offset,
+ buf->page, buf->count);
+
+out:
+ return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ struct debug_buffer *buf = file->private_data;
+
+ if (buf) {
+ if (buf->page)
+ free_page((unsigned long)buf->page);
+ kfree(buf);
+ }
+
+ return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private,
+ fill_periodic_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private,
+ fill_registers_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
static inline void create_debug_files (struct ehci_hcd *ehci)
{
- struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
- int retval;
+ struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
- retval = class_device_create_file(cldev, &class_device_attr_async);
- retval = class_device_create_file(cldev, &class_device_attr_periodic);
- retval = class_device_create_file(cldev, &class_device_attr_registers);
+ ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
+ if (!ehci->debug_dir)
+ goto dir_error;
+
+ ehci->debug_async = debugfs_create_file("async", S_IRUGO,
+ ehci->debug_dir, bus,
+ &debug_async_fops);
+ if (!ehci->debug_async)
+ goto async_error;
+
+ ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
+ ehci->debug_dir, bus,
+ &debug_periodic_fops);
+ if (!ehci->debug_periodic)
+ goto periodic_error;
+
+ ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+ ehci->debug_dir, bus,
+ &debug_registers_fops);
+ if (!ehci->debug_registers)
+ goto registers_error;
+ return;
+
+registers_error:
+ debugfs_remove(ehci->debug_periodic);
+periodic_error:
+ debugfs_remove(ehci->debug_async);
+async_error:
+ debugfs_remove(ehci->debug_dir);
+dir_error:
+ ehci->debug_periodic = NULL;
+ ehci->debug_async = NULL;
+ ehci->debug_dir = NULL;
}
static inline void remove_debug_files (struct ehci_hcd *ehci)
{
- struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
-
- class_device_remove_file(cldev, &class_device_attr_async);
- class_device_remove_file(cldev, &class_device_attr_periodic);
- class_device_remove_file(cldev, &class_device_attr_registers);
+ debugfs_remove(ehci->debug_registers);
+ debugfs_remove(ehci->debug_periodic);
+ debugfs_remove(ehci->debug_async);
+ debugfs_remove(ehci->debug_dir);
}
#endif /* STUB_DEBUG_FILES */
-
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 430821cb..adb0def 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -25,7 +25,7 @@
#include "ehci-fsl.h"
-/* FIXME: Power Managment is un-ported so temporarily disable it */
+/* FIXME: Power Management is un-ported so temporarily disable it */
#undef CONFIG_PM
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
@@ -323,6 +323,7 @@
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
};
static int ehci_fsl_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 5f2d74e..4caa6a8 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -33,6 +33,7 @@
#include <linux/usb.h>
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
#include "../core/hcd.h"
@@ -109,7 +110,7 @@
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
-#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
+#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
@@ -266,6 +267,7 @@
/*-------------------------------------------------------------------------*/
+static void end_unlink_async(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
#include "ehci-hub.c"
@@ -275,25 +277,41 @@
/*-------------------------------------------------------------------------*/
-static void ehci_watchdog (unsigned long param)
+static void ehci_iaa_watchdog(unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
+ u32 status, cmd;
spin_lock_irqsave (&ehci->lock, flags);
+ WARN_ON(!ehci->reclaim);
- /* lost IAA irqs wedge things badly; seen with a vt8235 */
+ status = ehci_readl(ehci, &ehci->regs->status);
+ cmd = ehci_readl(ehci, &ehci->regs->command);
+ ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+
+ /* lost IAA irqs wedge things badly; seen first with a vt8235 */
if (ehci->reclaim) {
- u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
- ehci->reclaim_ready = 1;
}
+ ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command);
+ end_unlink_async(ehci);
}
- /* stop async processing after it's idled a bit */
+ spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_watchdog(unsigned long param)
+{
+ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ /* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
start_unlink_async (ehci, ehci->async);
@@ -363,8 +381,6 @@
static void ehci_work (struct ehci_hcd *ehci)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
- if (ehci->reclaim_ready)
- end_unlink_async (ehci);
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
@@ -399,6 +415,7 @@
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
@@ -447,6 +464,10 @@
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;
+ init_timer(&ehci->iaa_watchdog);
+ ehci->iaa_watchdog.function = ehci_iaa_watchdog;
+ ehci->iaa_watchdog.data = (unsigned long) ehci;
+
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -463,7 +484,6 @@
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
ehci->reclaim = NULL;
- ehci->reclaim_ready = 0;
ehci->next_uframe = -1;
/*
@@ -654,8 +674,7 @@
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
- ehci->reclaim_ready = 1;
- bh = 1;
+ end_unlink_async(ehci);
}
/* remote wakeup [4.3.1] */
@@ -761,10 +780,16 @@
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /* if we need to use IAA and it's busy, defer */
- if (qh->qh_state == QH_STATE_LINKED
- && ehci->reclaim
- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+ /* failfast */
+ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+ end_unlink_async(ehci);
+
+ /* if it's not linked then there's nothing to do */
+ if (qh->qh_state != QH_STATE_LINKED)
+ ;
+
+ /* defer till later if busy */
+ else if (ehci->reclaim) {
struct ehci_qh *last;
for (last = ehci->reclaim;
@@ -774,12 +799,8 @@
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;
- /* bypass IAA if the hc can't care */
- } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
- end_unlink_async (ehci);
-
- /* something else might have unlinked the qh by now */
- if (qh->qh_state == QH_STATE_LINKED)
+ /* start IAA cycle */
+ } else
start_unlink_async (ehci, qh);
}
@@ -806,7 +827,19 @@
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
- unlink_async (ehci, qh);
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ unlink_async(ehci, qh);
+ break;
+ case QH_STATE_UNLINK:
+ case QH_STATE_UNLINK_WAIT:
+ /* already started */
+ break;
+ case QH_STATE_IDLE:
+ WARN_ON(1);
+ break;
+ }
break;
case PIPE_INTERRUPT:
@@ -829,16 +862,16 @@
/* reschedule QH iff another request is queued */
if (!list_empty (&qh->qtd_list)
&& HC_IS_RUNNING (hcd->state)) {
- int status;
+ int schedule_status;
- status = qh_schedule (ehci, qh);
+ schedule_status = qh_schedule (ehci, qh);
spin_unlock_irqrestore (&ehci->lock, flags);
- if (status != 0) {
+ if (schedule_status != 0) {
// shouldn't happen often, but ...
// FIXME kill those tds' urbs
err ("can't reschedule qh %p, err %d",
- qh, status);
+ qh, schedule_status);
}
return status;
}
@@ -898,6 +931,7 @@
unlink_async (ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
+ case QH_STATE_UNLINK_WAIT:
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
schedule_timeout_uninterruptible(1);
@@ -959,11 +993,26 @@
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
#endif
-#ifdef CONFIG_440EPX
+#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
#include "ehci-ppc-soc.c"
#define PLATFORM_DRIVER ehci_ppc_soc_driver
#endif
+#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
+#include "ehci-ppc-of.c"
+#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_ARCH_ORION
+#include "ehci-orion.c"
+#define PLATFORM_DRIVER ehci_orion_driver
+#endif
+
+#ifdef CONFIG_ARCH_IXP4XX
+#include "ehci-ixp4xx.c"
+#define PLATFORM_DRIVER ixp4xx_ehci_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ehci-hcd"
@@ -978,41 +1027,66 @@
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+#ifdef DEBUG
+ ehci_debug_root = debugfs_create_dir("ehci", NULL);
+ if (!ehci_debug_root)
+ return -ENOENT;
+#endif
+
#ifdef PLATFORM_DRIVER
retval = platform_driver_register(&PLATFORM_DRIVER);
if (retval < 0)
- return retval;
+ goto clean0;
#endif
#ifdef PCI_DRIVER
retval = pci_register_driver(&PCI_DRIVER);
- if (retval < 0) {
-#ifdef PLATFORM_DRIVER
- platform_driver_unregister(&PLATFORM_DRIVER);
-#endif
- return retval;
- }
+ if (retval < 0)
+ goto clean1;
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
- if (retval < 0) {
-#ifdef PLATFORM_DRIVER
- platform_driver_unregister(&PLATFORM_DRIVER);
-#endif
-#ifdef PCI_DRIVER
- pci_unregister_driver(&PCI_DRIVER);
-#endif
- return retval;
- }
+ if (retval < 0)
+ goto clean2;
#endif
+#ifdef OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto clean3;
+#endif
+ return retval;
+
+#ifdef OF_PLATFORM_DRIVER
+ /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
+clean3:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+clean2:
+#endif
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+clean1:
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+clean0:
+#endif
+#ifdef DEBUG
+ debugfs_remove(ehci_debug_root);
+ ehci_debug_root = NULL;
+#endif
return retval;
}
module_init(ehci_hcd_init);
static void __exit ehci_hcd_cleanup(void)
{
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
@@ -1022,6 +1096,9 @@
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
+#ifdef DEBUG
+ debugfs_remove(ehci_debug_root);
+#endif
}
module_exit(ehci_hcd_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 735db4a..40e8240 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -123,6 +123,8 @@
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
+ del_timer_sync(&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);
port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock);
@@ -134,7 +136,7 @@
}
ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async(ehci);
ehci_work(ehci);
/* Unlike other USB host controller types, EHCI doesn't have
@@ -170,8 +172,11 @@
}
}
+ /* Apparently some devices need a >= 1-uframe delay here */
+ if (ehci->bus_suspended)
+ udelay(150);
+
/* turn off now-idle HC */
- del_timer_sync (&ehci->watchdog);
ehci_halt (ehci);
hcd->state = HC_STATE_SUSPENDED;
@@ -291,14 +296,16 @@
/*-------------------------------------------------------------------------*/
/* Display the ports dedicated to the companion controller */
-static ssize_t show_companion(struct class_device *class_dev, char *buf)
+static ssize_t show_companion(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct ehci_hcd *ehci;
int nports, index, n;
int count = PAGE_SIZE;
char *ptr = buf;
- ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
nports = HCS_N_PORTS(ehci->hcs_params);
for (index = 0; index < nports; ++index) {
@@ -312,40 +319,21 @@
}
/*
- * Dedicate or undedicate a port to the companion controller.
- * Syntax is "[-]portnum", where a leading '-' sign means
- * return control of the port to the EHCI controller.
+ * Sets the owner of a port
*/
-static ssize_t store_companion(struct class_device *class_dev,
- const char *buf, size_t count)
+static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
{
- struct ehci_hcd *ehci;
- int portnum, new_owner, try;
u32 __iomem *status_reg;
u32 port_status;
+ int try;
- ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
- new_owner = PORT_OWNER; /* Owned by companion */
- if (sscanf(buf, "%d", &portnum) != 1)
- return -EINVAL;
- if (portnum < 0) {
- portnum = - portnum;
- new_owner = 0; /* Owned by EHCI */
- }
- if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
- return -ENOENT;
- status_reg = &ehci->regs->port_status[--portnum];
- if (new_owner)
- set_bit(portnum, &ehci->companion_ports);
- else
- clear_bit(portnum, &ehci->companion_ports);
+ status_reg = &ehci->regs->port_status[portnum];
/*
* The controller won't set the OWNER bit if the port is
* enabled, so this loop will sometimes require at least two
* iterations: one to disable the port and one to set OWNER.
*/
-
for (try = 4; try > 0; --try) {
spin_lock_irq(&ehci->lock);
port_status = ehci_readl(ehci, status_reg);
@@ -362,9 +350,39 @@
if (try > 1)
msleep(5);
}
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ehci_hcd *ehci;
+ int portnum, new_owner;
+
+ ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+ new_owner = PORT_OWNER; /* Owned by companion */
+ if (sscanf(buf, "%d", &portnum) != 1)
+ return -EINVAL;
+ if (portnum < 0) {
+ portnum = - portnum;
+ new_owner = 0; /* Owned by EHCI */
+ }
+ if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+ return -ENOENT;
+ portnum--;
+ if (new_owner)
+ set_bit(portnum, &ehci->companion_ports);
+ else
+ clear_bit(portnum, &ehci->companion_ports);
+ set_owner(ehci, portnum, new_owner);
return count;
}
-static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
static inline void create_companion_file(struct ehci_hcd *ehci)
{
@@ -372,16 +390,16 @@
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
- i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
- &class_device_attr_companion);
+ i = device_create_file(ehci_to_hcd(ehci)->self.dev,
+ &dev_attr_companion);
}
static inline void remove_companion_file(struct ehci_hcd *ehci)
{
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
- class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
- &class_device_attr_companion);
+ device_remove_file(ehci_to_hcd(ehci)->self.dev,
+ &dev_attr_companion);
}
@@ -393,10 +411,8 @@
u32 __iomem *status_reg,
int port_status
) {
- if (!(port_status & PORT_CONNECT)) {
- ehci->reset_done [index] = 0;
+ if (!(port_status & PORT_CONNECT))
return port_status;
- }
/* if reset finished and it's still not enabled -- handoff */
if (!(port_status & PORT_PE)) {
@@ -475,8 +491,6 @@
* controller by the user.
*/
- if (!(temp & PORT_CONNECT))
- ehci->reset_done [i] = 0;
if ((temp & mask) != 0
|| ((temp & PORT_RESUME) != 0
&& time_after_eq(jiffies,
@@ -864,3 +878,13 @@
spin_unlock_irqrestore (&ehci->lock, flags);
return retval;
}
+
+static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ if (ehci_is_TDI(ehci))
+ return;
+ set_owner(ehci, --portnum, PORT_OWNER);
+}
+
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
new file mode 100644
index 0000000..3041d8f
--- /dev/null
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -0,0 +1,152 @@
+/*
+ * IXP4XX EHCI Host Controller Driver
+ *
+ * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ *
+ * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/platform_device.h>
+
+static int ixp4xx_ehci_init(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval = 0;
+
+ ehci->big_endian_desc = 1;
+ ehci->big_endian_mmio = 1;
+
+ ehci->caps = hcd->regs + 0x100;
+ ehci->regs = hcd->regs + 0x100
+ + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ ehci->is_tdi_rh_tt = 1;
+ ehci_reset(ehci);
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_port_power(ehci, 0);
+
+ return retval;
+}
+
+static const struct hc_driver ixp4xx_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "IXP4XX EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = ixp4xx_ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .get_frame_number = ehci_get_frame,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#if defined(CONFIG_PM)
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+};
+
+static int ixp4xx_ehci_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ const struct hc_driver *driver = &ixp4xx_ehci_hc_driver;
+ struct resource *res;
+ int irq;
+ int retval;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ pdev->dev.bus_id);
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ pdev->dev.bus_id);
+ retval = -ENODEV;
+ goto fail_request_resource;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto fail_request_resource;
+ }
+
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto fail_ioremap;
+ }
+
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (retval)
+ goto fail_add_hcd;
+
+ return retval;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
+ return retval;
+}
+
+static int ixp4xx_ehci_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+MODULE_ALIAS("ixp4xx-ehci");
+
+static struct platform_driver ixp4xx_ehci_driver = {
+ .probe = ixp4xx_ehci_probe,
+ .remove = ixp4xx_ehci_remove,
+ .driver = {
+ .name = "ixp4xx-ehci",
+ .bus = &platform_bus_type
+ },
+};
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
new file mode 100644
index 0000000..e129981
--- /dev/null
+++ b/drivers/usb/host/ehci-orion.c
@@ -0,0 +1,272 @@
+/*
+ * drivers/usb/host/ehci-orion.c
+ *
+ * Tzachi Perelstein <tzachi@marvell.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/arch/orion.h>
+
+#define rdl(off) __raw_readl(hcd->regs + (off))
+#define wrl(off, val) __raw_writel((val), hcd->regs + (off))
+
+#define USB_CAUSE 0x310
+#define USB_MASK 0x314
+#define USB_CMD 0x140
+#define USB_MODE 0x1a8
+#define USB_IPG 0x360
+#define USB_PHY_PWR_CTRL 0x400
+#define USB_PHY_TX_CTRL 0x420
+#define USB_PHY_RX_CTRL 0x430
+#define USB_PHY_IVREF_CTRL 0x440
+#define USB_PHY_TST_GRP_CTRL 0x450
+
+/*
+ * Implement Orion USB controller specification guidelines
+ */
+static void orion_usb_setup(struct usb_hcd *hcd)
+{
+ /*
+ * Clear interrupt cause and mask
+ */
+ wrl(USB_CAUSE, 0);
+ wrl(USB_MASK, 0);
+
+ /*
+ * Reset controller
+ */
+ wrl(USB_CMD, rdl(USB_CMD) | 0x2);
+ while (rdl(USB_CMD) & 0x2);
+
+ /*
+ * GL# USB-10: Set IPG for non start of frame packets
+ * Bits[14:8]=0xc
+ */
+ wrl(USB_IPG, (rdl(USB_IPG) & ~0x7f00) | 0xc00);
+
+ /*
+ * GL# USB-9: USB 2.0 Power Control
+ * BG_VSEL[7:6]=0x1
+ */
+ wrl(USB_PHY_PWR_CTRL, (rdl(USB_PHY_PWR_CTRL) & ~0xc0)| 0x40);
+
+ /*
+ * GL# USB-1: USB PHY Tx Control - force calibration to '8'
+ * TXDATA_BLOCK_EN[21]=0x1, EXT_RCAL_EN[13]=0x1, IMP_CAL[6:3]=0x8
+ */
+ wrl(USB_PHY_TX_CTRL, (rdl(USB_PHY_TX_CTRL) & ~0x78) | 0x202040);
+
+ /*
+ * GL# USB-3 GL# USB-9: USB PHY Rx Control
+ * RXDATA_BLOCK_LENGHT[31:30]=0x3, EDGE_DET_SEL[27:26]=0,
+ * CDR_FASTLOCK_EN[21]=0, DISCON_THRESHOLD[9:8]=0, SQ_THRESH[7:4]=0x1
+ */
+ wrl(USB_PHY_RX_CTRL, (rdl(USB_PHY_RX_CTRL) & ~0xc2003f0) | 0xc0000010);
+
+ /*
+ * GL# USB-3 GL# USB-9: USB PHY IVREF Control
+ * PLLVDD12[1:0]=0x2, RXVDD[5:4]=0x3, Reserved[19]=0
+ */
+ wrl(USB_PHY_IVREF_CTRL, (rdl(USB_PHY_IVREF_CTRL) & ~0x80003 ) | 0x32);
+
+ /*
+ * GL# USB-3 GL# USB-9: USB PHY Test Group Control
+ * REG_FIFO_SQ_RST[15]=0
+ */
+ wrl(USB_PHY_TST_GRP_CTRL, rdl(USB_PHY_TST_GRP_CTRL) & ~0x8000);
+
+ /*
+ * Stop and reset controller
+ */
+ wrl(USB_CMD, rdl(USB_CMD) & ~0x1);
+ wrl(USB_CMD, rdl(USB_CMD) | 0x2);
+ while (rdl(USB_CMD) & 0x2);
+
+ /*
+ * GL# USB-5 Streaming disable REG_USB_MODE[4]=1
+ * TBD: This need to be done after each reset!
+ * GL# USB-4 Setup USB Host mode
+ */
+ wrl(USB_MODE, 0x13);
+}
+
+static int ehci_orion_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ /*
+ * data structure init
+ */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_reset(ehci);
+ ehci_port_power(ehci, 0);
+
+ return retval;
+}
+
+static const struct hc_driver ehci_orion_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Marvell Orion EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_orion_setup,
+ .start = ehci_run,
+#ifdef CONFIG_PM
+ .suspend = ehci_bus_suspend,
+ .resume = ehci_bus_resume,
+#endif
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+};
+
+static int __init ehci_orion_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ void __iomem *regs;
+ int irq, err;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_debug("Initializing Orion-SoC USB Host Controller\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ pdev->dev.bus_id);
+ err = -ENODEV;
+ goto err1;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ pdev->dev.bus_id);
+ err = -ENODEV;
+ goto err1;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ ehci_orion_hc_driver.description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ err = -EBUSY;
+ goto err1;
+ }
+
+ regs = ioremap(res->start, res->end - res->start + 1);
+ if (regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ err = -EFAULT;
+ goto err2;
+ }
+
+ hcd = usb_create_hcd(&ehci_orion_hc_driver,
+ &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ err = -ENOMEM;
+ goto err3;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+ hcd->regs = regs;
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs + 0x100;
+ ehci->regs = hcd->regs + 0x100 +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ ehci->is_tdi_rh_tt = 1;
+ ehci->sbrn = 0x20;
+
+ /*
+ * setup Orion USB controller
+ */
+ orion_usb_setup(hcd);
+
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+ if (err)
+ goto err4;
+
+ return 0;
+
+err4:
+ usb_put_hcd(hcd);
+err3:
+ iounmap(regs);
+err2:
+ release_mem_region(res->start, res->end - res->start + 1);
+err1:
+ dev_err(&pdev->dev, "init %s fail, %d\n",
+ pdev->dev.bus_id, err);
+
+ return err;
+}
+
+static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:orion-ehci");
+
+static struct platform_driver ehci_orion_driver = {
+ .probe = ehci_orion_drv_probe,
+ .remove = __exit_p(ehci_orion_drv_remove),
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver.name = "orion-ehci",
+};
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index ad0d496..3ba0166 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -305,7 +305,7 @@
/* emptying the schedule aborts any urbs */
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async(ehci);
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);
@@ -364,6 +364,7 @@
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
new file mode 100644
index 0000000..ee305b1
--- /dev/null
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -0,0 +1,238 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus
+ * Tested on AMCC PPC 440EPx
+ *
+ * Valentine Barshak <vbarshak@ru.mvista.com>
+ *
+ * Based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
+ * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+/* called during probe() after chip reset completes */
+static int ehci_ppc_of_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci->sbrn = 0x20;
+ return ehci_reset(ehci);
+}
+
+
+static const struct hc_driver ehci_ppc_of_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OF EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_ppc_of_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+};
+
+
+/*
+ * 440EPx Errata USBH_3
+ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
+ */
+#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0)
+static int __devinit
+ppc44x_enable_bmt(struct device_node *dn)
+{
+ __iomem u32 *insreg_virt;
+
+ insreg_virt = of_iomap(dn, 1);
+ if (!insreg_virt)
+ return -EINVAL;
+
+ out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT);
+
+ iounmap(insreg_virt);
+ return 0;
+}
+
+
+static int __devinit
+ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct resource res;
+ int irq;
+ int rv;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = res.end - res.start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ rv = -EBUSY;
+ goto err_rmr;
+ }
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+
+ if (of_get_property(dn, "big-endian", NULL)) {
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+ }
+ if (of_get_property(dn, "big-endian-regs", NULL))
+ ehci->big_endian_mmio = 1;
+ if (of_get_property(dn, "big-endian-desc", NULL))
+ ehci->big_endian_desc = 1;
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
+ rv = ppc44x_enable_bmt(dn);
+ ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
+ rv ? "NOT ": "");
+ }
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv == 0)
+ return 0;
+
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+
+static int ehci_hcd_ppc_of_remove(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+
+static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+
+ return 0;
+}
+
+
+static struct of_device_id ehci_hcd_ppc_of_match[] = {
+ {
+ .compatible = "usb-ehci",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
+
+
+static struct of_platform_driver ehci_hcd_ppc_of_driver = {
+ .name = "ppc-of-ehci",
+ .match_table = ehci_hcd_ppc_of_match,
+ .probe = ehci_hcd_ppc_of_probe,
+ .remove = ehci_hcd_ppc_of_remove,
+ .shutdown = ehci_hcd_ppc_of_shutdown,
+ .driver = {
+ .name = "ppc-of-ehci",
+ .owner = THIS_MODULE,
+ },
+};
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index 452d4b1..a324907 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -162,6 +162,7 @@
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 03a6b2f..bbda58e 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -72,6 +72,7 @@
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
+ .relinquish_port = ehci_relinquish_port,
};
static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index b10f39c..776a97f3 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -198,7 +198,8 @@
/* if async CSPLIT failed, try cleaning out the TT buffer */
if (status != -EPIPE
- && urb->dev->tt && !usb_pipeint (urb->pipe)
+ && urb->dev->tt
+ && !usb_pipeint(urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
&& (!ehci_is_TDI(ehci)
@@ -211,6 +212,9 @@
urb->dev->ttport, urb->dev->devnum,
usb_pipeendpoint (urb->pipe), token);
#endif /* DEBUG */
+ /* REVISIT ARC-derived cores don't clear the root
+ * hub TT buffer in this way...
+ */
usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
}
}
@@ -638,6 +642,7 @@
u32 info1 = 0, info2 = 0;
int is_input, type;
int maxp = 0;
+ struct usb_tt *tt = urb->dev->tt;
if (!qh)
return qh;
@@ -661,8 +666,9 @@
* For control/bulk requests, the HC or TT handles these.
*/
if (type == PIPE_INTERRUPT) {
- qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
- hb_mult (maxp) * max_packet (maxp)));
+ qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+ is_input, 0,
+ hb_mult(maxp) * max_packet(maxp)));
qh->start = NO_FRAME;
if (urb->dev->speed == USB_SPEED_HIGH) {
@@ -680,7 +686,6 @@
goto done;
}
} else {
- struct usb_tt *tt = urb->dev->tt;
int think_time;
/* gap is f(FS/LS transfer times) */
@@ -736,10 +741,8 @@
/* set the address of the TT; for TDI's integrated
* root hub tt, leave it zeroed.
*/
- if (!ehci_is_TDI(ehci)
- || urb->dev->tt->hub !=
- ehci_to_hcd(ehci)->self.root_hub)
- info2 |= urb->dev->tt->hub->devnum << 16;
+ if (tt && tt->hub != ehci_to_hcd(ehci)->self.root_hub)
+ info2 |= tt->hub->devnum << 16;
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
@@ -973,7 +976,7 @@
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
- timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_done(ehci);
// qh->hw_next = cpu_to_hc32(qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
@@ -983,7 +986,6 @@
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim = next;
- ehci->reclaim_ready = 0;
qh->reclaim = NULL;
qh_completions (ehci, qh);
@@ -1059,11 +1061,10 @@
return;
}
- ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
ehci_writel(ehci, cmd, &ehci->regs->command);
(void)ehci_readl(ehci, &ehci->regs->command);
- timer_action (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_start(ehci);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 80d99bc..8a8e08a 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -119,7 +119,8 @@
q = &q->fstn->fstn_next;
break;
case Q_TYPE_ITD:
- usecs += q->itd->usecs [uframe];
+ if (q->itd->hw_transaction[uframe])
+ usecs += q->itd->stream->usecs;
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next;
break;
@@ -211,7 +212,7 @@
* low/fullspeed transfer can "carry over" from one uframe to the next,
* since the TT just performs downstream transfers in sequence.
*
- * For example two seperate 100 usec transfers can start in the same uframe,
+ * For example two separate 100 usec transfers can start in the same uframe,
* and the second one would "carry over" 75 usecs into the next uframe.
*/
static void
@@ -1536,7 +1537,6 @@
uframe = next_uframe & 0x07;
frame = next_uframe >> 3;
- itd->usecs [uframe] = stream->usecs;
itd_patch(ehci, itd, iso_sched, packet, uframe);
next_uframe += stream->interval;
@@ -1565,6 +1565,16 @@
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+/* Process and recycle a completed ITD. Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly. That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs. It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
static unsigned
itd_complete (
struct ehci_hcd *ehci,
@@ -1577,6 +1587,7 @@
int urb_index = -1;
struct ehci_iso_stream *stream = itd->stream;
struct usb_device *dev;
+ unsigned retval = false;
/* for each uframe with a packet */
for (uframe = 0; uframe < 8; uframe++) {
@@ -1610,30 +1621,21 @@
}
}
- usb_put_urb (urb);
- itd->urb = NULL;
- itd->stream = NULL;
- list_move (&itd->itd_list, &stream->free_list);
- iso_stream_put (ehci, stream);
-
/* handle completion now? */
if (likely ((urb_index + 1) != urb->number_of_packets))
- return 0;
+ goto done;
/* ASSERT: it's really the last itd for this urb
list_for_each_entry (itd, &stream->td_list, itd_list)
BUG_ON (itd->urb == urb);
*/
- /* give urb back to the driver ... can be out-of-order */
+ /* give urb back to the driver; completion often (re)submits */
dev = urb->dev;
ehci_urb_done(ehci, urb, 0);
+ retval = true;
urb = NULL;
-
- /* defer stopping schedule; completion can submit */
ehci->periodic_sched--;
- if (unlikely (!ehci->periodic_sched))
- (void) disable_periodic (ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (unlikely (list_empty (&stream->td_list))) {
@@ -1645,8 +1647,15 @@
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
iso_stream_put (ehci, stream);
+ /* OK to recycle this ITD now that its completion callback ran. */
+done:
+ usb_put_urb(urb);
+ itd->urb = NULL;
+ itd->stream = NULL;
+ list_move(&itd->itd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
- return 1;
+ return retval;
}
/*-------------------------------------------------------------------------*/
@@ -1712,8 +1721,6 @@
return status;
}
-#ifdef CONFIG_USB_EHCI_SPLIT_ISO
-
/*-------------------------------------------------------------------------*/
/*
@@ -1950,6 +1957,16 @@
#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
| SITD_STS_XACT | SITD_STS_MMF)
+/* Process and recycle a completed SITD. Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly. That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs. It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
static unsigned
sitd_complete (
struct ehci_hcd *ehci,
@@ -1961,6 +1978,7 @@
int urb_index = -1;
struct ehci_iso_stream *stream = sitd->stream;
struct usb_device *dev;
+ unsigned retval = false;
urb_index = sitd->index;
desc = &urb->iso_frame_desc [urb_index];
@@ -1981,32 +1999,23 @@
desc->status = 0;
desc->actual_length = desc->length - SITD_LENGTH (t);
}
-
- usb_put_urb (urb);
- sitd->urb = NULL;
- sitd->stream = NULL;
- list_move (&sitd->sitd_list, &stream->free_list);
stream->depth -= stream->interval << 3;
- iso_stream_put (ehci, stream);
/* handle completion now? */
if ((urb_index + 1) != urb->number_of_packets)
- return 0;
+ goto done;
/* ASSERT: it's really the last sitd for this urb
list_for_each_entry (sitd, &stream->td_list, sitd_list)
BUG_ON (sitd->urb == urb);
*/
- /* give urb back to the driver */
+ /* give urb back to the driver; completion often (re)submits */
dev = urb->dev;
ehci_urb_done(ehci, urb, 0);
+ retval = true;
urb = NULL;
-
- /* defer stopping schedule; completion can submit */
ehci->periodic_sched--;
- if (!ehci->periodic_sched)
- (void) disable_periodic (ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (list_empty (&stream->td_list)) {
@@ -2018,8 +2027,15 @@
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
iso_stream_put (ehci, stream);
+ /* OK to recycle this SITD now that its completion callback ran. */
+done:
+ usb_put_urb(urb);
+ sitd->urb = NULL;
+ sitd->stream = NULL;
+ list_move(&sitd->sitd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
- return 1;
+ return retval;
}
@@ -2082,26 +2098,6 @@
return status;
}
-#else
-
-static inline int
-sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
-{
- ehci_dbg (ehci, "split iso support is disabled\n");
- return -ENOSYS;
-}
-
-static inline unsigned
-sitd_complete (
- struct ehci_hcd *ehci,
- struct ehci_sitd *sitd
-) {
- ehci_err (ehci, "sitd_complete %p?\n", sitd);
- return 0;
-}
-
-#endif /* USB_EHCI_SPLIT_ISO */
-
/*-------------------------------------------------------------------------*/
static void
@@ -2127,17 +2123,9 @@
for (;;) {
union ehci_shadow q, *q_p;
__hc32 type, *hw_p;
- unsigned uframes;
+ unsigned incomplete = false;
- /* don't scan past the live uframe */
frame = now_uframe >> 3;
- if (frame == (clock >> 3))
- uframes = now_uframe & 0x07;
- else {
- /* safe to scan the whole frame at once */
- now_uframe |= 0x07;
- uframes = 8;
- }
restart:
/* scan each element in frame's queue for completions */
@@ -2175,12 +2163,15 @@
q = q.fstn->fstn_next;
break;
case Q_TYPE_ITD:
- /* skip itds for later in the frame */
+ /* If this ITD is still active, leave it for
+ * later processing ... check the next entry.
+ */
rmb ();
- for (uf = live ? uframes : 8; uf < 8; uf++) {
+ for (uf = 0; uf < 8 && live; uf++) {
if (0 == (q.itd->hw_transaction [uf]
& ITD_ACTIVE(ehci)))
continue;
+ incomplete = true;
q_p = &q.itd->itd_next;
hw_p = &q.itd->hw_next;
type = Q_NEXT_TYPE(ehci,
@@ -2188,10 +2179,12 @@
q = *q_p;
break;
}
- if (uf != 8)
+ if (uf < 8 && live)
break;
- /* this one's ready ... HC won't cache the
+ /* Take finished ITDs out of the schedule
+ * and process them: recycle, maybe report
+ * URB completion. HC won't cache the
* pointer for much longer, if at all.
*/
*q_p = q.itd->itd_next;
@@ -2202,8 +2195,12 @@
q = *q_p;
break;
case Q_TYPE_SITD:
+ /* If this SITD is still active, leave it for
+ * later processing ... check the next entry.
+ */
if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
&& live) {
+ incomplete = true;
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE(ehci,
@@ -2211,6 +2208,11 @@
q = *q_p;
break;
}
+
+ /* Take finished SITDs out of the schedule
+ * and process them: recycle, maybe report
+ * URB completion.
+ */
*q_p = q.sitd->sitd_next;
*hw_p = q.sitd->hw_next;
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
@@ -2226,11 +2228,24 @@
}
/* assume completion callbacks modify the queue */
- if (unlikely (modified))
- goto restart;
+ if (unlikely (modified)) {
+ if (likely(ehci->periodic_sched > 0))
+ goto restart;
+ /* maybe we can short-circuit this scan! */
+ disable_periodic(ehci);
+ now_uframe = clock;
+ break;
+ }
}
- /* stop when we catch up to the HC */
+ /* If we can tell we caught up to the hardware, stop now.
+ * We can't advance our scan without collecting the ISO
+ * transfers that are still pending in this frame.
+ */
+ if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+ ehci->next_uframe = now_uframe;
+ break;
+ }
// FIXME: this assumes we won't get lapped when
// latencies climb; that should be rare, but...
@@ -2243,7 +2258,8 @@
if (now_uframe == clock) {
unsigned now;
- if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+ if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+ || ehci->periodic_sched == 0)
break;
ehci->next_uframe = now_uframe;
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 951d69f..bf92d20 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,6 @@
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
- unsigned reclaim_ready : 1;
unsigned scanning : 1;
/* periodic schedule support */
@@ -105,6 +104,7 @@
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
+ struct timer_list iaa_watchdog;
struct timer_list watchdog;
unsigned long actions;
unsigned stamp;
@@ -127,6 +127,14 @@
#else
# define COUNT(x) do {} while (0)
#endif
+
+ /* debug files */
+#ifdef DEBUG
+ struct dentry *debug_dir;
+ struct dentry *debug_async;
+ struct dentry *debug_periodic;
+ struct dentry *debug_registers;
+#endif
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
@@ -140,9 +148,21 @@
}
+static inline void
+iaa_watchdog_start(struct ehci_hcd *ehci)
+{
+ WARN_ON(timer_pending(&ehci->iaa_watchdog));
+ mod_timer(&ehci->iaa_watchdog,
+ jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
+}
+
+static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
+{
+ del_timer(&ehci->iaa_watchdog);
+}
+
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
- TIMER_IAA_WATCHDOG,
TIMER_ASYNC_SHRINK,
TIMER_ASYNC_OFF,
};
@@ -160,9 +180,6 @@
unsigned long t;
switch (action) {
- case TIMER_IAA_WATCHDOG:
- t = EHCI_IAA_JIFFIES;
- break;
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
break;
@@ -179,8 +196,7 @@
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
// watchdog stops unless there's still periodic traffic.
- if (action != TIMER_IAA_WATCHDOG
- && t > ehci->watchdog.expires
+ if (time_before_eq(t, ehci->watchdog.expires)
&& timer_pending (&ehci->watchdog))
return;
mod_timer (&ehci->watchdog, t);
@@ -534,8 +550,8 @@
* trusting urb->interval == f(epdesc->bInterval) and
* including the extra info for hw_bufp[0..2]
*/
- u8 interval;
u8 usecs, c_usecs;
+ u16 interval;
u16 tt_usecs;
u16 maxp;
u16 raw_mask;
@@ -586,7 +602,6 @@
unsigned frame; /* where scheduled */
unsigned pg;
unsigned index[8]; /* in urb->iso_frame_desc */
- u8 usecs[8];
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
@@ -725,11 +740,16 @@
* definition below can die once the 4xx support is
* finally ported over.
*/
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
#define readl_be(addr) in_be32((__force unsigned *)addr)
#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
#endif
+#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
+#define readl_be(addr) __raw_readl((__force unsigned *)addr)
+#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr)
+#endif
+
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
__u32 __iomem * regs)
{
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index c27417f..0130fd8 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -918,7 +918,6 @@
| RH_PS_OCIC | RH_PS_PRSC)) {
changed = 1;
buf[0] |= 1 << (i + 1);
- continue;
}
}
spin_unlock_irqrestore(&isp116x->lock, flags);
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index d849c80..126fcbd 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -17,6 +17,8 @@
#include <asm/mach-types.h>
#include <asm/hardware.h>
+#include <asm/gpio.h>
+
#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
@@ -271,12 +273,41 @@
static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
{
+ struct at91_usbh_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (pdata) {
+ /* REVISIT make the driver support per-port power switching,
+ * and also overcurrent detection. Here we assume the ports
+ * are always powered while this driver is active, and use
+ * active-low power switches.
+ */
+ for (i = 0; i < pdata->ports; i++) {
+ if (pdata->vbus_pin[i] <= 0)
+ continue;
+ gpio_request(pdata->vbus_pin[i], "ohci_vbus");
+ gpio_direction_output(pdata->vbus_pin[i], 0);
+ }
+ }
+
device_init_wakeup(&pdev->dev, 1);
return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
}
static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
{
+ struct at91_usbh_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (pdata) {
+ for (i = 0; i < pdata->ports; i++) {
+ if (pdata->vbus_pin[i] <= 0)
+ continue;
+ gpio_direction_output(pdata->vbus_pin[i], 1);
+ gpio_free(pdata->vbus_pin[i]);
+ }
+ }
+
device_init_wakeup(&pdev->dev, 0);
return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
}
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index ebab5ce..a22c30a 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -401,6 +401,42 @@
#else
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_async_open,
+ .read = debug_output,
+ .release = debug_close,
+};
+static const struct file_operations debug_periodic_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_periodic_open,
+ .read = debug_output,
+ .release = debug_close,
+};
+static const struct file_operations debug_registers_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_registers_open,
+ .read = debug_output,
+ .release = debug_close,
+};
+
+static struct dentry *ohci_debug_root;
+
+struct debug_buffer {
+ ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
+ struct device *dev;
+ struct mutex mutex; /* protect filling of buffer */
+ size_t count; /* number of characters filled into buffer */
+ char *page;
+};
+
static ssize_t
show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
{
@@ -467,8 +503,7 @@
return count - size;
}
-static ssize_t
-show_async (struct class_device *class_dev, char *buf)
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
{
struct usb_bus *bus;
struct usb_hcd *hcd;
@@ -476,25 +511,23 @@
size_t temp;
unsigned long flags;
- bus = class_get_devdata(class_dev);
+ bus = dev_get_drvdata(buf->dev);
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
/* display control and bulk lists together, for simplicity */
spin_lock_irqsave (&ohci->lock, flags);
- temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail);
- temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail);
+ temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail);
+ temp += show_list(ohci, buf->page + temp, buf->count - temp,
+ ohci->ed_bulktail);
spin_unlock_irqrestore (&ohci->lock, flags);
return temp;
}
-static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
-
#define DBG_SCHED_LIMIT 64
-static ssize_t
-show_periodic (struct class_device *class_dev, char *buf)
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
{
struct usb_bus *bus;
struct usb_hcd *hcd;
@@ -509,10 +542,10 @@
return 0;
seen_count = 0;
- bus = class_get_devdata(class_dev);
+ bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
- next = buf;
+ next = buf->page;
size = PAGE_SIZE;
temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
@@ -589,13 +622,9 @@
return PAGE_SIZE - size;
}
-static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
-
-
#undef DBG_SCHED_LIMIT
-static ssize_t
-show_registers (struct class_device *class_dev, char *buf)
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
{
struct usb_bus *bus;
struct usb_hcd *hcd;
@@ -606,11 +635,11 @@
char *next;
u32 rdata;
- bus = class_get_devdata(class_dev);
+ bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
regs = ohci->regs;
- next = buf;
+ next = buf->page;
size = PAGE_SIZE;
spin_lock_irqsave (&ohci->lock, flags);
@@ -677,29 +706,155 @@
done:
spin_unlock_irqrestore (&ohci->lock, flags);
+
return PAGE_SIZE - size;
}
-static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+static struct debug_buffer *alloc_buffer(struct device *dev,
+ ssize_t (*fill_func)(struct debug_buffer *))
+{
+ struct debug_buffer *buf;
+ buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+
+ if (buf) {
+ buf->dev = dev;
+ buf->fill_func = fill_func;
+ mutex_init(&buf->mutex);
+ }
+
+ return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+ int ret = 0;
+
+ if (!buf->page)
+ buf->page = (char *)get_zeroed_page(GFP_KERNEL);
+
+ if (!buf->page) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = buf->fill_func(buf);
+
+ if (ret >= 0) {
+ buf->count = ret;
+ ret = 0;
+ }
+
+out:
+ return ret;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+ size_t len, loff_t *offset)
+{
+ struct debug_buffer *buf = file->private_data;
+ int ret = 0;
+
+ mutex_lock(&buf->mutex);
+ if (buf->count == 0) {
+ ret = fill_buffer(buf);
+ if (ret != 0) {
+ mutex_unlock(&buf->mutex);
+ goto out;
+ }
+ }
+ mutex_unlock(&buf->mutex);
+
+ ret = simple_read_from_buffer(user_buf, len, offset,
+ buf->page, buf->count);
+
+out:
+ return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ struct debug_buffer *buf = file->private_data;
+
+ if (buf) {
+ if (buf->page)
+ free_page((unsigned long)buf->page);
+ kfree(buf);
+ }
+
+ return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private,
+ fill_periodic_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private,
+ fill_registers_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
static inline void create_debug_files (struct ohci_hcd *ohci)
{
- struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
- int retval;
+ struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
+ struct device *dev = bus->dev;
- retval = class_device_create_file(cldev, &class_device_attr_async);
- retval = class_device_create_file(cldev, &class_device_attr_periodic);
- retval = class_device_create_file(cldev, &class_device_attr_registers);
+ ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
+ if (!ohci->debug_dir)
+ goto dir_error;
+
+ ohci->debug_async = debugfs_create_file("async", S_IRUGO,
+ ohci->debug_dir, dev,
+ &debug_async_fops);
+ if (!ohci->debug_async)
+ goto async_error;
+
+ ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
+ ohci->debug_dir, dev,
+ &debug_periodic_fops);
+ if (!ohci->debug_periodic)
+ goto periodic_error;
+
+ ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+ ohci->debug_dir, dev,
+ &debug_registers_fops);
+ if (!ohci->debug_registers)
+ goto registers_error;
+
ohci_dbg (ohci, "created debug files\n");
+ return;
+
+registers_error:
+ debugfs_remove(ohci->debug_periodic);
+periodic_error:
+ debugfs_remove(ohci->debug_async);
+async_error:
+ debugfs_remove(ohci->debug_dir);
+dir_error:
+ ohci->debug_periodic = NULL;
+ ohci->debug_async = NULL;
+ ohci->debug_dir = NULL;
}
static inline void remove_debug_files (struct ohci_hcd *ohci)
{
- struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
-
- class_device_remove_file(cldev, &class_device_attr_async);
- class_device_remove_file(cldev, &class_device_attr_periodic);
- class_device_remove_file(cldev, &class_device_attr_registers);
+ debugfs_remove(ohci->debug_registers);
+ debugfs_remove(ohci->debug_periodic);
+ debugfs_remove(ohci->debug_async);
+ debugfs_remove(ohci->debug_dir);
}
#endif
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index ddd4ee1..dd4798e 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -36,6 +36,7 @@
#include <linux/dmapool.h>
#include <linux/reboot.h>
#include <linux/workqueue.h>
+#include <linux/debugfs.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -809,13 +810,9 @@
}
if (ints & OHCI_INTR_WDH) {
- if (HC_IS_RUNNING(hcd->state))
- ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable);
spin_lock (&ohci->lock);
dl_done_list (ohci);
spin_unlock (&ohci->lock);
- if (HC_IS_RUNNING(hcd->state))
- ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable);
}
if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
@@ -1032,6 +1029,13 @@
#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7763)
+#include "ohci-sh.c"
+#define PLATFORM_DRIVER ohci_hcd_sh_driver
+#endif
+
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
#include "ohci-ppc-of.c"
@@ -1048,6 +1052,11 @@
#define SSB_OHCI_DRIVER ssb_ohci_driver
#endif
+#ifdef CONFIG_MFD_SM501
+#include "ohci-sm501.c"
+#define PLATFORM_DRIVER ohci_hcd_sm501_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
@@ -1068,6 +1077,14 @@
pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
+#ifdef DEBUG
+ ohci_debug_root = debugfs_create_dir("ohci", NULL);
+ if (!ohci_debug_root) {
+ retval = -ENOENT;
+ goto error_debug;
+ }
+#endif
+
#ifdef PS3_SYSTEM_BUS_DRIVER
retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
if (retval < 0)
@@ -1130,6 +1147,12 @@
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
error_ps3:
#endif
+#ifdef DEBUG
+ debugfs_remove(ohci_debug_root);
+ ohci_debug_root = NULL;
+ error_debug:
+#endif
+
return retval;
}
module_init(ohci_hcd_mod_init);
@@ -1154,6 +1177,9 @@
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
+#ifdef DEBUG
+ debugfs_remove(ohci_debug_root);
+#endif
}
module_exit(ohci_hcd_mod_exit);
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
new file mode 100644
index 0000000..5309ac0
--- /dev/null
+++ b/drivers/usb/host/ohci-sh.c
@@ -0,0 +1,143 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+
+static int ohci_sh_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci_hcd_init(ohci);
+ ohci_init(ohci);
+ ohci_run(ohci);
+ hcd->state = HC_STATE_RUNNING;
+ return 0;
+}
+
+static const struct hc_driver ohci_sh_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SuperH OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_sh_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+static int ohci_hcd_sh_probe(struct platform_device *pdev)
+{
+ struct resource *res = NULL;
+ struct usb_hcd *hcd = NULL;
+ int irq = -1;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err("platform_get_resource error.");
+ return -ENODEV;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ err("platform_get_irq error.");
+ return -ENODEV;
+ }
+
+ /* initialize hcd */
+ hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name);
+ if (!hcd) {
+ err("Failed to create hcd");
+ return -ENOMEM;
+ }
+
+ hcd->regs = (void __iomem *)res->start;
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_len(res);
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret != 0) {
+ err("Failed to add hcd");
+ usb_put_hcd(hcd);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ohci_hcd_sh_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static struct platform_driver ohci_hcd_sh_driver = {
+ .probe = ohci_hcd_sh_probe,
+ .remove = ohci_hcd_sh_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "sh_ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
new file mode 100644
index 0000000..a970701
--- /dev/null
+++ b/drivers/usb/host/ohci-sm501.c
@@ -0,0 +1,264 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2005 David Brownell
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2008 Magnus Damm
+ *
+ * SM501 Bus Glue - based on ohci-omap.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+static int ohci_sm501_init(struct usb_hcd *hcd)
+{
+ return ohci_init(hcd_to_ohci(hcd));
+}
+
+static int ohci_sm501_start(struct usb_hcd *hcd)
+{
+ struct device *dev = hcd->self.controller;
+ int ret;
+
+ ret = ohci_run(hcd_to_ohci(hcd));
+ if (ret < 0) {
+ dev_err(dev, "can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ }
+
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_sm501_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SM501 OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ohci_sm501_init,
+ .start = ohci_sm501_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
+{
+ const struct hc_driver *driver = &ohci_sm501_hc_driver;
+ struct device *dev = &pdev->dev;
+ struct resource *res, *mem;
+ int retval, irq;
+ struct usb_hcd *hcd = 0;
+
+ irq = retval = platform_get_irq(pdev, 0);
+ if (retval < 0)
+ goto err0;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (mem == NULL) {
+ dev_err(dev, "no resource definition for memory\n");
+ retval = -ENOENT;
+ goto err0;
+ }
+
+ if (!request_mem_region(mem->start, mem->end - mem->start + 1,
+ pdev->name)) {
+ dev_err(dev, "request_mem_region failed\n");
+ retval = -EBUSY;
+ goto err0;
+ }
+
+ /* The sm501 chip is equipped with local memory that may be used
+ * by on-chip devices such as the video controller and the usb host.
+ * This driver uses dma_declare_coherent_memory() to make sure
+ * usb allocations with dma_alloc_coherent() allocate from
+ * this local memory. The dma_handle returned by dma_alloc_coherent()
+ * will be an offset starting from 0 for the first local memory byte.
+ *
+ * So as long as data is allocated using dma_alloc_coherent() all is
+ * fine. This is however not always the case - buffers may be allocated
+ * using kmalloc() - so the usb core needs to be told that it must copy
+ * data into our local memory if the buffers happen to be placed in
+ * regular memory. The HCD_LOCAL_MEM flag does just that.
+ */
+
+ if (!dma_declare_coherent_memory(dev, mem->start,
+ mem->start - mem->parent->start,
+ (mem->end - mem->start) + 1,
+ DMA_MEMORY_MAP |
+ DMA_MEMORY_EXCLUSIVE)) {
+ dev_err(dev, "cannot declare coherent memory\n");
+ retval = -ENXIO;
+ goto err1;
+ }
+
+ /* allocate, reserve and remap resources for registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "no resource definition for registers\n");
+ retval = -ENOENT;
+ goto err2;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) {
+ dev_err(dev, "request_mem_region failed\n");
+ retval = -EBUSY;
+ goto err3;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_err(dev, "cannot remap registers\n");
+ retval = -ENXIO;
+ goto err4;
+ }
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (retval)
+ goto err4;
+
+ /* enable power and unmask interrupts */
+
+ sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
+ sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
+
+ return 0;
+err4:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err3:
+ usb_put_hcd(hcd);
+err2:
+ dma_release_declared_memory(dev);
+err1:
+ release_mem_region(mem->start, mem->end - mem->start + 1);
+err0:
+ return retval;
+}
+
+static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ usb_remove_hcd(hcd);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ dma_release_declared_memory(&pdev->dev);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ release_mem_region(mem->start, mem->end - mem->start + 1);
+
+ /* mask interrupts and disable power */
+
+ sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
+ sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
+
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct device *dev = &pdev->dev;
+ struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
+ ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+ dev->power.power_state = PMSG_SUSPEND;
+ return 0;
+}
+
+static int ohci_sm501_resume(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
+ dev->power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(platform_get_drvdata(pdev));
+ return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Driver definition to register with the SM501 bus
+ */
+static struct platform_driver ohci_hcd_sm501_driver = {
+ .probe = ohci_hcd_sm501_drv_probe,
+ .remove = ohci_hcd_sm501_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+#ifdef CONFIG_PM
+ .suspend = ohci_sm501_suspend,
+ .resume = ohci_sm501_resume,
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sm501-usb",
+ },
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 47c5c66..dc544dd 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -408,6 +408,13 @@
unsigned eds_scheduled;
struct ed *ed_to_check;
unsigned zf_delay;
+
+#ifdef DEBUG
+ struct dentry *debug_dir;
+ struct dentry *debug_async;
+ struct dentry *debug_periodic;
+ struct dentry *debug_registers;
+#endif
};
#ifdef CONFIG_PCI
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index c225159..0ee694f 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -190,9 +190,8 @@
msleep(10);
}
if (wait_time <= 0)
- printk(KERN_WARNING "%s %s: BIOS handoff "
- "failed (BIOS bug ?) %08x\n",
- pdev->dev.bus_id, "OHCI",
+ dev_warn(&pdev->dev, "OHCI: BIOS handoff failed"
+ " (BIOS bug?) %08x\n",
readl(base + OHCI_CONTROL));
/* reset controller, preserving RWC */
@@ -243,8 +242,7 @@
switch (cap & 0xff) {
case 1: /* BIOS/SMM/... handoff support */
if ((cap & EHCI_USBLEGSUP_BIOS)) {
- pr_debug("%s %s: BIOS handoff\n",
- pdev->dev.bus_id, "EHCI");
+ dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
#if 0
/* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on,
@@ -285,9 +283,8 @@
/* well, possibly buggy BIOS... try to shut
* it down, and hope nothing goes too wrong
*/
- printk(KERN_WARNING "%s %s: BIOS handoff "
- "failed (BIOS bug ?) %08x\n",
- pdev->dev.bus_id, "EHCI", cap);
+ dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
+ " (BIOS bug?) %08x\n", cap);
pci_write_config_byte(pdev, offset + 2, 0);
}
@@ -306,17 +303,14 @@
cap = 0;
/* FALLTHROUGH */
default:
- printk(KERN_WARNING "%s %s: unrecognized "
- "capability %02x\n",
- pdev->dev.bus_id, "EHCI",
- cap & 0xff);
+ dev_warn(&pdev->dev, "EHCI: unrecognized capability "
+ "%02x\n", cap & 0xff);
break;
}
offset = (cap >> 8) & 0xff;
}
if (!count)
- printk(KERN_DEBUG "%s %s: capability loop?\n",
- pdev->dev.bus_id, "EHCI");
+ dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n");
/*
* halt EHCI & disable its interrupts in any case
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index fe9ceb07..5738825 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -405,7 +405,7 @@
struct r8a66597_pipe_info {
u16 pipenum;
- u16 address; /* R8A66597 HCD usb addres */
+ u16 address; /* R8A66597 HCD usb address */
u16 epnum;
u16 maxpacket;
u16 type;
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index d1131a8..0fb114c 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -478,8 +478,6 @@
{
irq_interval=intf_desc->endpoint [j].desc.bInterval;
}
-
- continue;
}
}
if (mdc800->endpoint[i] == -1)
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index d721380..9379404 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -1,7 +1,7 @@
/*
* cypress_cy7c63.c
*
-* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de)
+* Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de)
*
* This driver is based on the Cypress USB Driver by Marcus Maul
* (cyport) and the 2.0 version of Greg Kroah-Hartman's
@@ -21,6 +21,9 @@
* Supported functions: Read/Write Ports
*
*
+* For up-to-date information please visit:
+* http://www.obock.de/kernel/cypress
+*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
@@ -31,7 +34,7 @@
#include <linux/kernel.h>
#include <linux/usb.h>
-#define DRIVER_AUTHOR "Oliver Bock (o.bock@fh-wolfenbuettel.de)"
+#define DRIVER_AUTHOR "Oliver Bock (bock@tfh-berlin.de)"
#define DRIVER_DESC "Cypress CY7C63xxx USB driver"
#define CYPRESS_VENDOR_ID 0xa2c
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 764696f..8010705 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -715,7 +715,7 @@
* would use "struct net_driver" instead, and a serial
* device would use "struct tty_driver".
*/
-static struct file_operations iowarrior_fops = {
+static const struct file_operations iowarrior_fops = {
.owner = THIS_MODULE,
.write = iowarrior_write,
.read = iowarrior_read,
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index aab3200..6664043f 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -205,7 +205,7 @@
/* Structure to hold all of our device specific stuff */
struct lego_usb_tower {
- struct semaphore sem; /* locks this structure */
+ struct mutex lock; /* locks this structure */
struct usb_device* udev; /* save off the usb device pointer */
unsigned char minor; /* the starting minor number for this device */
@@ -361,7 +361,7 @@
}
/* lock this device */
- if (down_interruptible (&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->lock)) {
mutex_unlock(&open_disc_mutex);
retval = -ERESTARTSYS;
goto exit;
@@ -421,7 +421,7 @@
file->private_data = dev;
unlock_exit:
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
exit:
dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
@@ -448,7 +448,7 @@
}
mutex_lock(&open_disc_mutex);
- if (down_interruptible (&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->lock)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -460,7 +460,9 @@
}
if (dev->udev == NULL) {
/* the device was unplugged before the file was released */
- up (&dev->sem); /* unlock here as tower_delete frees dev */
+
+ /* unlock here as tower_delete frees dev */
+ mutex_unlock(&dev->lock);
tower_delete (dev);
goto exit;
}
@@ -473,7 +475,7 @@
dev->open_count = 0;
unlock_exit:
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
exit:
mutex_unlock(&open_disc_mutex);
@@ -586,7 +588,7 @@
dev = (struct lego_usb_tower *)file->private_data;
/* lock this object */
- if (down_interruptible (&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->lock)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -653,7 +655,7 @@
unlock_exit:
/* unlock the device */
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
exit:
dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
@@ -675,7 +677,7 @@
dev = (struct lego_usb_tower *)file->private_data;
/* lock this object */
- if (down_interruptible (&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->lock)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -737,7 +739,7 @@
unlock_exit:
/* unlock the device */
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
exit:
dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
@@ -862,7 +864,7 @@
goto exit;
}
- init_MUTEX (&dev->sem);
+ mutex_init(&dev->lock);
dev->udev = udev;
dev->open_count = 0;
@@ -1007,16 +1009,16 @@
/* give back our minor */
usb_deregister_dev (interface, &tower_class);
- down (&dev->sem);
+ mutex_lock(&dev->lock);
mutex_unlock(&open_disc_mutex);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
tower_delete (dev);
} else {
dev->udev = NULL;
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
}
info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 9244d06..cb7fa0e 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -323,7 +323,7 @@
usb_kill_urb(urb);
retval = -ETIMEDOUT;
} else {
- /* URB completed within timout */
+ /* URB completed within timeout */
retval = urb->status;
readbytes = urb->actual_length;
}
@@ -3195,20 +3195,6 @@
sisusb->present = 1;
-#ifdef SISUSB_OLD_CONFIG_COMPAT
- {
- int ret;
- /* Our ioctls are all "32/64bit compatible" */
- ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
- ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
- ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
- if (ret)
- dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
- else
- sisusb->ioctl32registered = 1;
- }
-#endif
-
if (dev->speed == USB_SPEED_HIGH) {
int initscreen = 1;
#ifdef INCL_SISUSB_CON
@@ -3271,19 +3257,6 @@
usb_set_intfdata(intf, NULL);
-#ifdef SISUSB_OLD_CONFIG_COMPAT
- if (sisusb->ioctl32registered) {
- int ret;
- sisusb->ioctl32registered = 0;
- ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
- ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
- ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
- if (ret) {
- dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
- }
- }
-#endif
-
sisusb->present = 0;
sisusb->ready = 0;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index d2d7872..cf0b4a5 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -120,9 +120,6 @@
int isopen; /* !=0 if open */
int present; /* !=0 if device is present on the bus */
int ready; /* !=0 if device is ready for userland */
-#ifdef SISUSB_OLD_CONFIG_COMPAT
- int ioctl32registered;
-#endif
int numobufs; /* number of obufs = number of out urbs */
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
int obufsize, ibufsize;
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index ea31621..da922df 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/scatterlist.h>
+#include <linux/mutex.h>
#include <linux/usb.h>
@@ -64,7 +65,7 @@
int in_iso_pipe;
int out_iso_pipe;
struct usb_endpoint_descriptor *iso_in, *iso_out;
- struct semaphore sem;
+ struct mutex lock;
#define TBUF_SIZE 256
u8 *buf;
@@ -1151,6 +1152,7 @@
dbg ("ep %02x couldn't get halt status, %d", ep, retval);
return retval;
}
+ le16_to_cpus(&status);
if (status != 1) {
dbg ("ep %02x bogus status: %04x != 1", ep, status);
return -EINVAL;
@@ -1310,7 +1312,7 @@
len += vary;
/* [real world] the "zero bytes IN" case isn't really used.
- * hardware can easily trip up in this wierd case, since its
+ * hardware can easily trip up in this weird case, since its
* status stage is IN, not OUT like other ep0in transfers.
*/
if (len > length)
@@ -1558,11 +1560,11 @@
|| param->sglen < 0 || param->vary < 0)
return -EINVAL;
- if (down_interruptible (&dev->sem))
+ if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
if (intf->dev.power.power_state.event != PM_EVENT_ON) {
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
return -EHOSTUNREACH;
}
@@ -1574,7 +1576,7 @@
int res;
if (intf->altsetting->desc.bInterfaceNumber) {
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
return -ENODEV;
}
res = set_altsetting (dev, dev->info->alt);
@@ -1582,7 +1584,7 @@
dev_err (&intf->dev,
"set altsetting to %d failed, %d\n",
dev->info->alt, res);
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
return res;
}
}
@@ -1855,7 +1857,7 @@
param->duration.tv_usec += 1000 * 1000;
param->duration.tv_sec -= 1;
}
- up (&dev->sem);
+ mutex_unlock(&dev->lock);
return retval;
}
@@ -1905,7 +1907,7 @@
return -ENOMEM;
info = (struct usbtest_info *) id->driver_info;
dev->info = info;
- init_MUTEX (&dev->sem);
+ mutex_init(&dev->lock);
dev->intf = intf;
@@ -1990,8 +1992,6 @@
{
struct usbtest_dev *dev = usb_get_intfdata (intf);
- down (&dev->sem);
-
usb_set_intfdata (intf, NULL);
dev_dbg (&intf->dev, "disconnect\n");
kfree (dev);
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index f06e4e2..1774ba5 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1026,6 +1026,8 @@
return mask;
}
+#if 0
+
/*
* open and close: just keep track of how many times the device is
* mapped, to use the proper memory allocation function.
@@ -1045,33 +1047,31 @@
/*
* Map ring pages to user space.
*/
-struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct mon_reader_bin *rp = vma->vm_private_data;
unsigned long offset, chunk_idx;
struct page *pageptr;
- offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ offset = vmf->pgoff << PAGE_SHIFT;
if (offset >= rp->b_size)
- return NOPAGE_SIGBUS;
+ return VM_FAULT_SIGBUS;
chunk_idx = offset / CHUNK_SIZE;
pageptr = rp->b_vec[chunk_idx].pg;
get_page(pageptr);
- if (type)
- *type = VM_FAULT_MINOR;
- return pageptr;
+ vmf->page = pageptr;
+ return 0;
}
struct vm_operations_struct mon_bin_vm_ops = {
.open = mon_bin_vma_open,
.close = mon_bin_vma_close,
- .nopage = mon_bin_vma_nopage,
+ .fault = mon_bin_vma_fault,
};
int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
{
- /* don't do anything here: "nopage" will set up page table entries */
+ /* don't do anything here: "fault" will set up page table entries */
vma->vm_ops = &mon_bin_vm_ops;
vma->vm_flags |= VM_RESERVED;
vma->vm_private_data = filp->private_data;
@@ -1079,7 +1079,9 @@
return 0;
}
-struct file_operations mon_fops_binary = {
+#endif /* 0 */
+
+static const struct file_operations mon_fops_binary = {
.owner = THIS_MODULE,
.open = mon_bin_open,
.llseek = no_llseek,
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 4a86696..c1e65df 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -2,10 +2,7 @@
# USB Serial device configuration
#
-menu "USB Serial Converter support"
- depends on USB!=n
-
-config USB_SERIAL
+menuconfig USB_SERIAL
tristate "USB Serial Converter support"
depends on USB
---help---
@@ -20,6 +17,8 @@
To compile this driver as a module, choose M here: the
module will be called usbserial.
+if USB_SERIAL
+
config USB_SERIAL_CONSOLE
bool "USB Serial Console device support (EXPERIMENTAL)"
depends on USB_SERIAL=y && EXPERIMENTAL
@@ -43,6 +42,12 @@
If unsure, say N.
+config USB_EZUSB
+ bool "Functions for loading firmware on EZUSB chips"
+ depends on USB_SERIAL
+ help
+ Say Y here if you need EZUSB device support.
+
config USB_SERIAL_GENERIC
bool "USB Generic Serial Driver"
depends on USB_SERIAL
@@ -105,6 +110,7 @@
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
help
Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
USB to serial converter device.
@@ -282,9 +288,21 @@
To compile this driver as a module, choose M here: the
module will be called ipw.
+config USB_SERIAL_IUU
+ tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)"
+ depends on USB_SERIAL && EXPERIMENTAL
+ help
+ Say Y here if you want to use a IUU in phoenix mode and get
+ an extra ttyUSBx device. More information available on
+ http://eczema.ecze.com/iuu_phoenix.html
+
+ To compile this driver as a module, choose M here: the
+ module will be called iuu_phoenix.o
+
config USB_SERIAL_KEYSPAN_PDA
tristate "USB Keyspan PDA Single Port Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
help
Say Y here if you want to use a Keyspan PDA single port USB to
serial converter device. This driver makes use of firmware
@@ -296,6 +314,7 @@
config USB_SERIAL_KEYSPAN
tristate "USB Keyspan USA-xxx Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
---help---
Say Y here if you want to use Keyspan USB to serial converter
devices. This driver makes use of Keyspan's official firmware
@@ -538,6 +557,7 @@
config USB_SERIAL_XIRCOM
tristate "USB Xircom / Entregra Single Port Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
help
Say Y here if you want to use a Xircom or Entregra single port USB to
serial converter device. This driver makes use of firmware
@@ -585,11 +605,4 @@
To compile this driver as a module, choose M here: the
module will be called usb-debug.
-config USB_EZUSB
- bool
- depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
- default y
-
-
-endmenu
-
+endif # USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index d6fb384..0db109a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -30,6 +30,7 @@
obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o
obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o
+obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 77bb893..f156dba 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -217,7 +217,10 @@
priv->rts_state = 0;
priv->dtr_state = 0;
- airprime_send_setup(port);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected)
+ airprime_send_setup(port);
+ mutex_lock(&port->serial->disc_mutex);
for (i = 0; i < NUM_READ_URBS; ++i) {
usb_kill_urb (priv->read_urbp[i]);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index ddfee91..fe2bfd6 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -151,8 +151,10 @@
return 0;
cleanup:
- for (--i; i >= 0; --i)
+ for (--i; i >= 0; --i) {
+ kfree(usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
+ }
return -ENOMEM;
}
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 86724e8..df0a2b3 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -350,14 +350,12 @@
unsigned long control_state;
int bad_flow_control;
speed_t baud;
+ struct ktermios *termios = port->tty->termios;
- if ((!port->tty) || (!port->tty->termios)) {
- dbg ("%s - no tty or termios structure", __FUNCTION__);
- return;
- }
+ iflag = termios->c_iflag;
+ cflag = termios->c_cflag;
- iflag = port->tty->termios->c_iflag;
- cflag = port->tty->termios->c_cflag;
+ termios->c_cflag &= ~CMSPAR;
/* get a local copy of the current port settings */
spin_lock_irqsave(&priv->lock, flags);
@@ -369,33 +367,30 @@
old_cflag = old_termios->c_cflag;
/* Set the baud rate */
- if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+ if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
/* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag&CBAUD) == B0 ) {
control_state |= (TIOCM_DTR|TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
err("Set DTR error");
/* don't set RTS if using hardware flow control */
- if (!(old_cflag&CRTSCTS) )
+ if (!(old_cflag & CRTSCTS))
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
err("Set RTS error");
}
}
baud = tty_get_baud_rate(port->tty);
- if (baud == 0) {
- dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__);
- return;
- }
- urb_value = BELKIN_SA_BAUD(baud);
- /* Clip to maximum speed */
- if (urb_value == 0)
- urb_value = 1;
- /* Turn it back into a resulting real baud rate */
- baud = BELKIN_SA_BAUD(urb_value);
- /* FIXME: Once the tty updates are done then push this back to the tty */
+ if (baud) {
+ urb_value = BELKIN_SA_BAUD(baud);
+ /* Clip to maximum speed */
+ if (urb_value == 0)
+ urb_value = 1;
+ /* Turn it back into a resulting real baud rate */
+ baud = BELKIN_SA_BAUD(urb_value);
- if ((cflag & CBAUD) != B0 ) {
+ /* Report the actual baud rate back to the caller */
+ tty_encode_baud_rate(port->tty, baud, baud);
if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
err("Set baudrate error");
} else {
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 0362654..66ce30c 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -64,8 +64,8 @@
struct usb_serial *serial;
struct usb_serial_port *port;
int retval = 0;
- struct tty_struct *tty;
- struct ktermios *termios;
+ struct tty_struct *tty = NULL;
+ struct ktermios *termios = NULL, dummy;
dbg ("%s", __FUNCTION__);
@@ -133,11 +133,14 @@
}
co->cflag = cflag;
- /* grab the first serial port that happens to be connected */
- serial = usb_serial_get_by_index(0);
+ /*
+ * no need to check the index here: if the index is wrong, console
+ * code won't call us
+ */
+ serial = usb_serial_get_by_index(co->index);
if (serial == NULL) {
/* no device is connected yet, sorry :( */
- err ("No USB device connected to ttyUSB0");
+ err ("No USB device connected to ttyUSB%i", co->index);
return -ENODEV;
}
@@ -148,49 +151,64 @@
++port->open_count;
if (port->open_count == 1) {
+ if (serial->type->set_termios) {
+ /*
+ * allocate a fake tty so the driver can initialize
+ * the termios structure, then later call set_termios to
+ * configure according to command line arguments
+ */
+ tty = kzalloc(sizeof(*tty), GFP_KERNEL);
+ if (!tty) {
+ retval = -ENOMEM;
+ err("no more memory");
+ goto reset_open_count;
+ }
+ termios = kzalloc(sizeof(*termios), GFP_KERNEL);
+ if (!termios) {
+ retval = -ENOMEM;
+ err("no more memory");
+ goto free_tty;
+ }
+ memset(&dummy, 0, sizeof(struct ktermios));
+ tty->termios = termios;
+ port->tty = tty;
+ }
+
/* only call the device specific open if this
* is the first time the port is opened */
if (serial->type->open)
retval = serial->type->open(port, NULL);
else
retval = usb_serial_generic_open(port, NULL);
- if (retval)
- port->open_count = 0;
- }
- if (retval) {
- err ("could not open USB console port");
- return retval;
- }
-
- if (serial->type->set_termios) {
- struct ktermios dummy;
- /* build up a fake tty structure so that the open call has something
- * to look at to get the cflag value */
- tty = kzalloc(sizeof(*tty), GFP_KERNEL);
- if (!tty) {
- err ("no more memory");
- return -ENOMEM;
+ if (retval) {
+ err("could not open USB console port");
+ goto free_termios;
}
- termios = kzalloc(sizeof(*termios), GFP_KERNEL);
- if (!termios) {
- err ("no more memory");
- kfree (tty);
- return -ENOMEM;
- }
- memset(&dummy, 0, sizeof(struct ktermios));
- termios->c_cflag = cflag;
- tty->termios = termios;
- port->tty = tty;
- /* set up the initial termios settings */
- serial->type->set_termios(port, &dummy);
- port->tty = NULL;
- kfree (termios);
- kfree (tty);
+ if (serial->type->set_termios) {
+ termios->c_cflag = cflag;
+ serial->type->set_termios(port, &dummy);
+
+ port->tty = NULL;
+ kfree(termios);
+ kfree(tty);
+ }
}
+ port->console = 1;
+ retval = 0;
+
+out:
return retval;
+free_termios:
+ kfree(termios);
+ port->tty = NULL;
+free_tty:
+ kfree(tty);
+reset_open_count:
+ port->open_count = 0;
+goto out;
}
static void usb_console_write(struct console *co, const char *buf, unsigned count)
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 2283358..f3ca660 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -59,6 +59,7 @@
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+ { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
@@ -76,8 +77,13 @@
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
+ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
+ { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
+ { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
+ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
};
@@ -342,7 +348,10 @@
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
- cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected)
+ cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+ mutex_unlock(&port->serial->disc_mutex);
}
/*
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 4353df9..8d9b045 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -319,7 +319,6 @@
/* React only to interrupts signaling a bulk_in transfer */
if( (urb->actual_length==4) && (data[0]==0x01) ) {
short old_rdtodo;
- int result;
/* This is a announcement of coming bulk_ins. */
unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 1633863..08c65c1 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -682,7 +682,6 @@
{
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned int c_cflag;
- unsigned long flags;
int bps;
long timeout;
wait_queue_t wait;
@@ -690,7 +689,7 @@
dbg("%s - port %d", __FUNCTION__, port->number);
/* wait for data to drain from buffer */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
timeout = CYPRESS_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&port->tty->write_wait, &wait);
@@ -698,18 +697,25 @@
set_current_state(TASK_INTERRUPTIBLE);
if (cypress_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->serial->interface))
+ /* without mutex, allowed due to harmless failure mode */
+ || port->serial->disconnected)
break;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
cypress_buf_clear(priv->buf);
- spin_unlock_irqrestore(&priv->lock, flags);
-
+ spin_unlock_irq(&priv->lock);
+
+ /* writing is potentially harmful, lock must be taken */
+ mutex_lock(&port->serial->disc_mutex);
+ if (port->serial->disconnected) {
+ mutex_unlock(&port->serial->disc_mutex);
+ return;
+ }
/* wait for characters to drain from device */
bps = tty_get_baud_rate(port->tty);
if (bps > 1200)
@@ -727,10 +733,10 @@
if (c_cflag & HUPCL) {
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->line_control = 0;
priv->cmd_ctrl = 1;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
cypress_write(port, NULL, 0);
}
}
@@ -738,6 +744,7 @@
if (stats)
dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
priv->bytes_in, priv->bytes_out, priv->cmd_count);
+ mutex_unlock(&port->serial->disc_mutex);
} /* cypress_close */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index ae410c4..5f9c6e4 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1405,19 +1405,19 @@
unsigned char buf[32];
struct tty_struct *tty = port->tty;
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
dbg("digi_close: TOP: port=%d, open_count=%d",
priv->dp_port_num, port->open_count);
+ mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
- if (!usb_get_intfdata(port->serial->interface))
+ if (port->serial->disconnected)
goto exit;
/* do cleanup only after final close on this port */
- spin_lock_irqsave(&priv->dp_port_lock, flags);
+ spin_lock_irq(&priv->dp_port_lock);
priv->dp_in_close = 1;
- spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ spin_unlock_irq(&priv->dp_port_lock);
/* tell line discipline to process only XON/XOFF */
tty->closing = 1;
@@ -1482,11 +1482,12 @@
}
tty->closing = 0;
exit:
- spin_lock_irqsave(&priv->dp_port_lock, flags);
+ spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
wake_up_interruptible(&priv->dp_close_wait);
- spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ spin_unlock_irq(&priv->dp_port_lock);
+ mutex_unlock(&port->serial->disc_mutex);
dbg("digi_close: done");
}
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 97ee718..3f698ba 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -53,6 +53,6 @@
}
-EXPORT_SYMBOL(ezusb_writememory);
-EXPORT_SYMBOL(ezusb_set_reset);
+EXPORT_SYMBOL_GPL(ezusb_writememory);
+EXPORT_SYMBOL_GPL(ezusb_set_reset);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c40e77d..90dcc62 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -17,226 +17,8 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation
*
- * (21/Jul/2004) Ian Abbott
- * Incorporated Steven Turner's code to add support for the FT2232C chip.
- * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have
- * fixed a couple of things.
- *
- * (27/May/2004) Ian Abbott
- * Improved throttling code, mostly stolen from the WhiteHEAT driver.
- *
- * (26/Mar/2004) Jan Capek
- * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
- *
- * (09/Feb/2004) Ian Abbott
- * Changed full name of USB-UIRT device to avoid "/" character.
- * Added FTDI's alternate PID (0x6006) for FT232/245 devices.
- * Added PID for "ELV USB Module UO100" from Stefan Frings.
- *
- * (21/Oct/2003) Ian Abbott
- * Renamed some VID/PID macros for Matrix Orbital and Perle Systems
- * devices. Removed Matrix Orbital and Perle Systems devices from the
- * 8U232AM device table, but left them in the FT232BM table, as they are
- * known to use only FT232BM.
- *
- * (17/Oct/2003) Scott Allen
- * Added vid/pid for Perle Systems UltraPort USB serial converters
- *
- * (21/Sep/2003) Ian Abbott
- * Added VID/PID for Omnidirectional Control Technology US101 USB to
- * RS-232 adapter (also rebadged as Dick Smith Electronics XH6381).
- * VID/PID supplied by Donald Gordon.
- *
- * (19/Aug/2003) Ian Abbott
- * Freed urb's transfer buffer in write bulk callback.
- * Omitted some paranoid checks in write bulk callback that don't matter.
- * Scheduled work in write bulk callback regardless of port's open count.
- *
- * (05/Aug/2003) Ian Abbott
- * Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter.
- * VID/PID provided by Steve Briggs.
- *
- * (23/Jul/2003) Ian Abbott
- * Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from
- * Wayne Wylupski.
- *
- * (10/Jul/2003) David Glance
- * Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800.
- *
- * (27/Jun/2003) Ian Abbott
- * Reworked the urb handling logic. We have no more pool, but dynamically
- * allocate the urb and the transfer buffer on the fly. In testing this
- * does not incure any measurable overhead. This also relies on the fact
- * that we have proper reference counting logic for urbs. I nicked this
- * from Greg KH's Visor driver.
- *
- * (23/Jun/2003) Ian Abbott
- * Reduced flip buffer pushes and corrected a data length test in
- * ftdi_read_bulk_callback.
- * Defererence pointers after any paranoid checks, not before.
- *
- * (21/Jun/2003) Erik Nygren
- * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
- * See <http://www.home-electro.com/tira1.htm>. Only operates properly
- * at 100000 and RTS-CTS, so set custom divisor mode on startup.
- * Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
- *
- * (18/Jun/2003) Ian Abbott
- * Added Device ID of the USB relais from Rudolf Gugler (backported from
- * Philipp Gühring's patch for 2.5.x kernel).
- * Moved read transfer buffer reallocation into startup function.
- * Free existing write urb and transfer buffer in startup function.
- * Only use urbs in write urb pool that were successfully allocated.
- * Moved some constant macros out of functions.
- * Minor whitespace and comment changes.
- *
- * (12/Jun/2003) David Norwood
- * Added support for USB-UIRT IR transceiver using 8U232AM chip.
- * See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>. Only
- * operates properly at 312500, so set custom divisor mode on startup.
- *
- * (12/Jun/2003) Ian Abbott
- * Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang
- * - I've eliminated some that don't seem to exist!
- * Added Home Electronics Tira-1 IR transceiver pid from Chris Horn
- * Some whitespace/coding-style cleanups
- *
- * (11/Jun/2003) Ian Abbott
- * Fixed unsafe spinlock usage in ftdi_write
- *
- * (24/Feb/2003) Richard Shooter
- * Increase read buffer size to improve read speeds at higher baud rates
- * (specifically tested with up to 1Mb/sec at 1.5M baud)
- *
- * (23/Feb/2003) John Wilkins
- * Added Xon/xoff flow control (activating support in the ftdi device)
- * Added vid/pid for Videonetworks/Homechoice (UK ISP)
- *
- * (23/Feb/2003) Bill Ryder
- * Added matrix orb device vid/pids from Wayne Wylupski
- *
- * (19/Feb/2003) Ian Abbott
- * For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
- * changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
- * ASYNC_SPD_SHI or ASYNC_SPD_WARP. Also, unless ASYNC_SPD_CUST is in
- * force, don't bother changing baud rate when custom_divisor has changed.
- *
- * (18/Feb/2003) Ian Abbott
- * Fixed TIOCMGET handling to include state of DTR and RTS, the state
- * of which are now saved by set_dtr() and set_rts().
- * Fixed improper storage class for buf in set_dtr() and set_rts().
- * Added FT232BM chip type and support for its extra baud rates (compared
- * to FT8U232AM).
- * Took account of special case divisor values for highest baud rates of
- * FT8U232AM and FT232BM.
- * For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
- * as previous alt_speed setting is now stale.
- * Moved startup code common between the startup routines for the
- * different chip types into a common subroutine.
- *
- * (17/Feb/2003) Bill Ryder
- * Added write urb buffer pool on a per device basis
- * Added more checking for open file on callbacks (fixed OOPS)
- * Added CrystalFontz 632 and 634 PIDs
- * (thanx to CrystalFontz for the sample devices - they flushed out
- * some driver bugs)
- * Minor debugging message changes
- * Added throttle, unthrottle and chars_in_buffer functions
- * Fixed FTDI_SIO (the original device) bug
- * Fixed some shutdown handling
- *
- *
- *
- *
- * (07/Jun/2002) Kuba Ober
- * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
- * function. It was getting too complex.
- * Fix the divisor calculation logic which was setting divisor of 0.125
- * instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
- * Also make it bump up the divisor to next integer in case of 7/8 - it's
- * a better approximation.
- *
- * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
- * Not tested by me but it doesn't break anything I use.
- *
- * (04/Jan/2002) Kuba Ober
- * Implemented 38400 baudrate kludge, where it can be substituted with other
- * values. That's the only way to set custom baudrates.
- * Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
- * FIXME: both baudrate things should eventually go to usbserial.c as other
- * devices may need that functionality too. Actually, it can probably be
- * merged in serial.c somehow - too many drivers repeat this code over
- * and over.
- * Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
- * Divisors for baudrates are calculated by a macro.
- * Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
- *
- * (04/Nov/2001) Bill Ryder
- * Fixed bug in read_bulk_callback where incorrect urb buffer was used.
- * Cleaned up write offset calculation
- * Added write_room since default values can be incorrect for sio
- * Changed write_bulk_callback to use same queue_task as other drivers
- * (the previous version caused panics)
- * Removed port iteration code since the device only has one I/O port and it
- * was wrong anyway.
- *
- * (31/May/2001) gkh
- * Switched from using spinlock to a semaphore, which fixes lots of problems.
- *
- * (23/May/2001) Bill Ryder
- * Added runtime debug patch (thanx Tyson D Sawyer).
- * Cleaned up comments for 8U232
- * Added parity, framing and overrun error handling
- * Added receive break handling.
- *
- * (04/08/2001) gb
- * Identify version on module load.
- *
- * (18/March/2001) Bill Ryder
- * (Not released)
- * Added send break handling. (requires kernel patch too)
- * Fixed 8U232AM hardware RTS/CTS etc status reporting.
- * Added flipbuf fix copied from generic device
- *
- * (12/3/2000) Bill Ryder
- * Added support for 8U232AM device.
- * Moved PID and VIDs into header file only.
- * Turned on low-latency for the tty (device will do high baudrates)
- * Added shutdown routine to close files when device removed.
- * More debug and error message cleanups.
- *
- * (11/13/2000) Bill Ryder
- * Added spinlock protected open code and close code.
- * Multiple opens work (sort of - see webpage mentioned above).
- * Cleaned up comments. Removed multiple PID/VID definitions.
- * Factorised cts/dtr code
- * Made use of __FUNCTION__ in dbg's
- *
- * (11/01/2000) Adam J. Richter
- * usb_device_id table support
- *
- * (10/05/2000) gkh
- * Fixed bug with urb->dev not being set properly, now that the usb
- * core needs it.
- *
- * (09/11/2000) gkh
- * Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (07/19/2000) gkh
- * Added module_init and module_exit functions to handle the fact that this
- * driver is a loadable module now.
- *
- * (04/04/2000) Bill Ryder
- * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
- * handled elsewhere in the tty io driver chain).
- *
- * (03/30/2000) Bill Ryder
- * Implemented lots of ioctls
- * Fixed a race condition in write
- * Changed some dbg's to errs
- *
- * (03/26/2000) gkh
- * Split driver up into device specific pieces.
+ * Change entries from 2004 and earlier can be found in versions of this
+ * file in kernel versions prior to the 2.6.24 release.
*
*/
@@ -309,12 +91,12 @@
void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */
};
-static int ftdi_olimex_probe (struct usb_serial *serial);
+static int ftdi_jtag_probe (struct usb_serial *serial);
static void ftdi_USB_UIRT_setup (struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv);
-static struct ftdi_sio_quirk ftdi_olimex_quirk = {
- .probe = ftdi_olimex_probe,
+static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ .probe = ftdi_jtag_probe,
};
static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
@@ -471,30 +253,28 @@
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
/*
- * These will probably use user-space drivers. Uncomment them if
- * you need them or use the user-specified vendor/product module
- * parameters (see ftdi_sio.h for the numbers). Make a fuss if
- * you think the driver should recognize any of them by default.
+ * Due to many user requests for multiple ELV devices we enable
+ * them by default.
*/
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -545,6 +325,7 @@
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
{ USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
@@ -569,8 +350,13 @@
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
- .driver_info = (kernel_ulong_t)&ftdi_olimex_quirk },
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -1283,10 +1069,11 @@
} /* ftdi_HE_TIRA1_setup */
/*
- * First port on Olimex arm-usb-ocd is reserved for JTAG interface
- * and can be accessed from userspace using openocd.
+ * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
+ * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
+ * userspace using openocd.
*/
-static int ftdi_olimex_probe(struct usb_serial *serial)
+static int ftdi_jtag_probe(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
@@ -1294,7 +1081,7 @@
dbg("%s",__FUNCTION__);
if (interface == udev->actconfig->interface[0]) {
- info("Ignoring reserved serial port on Olimex arm-usb-ocd\n");
+ info("Ignoring serial port reserved for JTAG");
return -ENODEV;
}
@@ -1411,7 +1198,8 @@
dbg("%s", __FUNCTION__);
- if (c_cflag & HUPCL){
+ mutex_lock(&port->serial->disc_mutex);
+ if (c_cflag & HUPCL && !port->serial->disconnected){
/* Disable flow control */
if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
@@ -1425,6 +1213,7 @@
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} /* Note change no line if hupcl is off */
+ mutex_unlock(&port->serial->disc_mutex);
/* cancel any scheduled reading */
cancel_delayed_work(&priv->rx_work);
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index b51cbb0..6eee2ab 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -98,6 +98,10 @@
#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
+/* OOCDlink by Joern Kaipf <joernk@web.de>
+ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
+#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
+
/* Interbiometrics USB I/O Board */
/* Developed for Interbiometrics by Rudolf Gugler */
#define INTERBIOMETRICS_VID 0x1209
@@ -245,6 +249,7 @@
#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
+#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */
/*
* Definitions for ID TECH (www.idt-net.com) devices
@@ -278,6 +283,7 @@
#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */
#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */
#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */
+#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */
/*
* Protego product ids
@@ -534,6 +540,8 @@
#define OLIMEX_VID 0x15BA
#define OLIMEX_ARM_USB_OCD_PID 0x0003
+/* www.elsterelectricity.com Elster Unicom III Optical Probe */
+#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */
/*
* The Mobility Lab (TML)
@@ -556,6 +564,13 @@
/*
+ * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
+ * Submitted by Harald Welte <laforge@openmoko.org>
+ */
+#define FIC_VID 0x1457
+#define FIC_NEO1973_DEBUG_PID 0x5118
+
+/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_E2_READ
* wValue: 0
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index f1c90cf..d74e43d 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1020,19 +1020,26 @@
if (!serial)
return;
- garmin_clear(garmin_data_p);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected)
+ garmin_clear(garmin_data_p);
/* shutdown our urbs */
usb_kill_urb (port->read_urb);
usb_kill_urb (port->write_urb);
- if (noResponseFromAppLayer(garmin_data_p) ||
- ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
- process_resetdev_request(port);
- garmin_data_p->state = STATE_RESET;
+ if (!port->serial->disconnected) {
+ if (noResponseFromAppLayer(garmin_data_p) ||
+ ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
+ process_resetdev_request(port);
+ garmin_data_p->state = STATE_RESET;
+ } else {
+ garmin_data_p->state = STATE_DISCONNECTED;
+ }
} else {
garmin_data_p->state = STATE_DISCONNECTED;
}
+ mutex_unlock(&port->serial->disc_mutex);
}
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index d415311..97fa3c4 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -175,6 +175,14 @@
struct usb_serial_port *port;
int i, c = 0, r;
+#ifdef CONFIG_PM
+ /*
+ * If this is an autoresume, don't submit URBs.
+ * They will be submitted in the open function instead.
+ */
+ if (serial->dev->auto_pm)
+ return 0;
+#endif
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (port->open_count && port->read_urb) {
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index a5d2e11..3428ccc 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -959,7 +959,7 @@
*
* This function will block the close until one of the following:
* 1. Response to our Chase comes from Edgeport
- * 2. A timout of 10 seconds without activity has expired
+ * 2. A timeout of 10 seconds without activity has expired
* (1K of Edgeport data @ 2400 baud ==> 4 sec to empty)
*
************************************************************************/
@@ -999,7 +999,7 @@
return;
}
} else {
- // Reset timout value back to 10 seconds
+ // Reset timeout value back to 10 seconds
dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
loop = 10;
}
@@ -1014,7 +1014,7 @@
* This function will block the close until one of the following:
* 1. TX count are 0
* 2. The edgeport has stopped
- * 3. A timout of 3 seconds without activity has expired
+ * 3. A timeout of 3 seconds without activity has expired
*
************************************************************************/
static void block_until_tx_empty (struct edgeport_port *edge_port)
@@ -1050,7 +1050,7 @@
return;
}
} else {
- // Reset timout value back to seconds
+ // Reset timeout value back to seconds
loop = 30;
}
}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index b867090..cd34059 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -34,6 +34,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/serial.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
@@ -133,7 +134,7 @@
struct product_info product_info;
u8 TI_I2C_Type; // Type of I2C in UMP
u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode
- struct semaphore es_sem;
+ struct mutex es_lock;
int num_ports_open;
struct usb_serial *serial;
};
@@ -1978,7 +1979,7 @@
}
/* set up the port settings */
- edge_set_termios (port, NULL);
+ edge_set_termios (port, port->tty->termios);
/* open up the port */
@@ -2044,7 +2045,7 @@
dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr);
edge_serial = edge_port->edge_serial;
- if (down_interruptible(&edge_serial->es_sem))
+ if (mutex_lock_interruptible(&edge_serial->es_lock))
return -ERESTARTSYS;
if (edge_serial->num_ports_open == 0) {
/* we are the first port to be opened, let's post the interrupt urb */
@@ -2052,7 +2053,7 @@
if (!urb) {
dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
status = -EINVAL;
- goto up_es_sem;
+ goto release_es_lock;
}
urb->complete = edge_interrupt_callback;
urb->context = edge_serial;
@@ -2060,7 +2061,7 @@
status = usb_submit_urb (urb, GFP_KERNEL);
if (status) {
dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
- goto up_es_sem;
+ goto release_es_lock;
}
}
@@ -2092,13 +2093,13 @@
dbg("%s - exited", __FUNCTION__);
- goto up_es_sem;
+ goto release_es_lock;
unlink_int_urb:
if (edge_port->edge_serial->num_ports_open == 0)
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-up_es_sem:
- up(&edge_serial->es_sem);
+release_es_lock:
+ mutex_unlock(&edge_serial->es_lock);
return status;
}
@@ -2137,14 +2138,14 @@
0,
NULL,
0);
- down(&edge_serial->es_sem);
+ mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
if (edge_port->edge_serial->num_ports_open <= 0) {
/* last port is now closed, let's shut down our interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
edge_port->edge_serial->num_ports_open = 0;
}
- up(&edge_serial->es_sem);
+ mutex_unlock(&edge_serial->es_lock);
edge_port->close_pending = 0;
dbg("%s - exited", __FUNCTION__);
@@ -2393,11 +2394,6 @@
dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
tty = edge_port->port->tty;
- if ((!tty) ||
- (!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
@@ -2492,15 +2488,21 @@
}
}
+ tty->termios->c_cflag &= ~CMSPAR;
+
/* Round the baud rate */
baud = tty_get_baud_rate(tty);
if (!baud) {
/* pick a default, any default... */
baud = 9600;
- }
+ } else
+ tty_encode_baud_rate(tty, baud, baud);
+
edge_port->baud_rate = baud;
config->wBaudRate = (__u16)((461550L + baud/2) / baud);
+ /* FIXME: Recompute actual baud from divisor here */
+
dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
dbg ("wBaudRate: %d", (int)(461550L / config->wBaudRate));
@@ -2538,19 +2540,12 @@
struct tty_struct *tty = port->tty;
unsigned int cflag;
- if (!port->tty || !port->tty->termios) {
- dbg ("%s - no tty or termios", __FUNCTION__);
- return;
- }
-
cflag = tty->termios->c_cflag;
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, tty->termios->c_iflag);
- if (old_termios) {
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag, old_termios->c_iflag);
- }
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag, old_termios->c_iflag);
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2743,7 +2738,7 @@
dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
return -ENOMEM;
}
- sema_init(&edge_serial->es_sem, 1);
+ mutex_init(&edge_serial->es_lock);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
new file mode 100644
index 0000000..fde188e
--- /dev/null
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -0,0 +1,1217 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * And tested with help of WB Electronics
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include "iuu_phoenix.h"
+#include <linux/random.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
+
+static struct usb_device_id id_table[] = {
+ {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver iuu_driver = {
+ .name = "iuu_phoenix",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+/* turbo parameter */
+static int boost = 100;
+static int clockmode = 1;
+static int cdmode = 1;
+static int iuu_cardin;
+static int iuu_cardout;
+static int xmas;
+
+static void read_rxcmd_callback(struct urb *urb);
+
+struct iuu_private {
+ spinlock_t lock; /* store irq state */
+ wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+ u8 termios_initialized;
+ int tiostatus; /* store IUART SIGNAL for tiocmget call */
+ u8 reset; /* if 1 reset is needed */
+ int poll; /* number of poll */
+ u8 *writebuf; /* buffer for writing to device */
+ int writelen; /* num of byte to write to device */
+ u8 *buf; /* used for initialize speed */
+ u8 *dbgbuf; /* debug buffer */
+ u8 len;
+};
+
+
+static void iuu_free_buf(struct iuu_private *priv)
+{
+ kfree(priv->buf);
+ kfree(priv->dbgbuf);
+ kfree(priv->writebuf);
+}
+
+static int iuu_alloc_buf(struct iuu_private *priv)
+{
+ priv->buf = kzalloc(256, GFP_KERNEL);
+ priv->dbgbuf = kzalloc(256, GFP_KERNEL);
+ priv->writebuf = kzalloc(256, GFP_KERNEL);
+ if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
+ iuu_free_buf(priv);
+ dbg("%s problem allocation buffer", __FUNCTION__);
+ return -ENOMEM;
+ }
+ dbg("%s - Privates buffers allocation success", __FUNCTION__);
+ return 0;
+}
+
+static int iuu_startup(struct usb_serial *serial)
+{
+ struct iuu_private *priv;
+ priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
+ dbg("%s- priv allocation success", __FUNCTION__);
+ if (!priv)
+ return -ENOMEM;
+ if (iuu_alloc_buf(priv)) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+ spin_lock_init(&priv->lock);
+ init_waitqueue_head(&priv->delta_msr_wait);
+ usb_set_serial_port_data(serial->port[0], priv);
+ return 0;
+}
+
+/* Shutdown function */
+static void iuu_shutdown(struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ if (!port)
+ return;
+
+ dbg("%s", __FUNCTION__);
+
+ if (priv) {
+ iuu_free_buf(priv);
+ dbg("%s - I will free all", __FUNCTION__);
+ usb_set_serial_port_data(port, NULL);
+
+ dbg("%s - priv is not anymore in port structure", __FUNCTION__);
+ kfree(priv);
+
+ dbg("%s priv is now kfree", __FUNCTION__);
+ }
+}
+
+static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ tty = port->tty;
+
+ dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__,
+ port->number, set, clear);
+ if (set & TIOCM_RTS)
+ priv->tiostatus = TIOCM_RTS;
+
+ if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) {
+ dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
+ priv->reset = 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+/* This is used to provide a carrier detect mechanism
+ * When a card is present, the response is 0x00
+ * When no card , the reader respond with TIOCM_CD
+ * This is known as CD autodetect mechanism
+ */
+static int iuu_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ return priv->tiostatus;
+}
+
+static void iuu_rxcmd(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+
+
+ memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 1,
+ read_rxcmd_callback, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static int iuu_reset(struct usb_serial_port *port, u8 wt)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ int result;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ dbg("%s - enter", __FUNCTION__);
+
+ /* Prepare the reset sequence */
+
+ *buf_ptr++ = IUU_RST_SET;
+ *buf_ptr++ = IUU_DELAY_MS;
+ *buf_ptr++ = wt;
+ *buf_ptr = IUU_RST_CLEAR;
+
+ /* send the sequence */
+
+ usb_fill_bulk_urb(port->write_urb,
+ port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 4, iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ priv->reset = 0;
+ return result;
+}
+
+/* Status Function
+ * Return value is
+ * 0x00 = no card
+ * 0x01 = smartcard
+ * 0x02 = sim card
+ */
+static void iuu_update_status_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ u8 *st;
+ dbg("%s - enter", __FUNCTION__);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+
+ st = urb->transfer_buffer;
+ dbg("%s - enter", __FUNCTION__);
+ if (urb->actual_length == 1) {
+ switch (st[0]) {
+ case 0x1:
+ priv->tiostatus = iuu_cardout;
+ break;
+ case 0x0:
+ priv->tiostatus = iuu_cardin;
+ break;
+ default:
+ priv->tiostatus = iuu_cardin;
+ }
+ }
+ iuu_rxcmd(urb);
+}
+
+static void iuu_status_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, 256,
+ iuu_update_status_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+}
+
+static int iuu_status(struct usb_serial_port *port)
+{
+ int result;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 1,
+ iuu_status_callback, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ return result;
+
+}
+
+static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+ int status;
+ struct usb_serial *serial = port->serial;
+ int actual = 0;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ /* send the data out the bulk port */
+
+ status =
+ usb_bulk_msg(serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress), buf,
+ count, &actual, HZ * 1);
+
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - error = %2x", __FUNCTION__, status);
+ } else {
+ dbg("%s - write OK !", __FUNCTION__);
+ }
+ return status;
+}
+
+static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+ int status;
+ struct usb_serial *serial = port->serial;
+ int actual = 0;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ /* send the data out the bulk port */
+
+ status =
+ usb_bulk_msg(serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress), buf,
+ count, &actual, HZ * 1);
+
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - error = %2x", __FUNCTION__, status);
+ } else {
+ dbg("%s - read OK !", __FUNCTION__);
+ }
+
+ return status;
+}
+
+static int iuu_led(struct usb_serial_port *port, unsigned int R,
+ unsigned int G, unsigned int B, u8 f)
+{
+ int status;
+ u8 *buf;
+ buf = kmalloc(8, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ buf[0] = IUU_SET_LED;
+ buf[1] = R & 0xFF;
+ buf[2] = (R >> 8) & 0xFF;
+ buf[3] = G & 0xFF;
+ buf[4] = (G >> 8) & 0xFF;
+ buf[5] = B & 0xFF;
+ buf[6] = (B >> 8) & 0xFF;
+ buf[7] = f;
+ status = bulk_immediate(port, buf, 8);
+ kfree(buf);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - led error status = %2x", __FUNCTION__, status);
+ else
+ dbg("%s - led OK !", __FUNCTION__);
+ return IUU_OPERATION_OK;
+}
+
+static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
+ u8 b2, u8 freq)
+{
+ *buf++ = IUU_SET_LED;
+ *buf++ = r1;
+ *buf++ = r2;
+ *buf++ = g1;
+ *buf++ = g2;
+ *buf++ = b1;
+ *buf++ = b2;
+ *buf = freq;
+}
+
+static void iuu_led_activity_on(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ *buf_ptr++ = IUU_SET_LED;
+ if (xmas == 1) {
+ get_random_bytes(buf_ptr, 6);
+ *(buf_ptr+7) = 1;
+ } else {
+ iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255);
+ }
+
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 8 ,
+ iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static void iuu_led_activity_off(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ if (xmas == 1) {
+ iuu_rxcmd(urb);
+ return;
+ } else {
+ *buf_ptr++ = IUU_SET_LED;
+ iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255);
+ }
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 8 ,
+ iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+
+
+static int iuu_clk(struct usb_serial_port *port, int dwFrq)
+{
+ int status;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ int Count = 0;
+ u8 FrqGenAdr = 0x69;
+ u8 DIV = 0; /* 8bit */
+ u8 XDRV = 0; /* 8bit */
+ u8 PUMP = 0; /* 3bit */
+ u8 PBmsb = 0; /* 2bit */
+ u8 PBlsb = 0; /* 8bit */
+ u8 PO = 0; /* 1bit */
+ u8 Q = 0; /* 7bit */
+ /* 24bit = 3bytes */
+ unsigned int P = 0;
+ unsigned int P2 = 0;
+ int frq = (int)dwFrq;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ if (frq == 0) {
+ priv->buf[Count++] = IUU_UART_WRITE_I2C;
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x09;
+ priv->buf[Count++] = 0x00;
+
+ status = bulk_immediate(port, (u8 *) priv->buf, Count);
+ if (status != 0) {
+ dbg("%s - write error ", __FUNCTION__);
+ return status;
+ }
+ } else if (frq == 3579000) {
+ DIV = 100;
+ P = 1193;
+ Q = 40;
+ XDRV = 0;
+ } else if (frq == 3680000) {
+ DIV = 105;
+ P = 161;
+ Q = 5;
+ XDRV = 0;
+ } else if (frq == 6000000) {
+ DIV = 66;
+ P = 66;
+ Q = 2;
+ XDRV = 0x28;
+ } else {
+ unsigned int result = 0;
+ unsigned int tmp = 0;
+ unsigned int check;
+ unsigned int check2;
+ char found = 0x00;
+ unsigned int lQ = 2;
+ unsigned int lP = 2055;
+ unsigned int lDiv = 4;
+
+ for (lQ = 2; lQ <= 47 && !found; lQ++)
+ for (lP = 2055; lP >= 8 && !found; lP--)
+ for (lDiv = 4; lDiv <= 127 && !found; lDiv++) {
+ tmp = (12000000 / lDiv) * (lP / lQ);
+ if (abs((int)(tmp - frq)) <
+ abs((int)(frq - result))) {
+ check2 = (12000000 / lQ);
+ if (check2 < 250000)
+ continue;
+ check = (12000000 / lQ) * lP;
+ if (check > 400000000)
+ continue;
+ if (check < 100000000)
+ continue;
+ if (lDiv < 4 || lDiv > 127)
+ continue;
+ result = tmp;
+ P = lP;
+ DIV = lDiv;
+ Q = lQ;
+ if (result == frq)
+ found = 0x01;
+ }
+ }
+ }
+ P2 = ((P - PO) / 2) - 4;
+ DIV = DIV;
+ PUMP = 0x04;
+ PBmsb = (P2 >> 8 & 0x03);
+ PBlsb = P2 & 0xFF;
+ PO = (P >> 10) & 0x01;
+ Q = Q - 2;
+
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x09;
+ priv->buf[Count++] = 0x20; /* Adr = 0x09 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x0C;
+ priv->buf[Count++] = DIV; /* Adr = 0x0C */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x12;
+ priv->buf[Count++] = XDRV; /* Adr = 0x12 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x13;
+ priv->buf[Count++] = 0x6B; /* Adr = 0x13 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x40;
+ priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) |
+ (PBmsb & 0x03); /* Adr = 0x40 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x41;
+ priv->buf[Count++] = PBlsb; /* Adr = 0x41 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x42;
+ priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x44;
+ priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x45;
+ priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x46;
+ priv->buf[Count++] = 0x7F; /* Adr = 0x46 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x47;
+ priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */
+
+ status = bulk_immediate(port, (u8 *) priv->buf, Count);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - write error ", __FUNCTION__);
+ return status;
+}
+
+static int iuu_uart_flush(struct usb_serial_port *port)
+{
+ int i;
+ int status;
+ u8 rxcmd = IUU_UART_RX;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s - enter", __FUNCTION__);
+
+ if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
+ return -EIO;
+
+ for (i = 0; i < 2; i++) {
+ status = bulk_immediate(port, &rxcmd, 1);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_flush_write error", __FUNCTION__);
+ return status;
+ }
+
+ status = read_immediate(port, &priv->len, 1);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_flush_read error", __FUNCTION__);
+ return status;
+ }
+
+ if (priv->len > 0) {
+ dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
+ priv->len);
+ status = read_immediate(port, priv->buf, priv->len);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_flush_read error", __FUNCTION__);
+ return status;
+ }
+ }
+ }
+ dbg("%s - uart_flush_read OK!", __FUNCTION__);
+ iuu_led(port, 0, 0xF000, 0, 0xFF);
+ return status;
+}
+
+static void read_buf_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ struct tty_struct *tty;
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ if (urb->status == -EPROTO) {
+ /* reschedule needed */
+ }
+ return;
+ }
+
+ dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length);
+ tty = port->tty;
+ if (data == NULL)
+ dbg("%s - data is NULL !!!", __FUNCTION__);
+ if (tty && urb->actual_length && data) {
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
+ }
+ iuu_led_activity_on(urb);
+}
+
+static int iuu_bulk_write(struct usb_serial_port *port)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned int flags;
+ int result;
+ int i;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ dbg("%s - enter", __FUNCTION__);
+
+ *buf_ptr++ = IUU_UART_ESC;
+ *buf_ptr++ = IUU_UART_TX;
+ *buf_ptr++ = priv->writelen;
+
+ memcpy(buf_ptr, priv->writebuf,
+ priv->writelen);
+ if (debug == 1) {
+ for (i = 0; i < priv->writelen; i++)
+ sprintf(priv->dbgbuf + i*2 ,
+ "%02X", priv->writebuf[i]);
+ priv->dbgbuf[priv->writelen+i*2] = 0;
+ dbg("%s - writing %i chars : %s", __FUNCTION__,
+ priv->writelen, priv->dbgbuf);
+ }
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, priv->writelen + 3,
+ iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->writelen = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ usb_serial_port_softint(port);
+ return result;
+}
+
+static int iuu_read_buf(struct usb_serial_port *port, int len)
+{
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, len,
+ read_buf_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ return result;
+}
+
+static void iuu_uart_read_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned int flags;
+ int status;
+ int error = 0;
+ int len = 0;
+ unsigned char *data = urb->transfer_buffer;
+ priv->poll++;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+ if (data == NULL)
+ dbg("%s - data is NULL !!!", __FUNCTION__);
+
+ if (urb->actual_length == 1 && data != NULL)
+ len = (int) data[0];
+
+ if (urb->actual_length > 1) {
+ dbg("%s - urb->actual_length = %i", __FUNCTION__,
+ urb->actual_length);
+ error = 1;
+ return;
+ }
+ /* if len > 0 call readbuf */
+
+ if (len > 0 && error == 0) {
+ dbg("%s - call read buf - len to read is %i ",
+ __FUNCTION__, len);
+ status = iuu_read_buf(port, len);
+ return;
+ }
+ /* need to update status ? */
+ if (priv->poll > 99) {
+ status = iuu_status(port);
+ priv->poll = 0;
+ return;
+ }
+
+ /* reset waiting ? */
+
+ if (priv->reset == 1) {
+ status = iuu_reset(port, 0xC);
+ return;
+ }
+ /* Writebuf is waiting */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->writelen > 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ status = iuu_bulk_write(port);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /* if nothing to write call again rxcmd */
+ dbg("%s - rxcmd recall", __FUNCTION__);
+ iuu_led_activity_off(urb);
+ return;
+}
+
+static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
+ int count)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned int flags;
+ dbg("%s - enter", __FUNCTION__);
+
+ if (count > 256)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->writelen > 0) {
+ /* buffer already filled but not commited */
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return (0);
+ }
+ /* fill the buffer */
+ memcpy(priv->writebuf, buf, count);
+ priv->writelen = count;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return (count);
+}
+
+static void read_rxcmd_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, 256,
+ iuu_uart_read_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ dbg("%s - submit result = %d", __FUNCTION__, result);
+ return;
+}
+
+static int iuu_uart_on(struct usb_serial_port *port)
+{
+ int status;
+ u8 *buf;
+
+ buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
+
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = IUU_UART_ENABLE;
+ buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
+ buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
+ buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
+
+ status = bulk_immediate(port, buf, 4);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_on error", __FUNCTION__);
+ goto uart_enable_failed;
+ }
+ /* iuu_reset() the card after iuu_uart_on() */
+ status = iuu_uart_flush(port);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - uart_flush error", __FUNCTION__);
+uart_enable_failed:
+ kfree(buf);
+ return status;
+}
+
+/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */
+static int iuu_uart_off(struct usb_serial_port *port)
+{
+ int status;
+ u8 *buf;
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = IUU_UART_DISABLE;
+
+ status = bulk_immediate(port, buf, 1);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - uart_off error", __FUNCTION__);
+
+ kfree(buf);
+ return status;
+}
+
+static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
+ u32 *actual, u8 parity)
+{
+ int status;
+ u8 *dataout;
+ u8 DataCount = 0;
+ u8 T1Frekvens = 0;
+ u8 T1reload = 0;
+ unsigned int T1FrekvensHZ = 0;
+
+ dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
+
+ if (!dataout)
+ return -ENOMEM;
+
+ if (baud < 1200 || baud > 230400) {
+ kfree(dataout);
+ return IUU_INVALID_PARAMETER;
+ }
+ if (baud > 977) {
+ T1Frekvens = 3;
+ T1FrekvensHZ = 500000;
+ }
+
+ if (baud > 3906) {
+ T1Frekvens = 2;
+ T1FrekvensHZ = 2000000;
+ }
+
+ if (baud > 11718) {
+ T1Frekvens = 1;
+ T1FrekvensHZ = 6000000;
+ }
+
+ if (baud > 46875) {
+ T1Frekvens = 0;
+ T1FrekvensHZ = 24000000;
+ }
+
+ T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2));
+
+ /* magic number here: ENTER_FIRMWARE_UPDATE; */
+ dataout[DataCount++] = IUU_UART_ESC;
+ /* magic number here: CHANGE_BAUD; */
+ dataout[DataCount++] = IUU_UART_CHANGE;
+ dataout[DataCount++] = T1Frekvens;
+ dataout[DataCount++] = T1reload;
+
+ *actual = (T1FrekvensHZ / (256 - T1reload)) / 2;
+
+ switch (parity & 0x0F) {
+ case IUU_PARITY_NONE:
+ dataout[DataCount++] = 0x00;
+ break;
+ case IUU_PARITY_EVEN:
+ dataout[DataCount++] = 0x01;
+ break;
+ case IUU_PARITY_ODD:
+ dataout[DataCount++] = 0x02;
+ break;
+ case IUU_PARITY_MARK:
+ dataout[DataCount++] = 0x03;
+ break;
+ case IUU_PARITY_SPACE:
+ dataout[DataCount++] = 0x04;
+ break;
+ default:
+ kfree(dataout);
+ return IUU_INVALID_PARAMETER;
+ break;
+ }
+
+ switch (parity & 0xF0) {
+ case IUU_ONE_STOP_BIT:
+ dataout[DataCount - 1] |= IUU_ONE_STOP_BIT;
+ break;
+
+ case IUU_TWO_STOP_BITS:
+ dataout[DataCount - 1] |= IUU_TWO_STOP_BITS;
+ break;
+ default:
+ kfree(dataout);
+ return IUU_INVALID_PARAMETER;
+ break;
+ }
+
+ status = bulk_immediate(port, dataout, DataCount);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - uart_off error", __FUNCTION__);
+ kfree(dataout);
+ return status;
+}
+
+static int set_control_lines(struct usb_device *dev, u8 value)
+{
+ return 0;
+}
+
+static void iuu_close(struct usb_serial_port *port, struct file *filp)
+{
+ /* iuu_led (port,255,0,0,0); */
+ struct usb_serial *serial;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int c_cflag;
+
+ serial = port->serial;
+ if (!serial)
+ return;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ iuu_uart_off(port);
+ if (serial->dev) {
+ if (port->tty) {
+ c_cflag = port->tty->termios->c_cflag;
+ if (c_cflag & HUPCL) {
+ /* drop DTR and RTS */
+ priv = usb_get_serial_port_data(port);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_control = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_control_lines(port->serial->dev, 0);
+ }
+ }
+ /* free writebuf */
+ /* shutdown our urbs */
+ dbg("%s - shutting down urbs", __FUNCTION__);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+ msleep(1000);
+ /* wait one second to free all buffers */
+ iuu_led(port, 0, 0, 0xF000, 0xFF);
+ msleep(1000);
+ usb_reset_device(port->serial->dev);
+ }
+}
+
+static int iuu_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ u8 *buf;
+ int result;
+ u32 actual;
+ unsigned long flags;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ buf = kmalloc(10, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ /* fixup the endpoint buffer size */
+ kfree(port->bulk_out_buffer);
+ port->bulk_out_buffer = kmalloc(512, GFP_KERNEL);
+ port->bulk_out_size = 512;
+ kfree(port->bulk_in_buffer);
+ port->bulk_in_buffer = kmalloc(512, GFP_KERNEL);
+ port->bulk_in_size = 512;
+
+ if (!port->bulk_out_buffer || !port->bulk_in_buffer) {
+ kfree(port->bulk_out_buffer);
+ kfree(port->bulk_in_buffer);
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->bulk_out_buffer, 512,
+ NULL, NULL);
+
+
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer, 512,
+ NULL, NULL);
+
+ /* set the termios structure */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+ port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+ | TIOCM_CTS | CSTOPB | PARENB;
+ port->tty->termios->c_lflag = 0;
+ port->tty->termios->c_oflag = 0;
+ port->tty->termios->c_iflag = 0;
+ priv->termios_initialized = 1;
+ port->tty->low_latency = 1;
+ priv->poll = 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* initialize writebuf */
+#define FISH(a, b, c, d) do { \
+ result = usb_control_msg(port->serial->dev, \
+ usb_rcvctrlpipe(port->serial->dev, 0), \
+ b, a, c, d, buf, 1, 1000); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \
+ buf[0]); } while (0);
+
+#define SOUP(a, b, c, d) do { \
+ result = usb_control_msg(port->serial->dev, \
+ usb_sndctrlpipe(port->serial->dev, 0), \
+ b, a, c, d, NULL, 0, 1000); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0)
+
+ /* This is not UART related but IUU USB driver related or something */
+ /* like that. Basically no IUU will accept any commands from the USB */
+ /* host unless it has received the following message */
+ /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
+
+ SOUP(0x03, 0x02, 0x02, 0x0);
+ kfree(buf);
+ iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
+ iuu_uart_on(port);
+ if (boost < 100)
+ boost = 100;
+ switch (clockmode) {
+ case 2: /* 3.680 Mhz */
+ iuu_clk(port, IUU_CLK_3680000 * boost / 100);
+ result =
+ iuu_uart_baud(port, 9600 * boost / 100, &actual,
+ IUU_PARITY_EVEN);
+ break;
+ case 3: /* 6.00 Mhz */
+ iuu_clk(port, IUU_CLK_6000000 * boost / 100);
+ result =
+ iuu_uart_baud(port, 16457 * boost / 100, &actual,
+ IUU_PARITY_EVEN);
+ break;
+ default: /* 3.579 Mhz */
+ iuu_clk(port, IUU_CLK_3579000 * boost / 100);
+ result =
+ iuu_uart_baud(port, 9600 * boost / 100, &actual,
+ IUU_PARITY_EVEN);
+ }
+
+ /* set the cardin cardout signals */
+ switch (cdmode) {
+ case 0:
+ iuu_cardin = 0;
+ iuu_cardout = 0;
+ break;
+ case 1:
+ iuu_cardin = TIOCM_CD;
+ iuu_cardout = 0;
+ break;
+ case 2:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_CD;
+ break;
+ case 3:
+ iuu_cardin = TIOCM_DSR;
+ iuu_cardout = 0;
+ break;
+ case 4:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_DSR;
+ break;
+ case 5:
+ iuu_cardin = TIOCM_CTS;
+ iuu_cardout = 0;
+ break;
+ case 6:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_CTS;
+ break;
+ case 7:
+ iuu_cardin = TIOCM_RNG;
+ iuu_cardout = 0;
+ break;
+ case 8:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_RNG;
+ }
+
+ iuu_uart_flush(port);
+
+ dbg("%s - initialization done", __FUNCTION__);
+
+ memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 1,
+ read_rxcmd_callback, port);
+ result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+
+ if (result) {
+ dev_err(&port->dev, "%s - failed submitting read urb,"
+ " error %d\n", __FUNCTION__, result);
+ iuu_close(port, NULL);
+ return -EPROTO;
+ } else {
+ dbg("%s - rxcmd OK", __FUNCTION__);
+ }
+ return result;
+}
+
+static struct usb_serial_driver iuu_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "iuu_phoenix",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = iuu_open,
+ .close = iuu_close,
+ .write = iuu_uart_write,
+ .read_bulk_callback = iuu_uart_read_callback,
+ .tiocmget = iuu_tiocmget,
+ .tiocmset = iuu_tiocmset,
+ .attach = iuu_startup,
+ .shutdown = iuu_shutdown,
+};
+
+static int __init iuu_init(void)
+{
+ int retval;
+ retval = usb_serial_register(&iuu_device);
+ if (retval)
+ goto failed_usb_serial_register;
+ retval = usb_register(&iuu_driver);
+ if (retval)
+ goto failed_usb_register;
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ return 0;
+failed_usb_register:
+ usb_serial_deregister(&iuu_device);
+failed_usb_serial_register:
+ return retval;
+}
+
+static void __exit iuu_exit(void)
+{
+ usb_deregister(&iuu_driver);
+ usb_serial_deregister(&iuu_device);
+}
+
+module_init(iuu_init);
+module_exit(iuu_exit);
+
+MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(DRIVER_VERSION);
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(xmas, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(xmas, "xmas color enabled or not");
+
+module_param(boost, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500");
+
+module_param(clockmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz");
+
+module_param(cdmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, "
+ "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING");
diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h
new file mode 100644
index 0000000..b82630a
--- /dev/null
+++ b/drivers/usb/serial/iuu_phoenix.h
@@ -0,0 +1,122 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ *
+ * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás )
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * And tested with help of WB Electronics
+ *
+ */
+
+#define IUU_USB_VENDOR_ID 0x104f
+#define IUU_USB_PRODUCT_ID 0x0004
+#define IUU_USB_OP_TIMEOUT 0x0200
+
+/* Programmer commands */
+
+#define IUU_NO_OPERATION 0x00
+#define IUU_GET_FIRMWARE_VERSION 0x01
+#define IUU_GET_PRODUCT_NAME 0x02
+#define IUU_GET_STATE_REGISTER 0x03
+#define IUU_SET_LED 0x04
+#define IUU_WAIT_MUS 0x05
+#define IUU_WAIT_MS 0x06
+#define IUU_GET_LOADER_VERSION 0x50
+#define IUU_RST_SET 0x52
+#define IUU_RST_CLEAR 0x53
+#define IUU_SET_VCC 0x59
+#define IUU_UART_ENABLE 0x49
+#define IUU_UART_DISABLE 0x4A
+#define IUU_UART_WRITE_I2C 0x4C
+#define IUU_UART_ESC 0x5E
+#define IUU_UART_TRAP 0x54
+#define IUU_UART_TRAP_BREAK 0x5B
+#define IUU_UART_RX 0x56
+#define IUU_AVR_ON 0x21
+#define IUU_AVR_OFF 0x22
+#define IUU_AVR_1CLK 0x23
+#define IUU_AVR_RESET 0x24
+#define IUU_AVR_RESET_PC 0x25
+#define IUU_AVR_INC_PC 0x26
+#define IUU_AVR_INCN_PC 0x27
+#define IUU_AVR_PREAD 0x29
+#define IUU_AVR_PREADN 0x2A
+#define IUU_AVR_PWRITE 0x28
+#define IUU_AVR_DREAD 0x2C
+#define IUU_AVR_DREADN 0x2D
+#define IUU_AVR_DWRITE 0x2B
+#define IUU_AVR_PWRITEN 0x2E
+#define IUU_EEPROM_ON 0x37
+#define IUU_EEPROM_OFF 0x38
+#define IUU_EEPROM_WRITE 0x39
+#define IUU_EEPROM_WRITEX 0x3A
+#define IUU_EEPROM_WRITE8 0x3B
+#define IUU_EEPROM_WRITE16 0x3C
+#define IUU_EEPROM_WRITEX32 0x3D
+#define IUU_EEPROM_WRITEX64 0x3E
+#define IUU_EEPROM_READ 0x3F
+#define IUU_EEPROM_READX 0x40
+#define IUU_EEPROM_BREAD 0x41
+#define IUU_EEPROM_BREADX 0x42
+#define IUU_PIC_CMD 0x0A
+#define IUU_PIC_CMD_LOAD 0x0B
+#define IUU_PIC_CMD_READ 0x0C
+#define IUU_PIC_ON 0x0D
+#define IUU_PIC_OFF 0x0E
+#define IUU_PIC_RESET 0x16
+#define IUU_PIC_INC_PC 0x0F
+#define IUU_PIC_INCN_PC 0x10
+#define IUU_PIC_PWRITE 0x11
+#define IUU_PIC_PREAD 0x12
+#define IUU_PIC_PREADN 0x13
+#define IUU_PIC_DWRITE 0x14
+#define IUU_PIC_DREAD 0x15
+#define IUU_UART_NOP 0x00
+#define IUU_UART_CHANGE 0x02
+#define IUU_UART_TX 0x04
+#define IUU_DELAY_MS 0x06
+
+#define IUU_OPERATION_OK 0x00
+#define IUU_DEVICE_NOT_FOUND 0x01
+#define IUU_INVALID_HANDLE 0x02
+#define IUU_INVALID_PARAMETER 0x03
+#define IUU_INVALID_voidERFACE 0x04
+#define IUU_INVALID_REQUEST_LENGTH 0x05
+#define IUU_UART_NOT_ENABLED 0x06
+#define IUU_WRITE_ERROR 0x07
+#define IUU_READ_ERROR 0x08
+#define IUU_TX_ERROR 0x09
+#define IUU_RX_ERROR 0x0A
+
+#define IUU_PARITY_NONE 0x00
+#define IUU_PARITY_EVEN 0x01
+#define IUU_PARITY_ODD 0x02
+#define IUU_PARITY_MARK 0x03
+#define IUU_PARITY_SPACE 0x04
+#define IUU_SC_INSERTED 0x01
+#define IUU_VERIFY_ERROR 0x02
+#define IUU_SIM_INSERTED 0x04
+#define IUU_TWO_STOP_BITS 0x00
+#define IUU_ONE_STOP_BIT 0x20
+#define IUU_BAUD_2400 0x0398
+#define IUU_BAUD_9600 0x0298
+#define IUU_BAUD_19200 0x0164
+#define IUU_BAUD_28800 0x0198
+#define IUU_BAUD_38400 0x01B2
+#define IUU_BAUD_57600 0x0030
+#define IUU_BAUD_115200 0x0098
+#define IUU_CLK_3579000 3579000
+#define IUU_CLK_3680000 3680000
+#define IUU_CLK_6000000 6000000
+#define IUU_FULLCARD_IN 0x01
+#define IUU_DEV_ERROR 0x02
+#define IUU_MINICARD_IN 0x04
+#define IUU_VCC_5V 0x00
+#define IUU_VCC_3V 0x01
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 7c069a0..ea7bba6 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -838,7 +838,7 @@
port = (struct usb_serial_port *) urb->context;
tty = port->tty;
- if (urb->actual_length) {
+ if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
/* no error on any byte */
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index be9ac20..b1fa5a3 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -303,7 +303,7 @@
}
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+static speed_t keyspan_pda_setbaud (struct usb_serial *serial, speed_t baud)
{
int rc;
int bindex;
@@ -319,7 +319,9 @@
case 38400: bindex = 7; break;
case 57600: bindex = 8; break;
case 115200: bindex = 9; break;
- default: return -EINVAL;
+ default:
+ bindex = 5; /* Default to 9600 */
+ baud = 9600;
}
/* rather than figure out how to sleep while waiting for this
@@ -334,7 +336,9 @@
NULL, /* &data */
0, /* size */
2000); /* timeout */
- return(rc);
+ if (rc < 0)
+ return 0;
+ return baud;
}
@@ -366,7 +370,7 @@
struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
- unsigned int cflag = port->tty->termios->c_cflag;
+ speed_t speed;
/* cflag specifies lots of stuff: number of stop bits, parity, number
of data bits, baud. What can the device actually handle?:
@@ -388,22 +392,18 @@
For now, just do baud. */
- switch (cflag & CBAUD) {
- /* we could support more values here, just need to calculate
- the necessary divisors in the firmware. <asm/termbits.h>
- has the Bnnn constants. */
- case B110: keyspan_pda_setbaud(serial, 110); break;
- case B300: keyspan_pda_setbaud(serial, 300); break;
- case B1200: keyspan_pda_setbaud(serial, 1200); break;
- case B2400: keyspan_pda_setbaud(serial, 2400); break;
- case B4800: keyspan_pda_setbaud(serial, 4800); break;
- case B9600: keyspan_pda_setbaud(serial, 9600); break;
- case B19200: keyspan_pda_setbaud(serial, 19200); break;
- case B38400: keyspan_pda_setbaud(serial, 38400); break;
- case B57600: keyspan_pda_setbaud(serial, 57600); break;
- case B115200: keyspan_pda_setbaud(serial, 115200); break;
- default: dbg("can't handle requested baud rate"); break;
+ speed = tty_get_baud_rate(port->tty);
+ speed = keyspan_pda_setbaud(serial, speed);
+
+ if (speed == 0) {
+ dbg("can't handle requested baud rate");
+ /* It hasn't changed so.. */
+ speed = tty_termios_baud_rate(old_termios);
}
+ /* Only speed can change so copy the old h/w parameters
+ then encode the new speed */
+ tty_termios_copy_hw(port->tty->termios, old_termios);
+ tty_encode_baud_rate(port->tty, speed, speed);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 90e3216..55736df 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -461,17 +461,21 @@
dbg("%s port %d", __FUNCTION__, port->number);
- /* send READ_OFF */
- rc = usb_control_msg (port->serial->dev,
- usb_sndctrlpipe(port->serial->dev, 0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
- 0, /* index */
- NULL, 0,
- KLSI_TIMEOUT);
- if (rc < 0)
- err("Disabling read failed (error = %d)", rc);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected) {
+ /* send READ_OFF */
+ rc = usb_control_msg (port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+ 0, /* index */
+ NULL, 0,
+ KLSI_TIMEOUT);
+ if (rc < 0)
+ err("Disabling read failed (error = %d)", rc);
+ }
+ mutex_unlock(&port->serial->disc_mutex);
/* shutdown our bulk reads and writes */
usb_kill_urb(port->write_urb);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index aee4502..17b3bae 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -114,6 +114,7 @@
.usb_driver = &kobil_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
+ .num_interrupt_out = NUM_DONT_CARE,
.num_bulk_in = 0,
.num_bulk_out = 0,
.num_ports = 1,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 0dc99f7..fc1cea4 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -182,10 +182,11 @@
/*
* Later day 2.6.0-test kernels have new baud rates like B230400 which
* we do not know how to support. We ignore them for the moment.
- * XXX Rate-limit the error message, it's user triggerable.
*/
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value)
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result)
{
+ *result = value;
+
if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
|| le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
switch (value) {
@@ -200,11 +201,13 @@
case 57600: return 0x0b;
case 115200: return 0x0c;
default:
- err("MCT USB-RS232: unsupported baudrate request 0x%x,"
- " using default of B9600", value);
+ *result = 9600;
return 0x08;
}
} else {
+ /* FIXME: Can we use any divider - should we do
+ divider = 115200/value;
+ real baud = 115200/divider */
switch (value) {
case 300: break;
case 600: break;
@@ -217,9 +220,8 @@
case 57600: break;
case 115200: break;
default:
- err("MCT USB-RS232: unsupported baudrate request 0x%x,"
- " using default of B9600", value);
value = 9600;
+ *result = 9600;
}
return 115200/value;
}
@@ -232,16 +234,19 @@
int rc;
unsigned char zero_byte = 0;
unsigned char cts_enable_byte = 0;
+ speed_t speed;
- divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
+ divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value, &speed));
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_BAUD_RATE_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
WDR_TIMEOUT);
- if (rc < 0)
+ if (rc < 0) /*FIXME: What value speed results */
err("Set BAUD RATE %d failed (error = %d)", value, rc);
+ else
+ tty_encode_baud_rate(port->tty, speed, speed);
dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
@@ -482,21 +487,22 @@
static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
{
unsigned int c_cflag;
- unsigned long flags;
unsigned int control_state;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
dbg("%s port %d", __FUNCTION__, port->number);
if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
- if (c_cflag & HUPCL) {
- /* drop DTR and RTS */
- spin_lock_irqsave(&priv->lock, flags);
- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- control_state = priv->control_state;
- spin_unlock_irqrestore(&priv->lock, flags);
- mct_u232_set_modem_ctrl(port->serial, control_state);
+ mutex_lock(&port->serial->disc_mutex);
+ if (c_cflag & HUPCL && !port->serial->disconnected) {
+ /* drop DTR and RTS */
+ spin_lock_irq(&priv->lock);
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ control_state = priv->control_state;
+ spin_unlock_irq(&priv->lock);
+ mct_u232_set_modem_ctrl(port->serial, control_state);
}
+ mutex_unlock(&port->serial->disc_mutex);
}
@@ -608,7 +614,8 @@
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- unsigned int cflag = port->tty->termios->c_cflag;
+ struct ktermios *termios = port->tty->termios;
+ unsigned int cflag = termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned long flags;
unsigned int control_state;
@@ -670,6 +677,8 @@
break;
}
+ termios->c_cflag &= ~CMSPAR;
+
/* set the number of stop bits */
last_lcr |= (cflag & CSTOPB) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index aae10c8..07b6bec 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -79,7 +79,7 @@
* and "Intel solution". They are the regular MCT and "Sitecom" for us.
* This is pointless to document in the header, see the code for the bits.
*/
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value);
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result);
/*
* Line Control Register (LCR)
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e02c198..40f3a01 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -564,22 +564,25 @@
}
/* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- dbg("Shutdown bulk write");
- usb_kill_urb(port->write_urb);
- dbg("Shutdown bulk read");
- usb_kill_urb(port->read_urb);
+ * and interrupt read if they exists, otherwise nop */
+ dbg("Shutdown bulk write");
+ usb_kill_urb(port->write_urb);
+ dbg("Shutdown bulk read");
+ usb_kill_urb(port->read_urb);
+
+ mutex_lock(&serial->disc_mutex);
+ /* these commands must not be issued if the device has
+ * been disconnected */
+ if (!serial->disconnected) {
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x04, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x01, &data);
}
-
- data = 0x00;
- send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
- 0x04, &data);
-
- data = 0x00;
- send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
- 0x01, &data);
-
+ mutex_unlock(&serial->disc_mutex);
mos7720_port->open = 0;
dbg("Leaving %s", __FUNCTION__);
@@ -1040,11 +1043,6 @@
tty = mos7720_port->port->tty;
- if ((!tty) || (!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
dbg("%s: Entering ..........", __FUNCTION__);
lData = UART_LCR_WLEN8;
@@ -1175,7 +1173,10 @@
dbg("%s - baud rate = %d", __FUNCTION__, baud);
status = send_cmd_write_baud_rate(mos7720_port, baud);
-
+ /* FIXME: needs to write actual resulting baud back not just
+ blindly do so */
+ if (cflag & CBAUD)
+ tty_encode_baud_rate(tty, baud, baud);
/* Enable Interrupts */
data = 0x0c;
send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
@@ -1214,10 +1215,6 @@
tty = port->tty;
- if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty or termios", __FUNCTION__);
- return;
- }
if (!mos7720_port->open) {
dbg("%s - port not opened", __FUNCTION__);
@@ -1228,19 +1225,13 @@
cflag = tty->termios->c_cflag;
- if (!cflag) {
- printk("%s %s\n",__FUNCTION__,"cflag is NULL");
- return;
- }
-
- dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ dbg("%s - cflag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag,
RELEVANT_IFLAG(tty->termios->c_iflag));
- if (old_termios)
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag,
- RELEVANT_IFLAG(old_termios->c_iflag));
+ dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag,
+ RELEVANT_IFLAG(old_termios->c_iflag));
dbg("%s - port %d", __FUNCTION__, port->number);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c29c912..869ecd3 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1133,7 +1133,7 @@
* This function will block the close until one of the following:
* 1. TX count are 0
* 2. The mos7840 has stopped
- * 3. A timout of 3 seconds without activity has expired
+ * 3. A timeout of 3 seconds without activity has expired
*
************************************************************************/
static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
@@ -1161,7 +1161,7 @@
dbg("%s - TIMEOUT", __FUNCTION__);
return;
} else {
- /* Reset timout value back to seconds */
+ /* Reset timeout value back to seconds */
wait = 30;
}
}
@@ -1275,7 +1275,7 @@
*
* This function will block the close until one of the following:
* 1. Response to our Chase comes from mos7840
- * 2. A timout of 10 seconds without activity has expired
+ * 2. A timeout of 10 seconds without activity has expired
* (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
*
************************************************************************/
@@ -1304,7 +1304,7 @@
dbg("%s - TIMEOUT", __FUNCTION__);
return;
} else {
- /* Reset timout value back to seconds */
+ /* Reset timeout value back to seconds */
wait = 10;
}
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index d1185f5..5e8bf1b 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -180,6 +180,7 @@
{ USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
@@ -640,7 +641,10 @@
portdata->dtr_state = 0;
if (serial->dev) {
- option_send_setup(port);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ option_send_setup(port);
+ mutex_unlock(&serial->disc_mutex);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index eea226ae..a3847d6 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -79,7 +79,7 @@
#define PL2303_BUF_SIZE 1024
#define PL2303_TMP_BUF_SIZE 1024
-struct pl2303_buf {
+struct oti6858_buf {
unsigned int buf_size;
char *buf_buf;
char *buf_get;
@@ -161,14 +161,14 @@
static void oti6858_shutdown(struct usb_serial *serial);
/* functions operating on buffers */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
-static void pl2303_buf_free(struct pl2303_buf *pb);
-static void pl2303_buf_clear(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
+static void oti6858_buf_free(struct oti6858_buf *pb);
+static void oti6858_buf_clear(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
unsigned int count);
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
unsigned int count);
@@ -203,7 +203,7 @@
struct oti6858_private {
spinlock_t lock;
- struct pl2303_buf *buf;
+ struct oti6858_buf *buf;
struct oti6858_control_pkt status;
struct {
@@ -316,7 +316,7 @@
}
priv->flags.write_urb_in_use = 1;
- count = pl2303_buf_data_avail(priv->buf);
+ count = oti6858_buf_data_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
if (count > port->bulk_out_size)
count = port->bulk_out_size;
@@ -345,7 +345,7 @@
}
spin_lock_irqsave(&priv->lock, flags);
- pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
+ oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
spin_unlock_irqrestore(&priv->lock, flags);
port->write_urb->transfer_buffer_length = count;
@@ -370,7 +370,7 @@
priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
if (!priv)
break;
- priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
+ priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE);
if (priv->buf == NULL) {
kfree(priv);
break;
@@ -391,7 +391,7 @@
for (--i; i >= 0; --i) {
priv = usb_get_serial_port_data(serial->port[i]);
- pl2303_buf_free(priv->buf);
+ oti6858_buf_free(priv->buf);
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
@@ -410,7 +410,7 @@
return count;
spin_lock_irqsave(&priv->lock, flags);
- count = pl2303_buf_put(priv->buf, buf, count);
+ count = oti6858_buf_put(priv->buf, buf, count);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
@@ -425,7 +425,7 @@
dbg("%s(port = %d)", __FUNCTION__, port->number);
spin_lock_irqsave(&priv->lock, flags);
- room = pl2303_buf_space_avail(priv->buf);
+ room = oti6858_buf_space_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
return room;
@@ -440,7 +440,7 @@
dbg("%s(port = %d)", __FUNCTION__, port->number);
spin_lock_irqsave(&priv->lock, flags);
- chars = pl2303_buf_data_avail(priv->buf);
+ chars = oti6858_buf_data_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
return chars;
@@ -458,7 +458,7 @@
dbg("%s(port = %d)", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s(): no tty structures", __FUNCTION__);
return;
}
@@ -468,6 +468,8 @@
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
priv->flags.termios_initialized = 1;
+ port->tty->termios->c_ispeed = 38400;
+ port->tty->termios->c_ospeed = 38400;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -504,19 +506,14 @@
br = tty_get_baud_rate(port->tty);
if (br == 0) {
divisor = 0;
- } else if (br <= OTI6858_MAX_BAUD_RATE) {
+ } else {
int real_br;
+ br = min(br, OTI6858_MAX_BAUD_RATE);
divisor = (96000000 + 8 * br) / (16 * br);
real_br = 96000000 / (16 * divisor);
- if ((((real_br - br) * 100 + br - 1) / br) > 2) {
- dbg("%s(): baud rate %d is invalid", __FUNCTION__, br);
- return;
- }
divisor = cpu_to_le16(divisor);
- } else {
- dbg("%s(): baud rate %d is too high", __FUNCTION__, br);
- return;
+ tty_encode_baud_rate(port->tty, real_br, real_br);
}
frame_fmt &= ~FMT_STOP_BITS_MASK;
@@ -650,9 +647,9 @@
dbg("%s(): entering wait loop", __FUNCTION__);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (pl2303_buf_data_avail(priv->buf) == 0
+ if (oti6858_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ || port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
@@ -663,7 +660,7 @@
dbg("%s(): after wait loop", __FUNCTION__);
/* clear out any remaining data in the buffer */
- pl2303_buf_clear(priv->buf);
+ oti6858_buf_clear(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
/* wait for characters to drain from the device */
@@ -831,21 +828,6 @@
return -EFAULT;
return oti6858_tiocmset(port, NULL, 0, x);
- case TIOCGSERIAL:
- if (copy_to_user(user_arg, port->tty->termios,
- sizeof(struct ktermios))) {
- return -EFAULT;
- }
- return 0;
-
- case TIOCSSERIAL:
- if (copy_from_user(port->tty->termios, user_arg,
- sizeof(struct ktermios))) {
- return -EFAULT;
- }
- oti6858_set_termios(port, NULL);
- return 0;
-
case TIOCMIWAIT:
dbg("%s(): TIOCMIWAIT", __FUNCTION__);
return wait_modem_info(port, arg);
@@ -887,7 +869,7 @@
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
if (priv) {
- pl2303_buf_free(priv->buf);
+ oti6858_buf_free(priv->buf);
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
@@ -987,7 +969,7 @@
spin_lock_irqsave(&priv->lock, flags);
if (priv->flags.write_urb_in_use == 0
- && pl2303_buf_data_avail(priv->buf) != 0) {
+ && oti6858_buf_data_avail(priv->buf) != 0) {
schedule_delayed_work(&priv->delayed_write_work,0);
resubmit = 0;
}
@@ -1015,9 +997,8 @@
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
- int i, result;
int status = urb->status;
- char tty_flag;
+ int result;
dbg("%s(port = %d, status = %d)",
__FUNCTION__, port->number, status);
@@ -1045,27 +1026,9 @@
return;
}
- // get tty_flag from status
- tty_flag = TTY_NORMAL;
-
-/* FIXME: probably, errors will be signalled using interrupt pipe! */
-/*
- // break takes precedence over parity,
- // which takes precedence over framing errors
- if (status & UART_BREAK_ERROR )
- tty_flag = TTY_BREAK;
- else if (status & UART_PARITY_ERROR)
- tty_flag = TTY_PARITY;
- else if (status & UART_FRAME_ERROR)
- tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
-*/
-
tty = port->tty;
if (tty != NULL && urb->actual_length > 0) {
- tty_buffer_request_room(tty, urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i)
- tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
@@ -1133,18 +1096,18 @@
/*
- * pl2303_buf_alloc
+ * oti6858_buf_alloc
*
* Allocate a circular buffer and all associated memory.
*/
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+static struct oti6858_buf *oti6858_buf_alloc(unsigned int size)
{
- struct pl2303_buf *pb;
+ struct oti6858_buf *pb;
if (size == 0)
return NULL;
- pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;
@@ -1161,11 +1124,11 @@
}
/*
- * pl2303_buf_free
+ * oti6858_buf_free
*
* Free the buffer and all associated memory.
*/
-static void pl2303_buf_free(struct pl2303_buf *pb)
+static void oti6858_buf_free(struct oti6858_buf *pb)
{
if (pb) {
kfree(pb->buf_buf);
@@ -1174,11 +1137,11 @@
}
/*
- * pl2303_buf_clear
+ * oti6858_buf_clear
*
* Clear out all data in the circular buffer.
*/
-static void pl2303_buf_clear(struct pl2303_buf *pb)
+static void oti6858_buf_clear(struct oti6858_buf *pb)
{
if (pb != NULL) {
/* equivalent to a get of all data available */
@@ -1187,12 +1150,12 @@
}
/*
- * pl2303_buf_data_avail
+ * oti6858_buf_data_avail
*
* Return the number of bytes of data available in the circular
* buffer.
*/
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb)
{
if (pb == NULL)
return 0;
@@ -1200,12 +1163,12 @@
}
/*
- * pl2303_buf_space_avail
+ * oti6858_buf_space_avail
*
* Return the number of bytes of space available in the circular
* buffer.
*/
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb)
{
if (pb == NULL)
return 0;
@@ -1213,14 +1176,14 @@
}
/*
- * pl2303_buf_put
+ * oti6858_buf_put
*
* Copy data data from a user buffer and put it into the circular buffer.
* Restrict to the amount of space available.
*
* Return the number of bytes copied.
*/
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
unsigned int count)
{
unsigned int len;
@@ -1228,7 +1191,7 @@
if (pb == NULL)
return 0;
- len = pl2303_buf_space_avail(pb);
+ len = oti6858_buf_space_avail(pb);
if (count > len)
count = len;
@@ -1252,14 +1215,14 @@
}
/*
- * pl2303_buf_get
+ * oti6858_buf_get
*
* Get data from the circular buffer and copy to the given buffer.
* Restrict to the amount of data available.
*
* Return the number of bytes copied.
*/
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
unsigned int count)
{
unsigned int len;
@@ -1267,7 +1230,7 @@
if (pb == NULL)
return 0;
- len = pl2303_buf_data_avail(pb);
+ len = oti6858_buf_data_avail(pb);
if (count > len)
count = len;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 0da1df9..ae3ec1a 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -65,6 +65,7 @@
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
+ { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
@@ -84,9 +85,10 @@
{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
+ { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
+ { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -97,7 +99,10 @@
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
.no_dynamic_id = 1,
+ .supports_autosuspend = 1,
};
#define SET_LINE_REQUEST_TYPE 0x21
@@ -310,12 +315,39 @@
return count;
}
+static int pl2303_vendor_read(__u16 value, __u16 index,
+ struct usb_serial *serial, unsigned char *buf)
+{
+ int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
+ value, index, buf, 1, 100);
+ dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
+ VENDOR_READ_REQUEST, value, index, res, buf[0]);
+ return res;
+}
+
+static int pl2303_vendor_write(__u16 value, __u16 index,
+ struct usb_serial *serial)
+{
+ int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
+ value, index, NULL, 0, 100);
+ dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
+ VENDOR_WRITE_REQUEST, value, index, res);
+ return res;
+}
+
static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_private *priv;
enum pl2303_type type = type_0;
+ unsigned char *buf;
int i;
+ buf = kmalloc(10, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
if (serial->dev->descriptor.bDeviceClass == 0x02)
type = type_0;
else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
@@ -340,9 +372,27 @@
priv->type = type;
usb_set_serial_port_data(serial->port[i], priv);
}
+
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_write(0x0404, 0, serial);
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_read(0x8383, 0, serial, buf);
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_write(0x0404, 1, serial);
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_read(0x8383, 0, serial, buf);
+ pl2303_vendor_write(0, 1, serial);
+ pl2303_vendor_write(1, 0, serial);
+ if (type == HX)
+ pl2303_vendor_write(2, 0x44, serial);
+ else
+ pl2303_vendor_write(2, 0x24, serial);
+
+ kfree(buf);
return 0;
cleanup:
+ kfree(buf);
for (--i; i>=0; --i) {
priv = usb_get_serial_port_data(serial->port[i]);
pl2303_buf_free(priv->buf);
@@ -582,24 +632,12 @@
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CRTSCTS) {
- __u16 index;
if (priv->type == HX)
- index = 0x61;
+ pl2303_vendor_write(0x0, 0x61, serial);
else
- index = 0x41;
- i = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- VENDOR_WRITE_REQUEST,
- VENDOR_WRITE_REQUEST_TYPE,
- 0x0, index, NULL, 0, 100);
- dbg("0x40:0x1:0x0:0x%x %d", index, i);
+ pl2303_vendor_write(0x0, 0x41, serial);
} else {
- i = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- VENDOR_WRITE_REQUEST,
- VENDOR_WRITE_REQUEST_TYPE,
- 0x0, 0x0, NULL, 0, 100);
- dbg ("0x40:0x1:0x0:0x0 %d", i);
+ pl2303_vendor_write(0x0, 0x0, serial);
}
/* FIXME: Need to read back resulting baud rate */
@@ -629,7 +667,7 @@
set_current_state(TASK_INTERRUPTIBLE);
if (pl2303_buf_data_avail(priv->buf) == 0 ||
timeout == 0 || signal_pending(current) ||
- !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
@@ -678,7 +716,6 @@
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned char *buf;
int result;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -686,45 +723,12 @@
if (priv->type != HX) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
- }
-
- buf = kmalloc(10, GFP_KERNEL);
- if (buf==NULL)
- return -ENOMEM;
-
-#define FISH(a,b,c,d) \
- result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
- b, a, c, d, buf, 1, 100); \
- dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
-
-#define SOUP(a,b,c,d) \
- result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
- b, a, c, d, NULL, 0, 100); \
- dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
-
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
-
- if (priv->type == HX) {
- /* HX chip */
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
- /* reset upstream data pipes */
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
} else {
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
+ /* reset upstream data pipes */
+ pl2303_vendor_write(8, 0, serial);
+ pl2303_vendor_write(9, 0, serial);
}
- kfree(buf);
-
/* Setup termios */
if (port->tty) {
pl2303_set_termios(port, &tmp_termios);
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index d31f5d2..237a41f 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -35,6 +35,7 @@
#define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000
+#define RATOC_PRODUCT_ID_USB60F 0xb020
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
@@ -96,10 +97,6 @@
#define ALCOR_VENDOR_ID 0x058F
#define ALCOR_PRODUCT_ID 0x9720
-/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
-#define HUAWEI_VENDOR_ID 0x12d1
-#define HUAWEI_PRODUCT_ID 0x1001
-
/* Willcom WS002IN Data Driver (by NetIndex Inc.) */
#define WS002IN_VENDOR_ID 0x11f6
#define WS002IN_PRODUCT_ID 0x2001
@@ -107,3 +104,11 @@
/* Corega CG-USBRS232R Serial Adapter */
#define COREGA_VENDOR_ID 0x07aa
#define COREGA_PRODUCT_ID 0x002a
+
+/* HL HL-340 (ID: 4348:5523) */
+#define HL340_VENDOR_ID 0x4348
+#define HL340_PRODUCT_ID 0x5523
+
+/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
+#define YCCABLE_VENDOR_ID 0x05ad
+#define YCCABLE_PRODUCT_ID 0x0fba
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index c295d04..4c925e3 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
/*
USB Driver for Sierra Wireless
- Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com>
+ Copyright (C) 2006, 2007, 2008 Kevin Lloyd <linux@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
@@ -14,7 +14,7 @@
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
*/
-#define DRIVER_VERSION "v.1.2.5b"
+#define DRIVER_VERSION "v.1.2.7"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -26,10 +26,12 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <linux/usb/ch9.h>
+#define SWIMS_USB_REQUEST_SetPower 0x00
+#define SWIMS_USB_REQUEST_SetNmea 0x07
#define SWIMS_USB_REQUEST_SetMode 0x0B
-#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
-#define SWIMS_USB_INDEX_SetMode 0x0000
+#define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40
#define SWIMS_SET_MODE_Modem 0x0001
/* per port private data */
@@ -38,6 +40,8 @@
#define IN_BUFLEN 4096
static int debug;
+static int nmea;
+static int truinstall = 1;
enum devicetype {
DEVICE_3_PORT = 0,
@@ -50,48 +54,96 @@
int result;
dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x00, /* __u8 request */
- 0x40, /* __u8 request type */
- swiState, /* __u16 value */
- 0, /* __u16 index */
- NULL, /* void *data */
- 0, /* __u16 size */
- USB_CTRL_SET_TIMEOUT); /* int timeout */
+ SWIMS_USB_REQUEST_SetPower, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ swiState, /* __u16 value */
+ 0, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
return result;
}
-static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
{
int result;
dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetMode, /* __u8 request */
- SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
- eSocMode, /* __u16 value */
- SWIMS_USB_INDEX_SetMode, /* __u16 index */
+ SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ eSWocMode, /* __u16 value */
+ 0x0000, /* __u16 index */
NULL, /* void *data */
0, /* __u16 size */
USB_CTRL_SET_TIMEOUT); /* int timeout */
return result;
}
-static int sierra_probe(struct usb_interface *iface,
- const struct usb_device_id *id)
+static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
{
int result;
- struct usb_device *udev;
+ dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ enable, /* __u16 value */
+ 0x0000, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
- udev = usb_get_dev(interface_to_usbdev(iface));
+static int sierra_calc_num_ports(struct usb_serial *serial)
+{
+ int result;
+ int *num_ports = usb_get_serial_data(serial);
- /* Check if in installer mode */
- if (id->driver_info == DEVICE_INSTALLER) {
- dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
- result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
- /*We do not want to bind to the device when in installer mode*/
- return -EIO;
+ result = *num_ports;
+
+ if (result) {
+ kfree(num_ports);
+ usb_set_serial_data(serial, NULL);
}
- return usb_serial_probe(iface, id);
+ return result;
+}
+
+static int sierra_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ int result = 0;
+ struct usb_device *udev;
+ int *num_ports;
+ u8 ifnum;
+
+ num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
+ if (!num_ports)
+ return -ENOMEM;
+
+ ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+ udev = serial->dev;
+
+ /* Check if in installer mode */
+ if (truinstall && id->driver_info == DEVICE_INSTALLER) {
+ dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n");
+ result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+ /* Don't bind to the device when in installer mode */
+ kfree(num_ports);
+ return -EIO;
+ } else if (id->driver_info == DEVICE_1_PORT)
+ *num_ports = 1;
+ else if (ifnum == 0x99)
+ *num_ports = 0;
+ else
+ *num_ports = 3;
+ /*
+ * save off our num_ports info so that we can use it in the
+ * calc_num_ports callback
+ */
+ usb_set_serial_data(serial, (void *)num_ports);
+
+ return result;
}
static struct usb_device_id id_table [] = {
@@ -104,6 +156,7 @@
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+ { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
@@ -117,56 +170,29 @@
{ USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
{ USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
{ USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
+ { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */
+ { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
+
+ { USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */
+ { USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */
{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+ { USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_device_id id_table_1port [] = {
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
- { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
- { }
-};
-
-static struct usb_device_id id_table_3port [] = {
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
- { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
- { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
- { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
-
- { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
- { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
- { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */
- { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
- { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
- { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
- { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
- { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
- { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
- { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
- { }
-};
-
static struct usb_driver sierra_driver = {
.name = "sierra",
- .probe = sierra_probe,
+ .probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
-
struct sierra_port_private {
spinlock_t lock; /* lock the structure */
int outstanding_urbs; /* number of out urbs in flight */
@@ -188,6 +214,7 @@
{
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
+ __u16 interface = 0;
dbg("%s", __FUNCTION__);
@@ -200,9 +227,18 @@
if (portdata->rts_state)
val |= 0x02;
+ /* Determine which port is targeted */
+ if (port->bulk_out_endpointAddress == 2)
+ interface = 0;
+ else if (port->bulk_out_endpointAddress == 4)
+ interface = 1;
+ else if (port->bulk_out_endpointAddress == 5)
+ interface = 2;
+
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
- 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ 0x22, 0x21, val, interface,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
}
return 0;
@@ -561,7 +597,10 @@
portdata->dtr_state = 0;
if (serial->dev) {
- sierra_send_setup(port);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ sierra_send_setup(port);
+ mutex_unlock(&serial->disc_mutex);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
@@ -583,9 +622,13 @@
dbg("%s", __FUNCTION__);
- /*Set Device mode to D0 */
+ /* Set Device mode to D0 */
sierra_set_power_state(serial->dev, 0x0000);
+ /* Check NMEA and set */
+ if (nmea)
+ sierra_vsc_set_nmea(serial->dev, 1);
+
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -646,47 +689,19 @@
}
}
-static struct usb_serial_driver sierra_1port_device = {
+static struct usb_serial_driver sierra_device = {
.driver = {
.owner = THIS_MODULE,
.name = "sierra1",
},
- .description = "Sierra USB modem (1 port)",
- .id_table = id_table_1port,
+ .description = "Sierra USB modem",
+ .id_table = id_table,
.usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = sierra_open,
- .close = sierra_close,
- .write = sierra_write,
- .write_room = sierra_write_room,
- .chars_in_buffer = sierra_chars_in_buffer,
- .throttle = sierra_rx_throttle,
- .unthrottle = sierra_rx_unthrottle,
- .ioctl = sierra_ioctl,
- .set_termios = sierra_set_termios,
- .break_ctl = sierra_break_ctl,
- .tiocmget = sierra_tiocmget,
- .tiocmset = sierra_tiocmset,
- .attach = sierra_startup,
- .shutdown = sierra_shutdown,
- .read_int_callback = sierra_instat_callback,
-};
-
-static struct usb_serial_driver sierra_3port_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "sierra3",
- },
- .description = "Sierra USB modem (3 port)",
- .id_table = id_table_3port,
- .usb_driver = &sierra_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 3,
- .num_bulk_out = 3,
- .num_ports = 3,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .calc_num_ports = sierra_calc_num_ports,
+ .probe = sierra_probe,
.open = sierra_open,
.close = sierra_close,
.write = sierra_write,
@@ -708,12 +723,9 @@
static int __init sierra_init(void)
{
int retval;
- retval = usb_serial_register(&sierra_1port_device);
+ retval = usb_serial_register(&sierra_device);
if (retval)
- goto failed_1port_device_register;
- retval = usb_serial_register(&sierra_3port_device);
- if (retval)
- goto failed_3port_device_register;
+ goto failed_device_register;
retval = usb_register(&sierra_driver);
@@ -725,18 +737,15 @@
return 0;
failed_driver_register:
- usb_serial_deregister(&sierra_3port_device);
-failed_3port_device_register:
- usb_serial_deregister(&sierra_1port_device);
-failed_1port_device_register:
+ usb_serial_deregister(&sierra_device);
+failed_device_register:
return retval;
}
static void __exit sierra_exit(void)
{
usb_deregister (&sierra_driver);
- usb_serial_deregister(&sierra_1port_device);
- usb_serial_deregister(&sierra_3port_device);
+ usb_serial_deregister(&sierra_device);
}
module_init(sierra_init);
@@ -747,6 +756,12 @@
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
+module_param(truinstall, bool, 0);
+MODULE_PARM_DESC(truinstall, "TRU-Install support");
+
+module_param(nmea, bool, 0);
+MODULE_PARM_DESC(nmea, "NMEA streaming");
+
#ifdef CONFIG_USB_DEBUG
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 1f01494..b517f93 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -80,6 +80,7 @@
#include <linux/ioctl.h>
#include <linux/serial.h>
#include <linux/circ_buf.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <linux/usb.h>
@@ -139,7 +140,7 @@
};
struct ti_device {
- struct semaphore td_open_close_sem;
+ struct mutex td_open_close_lock;
int td_open_port_count;
struct usb_serial *td_serial;
int td_is_3410;
@@ -424,7 +425,7 @@
dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
return -ENOMEM;
}
- sema_init(&tdev->td_open_close_sem, 1);
+ mutex_init(&tdev->td_open_close_lock);
tdev->td_serial = serial;
usb_set_serial_data(serial, tdev);
@@ -547,7 +548,7 @@
tdev = tport->tp_tdev;
/* only one open on any port on a device at a time */
- if (down_interruptible(&tdev->td_open_close_sem))
+ if (mutex_lock_interruptible(&tdev->td_open_close_lock))
return -ERESTARTSYS;
if (port->tty)
@@ -568,7 +569,7 @@
if (!urb) {
dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__);
status = -EINVAL;
- goto up_sem;
+ goto release_lock;
}
urb->complete = ti_interrupt_callback;
urb->context = tdev;
@@ -576,11 +577,11 @@
status = usb_submit_urb(urb, GFP_KERNEL);
if (status) {
dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status);
- goto up_sem;
+ goto release_lock;
}
}
- ti_set_termios(port, NULL);
+ ti_set_termios(port, port->tty->termios);
dbg("%s - sending TI_OPEN_PORT", __FUNCTION__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -617,7 +618,7 @@
usb_clear_halt(dev, port->write_urb->pipe);
usb_clear_halt(dev, port->read_urb->pipe);
- ti_set_termios(port, NULL);
+ ti_set_termios(port, port->tty->termios);
dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -656,13 +657,13 @@
tport->tp_is_open = 1;
++tdev->td_open_port_count;
- goto up_sem;
+ goto release_lock;
unlink_int_urb:
if (tdev->td_open_port_count == 0)
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-up_sem:
- up(&tdev->td_open_close_sem);
+release_lock:
+ mutex_unlock(&tdev->td_open_close_lock);
dbg("%s - exit %d", __FUNCTION__, status);
return status;
}
@@ -674,7 +675,7 @@
struct ti_port *tport;
int port_number;
int status;
- int do_up;
+ int do_unlock;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -699,16 +700,16 @@
if (status)
dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status);
- /* if down is interrupted, continue anyway */
- do_up = !down_interruptible(&tdev->td_open_close_sem);
+ /* if mutex_lock is interrupted, continue anyway */
+ do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
--tport->tp_tdev->td_open_port_count;
if (tport->tp_tdev->td_open_port_count <= 0) {
/* last port is closed, shut down interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
tport->tp_tdev->td_open_port_count = 0;
}
- if (do_up)
- up(&tdev->td_open_close_sem);
+ if (do_unlock)
+ mutex_unlock(&tdev->td_open_close_lock);
dbg("%s - exit", __FUNCTION__);
}
@@ -896,24 +897,11 @@
dbg("%s - port %d", __FUNCTION__, port->number);
- if (!tty || !tty->termios) {
- dbg("%s - no tty or termios", __FUNCTION__);
- return;
- }
-
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
- if (old_termios && cflag == old_termios->c_cflag
- && iflag == old_termios->c_iflag) {
- dbg("%s - nothing to change", __FUNCTION__);
- return;
- }
-
- dbg("%s - clfag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
-
- if (old_termios)
- dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
+ dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
+ dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
if (tport == NULL)
return;
@@ -947,6 +935,9 @@
break;
}
+ /* CMSPAR isn't supported by this driver */
+ tty->termios->c_cflag &= ~CMSPAR;
+
if (cflag & PARENB) {
if (cflag & PARODD) {
config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING;
@@ -989,12 +980,17 @@
}
baud = tty_get_baud_rate(tty);
- if (!baud) baud = 9600;
+ if (!baud)
+ baud = 9600;
if (tport->tp_tdev->td_is_3410)
config->wBaudRate = (__u16)((923077 + baud/2) / baud);
else
config->wBaudRate = (__u16)((461538 + baud/2) / baud);
+ /* FIXME: Should calculate resulting baud here and report it back */
+ if ((cflag & CBAUD) != B0)
+ tty_encode_baud_rate(tty, baud, baud);
+
dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
__FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
@@ -1497,11 +1493,10 @@
struct ti_device *tdev = tport->tp_tdev;
struct usb_serial_port *port = tport->tp_port;
wait_queue_t wait;
- unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
- spin_lock_irqsave(&tport->tp_lock, flags);
+ spin_lock_irq(&tport->tp_lock);
/* wait for data to drain from the buffer */
tdev->td_urb_error = 0;
@@ -1512,11 +1507,11 @@
if (ti_buf_data_avail(tport->tp_write_buf) == 0
|| timeout == 0 || signal_pending(current)
|| tdev->td_urb_error
- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ || port->serial->disconnected) /* disconnect */
break;
- spin_unlock_irqrestore(&tport->tp_lock, flags);
+ spin_unlock_irq(&tport->tp_lock);
timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&tport->tp_lock, flags);
+ spin_lock_irq(&tport->tp_lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tport->tp_write_wait, &wait);
@@ -1525,19 +1520,23 @@
if (flush)
ti_buf_clear(tport->tp_write_buf);
- spin_unlock_irqrestore(&tport->tp_lock, flags);
+ spin_unlock_irq(&tport->tp_lock);
+ mutex_lock(&port->serial->disc_mutex);
/* wait for data to drain from the device */
/* wait for empty tx register, plus 20 ms */
timeout += jiffies;
tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
&& !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
- && usb_get_intfdata(port->serial->interface)) { /* not disconnected */
+ && !port->serial->disconnected) {
if (ti_get_lsr(tport))
break;
+ mutex_unlock(&port->serial->disc_mutex);
msleep_interruptible(20);
+ mutex_lock(&port->serial->disc_mutex);
}
+ mutex_unlock(&port->serial->disc_mutex);
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 497e29a..3ce98e8 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -225,16 +225,21 @@
goto bailout_mutex_unlock;
}
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto bailout_module_put;
/* only call the device specific open if this
* is the first time the port is opened */
retval = serial->type->open(port, filp);
if (retval)
- goto bailout_module_put;
+ goto bailout_interface_put;
}
mutex_unlock(&port->mutex);
return 0;
+bailout_interface_put:
+ usb_autopm_put_interface(serial->interface);
bailout_module_put:
module_put(serial->type->driver.owner);
bailout_mutex_unlock:
@@ -264,17 +269,21 @@
}
--port->open_count;
- if (port->open_count == 0) {
+ if (port->open_count == 0)
/* only call the device specific close if this
* port is being closed by the last owner */
port->serial->type->close(port, filp);
+ if (port->open_count == (port->console? 1 : 0)) {
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
+ }
+ if (port->open_count == 0) {
+ usb_autopm_put_interface(port->serial->interface);
module_put(port->serial->type->driver.owner);
}
@@ -625,6 +634,7 @@
serial->type = driver;
serial->interface = interface;
kref_init(&serial->kref);
+ mutex_init(&serial->disc_mutex);
return serial;
}
@@ -1080,20 +1090,22 @@
usb_serial_console_disconnect(serial);
dbg ("%s", __FUNCTION__);
+ mutex_lock(&serial->disc_mutex);
usb_set_intfdata (interface, NULL);
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port) {
- if (port->tty)
- tty_hangup(port->tty);
- kill_traffic(port);
- }
+ /* must set a flag, to signal subdrivers */
+ serial->disconnected = 1;
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
}
- /* let the last holder of this object
- * cause it to be cleaned up */
- usb_serial_put(serial);
}
+ /* let the last holder of this object
+ * cause it to be cleaned up */
+ mutex_unlock(&serial->disc_mutex);
+ usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
@@ -1103,9 +1115,6 @@
struct usb_serial_port *port;
int i, r = 0;
- if (!serial) /* device has been disconnected */
- return 0;
-
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port)
@@ -1253,6 +1262,7 @@
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, shutdown);
+ set_to_generic_if_null(device, resume);
}
int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 7ee087f..22b3f78 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -349,16 +349,20 @@
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
- /* Try to send shutdown message, if the device is gone, this will just fail. */
- transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- if (transfer_buffer) {
- usb_control_msg (port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
- VISOR_CLOSE_NOTIFICATION, 0xc2,
- 0x0000, 0x0000,
- transfer_buffer, 0x12, 300);
- kfree (transfer_buffer);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected) {
+ /* Try to send shutdown message, unless the device is gone */
+ transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+ if (transfer_buffer) {
+ usb_control_msg (port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ VISOR_CLOSE_NOTIFICATION, 0xc2,
+ 0x0000, 0x0000,
+ transfer_buffer, 0x12, 300);
+ kfree (transfer_buffer);
+ }
}
+ mutex_unlock(&port->serial->disc_mutex);
if (stats)
dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n",
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index ee5dd8b..38726ef 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -610,8 +610,7 @@
if (retval)
goto exit;
- if (port->tty)
- port->tty->low_latency = 1;
+ port->tty->low_latency = 1;
/* send an open port command */
retval = firm_open(port);
@@ -659,11 +658,14 @@
struct list_head *tmp2;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ mutex_lock(&port->serial->disc_mutex);
/* filp is NULL when called from usb_serial_disconnect */
- if (filp && (tty_hung_up_p(filp))) {
+ if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
+ mutex_unlock(&port->serial->disc_mutex);
return;
}
+ mutex_unlock(&port->serial->disc_mutex);
port->tty->closing = 1;
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index ee5b42a..187dd1e 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -66,7 +66,8 @@
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
- int res, partial;
+ int res;
+ unsigned int partial;
static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 0db4886..2ae1e86 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -48,7 +48,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/hdreg.h>
-#include <linux/ide.h>
#include <linux/scatterlist.h>
#include <scsi/scsi.h>
@@ -110,6 +109,12 @@
#define REG_STATUS 0x80
#define REG_COMMAND 0x80
+/* ATA registers offset definitions */
+#define ATA_REG_ERROR_OFFSET 1
+#define ATA_REG_LCYL_OFFSET 4
+#define ATA_REG_HCYL_OFFSET 5
+#define ATA_REG_STATUS_OFFSET 7
+
/* ATA error definitions not in <linux/hdreg.h> */
#define ATA_ERROR_MEDIA_CHANGE 0x20
@@ -360,7 +365,7 @@
{
struct isd200_info *info = (struct isd200_info *)us->extra;
struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
- unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
+ unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET];
if(error & ATA_ERROR_MEDIA_CHANGE) {
buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
@@ -549,8 +554,8 @@
retStatus = ISD200_ERROR;
} else {
memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
- US_DEBUGP(" Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n",
- info->ATARegs[IDE_ERROR_OFFSET]);
+ US_DEBUGP(" Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
+ info->ATARegs[ATA_REG_ERROR_OFFSET]);
}
return retStatus;
@@ -892,7 +897,7 @@
break;
if (!detect) {
- if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) {
+ if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) {
US_DEBUGP(" %s status is still BSY, try again...\n",mstr);
} else {
US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr);
@@ -902,12 +907,12 @@
/* check for BUSY_STAT and */
/* WRERR_STAT (workaround ATA Zip drive) and */
/* ERR_STAT (workaround for Archos CD-ROM) */
- else if (regs[IDE_STATUS_OFFSET] &
+ else if (regs[ATA_REG_STATUS_OFFSET] &
(BUSY_STAT | WRERR_STAT | ERR_STAT )) {
US_DEBUGP(" Status indicates it is not ready, try again...\n");
}
/* check for DRDY, ATA devices set DRDY after SRST */
- else if (regs[IDE_STATUS_OFFSET] & READY_STAT) {
+ else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) {
US_DEBUGP(" Identified ATA device\n");
info->DeviceFlags |= DF_ATA_DEVICE;
info->DeviceHead = master_slave;
@@ -916,8 +921,8 @@
/* check Cylinder High/Low to
determine if it is an ATAPI device
*/
- else if ((regs[IDE_HCYL_OFFSET] == 0xEB) &&
- (regs[IDE_LCYL_OFFSET] == 0x14)) {
+ else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB &&
+ regs[ATA_REG_LCYL_OFFSET] == 0x14) {
/* It seems that the RICOH
MP6200A CD/RW drive will
report itself okay as a
@@ -1001,12 +1006,6 @@
return(retStatus);
}
-/*
- * We are the last non IDE user of the legacy IDE ident structures
- * and we thus want to keep a private copy of this function so the
- * driver can be used without the obsolete drivers/ide layer
- */
-
static void isd200_fix_driveid (struct hd_driveid *id)
{
#ifndef __LITTLE_ENDIAN
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 6d6108b..fe12737 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -86,6 +86,14 @@
US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
#endif
+/* Reported by Grant Grundler <grundler@parisc-linux.org>
+ * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware.
+ */
+UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001,
+ "HP",
+ "PhotoSmart R707",
+ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY),
+
/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
* and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
* for USB floppies that need the SINGLE_LUN enforcement.
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index f8e7111..fc65c02 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -16,6 +16,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/backlight.h>
#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
@@ -69,6 +70,107 @@
}
#endif
+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+/* some bl->props field just changed */
+static int atmel_bl_update_status(struct backlight_device *bl)
+{
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+ int power = sinfo->bl_power;
+ int brightness = bl->props.brightness;
+
+ /* REVISIT there may be a meaningful difference between
+ * fb_blank and power ... there seem to be some cases
+ * this doesn't handle correctly.
+ */
+ if (bl->props.fb_blank != sinfo->bl_power)
+ power = bl->props.fb_blank;
+ else if (bl->props.power != sinfo->bl_power)
+ power = bl->props.power;
+
+ if (brightness < 0 && power == FB_BLANK_UNBLANK)
+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ else if (power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+ brightness ? contrast_ctr : 0);
+
+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+ return 0;
+}
+
+static int atmel_bl_get_brightness(struct backlight_device *bl)
+{
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+}
+
+static struct backlight_ops atmel_lcdc_bl_ops = {
+ .update_status = atmel_bl_update_status,
+ .get_brightness = atmel_bl_get_brightness,
+};
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ struct backlight_device *bl;
+
+ sinfo->bl_power = FB_BLANK_UNBLANK;
+
+ if (sinfo->backlight)
+ return;
+
+ bl = backlight_device_register("backlight", &sinfo->pdev->dev,
+ sinfo, &atmel_lcdc_bl_ops);
+ if (IS_ERR(sinfo->backlight)) {
+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+ return;
+ }
+ sinfo->backlight = bl;
+
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.max_brightness = 0xff;
+ bl->props.brightness = atmel_bl_get_brightness(bl);
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->backlight)
+ backlight_device_unregister(sinfo->backlight);
+}
+
+#else
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+}
+
+#endif
+
+static void init_contrast(struct atmel_lcdfb_info *sinfo)
+{
+ /* have some default contrast/backlight settings */
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+
+ if (sinfo->lcdcon_is_backlight)
+ init_backlight(sinfo);
+}
+
static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.type = FB_TYPE_PACKED_PIXELS,
@@ -203,6 +305,26 @@
var->transp.offset = var->transp.length = 0;
var->xoffset = var->yoffset = 0;
+ /* Saturate vertical and horizontal timings at maximum values */
+ var->vsync_len = min_t(u32, var->vsync_len,
+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+ var->upper_margin = min_t(u32, var->upper_margin,
+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+ var->lower_margin = min_t(u32, var->lower_margin,
+ ATMEL_LCDC_VFP);
+ var->right_margin = min_t(u32, var->right_margin,
+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+ var->hsync_len = min_t(u32, var->hsync_len,
+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+ var->left_margin = min_t(u32, var->left_margin,
+ ATMEL_LCDC_HBP + 1);
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+ var->right_margin = max_t(u32, var->right_margin, 1);
+ var->hsync_len = max_t(u32, var->hsync_len, 1);
+ var->left_margin = max_t(u32, var->left_margin, 1);
+
switch (var->bits_per_pixel) {
case 1:
case 2:
@@ -370,10 +492,6 @@
/* Disable all interrupts */
lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
- /* Set contrast */
- value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
/* ...wait for DMA engine to become idle... */
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
msleep(10);
@@ -577,6 +695,7 @@
sinfo->default_monspecs = pdata_sinfo->default_monspecs;
sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
sinfo->guard_time = pdata_sinfo->guard_time;
+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
} else {
dev_err(dev, "cannot get default configuration\n");
goto free_info;
@@ -670,6 +789,9 @@
goto release_mem;
}
+ /* Initialize PWM for contrast or backlight ("off") */
+ init_contrast(sinfo);
+
/* interrupt */
ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
if (ret) {
@@ -721,6 +843,7 @@
unregister_irqs:
free_irq(sinfo->irq_base, info);
unmap_mmio:
+ exit_backlight(sinfo);
iounmap(sinfo->mmio);
release_mem:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
@@ -755,6 +878,7 @@
if (!sinfo)
return 0;
+ exit_backlight(sinfo);
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(0);
unregister_framebuffer(info);
@@ -781,6 +905,9 @@
static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),
+
+// FIXME need suspend, resume
+
.driver = {
.name = "atmel_lcdfb",
.owner = THIS_MODULE,
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 83ee3e7..675abda 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -2561,7 +2561,7 @@
pci_read_config_dword(rinfo->pdev, i * 4,
&rinfo->cfg_save[i]);
- /* Switch PCI power managment to D2. */
+ /* Switch PCI power management to D2. */
pci_disable_device(rinfo->pdev);
for (;;) {
pci_read_config_word(
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 9609a6c..924e255 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -50,6 +50,19 @@
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
+config BACKLIGHT_ATMEL_LCDC
+ bool "Atmel LCDC Contrast-as-Backlight control"
+ depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+ default y if MACH_SAM9261EK || MACH_SAM9263EK
+ help
+ This provides a backlight control internal to the Atmel LCDC
+ driver. If the LCD "contrast control" on your board is wired
+ so it controls the backlight brightness, select this option to
+ export this as a PWM-based backlight control.
+
+ If in doubt, it's safe to enable this option; it doesn't kick
+ in unless the board's description says it's wired that way.
+
config BACKLIGHT_CORGI
tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index c8e7427..0ce791e 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -498,8 +498,7 @@
static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
{
-
- /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/
+ /*struct bfin_bf54xfb_info *info = dev_id;*/
u16 status = bfin_read_EPPI0_STATUS();
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 308850d..69864b1 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -63,7 +63,7 @@
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
struct fb_fillrect region;
- region.color = attr_bgcol_ec(bgshift, vc);
+ region.color = attr_bgcol_ec(bgshift, vc, info);
region.dx = sx * vc->vc_font.width;
region.dy = sy * vc->vc_font.height;
region.width = width * vc->vc_font.width;
@@ -213,7 +213,7 @@
unsigned int bs = info->var.yres - bh;
struct fb_fillrect region;
- region.color = attr_bgcol_ec(bgshift, vc);
+ region.color = attr_bgcol_ec(bgshift, vc, info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 0f32f4a..0222824 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -84,7 +84,7 @@
#ifdef CONFIG_MAC
#include <asm/macints.h>
#endif
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
#include <asm/machdep.h>
#include <asm/setup.h>
#endif
@@ -147,7 +147,7 @@
static int info_idx = -1;
/* console rotation */
-static int rotate;
+static int initial_rotation;
static int fbcon_has_sysfs;
static const struct consw fb_con;
@@ -334,10 +334,7 @@
switch (depth) {
case 1:
{
- int col = ~(0xfff << (max(info->var.green.length,
- max(info->var.red.length,
- info->var.blue.length)))) & 0xff;
-
+ int col = mono_col(info);
/* 0 or 1 */
int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0;
int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
@@ -537,9 +534,9 @@
if (!strncmp(options, "rotate:", 7)) {
options += 7;
if (*options)
- rotate = simple_strtoul(options, &options, 0);
- if (rotate > 3)
- rotate = 0;
+ initial_rotation = simple_strtoul(options, &options, 0);
+ if (initial_rotation > 3)
+ initial_rotation = 0;
}
}
return 1;
@@ -989,7 +986,7 @@
ops->graphics = 1;
ops->cur_rotate = -1;
info->fbcon_par = ops;
- p->con_rotate = rotate;
+ p->con_rotate = initial_rotation;
set_blitting_type(vc, info);
if (info->fix.type != FB_TYPE_TEXT) {
@@ -1176,7 +1173,7 @@
con_copy_unimap(vc, svc);
ops = info->fbcon_par;
- p->con_rotate = rotate;
+ p->con_rotate = initial_rotation;
set_blitting_type(vc, info);
cols = vc->vc_cols;
@@ -2795,7 +2792,7 @@
{
struct fb_info *info = registered_fb[con2fb_map[fg_console]];
struct fbcon_ops *ops = info->fbcon_par;
- struct display *p = &fb_display[fg_console];
+ struct display *disp = &fb_display[fg_console];
int offset, limit, scrollback_old;
if (softback_top) {
@@ -2833,7 +2830,7 @@
logo_shown = FBCON_LOGO_CANSHOW;
}
fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
- fbcon_redraw_softback(vc, p, lines);
+ fbcon_redraw_softback(vc, disp, lines);
fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
return 0;
}
@@ -2855,9 +2852,9 @@
fbcon_cursor(vc, CM_ERASE);
- offset = p->yscroll - scrollback_current;
- limit = p->vrows;
- switch (p->scrollmode) {
+ offset = disp->yscroll - scrollback_current;
+ limit = disp->vrows;
+ switch (disp->scrollmode) {
case SCROLL_WRAP_MOVE:
info->var.vmode |= FB_VMODE_YWRAP;
break;
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 8e6ef4b..3706307 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -93,10 +93,6 @@
(((s) >> (fgshift)) & 0x0f)
#define attr_bgcol(bgshift,s) \
(((s) >> (bgshift)) & 0x0f)
-#define attr_bgcol_ec(bgshift,vc) \
- ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0)
-#define attr_fgcol_ec(fgshift,vc) \
- ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0)
/* Monochrome */
#define attr_bold(s) \
@@ -108,6 +104,49 @@
#define attr_blink(s) \
((s) & 0x8000)
+#define mono_col(info) \
+ (~(0xfff << (max((info)->var.green.length, \
+ max((info)->var.red.length, \
+ (info)->var.blue.length)))) & 0xff)
+
+static inline int attr_col_ec(int shift, struct vc_data *vc,
+ struct fb_info *info, int is_fg)
+{
+ int is_mono01;
+ int col;
+ int fg;
+ int bg;
+
+ if (!vc)
+ return 0;
+
+ if (vc->vc_can_do_color)
+ return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char)
+ : attr_bgcol(shift,vc->vc_video_erase_char);
+
+ if (!info)
+ return 0;
+
+ col = mono_col(info);
+ is_mono01 = info->fix.visual == FB_VISUAL_MONO01;
+
+ if (attr_reverse(vc->vc_video_erase_char)) {
+ fg = is_mono01 ? col : 0;
+ bg = is_mono01 ? 0 : col;
+ }
+ else {
+ fg = is_mono01 ? 0 : col;
+ bg = is_mono01 ? col : 0;
+ }
+
+ return is_fg ? fg : bg;
+}
+
+#define attr_bgcol_ec(bgshift,vc,info) \
+ attr_col_ec(bgshift,vc,info,0);
+#define attr_fgcol_ec(fgshift,vc,info) \
+ attr_col_ec(fgshift,vc,info,1);
+
/* Font */
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
index 825e6d6..bdf913e 100644
--- a/drivers/video/console/fbcon_ccw.c
+++ b/drivers/video/console/fbcon_ccw.c
@@ -84,7 +84,7 @@
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
u32 vyres = GETVYRES(ops->p->scrollmode, info);
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = sy * vc->vc_font.height;
region.dy = vyres - ((sx + width) * vc->vc_font.width);
region.height = width * vc->vc_font.width;
@@ -198,7 +198,7 @@
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index c637e63..a6819b9 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -70,7 +70,7 @@
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
u32 vxres = GETVXRES(ops->p->scrollmode, info);
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = vxres - ((sy + height) * vc->vc_font.height);
region.dy = sx * vc->vc_font.width;
region.height = width * vc->vc_font.width;
@@ -182,7 +182,7 @@
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
index 1473506..d9b5d6e 100644
--- a/drivers/video/console/fbcon_ud.c
+++ b/drivers/video/console/fbcon_ud.c
@@ -71,7 +71,7 @@
u32 vyres = GETVYRES(ops->p->scrollmode, info);
u32 vxres = GETVXRES(ops->p->scrollmode, info);
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.dy = vyres - ((sy + height) * vc->vc_font.height);
region.dx = vxres - ((sx + width) * vc->vc_font.width);
region.width = width * vc->vc_font.width;
@@ -228,7 +228,7 @@
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- region.color = attr_bgcol_ec(bgshift,vc);
+ region.color = attr_bgcol_ec(bgshift,vc,info);
region.rop = ROP_COPY;
if (rw && !bottom_only) {
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index 96979c3..d0c03fd 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
#include <asm/setup.h>
#endif
#include <linux/font.h>
@@ -120,7 +120,7 @@
for(i=0; i<num_fonts; i++) {
f = fonts[i];
c = f->pref;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
#ifdef CONFIG_FONT_PEARL_8x8
if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
c = 100;
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
index d981fe4..0056a41 100644
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -40,8 +40,8 @@
rect.index = vc->vc_video_erase_char &
((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
- rect.fg = attr_fgcol_ec(fgshift, vc);
- rect.bg = attr_bgcol_ec(bgshift, vc);
+ rect.fg = attr_fgcol_ec(fgshift, vc, info);
+ rect.bg = attr_bgcol_ec(bgshift, vc, info);
rect.sx = sx;
rect.sy = sy;
rect.width = width;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index f65bcd3..6df29a6 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1153,8 +1153,6 @@
/* if 512 char mode is already enabled don't re-enable it. */
if ((set) && (ch512 != vga_512_chars)) {
- int i;
-
/* attribute controller */
for (i = 0; i < MAX_NR_CONSOLES; i++) {
struct vc_data *c = vc_cons[i].d;
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
index e23324d..9704b73 100644
--- a/drivers/video/cyblafb.c
+++ b/drivers/video/cyblafb.c
@@ -1156,7 +1156,7 @@
// need altered timings to display correctly. So I decided that it is much
// better to provide a limited optimized set of modes plus the option of
// using the mode in effect at startup time (might be selected using the
-// vga=??? paramter). After that the user might use fbset to select any
+// vga=??? parameter). After that the user might use fbset to select any
// mode he likes, check_var will not try to alter geometry parameters as
// it would be necessary otherwise.
//
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index a0c5d9d..0f8cfb9 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -25,8 +25,8 @@
#include <linux/pagemap.h>
/* this is to find and return the vmalloc-ed fb pages */
-static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
- unsigned long vaddr, int *type)
+static int fb_deferred_io_fault(struct vm_area_struct *vma,
+ struct vm_fault *vmf)
{
unsigned long offset;
struct page *page;
@@ -34,18 +34,17 @@
/* info->screen_base is in System RAM */
void *screen_base = (void __force *) info->screen_base;
- offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ offset = vmf->pgoff << PAGE_SHIFT;
if (offset >= info->fix.smem_len)
- return NOPAGE_SIGBUS;
+ return VM_FAULT_SIGBUS;
page = vmalloc_to_page(screen_base + offset);
if (!page)
- return NOPAGE_OOM;
+ return VM_FAULT_SIGBUS;
get_page(page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ vmf->page = page;
+ return 0;
}
int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
@@ -84,7 +83,7 @@
}
static struct vm_operations_struct fb_deferred_io_vm_ops = {
- .nopage = fb_deferred_io_nopage,
+ .fault = fb_deferred_io_fault,
.page_mkwrite = fb_deferred_io_mkwrite,
};
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index cdafbe1..a2a0618 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -91,6 +91,7 @@
val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
if (bswapmask & 3)
val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
+ return val;
}
static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 4ba9c08..052e180 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -4,7 +4,7 @@
* Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
*
* Credits:
- *
+ *
* The EDID Parser is a conglomeration from the following sources:
*
* 1. SciTech SNAP Graphics Architecture
@@ -12,13 +12,13 @@
*
* 2. XFree86 4.3.0, interpret_edid.c
* Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
- *
- * 3. John Fremlin <vii@users.sourceforge.net> and
+ *
+ * 3. John Fremlin <vii@users.sourceforge.net> and
* Ani Joshi <ajoshi@unixbox.com>
- *
+ *
* Generalized Timing Formula is derived from:
*
- * GTF Spreadsheet by Andy Morrish (1/5/97)
+ * GTF Spreadsheet by Andy Morrish (1/5/97)
* available at http://www.vesa.org
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -36,7 +36,7 @@
#endif
#include "edid.h"
-/*
+/*
* EDID parser
*/
@@ -160,8 +160,8 @@
for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
brokendb[i].model == model) {
- fix = brokendb[i].fix;
- break;
+ fix = brokendb[i].fix;
+ break;
}
}
@@ -323,7 +323,7 @@
(flags & DPMS_SUSPEND) ? "yes" : "no",
(flags & DPMS_STANDBY) ? "yes" : "no");
}
-
+
static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
{
int tmp;
@@ -365,7 +365,7 @@
tmp += 512;
specs->chroma.bluey = tmp/1024;
DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey);
-
+
tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
tmp *= 1000;
tmp += 512;
@@ -383,7 +383,7 @@
struct fb_videomode *mode)
{
struct fb_var_screeninfo *var;
-
+
var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
if (var) {
@@ -451,11 +451,11 @@
c = block[1];
if (c&0x80) {
- mode[num++] = vesa_modes[9];
+ mode[num++] = vesa_modes[9];
DPRINTK(" 800x600@72Hz\n");
}
if (c&0x40) {
- mode[num++] = vesa_modes[10];
+ mode[num++] = vesa_modes[10];
DPRINTK(" 800x600@75Hz\n");
}
if (c&0x20) {
@@ -495,7 +495,7 @@
static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
{
int xres, yres = 0, refresh, ratio, i;
-
+
xres = (block[0] + 31) * 8;
if (xres <= 256)
return 0;
@@ -519,7 +519,7 @@
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
for (i = 0; i < VESA_MODEDB_SIZE; i++) {
- if (vesa_modes[i].xres == xres &&
+ if (vesa_modes[i].xres == xres &&
vesa_modes[i].yres == yres &&
vesa_modes[i].refresh == refresh) {
*mode = vesa_modes[i];
@@ -536,13 +536,13 @@
{
int j, num = 0;
- for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE)
+ for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
num += get_std_timing(block, &mode[num]);
return num;
}
-static void get_detailed_timing(unsigned char *block,
+static void get_detailed_timing(unsigned char *block,
struct fb_videomode *mode)
{
mode->xres = H_ACTIVE;
@@ -553,7 +553,7 @@
mode->right_margin = H_SYNC_OFFSET;
mode->left_margin = (H_ACTIVE + H_BLANKING) -
(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
- mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+ mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
V_SYNC_WIDTH;
mode->lower_margin = V_SYNC_OFFSET;
mode->hsync_len = H_SYNC_WIDTH;
@@ -597,7 +597,7 @@
if (mode == NULL)
return NULL;
- if (edid == NULL || !edid_checksum(edid) ||
+ if (edid == NULL || !edid_checksum(edid) ||
!edid_check_header(edid)) {
kfree(mode);
return NULL;
@@ -632,7 +632,7 @@
if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
num += get_dst_timing(block + 5, &mode[num]);
}
-
+
/* Yikes, EDID data is totally useless */
if (!num) {
kfree(mode);
@@ -686,7 +686,7 @@
/* estimate monitor limits based on modes supported */
if (retval) {
struct fb_videomode *modes, *mode;
- int num_modes, i, hz, hscan, pixclock;
+ int num_modes, hz, hscan, pixclock;
int vtotal, htotal;
modes = fb_create_modedb(edid, &num_modes);
@@ -713,7 +713,7 @@
hscan = (pixclock + htotal / 2) / htotal;
hscan = (hscan + 500) / 1000 * 1000;
hz = (hscan + vtotal / 2) / vtotal;
-
+
if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
specs->dclkmax = pixclock;
@@ -966,8 +966,8 @@
DPRINTK("========================================\n");
}
-/*
- * VESA Generalized Timing Formula (GTF)
+/*
+ * VESA Generalized Timing Formula (GTF)
*/
#define FLYBACK 550
@@ -996,7 +996,7 @@
* @hfreq: horizontal freq
*
* DESCRIPTION:
- * vblank = right_margin + vsync_len + left_margin
+ * vblank = right_margin + vsync_len + left_margin
*
* given: right_margin = 1 (V_FRONTPORCH)
* vsync_len = 3
@@ -1010,12 +1010,12 @@
{
u32 vblank;
- vblank = (hfreq * FLYBACK)/1000;
+ vblank = (hfreq * FLYBACK)/1000;
vblank = (vblank + 500)/1000;
return (vblank + V_FRONTPORCH);
}
-/**
+/**
* fb_get_hblank_by_freq - get horizontal blank time given hfreq
* @hfreq: horizontal freq
* @xres: horizontal resolution in pixels
@@ -1031,7 +1031,7 @@
*
* where: C = ((offset - scale factor) * blank_scale)
* -------------------------------------- + scale factor
- * 256
+ * 256
* M = blank_scale * gradient
*
*/
@@ -1039,7 +1039,7 @@
{
u32 c_val, m_val, duty_cycle, hblank;
- c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
+ c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
H_SCALEFACTOR) * 1000;
m_val = (H_BLANKSCALE * H_GRADIENT)/256;
m_val = (m_val * 1000000)/hfreq;
@@ -1048,7 +1048,7 @@
return (hblank);
}
-/**
+/**
* fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
* @dclk: pixelclock in Hz
* @xres: horizontal resolution in pixels
@@ -1061,7 +1061,7 @@
*
* duty cycle = percent of htotal assigned to inactive display
* duty cycle = C - (M * h_period)
- *
+ *
* where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
* -----------------------------------------------
* 2 * M
@@ -1077,11 +1077,11 @@
h_period = 100 - C_VAL;
h_period *= h_period;
h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
- h_period *=10000;
+ h_period *= 10000;
h_period = int_sqrt(h_period);
h_period -= (100 - C_VAL) * 100;
- h_period *= 1000;
+ h_period *= 1000;
h_period /= 2 * M_VAL;
duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
@@ -1089,7 +1089,7 @@
hblank &= ~15;
return (hblank);
}
-
+
/**
* fb_get_hfreq - estimate hsync
* @vfreq: vertical refresh rate
@@ -1100,13 +1100,13 @@
* (yres + front_port) * vfreq * 1000000
* hfreq = -------------------------------------
* (1000000 - (vfreq * FLYBACK)
- *
+ *
*/
static u32 fb_get_hfreq(u32 vfreq, u32 yres)
{
u32 divisor, hfreq;
-
+
divisor = (1000000 - (vfreq * FLYBACK))/1000;
hfreq = (yres + V_FRONTPORCH) * vfreq * 1000;
return (hfreq/divisor);
@@ -1117,7 +1117,7 @@
timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
timings->vblank = fb_get_vblank(timings->hfreq);
timings->vtotal = timings->vactive + timings->vblank;
- timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
+ timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
timings->hactive);
timings->htotal = timings->hactive + timings->hblank;
timings->dclk = timings->htotal * timings->hfreq;
@@ -1128,7 +1128,7 @@
timings->vblank = fb_get_vblank(timings->hfreq);
timings->vtotal = timings->vactive + timings->vblank;
timings->vfreq = timings->hfreq/timings->vtotal;
- timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
+ timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
timings->hactive);
timings->htotal = timings->hactive + timings->hblank;
timings->dclk = timings->htotal * timings->hfreq;
@@ -1136,7 +1136,7 @@
static void fb_timings_dclk(struct __fb_timings *timings)
{
- timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
+ timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
timings->hactive);
timings->htotal = timings->hactive + timings->hblank;
timings->hfreq = timings->dclk/timings->htotal;
@@ -1156,29 +1156,29 @@
* @info: pointer to fb_info
*
* DESCRIPTION:
- * Calculates video mode based on monitor specs using VESA GTF.
- * The GTF is best for VESA GTF compliant monitors but is
+ * Calculates video mode based on monitor specs using VESA GTF.
+ * The GTF is best for VESA GTF compliant monitors but is
* specifically formulated to work for older monitors as well.
*
- * If @flag==0, the function will attempt to maximize the
+ * If @flag==0, the function will attempt to maximize the
* refresh rate. Otherwise, it will calculate timings based on
- * the flag and accompanying value.
+ * the flag and accompanying value.
*
- * If FB_IGNOREMON bit is set in @flags, monitor specs will be
+ * If FB_IGNOREMON bit is set in @flags, monitor specs will be
* ignored and @var will be filled with the calculated timings.
*
* All calculations are based on the VESA GTF Spreadsheet
* available at VESA's public ftp (http://www.vesa.org).
- *
+ *
* NOTES:
* The timings generated by the GTF will be different from VESA
* DMT. It might be a good idea to keep a table of standard
* VESA modes as well. The GTF may also not work for some displays,
* such as, and especially, analog TV.
- *
+ *
* REQUIRES:
* A valid info->monspecs, otherwise 'safe numbers' will be used.
- */
+ */
int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
{
struct __fb_timings *timings;
@@ -1191,7 +1191,7 @@
if (!timings)
return -ENOMEM;
- /*
+ /*
* If monspecs are invalid, use values that are enough
* for 640x480@60
*/
@@ -1214,7 +1214,7 @@
timings->hactive = var->xres;
timings->vactive = var->yres;
- if (var->vmode & FB_VMODE_INTERLACED) {
+ if (var->vmode & FB_VMODE_INTERLACED) {
timings->vactive /= 2;
interlace = 2;
}
@@ -1250,9 +1250,9 @@
break;
default:
err = -EINVAL;
-
- }
-
+
+ }
+
if (err || (!(flags & FB_IGNOREMON) &&
(timings->vfreq < vfmin || timings->vfreq > vfmax ||
timings->hfreq < hfmin || timings->hfreq > hfmax ||
@@ -1269,7 +1269,7 @@
var->upper_margin = (timings->vblank * interlace)/dscan -
(var->vsync_len + var->lower_margin);
}
-
+
kfree(timings);
return err;
}
@@ -1291,7 +1291,7 @@
return -EINVAL;
}
#endif /* CONFIG_FB_MODE_HELPERS */
-
+
/*
* fb_validate_mode - validates var against monitor capabilities
* @var: pointer to fb_var_screeninfo
@@ -1309,7 +1309,7 @@
u32 hfreq, vfreq, htotal, vtotal, pixclock;
u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
- /*
+ /*
* If monspecs are invalid, use values that are enough
* for 640x480@60
*/
@@ -1333,10 +1333,10 @@
if (!var->pixclock)
return -EINVAL;
pixclock = PICOS2KHZ(var->pixclock) * 1000;
-
- htotal = var->xres + var->right_margin + var->hsync_len +
+
+ htotal = var->xres + var->right_margin + var->hsync_len +
var->left_margin;
- vtotal = var->yres + var->lower_margin + var->vsync_len +
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
var->upper_margin;
if (var->vmode & FB_VMODE_INTERLACED)
@@ -1349,7 +1349,7 @@
vfreq = hfreq/vtotal;
- return (vfreq < vfmin || vfreq > vfmax ||
+ return (vfreq < vfmin || vfreq > vfmax ||
hfreq < hfmin || hfreq > hfmax ||
pixclock < dclkmin || pixclock > dclkmax) ?
-EINVAL : 0;
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
index 583185f..eb6b881 100644
--- a/drivers/video/geode/lxfb_core.c
+++ b/drivers/video/geode/lxfb_core.c
@@ -34,7 +34,7 @@
* we try to make it something sane - 640x480-60 is sane
*/
-const struct fb_videomode geode_modedb[] __initdata = {
+static const struct fb_videomode geode_modedb[] __initdata = {
/* 640x480-60 */
{ NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index b18486a..2eb4fb1 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -207,7 +207,8 @@
#define HPFB_FBOMSB 0x5d /* Frame buffer offset */
#define HPFB_FBOLSB 0x5f
-static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
+static int __devinit hpfb_init_one(unsigned long phys_base,
+ unsigned long virt_base)
{
unsigned long fboff, fb_width, fb_height, fb_start;
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 1a7d778..1d13dd0 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1476,7 +1476,7 @@
struct i810fb_par *par = info->par;
u8 __iomem *mmio = par->mmio_start_virtual;
- if (!par->dev_flags & LOCKUP)
+ if (!(par->dev_flags & LOCKUP))
return -ENXIO;
if (cursor->image.width > 64 || cursor->image.height > 64)
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index b87ea21..3a81060 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -400,6 +400,7 @@
info = kzalloc(size, GFP_ATOMIC);
if (!info) {
printk("igafb_init: can't alloc fb_info\n");
+ pci_dev_put(pdev);
return -ENOMEM;
}
@@ -409,12 +410,14 @@
if ((addr = pdev->resource[0].start) == 0) {
printk("igafb_init: no memory start\n");
kfree(info);
+ pci_dev_put(pdev);
return -ENXIO;
}
if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
printk("igafb_init: can't remap %lx[2M]\n", addr);
kfree(info);
+ pci_dev_put(pdev);
return -ENXIO;
}
@@ -449,6 +452,7 @@
printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
iounmap((void *)info->screen_base);
kfree(info);
+ pci_dev_put(pdev);
return -ENXIO;
}
@@ -466,6 +470,7 @@
iounmap((void *)par->io_base);
iounmap(info->screen_base);
kfree(info);
+ pci_dev_put(pdev);
return -ENOMEM;
}
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 2fe3f7de..8367961 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -111,7 +111,7 @@
#define FIXED_MODE(d) ((d)->fixed_mode)
-/*** Driver paramters ***/
+/*** Driver parameters ***/
#define RINGBUFFER_SIZE KB(64)
#define HW_CURSOR_SIZE KB(4)
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 5f6fb7d..fa1fff5 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1971,7 +1971,7 @@
static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
{
u16 tmp;
- struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
+ struct intelfb_info *dinfo = dev_id;
spin_lock(&dinfo->int_lock);
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 4b6a99b..5246b04 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -2066,40 +2066,49 @@
switch (info->fix.accel) {
case FB_ACCEL_NEOMAGIC_NM2070:
- sprintf(info->fix.id, "MagicGraph 128");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128");
break;
case FB_ACCEL_NEOMAGIC_NM2090:
- sprintf(info->fix.id, "MagicGraph 128V");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128V");
break;
case FB_ACCEL_NEOMAGIC_NM2093:
- sprintf(info->fix.id, "MagicGraph 128ZV");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128ZV");
break;
case FB_ACCEL_NEOMAGIC_NM2097:
- sprintf(info->fix.id, "MagicGraph 128ZV+");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128ZV+");
break;
case FB_ACCEL_NEOMAGIC_NM2160:
- sprintf(info->fix.id, "MagicGraph 128XD");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 128XD");
break;
case FB_ACCEL_NEOMAGIC_NM2200:
- sprintf(info->fix.id, "MagicGraph 256AV");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256AV");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
break;
case FB_ACCEL_NEOMAGIC_NM2230:
- sprintf(info->fix.id, "MagicGraph 256AV+");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256AV+");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
break;
case FB_ACCEL_NEOMAGIC_NM2360:
- sprintf(info->fix.id, "MagicGraph 256ZX");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256ZX");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
break;
case FB_ACCEL_NEOMAGIC_NM2380:
- sprintf(info->fix.id, "MagicGraph 256XL+");
+ snprintf(info->fix.id, sizeof(info->fix.id),
+ "MagicGraph 256XL+");
info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT;
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 30e14eb..74517b1 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -849,9 +849,27 @@
if (!mode_valid && info->monspecs.modedb_len)
return -EINVAL;
+ /*
+ * If we're on a flat panel, check if the mode is outside of the
+ * panel dimensions. If so, cap it and try for the next best mode
+ * before bailing out.
+ */
if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
- par->fpHeight < var->yres))
- return -EINVAL;
+ par->fpHeight < var->yres)) {
+ const struct fb_videomode *mode;
+
+ var->xres = par->fpWidth;
+ var->yres = par->fpHeight;
+
+ mode = fb_find_best_mode(var, &info->modelist);
+ if (!mode) {
+ printk(KERN_ERR PFX "mode out of range of flat "
+ "panel dimensions\n");
+ return -EINVAL;
+ }
+
+ fb_videomode_to_var(var, mode);
+ }
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
index 9085188d..fb19ed4 100644
--- a/drivers/video/omap/lcdc.c
+++ b/drivers/video/omap/lcdc.c
@@ -312,7 +312,7 @@
/*
* Change to a new video mode. We defer this to a later time to avoid any
* flicker and not to mess up the current LCD DMA context. For this we disable
- * the LCD controler, which will generate a DONE irq after the last frame has
+ * the LCD controller, which will generate a DONE irq after the last frame has
* been transferred. Then it'll be safe to reconfigure both the LCD controller
* as well as the LCD DMA.
*/
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 5591dfb..30181b5 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -1159,6 +1159,11 @@
u32 fgx, bgx;
const u32 *src = (const u32 *)image->data;
u32 xres = (info->var.xres + 31) & ~31;
+ int raster_mode = 1; /* invert bits */
+
+#ifdef __LITTLE_ENDIAN
+ raster_mode |= 3 << 7; /* reverse byte order */
+#endif
if (info->state != FBINFO_STATE_RUNNING)
return;
@@ -1208,9 +1213,8 @@
pm2_WR(par, PM2R_RENDER,
PM2F_RENDER_RECTANGLE |
PM2F_INCREASE_X | PM2F_INCREASE_Y);
- /* BitMapPackEachScanline & invert bits and byte order*/
- /* force background */
- pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7));
+ /* BitMapPackEachScanline */
+ pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
pm2_WR(par, PM2R_RENDER,
PM2F_RENDER_RECTANGLE |
@@ -1224,8 +1228,7 @@
PM2F_RENDER_RECTANGLE |
PM2F_RENDER_FASTFILL |
PM2F_INCREASE_X | PM2F_INCREASE_Y);
- /* invert bits and byte order*/
- pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7));
+ pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
pm2_WR(par, PM2R_RENDER,
PM2F_RENDER_RECTANGLE |
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 07065999..5dba8cd 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1227,7 +1227,7 @@
/* mmio register are already mapped when this function is called */
/* the pm3fb_fix.smem_start is also set */
-static unsigned long pm3fb_size_memory(struct pm3_par *par)
+static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
{
unsigned long memsize = 0;
unsigned long tempBypass, i, temp1, temp2;
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index a864438..6515ec1 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -150,7 +150,7 @@
{
struct aafb_info *info = (struct aafb_info *)disp->fb_info;
struct aafb_cursor *c = &info->cursor;
- u8 fgc = ~attr_bgcol_ec(disp, disp->conp);
+ u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info);
if (width > 64 || height > 64 || width < 0 || height < 0)
return -EINVAL;
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 044a423..dc3af1c 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -57,8 +57,6 @@
#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64)
#define GPU_MAX_LINE_LENGTH (65536 - 64)
-#define PS3FB_FULL_MODE_BIT 0x80
-
#define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */
#define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */
#define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */
@@ -118,8 +116,6 @@
unsigned int irq_no;
u64 context_handle, memory_handle;
- void *xdr_ea;
- size_t xdr_size;
struct gpu_driver_info *dinfo;
u64 vblank_count; /* frame count */
@@ -136,42 +132,19 @@
struct ps3fb_par {
u32 pseudo_palette[16];
int mode_id, new_mode_id;
- int res_index;
unsigned int num_frames; /* num of frame buffers */
unsigned int width;
unsigned int height;
- unsigned long full_offset; /* start of fullscreen DDR fb */
- unsigned long fb_offset; /* start of actual DDR fb */
- unsigned long pan_offset;
+ unsigned int ddr_line_length;
+ unsigned int ddr_frame_size;
+ unsigned int xdr_frame_size;
+ unsigned int full_offset; /* start of fullscreen DDR fb */
+ unsigned int fb_offset; /* start of actual DDR fb */
+ unsigned int pan_offset;
};
-struct ps3fb_res_table {
- u32 xres;
- u32 yres;
- u32 xoff;
- u32 yoff;
- u32 type;
-};
-#define PS3FB_RES_FULL 1
-static const struct ps3fb_res_table ps3fb_res[] = {
- /* res_x,y margin_x,y full */
- { 720, 480, 72, 48 , 0},
- { 720, 576, 72, 58 , 0},
- { 1280, 720, 78, 38 , 0},
- { 1920, 1080, 116, 58 , 0},
- /* full mode */
- { 720, 480, 0, 0 , PS3FB_RES_FULL},
- { 720, 576, 0, 0 , PS3FB_RES_FULL},
- { 1280, 720, 0, 0 , PS3FB_RES_FULL},
- { 1920, 1080, 0, 0 , PS3FB_RES_FULL},
- /* vesa: normally full mode */
- { 1280, 768, 0, 0 , 0},
- { 1280, 1024, 0, 0 , 0},
- { 1920, 1200, 0, 0 , 0},
- { 0, 0, 0, 0 , 0} };
-/* default resolution */
-#define GPU_RES_INDEX 0 /* 720 x 480 */
+#define FIRST_NATIVE_MODE_INDEX 10
static const struct fb_videomode ps3fb_modedb[] = {
/* 60 Hz broadcast modes (modes "1" to "5") */
@@ -211,7 +184,7 @@
"720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
}, {
- /* 1080 */
+ /* 1080i */
"1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
}, {
@@ -220,24 +193,7 @@
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
},
- /* VESA modes (modes "11" to "13") */
- {
- /* WXGA */
- "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
- 0, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- }, {
- /* SXGA */
- "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- }, {
- /* WUXGA */
- "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
- FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- },
-
+ [FIRST_NATIVE_MODE_INDEX] =
/* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
{
/* 480if */
@@ -276,12 +232,30 @@
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
}, {
/* 1080if */
- "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
+ "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
}, {
/* 1080pf */
"1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ },
+
+ /* VESA modes (modes "11" to "13") */
+ {
+ /* WXGA */
+ "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* SXGA */
+ "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* WUXGA */
+ "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
}
};
@@ -289,110 +263,188 @@
#define HEAD_A
#define HEAD_B
-#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */
-#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */
-#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */
-#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */
#define BPP 4 /* number of bytes per pixel */
-/* Start of the virtual frame buffer (relative to fullscreen ) */
-#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
-
static int ps3fb_mode;
module_param(ps3fb_mode, int, 0);
static char *mode_option __devinitdata;
-static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
+static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
+ const struct fb_var_screeninfo *var)
{
- int full_mode;
- unsigned int i;
- u32 x, y, f;
+ long xres, yres, left_margin, right_margin, upper_margin, lower_margin;
+ long dx, dy;
- full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
- for (i = 0;; i++) {
- x = ps3fb_res[i].xres;
- y = ps3fb_res[i].yres;
- f = ps3fb_res[i].type;
+ /* maximum values */
+ if (var->xres > vmode->xres || var->yres > vmode->yres ||
+ var->pixclock > vmode->pixclock ||
+ var->hsync_len > vmode->hsync_len ||
+ var->vsync_len > vmode->vsync_len)
+ return -1;
- if (!x) {
- pr_debug("ERROR: ps3fb_get_res_table()\n");
- return -1;
- }
+ /* progressive/interlaced must match */
+ if ((var->vmode & FB_VMODE_MASK) != vmode->vmode)
+ return -1;
- if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
- continue;
+ /* minimum resolution */
+ xres = max(var->xres, 1U);
+ yres = max(var->yres, 1U);
- if (x == xres && (yres == 0 || y == yres))
- break;
+ /* minimum margins */
+ left_margin = max(var->left_margin, vmode->left_margin);
+ right_margin = max(var->right_margin, vmode->right_margin);
+ upper_margin = max(var->upper_margin, vmode->upper_margin);
+ lower_margin = max(var->lower_margin, vmode->lower_margin);
- x = x - 2 * ps3fb_res[i].xoff;
- y = y - 2 * ps3fb_res[i].yoff;
- if (x == xres && (yres == 0 || y == yres))
- break;
- }
- return i;
+ /* resolution + margins may not exceed native parameters */
+ dx = ((long)vmode->left_margin + (long)vmode->xres +
+ (long)vmode->right_margin) -
+ (left_margin + xres + right_margin);
+ if (dx < 0)
+ return -1;
+
+ dy = ((long)vmode->upper_margin + (long)vmode->yres +
+ (long)vmode->lower_margin) -
+ (upper_margin + yres + lower_margin);
+ if (dy < 0)
+ return -1;
+
+ /* exact match */
+ if (!dx && !dy)
+ return 0;
+
+ /* resolution difference */
+ return (vmode->xres - xres) * (vmode->yres - yres);
}
-static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
+static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id)
+{
+ return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];
+}
+
+static const struct fb_videomode *ps3fb_vmode(int id)
+{
+ u32 mode = id & PS3AV_MODE_MASK;
+
+ if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
+ return NULL;
+
+ if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) {
+ /* Non-fullscreen broadcast mode */
+ return &ps3fb_modedb[mode - 1];
+ }
+
+ return ps3fb_native_vmode(mode);
+}
+
+static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var,
u32 *ddr_line_length, u32 *xdr_line_length)
{
- unsigned int i, mode;
+ unsigned int id, best_id;
+ int diff, best_diff;
+ const struct fb_videomode *vmode;
+ long gap;
- for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
- if (var->xres == ps3fb_modedb[i].xres &&
- var->yres == ps3fb_modedb[i].yres &&
- var->pixclock == ps3fb_modedb[i].pixclock &&
- var->hsync_len == ps3fb_modedb[i].hsync_len &&
- var->vsync_len == ps3fb_modedb[i].vsync_len &&
- var->left_margin == ps3fb_modedb[i].left_margin &&
- var->right_margin == ps3fb_modedb[i].right_margin &&
- var->upper_margin == ps3fb_modedb[i].upper_margin &&
- var->lower_margin == ps3fb_modedb[i].lower_margin &&
- var->sync == ps3fb_modedb[i].sync &&
- (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
- goto found;
+ best_id = 0;
+ best_diff = INT_MAX;
+ pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__,
+ var->left_margin, var->xres, var->right_margin,
+ var->upper_margin, var->yres, var->lower_margin);
+ for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) {
+ vmode = ps3fb_native_vmode(id);
+ diff = ps3fb_cmp_mode(vmode, var);
+ pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n",
+ __func__, id, vmode->left_margin, vmode->xres,
+ vmode->right_margin, vmode->upper_margin,
+ vmode->yres, vmode->lower_margin, diff);
+ if (diff < 0)
+ continue;
+ if (diff < best_diff) {
+ best_id = id;
+ if (!diff)
+ break;
+ best_diff = diff;
+ }
+ }
- pr_debug("ps3fb_find_mode: mode not found\n");
- return 0;
+ if (!best_id) {
+ pr_debug("%s: no suitable mode found\n", __func__);
+ return 0;
+ }
-found:
- /* Cropped broadcast modes use the full line length */
- *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP;
+ id = best_id;
+ vmode = ps3fb_native_vmode(id);
+
+ *ddr_line_length = vmode->xres * BPP;
+
+ /* minimum resolution */
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+
+ /* minimum virtual resolution */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ /* minimum margins */
+ if (var->left_margin < vmode->left_margin)
+ var->left_margin = vmode->left_margin;
+ if (var->right_margin < vmode->right_margin)
+ var->right_margin = vmode->right_margin;
+ if (var->upper_margin < vmode->upper_margin)
+ var->upper_margin = vmode->upper_margin;
+ if (var->lower_margin < vmode->lower_margin)
+ var->lower_margin = vmode->lower_margin;
+
+ /* extra margins */
+ gap = ((long)vmode->left_margin + (long)vmode->xres +
+ (long)vmode->right_margin) -
+ ((long)var->left_margin + (long)var->xres +
+ (long)var->right_margin);
+ if (gap > 0) {
+ var->left_margin += gap/2;
+ var->right_margin += (gap+1)/2;
+ pr_debug("%s: rounded up H to %u [%u] %u\n", __func__,
+ var->left_margin, var->xres, var->right_margin);
+ }
+
+ gap = ((long)vmode->upper_margin + (long)vmode->yres +
+ (long)vmode->lower_margin) -
+ ((long)var->upper_margin + (long)var->yres +
+ (long)var->lower_margin);
+ if (gap > 0) {
+ var->upper_margin += gap/2;
+ var->lower_margin += (gap+1)/2;
+ pr_debug("%s: rounded up V to %u [%u] %u\n", __func__,
+ var->upper_margin, var->yres, var->lower_margin);
+ }
+
+ /* fixed fields */
+ var->pixclock = vmode->pixclock;
+ var->hsync_len = vmode->hsync_len;
+ var->vsync_len = vmode->vsync_len;
+ var->sync = vmode->sync;
if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
- *xdr_line_length = GPU_ALIGN_UP(max(var->xres,
- var->xres_virtual) * BPP);
+ *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP);
if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
*xdr_line_length = GPU_MAX_LINE_LENGTH;
} else
*xdr_line_length = *ddr_line_length;
- /* Full broadcast modes have the full mode bit set */
- mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
-
- pr_debug("ps3fb_find_mode: mode %u\n", mode);
-
- return mode;
-}
-
-static const struct fb_videomode *ps3fb_default_mode(int id)
-{
- u32 mode = id & PS3AV_MODE_MASK;
- u32 flags;
-
- if (mode < 1 || mode > 13)
- return NULL;
-
- flags = id & ~PS3AV_MODE_MASK;
-
- if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
- /* Full broadcast mode */
- return &ps3fb_modedb[mode + 12];
+ if (vmode->sync & FB_SYNC_BROADCAST) {
+ /* Full broadcast modes have the full mode bit set */
+ if (vmode->xres == var->xres && vmode->yres == var->yres)
+ id |= PS3AV_MODE_FULL;
}
- return &ps3fb_modedb[mode - 1];
+ pr_debug("%s: mode %u\n", __func__, id);
+ return id;
}
static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
@@ -439,8 +491,7 @@
static int ps3fb_sync(struct fb_info *info, u32 frame)
{
struct ps3fb_par *par = info->par;
- int i, error = 0;
- u32 ddr_line_length, xdr_line_length;
+ int error = 0;
u64 ddr_base, xdr_base;
if (frame > par->num_frames - 1) {
@@ -450,16 +501,13 @@
goto out;
}
- i = par->res_index;
- xdr_line_length = info->fix.line_length;
- ddr_line_length = ps3fb_res[i].xres * BPP;
- xdr_base = frame * info->var.yres_virtual * xdr_line_length;
- ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
+ xdr_base = frame * par->xdr_frame_size;
+ ddr_base = frame * par->ddr_frame_size;
ps3fb_sync_image(info->device, ddr_base + par->full_offset,
ddr_base + par->fb_offset, xdr_base + par->pan_offset,
- par->width, par->height, ddr_line_length,
- xdr_line_length);
+ par->width, par->height, par->ddr_line_length,
+ info->fix.line_length);
out:
return error;
@@ -498,22 +546,11 @@
u32 xdr_line_length, ddr_line_length;
int mode;
- dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
- info->var.xres);
- dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,
- info->var.yres);
-
- /* FIXME For now we do exact matches only */
mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
if (!mode)
return -EINVAL;
/* Virtual screen */
- if (var->xres_virtual < var->xres)
- var->xres_virtual = var->xres;
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
-
if (var->xres_virtual > xdr_line_length / BPP) {
dev_dbg(info->device,
"Horizontal virtual screen size too large\n");
@@ -559,7 +596,7 @@
}
/* Memory limit */
- if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {
+ if (var->yres_virtual * xdr_line_length > info->fix.smem_len) {
dev_dbg(info->device, "Not enough memory\n");
return -ENOMEM;
}
@@ -578,39 +615,38 @@
{
struct ps3fb_par *par = info->par;
unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
- int i;
- unsigned long offset;
+ unsigned int ddr_xoff, ddr_yoff, offset;
+ const struct fb_videomode *vmode;
u64 dst;
- dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
- info->var.xres, info->var.xres_virtual,
- info->var.yres, info->var.yres_virtual, info->var.pixclock);
-
mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
if (!mode)
return -EINVAL;
- i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
- par->res_index = i;
+ vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK);
- info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
- info->fix.smem_len = ps3fb.xdr_size;
info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
info->fix.line_length = xdr_line_length;
- info->screen_base = (char __iomem *)ps3fb.xdr_ea;
+ par->ddr_line_length = ddr_line_length;
+ par->ddr_frame_size = vmode->yres * ddr_line_length;
+ par->xdr_frame_size = info->var.yres_virtual * xdr_line_length;
- par->num_frames = ps3fb.xdr_size /
- max(ps3fb_res[i].yres * ddr_line_length,
- info->var.yres_virtual * xdr_line_length);
+ par->num_frames = info->fix.smem_len /
+ max(par->ddr_frame_size, par->xdr_frame_size);
/* Keep the special bits we cannot set using fb_var_screeninfo */
par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
par->width = info->var.xres;
par->height = info->var.yres;
- offset = VP_OFF(i);
+
+ /* Start of the virtual frame buffer (relative to fullscreen) */
+ ddr_xoff = info->var.left_margin - vmode->left_margin;
+ ddr_yoff = info->var.upper_margin - vmode->upper_margin;
+ offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP;
+
par->fb_offset = GPU_ALIGN_UP(offset);
par->full_offset = par->fb_offset - offset;
par->pan_offset = info->var.yoffset * xdr_line_length +
@@ -625,16 +661,16 @@
}
/* Clear XDR frame buffer memory */
- memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
+ memset((void __force *)info->screen_base, 0, info->fix.smem_len);
/* Clear DDR frame buffer memory */
- lines = ps3fb_res[i].yres * par->num_frames;
+ lines = vmode->yres * par->num_frames;
if (par->full_offset)
lines++;
- maxlines = ps3fb.xdr_size / ddr_line_length;
+ maxlines = info->fix.smem_len / ddr_line_length;
for (dst = 0; lines; dst += maxlines * ddr_line_length) {
unsigned int l = min(lines, maxlines);
- ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
+ ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l,
ddr_line_length, ddr_line_length);
lines -= l;
}
@@ -797,7 +833,7 @@
case PS3FB_IOCTL_SETMODE:
{
struct ps3fb_par *par = info->par;
- const struct fb_videomode *mode;
+ const struct fb_videomode *vmode;
struct fb_var_screeninfo var;
if (copy_from_user(&val, argp, sizeof(val)))
@@ -810,10 +846,10 @@
}
dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
retval = -EINVAL;
- mode = ps3fb_default_mode(val);
- if (mode) {
+ vmode = ps3fb_vmode(val);
+ if (vmode) {
var = info->var;
- fb_videomode_to_var(&var, mode);
+ fb_videomode_to_var(&var, vmode);
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
/* Force, in case only special bits changed */
@@ -975,10 +1011,9 @@
__func__, status);
return -ENXIO;
}
- dev_dbg(dev,
- "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
- ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
- virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
+ dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n",
+ ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
+ ps3fb_videomemory.size);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
@@ -1055,14 +1090,14 @@
struct fb_info *info;
struct ps3fb_par *par;
int retval = -ENOMEM;
- u32 xres, yres;
u64 ddr_lpar = 0;
u64 lpar_dma_control = 0;
u64 lpar_driver_info = 0;
u64 lpar_reports = 0;
u64 lpar_reports_size = 0;
u64 xdr_lpar;
- int status, res_index;
+ void *fb_start;
+ int status;
struct task_struct *task;
unsigned long max_ps3fb_size;
@@ -1080,14 +1115,7 @@
if (!ps3fb_mode)
ps3fb_mode = ps3av_get_mode();
- dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode);
-
- if (ps3fb_mode > 0 &&
- !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
- res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
- dev_dbg(&dev->core, "res_index:%d\n", res_index);
- } else
- res_index = GPU_RES_INDEX;
+ dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode);
atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
@@ -1124,7 +1152,7 @@
}
/* vsync interrupt */
- ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
+ ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
if (!ps3fb.dinfo) {
dev_err(&dev->core, "%s: ioremap failed\n", __func__);
goto err_gpu_context_free;
@@ -1134,22 +1162,10 @@
if (retval)
goto err_iounmap_dinfo;
- /* XDR frame buffer */
- ps3fb.xdr_ea = ps3fb_videomemory.address;
- xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
-
/* Clear memory to prevent kernel info leakage into userspace */
- memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
+ memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
- /*
- * The GPU command buffer is at the start of video memory
- * As we don't use the full command buffer, we can put the actual
- * frame buffer at offset GPU_FB_START and save some precious XDR
- * memory
- */
- ps3fb.xdr_ea += GPU_FB_START;
- ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START;
-
+ xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
if (retval)
goto err_free_irq;
@@ -1161,15 +1177,22 @@
par = info->par;
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
par->new_mode_id = ps3fb_mode;
- par->res_index = res_index;
par->num_frames = 1;
- info->screen_base = (char __iomem *)ps3fb.xdr_ea;
info->fbops = &ps3fb_ops;
-
info->fix = ps3fb_fix;
- info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
- info->fix.smem_len = ps3fb.xdr_size;
+
+ /*
+ * The GPU command buffer is at the start of video memory
+ * As we don't use the full command buffer, we can put the actual
+ * frame buffer at offset GPU_FB_START and save some precious XDR
+ * memory
+ */
+ fb_start = ps3fb_videomemory.address + GPU_FB_START;
+ info->screen_base = (char __force __iomem *)fb_start;
+ info->fix.smem_start = virt_to_abs(fb_start);
+ info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START;
+
info->pseudo_palette = par->pseudo_palette;
info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
@@ -1180,7 +1203,7 @@
if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
ARRAY_SIZE(ps3fb_modedb),
- ps3fb_default_mode(par->new_mode_id), 32)) {
+ ps3fb_vmode(par->new_mode_id), 32)) {
retval = -EINVAL;
goto err_fb_dealloc;
}
@@ -1194,9 +1217,9 @@
dev->core.driver_data = info;
- dev_info(info->device, "%s %s, using %lu KiB of video memory\n",
+ dev_info(info->device, "%s %s, using %u KiB of video memory\n",
dev_driver_string(info->dev), info->dev->bus_id,
- ps3fb.xdr_size >> 10);
+ info->fix.smem_len >> 10);
task = kthread_run(ps3fbd, info, DEVICE_NAME);
if (IS_ERR(task)) {
@@ -1219,7 +1242,7 @@
free_irq(ps3fb.irq_no, &dev->core);
ps3_irq_plug_destroy(ps3fb.irq_no);
err_iounmap_dinfo:
- iounmap((u8 __iomem *)ps3fb.dinfo);
+ iounmap((u8 __force __iomem *)ps3fb.dinfo);
err_gpu_context_free:
lv1_gpu_context_free(ps3fb.context_handle);
err_gpu_memory_free:
@@ -1254,7 +1277,7 @@
framebuffer_release(info);
info = dev->core.driver_data = NULL;
}
- iounmap((u8 __iomem *)ps3fb.dinfo);
+ iounmap((u8 __force __iomem *)ps3fb.dinfo);
status = lv1_gpu_context_free(ps3fb.context_handle);
if (status)
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index b3c31d9..71fa6ed 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -110,6 +110,11 @@
/* useful functions */
+static int is_s3c2412(struct s3c2410fb_info *fbi)
+{
+ return (fbi->drv_type == DRV_S3C2412);
+}
+
/* s3c2410fb_set_lcdaddr
*
* initialise lcd controller address pointers
@@ -501,7 +506,7 @@
{
unsigned long flags;
unsigned long irqen;
- void __iomem *regs = fbi->io;
+ void __iomem *irq_base = fbi->irq_base;
local_irq_save(flags);
@@ -511,9 +516,9 @@
fbi->palette_ready = 1;
/* enable IRQ */
- irqen = readl(regs + S3C2410_LCDINTMSK);
+ irqen = readl(irq_base + S3C24XX_LCDINTMSK);
irqen &= ~S3C2410_LCDINT_FRSYNC;
- writel(irqen, regs + S3C2410_LCDINTMSK);
+ writel(irqen, irq_base + S3C24XX_LCDINTMSK);
}
local_irq_restore(flags);
@@ -594,15 +599,17 @@
static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
- void __iomem *regs = fbi->io;
+ void __iomem *tpal_reg = fbi->io;
dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
+ tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
+
if (blank_mode == FB_BLANK_UNBLANK)
- writel(0x0, regs + S3C2410_TPAL);
+ writel(0x0, tpal_reg);
else {
dprintk("setting TPAL to output 0x000000\n");
- writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
+ writel(S3C2410_TPAL_EN, tpal_reg);
}
return 0;
@@ -663,7 +670,7 @@
dma_addr_t map_dma;
unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
- dprintk("map_video_memory(fbi=%p)\n", fbi);
+ dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
&map_dma, GFP_KERNEL);
@@ -672,7 +679,7 @@
/* prevent initial garbage on screen */
dprintk("map_video_memory: clear %p:%08x\n",
info->screen_base, map_size);
- memset(info->screen_base, 0xf0, map_size);
+ memset(info->screen_base, 0x00, map_size);
info->fix.smem_start = map_dma;
@@ -709,6 +716,16 @@
struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
unsigned long flags;
void __iomem *regs = fbi->io;
+ void __iomem *tpal;
+ void __iomem *lpcsel;
+
+ if (is_s3c2412(fbi)) {
+ tpal = regs + S3C2412_TPAL;
+ lpcsel = regs + S3C2412_TCONSEL;
+ } else {
+ tpal = regs + S3C2410_TPAL;
+ lpcsel = regs + S3C2410_LPCSEL;
+ }
/* Initialise LCD with values from haret */
@@ -724,12 +741,12 @@
local_irq_restore(flags);
dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel);
- writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
+ writel(mach_info->lpcsel, lpcsel);
- dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
+ dprintk("replacing TPAL %08x\n", readl(tpal));
/* ensure temporary palette disabled */
- writel(0x00, regs + S3C2410_TPAL);
+ writel(0x00, tpal);
return 0;
}
@@ -763,15 +780,15 @@
static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
{
struct s3c2410fb_info *fbi = dev_id;
- void __iomem *regs = fbi->io;
- unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
+ void __iomem *irq_base = fbi->irq_base;
+ unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);
if (lcdirq & S3C2410_LCDINT_FRSYNC) {
if (fbi->palette_ready)
s3c2410fb_write_palette(fbi);
- writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
- writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
+ writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);
+ writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);
}
return IRQ_HANDLED;
@@ -779,7 +796,8 @@
static char driver_name[] = "s3c2410fb";
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __init s3c24xxfb_probe(struct platform_device *pdev,
+ enum s3c_drv_type drv_type)
{
struct s3c2410fb_info *info;
struct s3c2410fb_display *display;
@@ -799,6 +817,12 @@
return -EINVAL;
}
+ if (mach_info->default_display >= mach_info->num_displays) {
+ dev_err(&pdev->dev, "default is %d but only %d displays\n",
+ mach_info->default_display, mach_info->num_displays);
+ return -EINVAL;
+ }
+
display = mach_info->displays + mach_info->default_display;
irq = platform_get_irq(pdev, 0);
@@ -815,6 +839,7 @@
info = fbinfo->par;
info->dev = &pdev->dev;
+ info->drv_type = drv_type;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
@@ -838,6 +863,8 @@
goto release_mem;
}
+ info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
+
dprintk("devinit\n");
strcpy(fbinfo->fix.id, driver_name);
@@ -946,6 +973,16 @@
return ret;
}
+static int __init s3c2410fb_probe(struct platform_device *pdev)
+{
+ return s3c24xxfb_probe(pdev, DRV_S3C2410);
+}
+
+static int __init s3c2412fb_probe(struct platform_device *pdev)
+{
+ return s3c24xxfb_probe(pdev, DRV_S3C2412);
+}
+
/* s3c2410fb_stop_lcd
*
* shutdown the lcd controller
@@ -1047,14 +1084,31 @@
},
};
+static struct platform_driver s3c2412fb_driver = {
+ .probe = s3c2412fb_probe,
+ .remove = s3c2410fb_remove,
+ .suspend = s3c2410fb_suspend,
+ .resume = s3c2410fb_resume,
+ .driver = {
+ .name = "s3c2412-lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
int __init s3c2410fb_init(void)
{
- return platform_driver_register(&s3c2410fb_driver);
+ int ret = platform_driver_register(&s3c2410fb_driver);
+
+ if (ret == 0)
+ ret = platform_driver_register(&s3c2412fb_driver);;
+
+ return ret;
}
static void __exit s3c2410fb_cleanup(void)
{
platform_driver_unregister(&s3c2410fb_driver);
+ platform_driver_unregister(&s3c2412fb_driver);
}
module_init(s3c2410fb_init);
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index 6ce5dc26..dbb73b9 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -25,13 +25,20 @@
#ifndef __S3C2410FB_H
#define __S3C2410FB_H
+enum s3c_drv_type {
+ DRV_S3C2410,
+ DRV_S3C2412,
+};
+
struct s3c2410fb_info {
struct device *dev;
struct clk *clk;
struct resource *mem;
void __iomem *io;
+ void __iomem *irq_base;
+ enum s3c_drv_type drv_type;
struct s3c2410fb_hw regs;
unsigned int palette_ready;
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index d53bf69..9b05da6 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -39,12 +39,7 @@
#include <linux/spinlock.h>
#ifdef CONFIG_COMPAT
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
-#include <linux/ioctl32.h>
-#define SIS_OLD_CONFIG_COMPAT
-#else
#define SIS_NEW_CONFIG_COMPAT
-#endif
#endif /* CONFIG_COMPAT */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
@@ -607,9 +602,6 @@
int haveXGIROM;
int registered;
int warncount;
-#ifdef SIS_OLD_CONFIG_COMPAT
- int ioctl32registered;
-#endif
int sisvga_engine;
int hwcursor_size;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 37bd24b..7380362 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -427,7 +427,7 @@
monitor->feature = buffer[0x18];
- if(!buffer[0x14] & 0x80) {
+ if(!(buffer[0x14] & 0x80)) {
if(!(buffer[0x14] & 0x08)) {
printk(KERN_INFO
"sisfb: WARNING: Monitor does not support separate syncs\n");
@@ -4621,9 +4621,9 @@
while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
temp = pdev->vendor;
- pci_dev_put(pdev);
if(temp == pcivendor) {
ret = 1;
+ pci_dev_put(pdev);
break;
}
}
@@ -5805,9 +5805,6 @@
ivideo->pcifunc = PCI_FUNC(pdev->devfn);
ivideo->subsysvendor = pdev->subsystem_vendor;
ivideo->subsysdevice = pdev->subsystem_device;
-#ifdef SIS_OLD_CONFIG_COMPAT
- ivideo->ioctl32registered = 0;
-#endif
#ifndef MODULE
if(sisfb_mode_idx == -1) {
@@ -6420,30 +6417,6 @@
ivideo->next = card_list;
card_list = ivideo;
-#ifdef SIS_OLD_CONFIG_COMPAT
- {
- int ret;
- /* Our ioctls are all "32/64bit compatible" */
- ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
- ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
- ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
- ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
- ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
- ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
- ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
- ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
- ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
- ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
- ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
- ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
- if(ret)
- printk(KERN_ERR
- "sisfb: Error registering ioctl32 translations\n");
- else
- ivideo->ioctl32registered = 1;
- }
-#endif
-
printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
ivideo->sisfb_accel ? "enabled" : "disabled",
ivideo->sisfb_ypan ?
@@ -6473,27 +6446,6 @@
int registered = ivideo->registered;
int modechanged = ivideo->modechanged;
-#ifdef SIS_OLD_CONFIG_COMPAT
- if(ivideo->ioctl32registered) {
- int ret;
- ret = unregister_ioctl32_conversion(FBIO_ALLOC);
- ret |= unregister_ioctl32_conversion(FBIO_FREE);
- ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
- ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
- ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
- ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
- ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
- ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
- ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
- ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
- ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
- ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
- if(ret)
- printk(KERN_ERR
- "sisfb: Error unregistering ioctl32 translations\n");
- }
-#endif
-
/* Unmap */
iounmap(ivideo->mmio_vbase);
iounmap(ivideo->video_vbase);
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 1be95a68..e83dfba 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -48,7 +48,7 @@
HEAD_PANEL = 1,
};
-/* SM501 memory adress */
+/* SM501 memory address */
struct sm501_mem {
unsigned long size;
unsigned long sm_addr;
@@ -641,6 +641,7 @@
{
unsigned long control;
void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+ struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
control = readl(ctrl_reg);
@@ -657,26 +658,34 @@
sm501fb_sync_regs(fbi);
mdelay(10);
- control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
- writel(control, ctrl_reg);
- sm501fb_sync_regs(fbi);
- mdelay(10);
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+ control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
- control |= SM501_DC_PANEL_CONTROL_FPEN;
- writel(control, ctrl_reg);
-
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+ control |= SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
} else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
/* disable panel power */
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+ control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
- control &= ~SM501_DC_PANEL_CONTROL_FPEN;
- writel(control, ctrl_reg);
- sm501fb_sync_regs(fbi);
- mdelay(10);
-
- control &= ~SM501_DC_PANEL_CONTROL_BIAS;
- writel(control, ctrl_reg);
- sm501fb_sync_regs(fbi);
- mdelay(10);
+ if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+ control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
control &= ~SM501_DC_PANEL_CONTROL_DATA;
writel(control, ctrl_reg);
@@ -1267,6 +1276,7 @@
{
struct resource *res;
struct device *dev;
+ int k;
int ret;
info->dev = dev = &pdev->dev;
@@ -1328,6 +1338,13 @@
info->fbmem_len = (res->end - res->start)+1;
+ /* clear framebuffer memory - avoids garbage data on unused fb */
+ memset(info->fbmem, 0, info->fbmem_len);
+
+ /* clear palette ram - undefined at power on */
+ for (k = 0; k < (256 * 3); k++)
+ writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
+
/* enable display controller */
sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
@@ -1681,6 +1698,15 @@
if (par->screen.size == 0)
return 0;
+ /* blank the relevant interface to ensure unit power minimised */
+ (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+ /* tell console/fb driver we are suspending */
+
+ acquire_console_sem();
+ fb_set_suspend(fbi, 1);
+ release_console_sem();
+
/* backup copies in case chip is powered down over suspend */
par->store_fb = vmalloc(par->screen.size);
@@ -1700,12 +1726,6 @@
memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
- /* blank the relevant interface to ensure unit power minimised */
- (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
-
- acquire_console_sem();
- fb_set_suspend(fbi, 1);
- release_console_sem();
return 0;
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 057bdd5..71e179e 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -1342,7 +1342,7 @@
}
#ifndef MODULE
-static void tdfxfb_setup(char *options)
+static void __init tdfxfb_setup(char *options)
{
char *this_opt;
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index a14ef89..be27b9c 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -2003,12 +2003,12 @@
module_exit(uvesafb_exit);
-static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
+static int param_get_scroll(char *buffer, struct kernel_param *kp)
{
return 0;
}
-static inline int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, struct kernel_param *kp)
{
ypan = 0;
@@ -2022,11 +2022,11 @@
return 0;
}
-#define param_check_scroll(name, p) __param_check(name, p, void);
+#define param_check_scroll(name, p) __param_check(name, p, void)
module_param_named(scroll, ypan, scroll, 0);
MODULE_PARM_DESC(scroll,
- "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
+ "Scrolling mode, set to 'redraw', 'ypan', or 'ywrap'");
module_param_named(vgapal, pmi_setpal, invbool, 0);
MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
module_param_named(pmipal, pmi_setpal, bool, 0);
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index 1c65666..2aa71eb 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -651,7 +651,7 @@
return -EINVAL;
}
- pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
+ pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40);
mem = pitch * var->yres_virtual;
if (mem > vinfo->vram_contig_size) {
return -ENOMEM;
@@ -785,8 +785,7 @@
int clock;
vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
- vinfo->stride =
- __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
+ vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40);
info->fix.line_length = vinfo->stride;
if (!subsys)
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 9e33fc4..3dd6294 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -1,8 +1,35 @@
# Virtio always gets selected by whoever wants it.
config VIRTIO
- bool
+ tristate
# Similarly the virtio ring implementation.
config VIRTIO_RING
- bool
+ tristate
depends on VIRTIO
+
+config VIRTIO_PCI
+ tristate "PCI driver for virtio devices (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select VIRTIO
+ select VIRTIO_RING
+ ---help---
+ This drivers provides support for virtio based paravirtual device
+ drivers over PCI. This requires that your VMM has appropriate PCI
+ virtio backends. Most QEMU based VMMs should support these devices
+ (like KVM or Xen).
+
+ Currently, the ABI is not considered stable so there is no guarantee
+ that this version of the driver will work with your VMM.
+
+ If unsure, say M.
+
+config VIRTIO_BALLOON
+ tristate "Virtio balloon driver (EXPERIMENTAL)"
+ select VIRTIO
+ select VIRTIO_RING
+ ---help---
+ This driver supports increasing and decreasing the amount
+ of memory within a KVM guest.
+
+ If unsure, say M.
+
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index f70e409..6738c44 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -1,2 +1,4 @@
obj-$(CONFIG_VIRTIO) += virtio.o
obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
+obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
+obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 69d7ea0..b535483 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -102,9 +102,13 @@
struct virtio_driver *drv = container_of(dev->dev.driver,
struct virtio_driver, driver);
- dev->config->set_status(dev, dev->config->get_status(dev)
- & ~VIRTIO_CONFIG_S_DRIVER);
drv->remove(dev);
+
+ /* Driver should have reset device. */
+ BUG_ON(dev->config->get_status(dev));
+
+ /* Acknowledge the device's existence again. */
+ add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
return 0;
}
@@ -130,6 +134,10 @@
dev->dev.bus = &virtio_bus;
sprintf(dev->dev.bus_id, "%u", dev->index);
+ /* We always start by resetting the device, in case a previous
+ * driver messed it up. This also tests that code path a little. */
+ dev->config->reset(dev);
+
/* Acknowledge that we've seen the device. */
add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
@@ -148,55 +156,18 @@
}
EXPORT_SYMBOL_GPL(unregister_virtio_device);
-int __virtio_config_val(struct virtio_device *vdev,
- u8 type, void *val, size_t size)
-{
- void *token;
- unsigned int len;
-
- token = vdev->config->find(vdev, type, &len);
- if (!token)
- return -ENOENT;
-
- if (len != size)
- return -EIO;
-
- vdev->config->get(vdev, token, val, size);
- return 0;
-}
-EXPORT_SYMBOL_GPL(__virtio_config_val);
-
-int virtio_use_bit(struct virtio_device *vdev,
- void *token, unsigned int len, unsigned int bitnum)
-{
- unsigned long bits[16];
-
- /* This makes it convenient to pass-through find() results. */
- if (!token)
- return 0;
-
- /* bit not in range of this bitfield? */
- if (bitnum * 8 >= len / 2)
- return 0;
-
- /* Giant feature bitfields are silly. */
- BUG_ON(len > sizeof(bits));
- vdev->config->get(vdev, token, bits, len);
-
- if (!test_bit(bitnum, bits))
- return 0;
-
- /* Set acknowledge bit, and write it back. */
- set_bit(bitnum + len * 8 / 2, bits);
- vdev->config->set(vdev, token, bits, len);
- return 1;
-}
-EXPORT_SYMBOL_GPL(virtio_use_bit);
-
static int virtio_init(void)
{
if (bus_register(&virtio_bus) != 0)
panic("virtio bus registration failed");
return 0;
}
+
+static void __exit virtio_exit(void)
+{
+ bus_unregister(&virtio_bus);
+}
core_initcall(virtio_init);
+module_exit(virtio_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
new file mode 100644
index 0000000..c8a4332
--- /dev/null
+++ b/drivers/virtio/virtio_balloon.c
@@ -0,0 +1,285 @@
+/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
+ * Tosatti's implementations.
+ *
+ * Copyright 2008 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+//#define DEBUG
+#include <linux/virtio.h>
+#include <linux/virtio_balloon.h>
+#include <linux/swap.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/delay.h>
+
+struct virtio_balloon
+{
+ struct virtio_device *vdev;
+ struct virtqueue *inflate_vq, *deflate_vq;
+
+ /* Where the ballooning thread waits for config to change. */
+ wait_queue_head_t config_change;
+
+ /* The thread servicing the balloon. */
+ struct task_struct *thread;
+
+ /* Waiting for host to ack the pages we released. */
+ struct completion acked;
+
+ /* Do we have to tell Host *before* we reuse pages? */
+ bool tell_host_first;
+
+ /* The pages we've told the Host we're not using. */
+ unsigned int num_pages;
+ struct list_head pages;
+
+ /* The array of pfns we tell the Host about. */
+ unsigned int num_pfns;
+ u32 pfns[256];
+};
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_BALLOON, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static void balloon_ack(struct virtqueue *vq)
+{
+ struct virtio_balloon *vb;
+ unsigned int len;
+
+ vb = vq->vq_ops->get_buf(vq, &len);
+ if (vb)
+ complete(&vb->acked);
+}
+
+static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
+{
+ struct scatterlist sg;
+
+ sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
+
+ init_completion(&vb->acked);
+
+ /* We should always be able to add one buffer to an empty queue. */
+ if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) != 0)
+ BUG();
+ vq->vq_ops->kick(vq);
+
+ /* When host has read buffer, this completes via balloon_ack */
+ wait_for_completion(&vb->acked);
+}
+
+static void fill_balloon(struct virtio_balloon *vb, size_t num)
+{
+ /* We can only do one array worth at a time. */
+ num = min(num, ARRAY_SIZE(vb->pfns));
+
+ for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
+ struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY);
+ if (!page) {
+ if (printk_ratelimit())
+ dev_printk(KERN_INFO, &vb->vdev->dev,
+ "Out of puff! Can't get %zu pages\n",
+ num);
+ /* Sleep for at least 1/5 of a second before retry. */
+ msleep(200);
+ break;
+ }
+ vb->pfns[vb->num_pfns] = page_to_pfn(page);
+ totalram_pages--;
+ vb->num_pages++;
+ list_add(&page->lru, &vb->pages);
+ }
+
+ /* Didn't get any? Oh well. */
+ if (vb->num_pfns == 0)
+ return;
+
+ tell_host(vb, vb->inflate_vq);
+}
+
+static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ __free_page(pfn_to_page(pfns[i]));
+ totalram_pages++;
+ }
+}
+
+static void leak_balloon(struct virtio_balloon *vb, size_t num)
+{
+ struct page *page;
+
+ /* We can only do one array worth at a time. */
+ num = min(num, ARRAY_SIZE(vb->pfns));
+
+ for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
+ page = list_first_entry(&vb->pages, struct page, lru);
+ list_del(&page->lru);
+ vb->pfns[vb->num_pfns] = page_to_pfn(page);
+ vb->num_pages--;
+ }
+
+ if (vb->tell_host_first) {
+ tell_host(vb, vb->deflate_vq);
+ release_pages_by_pfn(vb->pfns, vb->num_pfns);
+ } else {
+ release_pages_by_pfn(vb->pfns, vb->num_pfns);
+ tell_host(vb, vb->deflate_vq);
+ }
+}
+
+static void virtballoon_changed(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb = vdev->priv;
+
+ wake_up(&vb->config_change);
+}
+
+static inline int towards_target(struct virtio_balloon *vb)
+{
+ u32 v;
+ __virtio_config_val(vb->vdev,
+ offsetof(struct virtio_balloon_config, num_pages),
+ &v);
+ return v - vb->num_pages;
+}
+
+static void update_balloon_size(struct virtio_balloon *vb)
+{
+ __le32 actual = cpu_to_le32(vb->num_pages);
+
+ vb->vdev->config->set(vb->vdev,
+ offsetof(struct virtio_balloon_config, actual),
+ &actual, sizeof(actual));
+}
+
+static int balloon(void *_vballoon)
+{
+ struct virtio_balloon *vb = _vballoon;
+
+ set_freezable();
+ while (!kthread_should_stop()) {
+ int diff;
+
+ try_to_freeze();
+ wait_event_interruptible(vb->config_change,
+ (diff = towards_target(vb)) != 0
+ || kthread_should_stop());
+ if (diff > 0)
+ fill_balloon(vb, diff);
+ else if (diff < 0)
+ leak_balloon(vb, -diff);
+ update_balloon_size(vb);
+ }
+ return 0;
+}
+
+static int virtballoon_probe(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb;
+ int err;
+
+ vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
+ if (!vb) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&vb->pages);
+ vb->num_pages = 0;
+ init_waitqueue_head(&vb->config_change);
+ vb->vdev = vdev;
+
+ /* We expect two virtqueues. */
+ vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
+ if (IS_ERR(vb->inflate_vq)) {
+ err = PTR_ERR(vb->inflate_vq);
+ goto out_free_vb;
+ }
+
+ vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
+ if (IS_ERR(vb->deflate_vq)) {
+ err = PTR_ERR(vb->deflate_vq);
+ goto out_del_inflate_vq;
+ }
+
+ vb->thread = kthread_run(balloon, vb, "vballoon");
+ if (IS_ERR(vb->thread)) {
+ err = PTR_ERR(vb->thread);
+ goto out_del_deflate_vq;
+ }
+
+ vb->tell_host_first
+ = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+
+ return 0;
+
+out_del_deflate_vq:
+ vdev->config->del_vq(vb->deflate_vq);
+out_del_inflate_vq:
+ vdev->config->del_vq(vb->inflate_vq);
+out_free_vb:
+ kfree(vb);
+out:
+ return err;
+}
+
+static void virtballoon_remove(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb = vdev->priv;
+
+ kthread_stop(vb->thread);
+
+ /* There might be pages left in the balloon: free them. */
+ while (vb->num_pages)
+ leak_balloon(vb, vb->num_pages);
+
+ /* Now we reset the device so we can clean up the queues. */
+ vdev->config->reset(vdev);
+
+ vdev->config->del_vq(vb->deflate_vq);
+ vdev->config->del_vq(vb->inflate_vq);
+ kfree(vb);
+}
+
+static struct virtio_driver virtio_balloon = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtballoon_probe,
+ .remove = __devexit_p(virtballoon_remove),
+ .config_changed = virtballoon_changed,
+};
+
+static int __init init(void)
+{
+ return register_virtio_driver(&virtio_balloon);
+}
+
+static void __exit fini(void)
+{
+ unregister_virtio_driver(&virtio_balloon);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio balloon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
new file mode 100644
index 0000000..26f787d
--- /dev/null
+++ b/drivers/virtio/virtio_pci.c
@@ -0,0 +1,446 @@
+/*
+ * Virtio PCI driver
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_pci.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+
+MODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>");
+MODULE_DESCRIPTION("virtio-pci");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+/* Our device structure */
+struct virtio_pci_device
+{
+ struct virtio_device vdev;
+ struct pci_dev *pci_dev;
+
+ /* the IO mapping for the PCI config space */
+ void *ioaddr;
+
+ /* a list of queues so we can dispatch IRQs */
+ spinlock_t lock;
+ struct list_head virtqueues;
+};
+
+struct virtio_pci_vq_info
+{
+ /* the actual virtqueue */
+ struct virtqueue *vq;
+
+ /* the number of entries in the queue */
+ int num;
+
+ /* the index of the queue */
+ int queue_index;
+
+ /* the virtual address of the ring queue */
+ void *queue;
+
+ /* the list node for the virtqueues list */
+ struct list_head node;
+};
+
+/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
+static struct pci_device_id virtio_pci_id_table[] = {
+ { 0x1af4, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
+
+/* A PCI device has it's own struct device and so does a virtio device so
+ * we create a place for the virtio devices to show up in sysfs. I think it
+ * would make more sense for virtio to not insist on having it's own device. */
+static struct device virtio_pci_root = {
+ .parent = NULL,
+ .bus_id = "virtio-pci",
+};
+
+/* Unique numbering for devices under the kvm root */
+static unsigned int dev_index;
+
+/* Convert a generic virtio device to our structure */
+static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
+{
+ return container_of(vdev, struct virtio_pci_device, vdev);
+}
+
+/* virtio config->feature() implementation */
+static bool vp_feature(struct virtio_device *vdev, unsigned bit)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ u32 mask;
+
+ /* Since this function is supposed to have the side effect of
+ * enabling a queried feature, we simulate that by doing a read
+ * from the host feature bitmask and then writing to the guest
+ * feature bitmask */
+ mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+ if (mask & (1 << bit)) {
+ mask |= (1 << bit);
+ iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+ }
+
+ return !!(mask & (1 << bit));
+}
+
+/* virtio config->get() implementation */
+static void vp_get(struct virtio_device *vdev, unsigned offset,
+ void *buf, unsigned len)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ void *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+ u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = ioread8(ioaddr + i);
+}
+
+/* the config->set() implementation. it's symmetric to the config->get()
+ * implementation */
+static void vp_set(struct virtio_device *vdev, unsigned offset,
+ const void *buf, unsigned len)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ void *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+ const u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ iowrite8(ptr[i], ioaddr + i);
+}
+
+/* config->{get,set}_status() implementations */
+static u8 vp_get_status(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ return ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static void vp_set_status(struct virtio_device *vdev, u8 status)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ /* We should never be setting status to 0. */
+ BUG_ON(status == 0);
+ return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static void vp_reset(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ /* 0 status means a reset. */
+ return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+/* the notify function used when creating a virt queue */
+static void vp_notify(struct virtqueue *vq)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+ struct virtio_pci_vq_info *info = vq->priv;
+
+ /* we write the queue's selector into the notification register to
+ * signal the other end */
+ iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+
+/* A small wrapper to also acknowledge the interrupt when it's handled.
+ * I really need an EIO hook for the vring so I can ack the interrupt once we
+ * know that we'll be handling the IRQ but before we invoke the callback since
+ * the callback may notify the host which results in the host attempting to
+ * raise an interrupt that we would then mask once we acknowledged the
+ * interrupt. */
+static irqreturn_t vp_interrupt(int irq, void *opaque)
+{
+ struct virtio_pci_device *vp_dev = opaque;
+ struct virtio_pci_vq_info *info;
+ irqreturn_t ret = IRQ_NONE;
+ u8 isr;
+
+ /* reading the ISR has the effect of also clearing it so it's very
+ * important to save off the value. */
+ isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
+
+ /* It's definitely not us if the ISR was not high */
+ if (!isr)
+ return IRQ_NONE;
+
+ /* Configuration change? Tell driver if it wants to know. */
+ if (isr & VIRTIO_PCI_ISR_CONFIG) {
+ struct virtio_driver *drv;
+ drv = container_of(vp_dev->vdev.dev.driver,
+ struct virtio_driver, driver);
+
+ if (drv->config_changed)
+ drv->config_changed(&vp_dev->vdev);
+ }
+
+ spin_lock(&vp_dev->lock);
+ list_for_each_entry(info, &vp_dev->virtqueues, node) {
+ if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+ }
+ spin_unlock(&vp_dev->lock);
+
+ return ret;
+}
+
+/* the config->find_vq() implementation */
+static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
+ void (*callback)(struct virtqueue *vq))
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_vq_info *info;
+ struct virtqueue *vq;
+ u16 num;
+ int err;
+
+ /* Select the queue we're interested in */
+ iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* Check if queue is either not available or already active. */
+ num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
+ return ERR_PTR(-ENOENT);
+
+ /* allocate and fill out our structure the represents an active
+ * queue */
+ info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->queue_index = index;
+ info->num = num;
+
+ info->queue = kzalloc(PAGE_ALIGN(vring_size(num,PAGE_SIZE)), GFP_KERNEL);
+ if (info->queue == NULL) {
+ err = -ENOMEM;
+ goto out_info;
+ }
+
+ /* activate the queue */
+ iowrite32(virt_to_phys(info->queue) >> PAGE_SHIFT,
+ vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ /* create the vring */
+ vq = vring_new_virtqueue(info->num, vdev, info->queue,
+ vp_notify, callback);
+ if (!vq) {
+ err = -ENOMEM;
+ goto out_activate_queue;
+ }
+
+ vq->priv = info;
+ info->vq = vq;
+
+ spin_lock(&vp_dev->lock);
+ list_add(&info->node, &vp_dev->virtqueues);
+ spin_unlock(&vp_dev->lock);
+
+ return vq;
+
+out_activate_queue:
+ iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+ kfree(info->queue);
+out_info:
+ kfree(info);
+ return ERR_PTR(err);
+}
+
+/* the config->del_vq() implementation */
+static void vp_del_vq(struct virtqueue *vq)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+ struct virtio_pci_vq_info *info = vq->priv;
+
+ spin_lock(&vp_dev->lock);
+ list_del(&info->node);
+ spin_unlock(&vp_dev->lock);
+
+ vring_del_virtqueue(vq);
+
+ /* Select and deactivate the queue */
+ iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+ iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ kfree(info->queue);
+ kfree(info);
+}
+
+static struct virtio_config_ops virtio_pci_config_ops = {
+ .feature = vp_feature,
+ .get = vp_get,
+ .set = vp_set,
+ .get_status = vp_get_status,
+ .set_status = vp_set_status,
+ .reset = vp_reset,
+ .find_vq = vp_find_vq,
+ .del_vq = vp_del_vq,
+};
+
+/* the PCI probing function */
+static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ struct virtio_pci_device *vp_dev;
+ int err;
+
+ /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
+ if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)
+ return -ENODEV;
+
+ if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION) {
+ printk(KERN_ERR "virtio_pci: expected ABI version %d, got %d\n",
+ VIRTIO_PCI_ABI_VERSION, pci_dev->revision);
+ return -ENODEV;
+ }
+
+ /* allocate our structure and fill it out */
+ vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
+ if (vp_dev == NULL)
+ return -ENOMEM;
+
+ snprintf(vp_dev->vdev.dev.bus_id, BUS_ID_SIZE, "virtio%d", dev_index);
+ vp_dev->vdev.index = dev_index;
+ dev_index++;
+
+ vp_dev->vdev.dev.parent = &virtio_pci_root;
+ vp_dev->vdev.config = &virtio_pci_config_ops;
+ vp_dev->pci_dev = pci_dev;
+ INIT_LIST_HEAD(&vp_dev->virtqueues);
+ spin_lock_init(&vp_dev->lock);
+
+ /* enable the device */
+ err = pci_enable_device(pci_dev);
+ if (err)
+ goto out;
+
+ err = pci_request_regions(pci_dev, "virtio-pci");
+ if (err)
+ goto out_enable_device;
+
+ vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0);
+ if (vp_dev->ioaddr == NULL)
+ goto out_req_regions;
+
+ pci_set_drvdata(pci_dev, vp_dev);
+
+ /* we use the subsystem vendor/device id as the virtio vendor/device
+ * id. this allows us to use the same PCI vendor/device id for all
+ * virtio devices and to identify the particular virtio driver by
+ * the subsytem ids */
+ vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
+ vp_dev->vdev.id.device = pci_dev->subsystem_device;
+
+ /* register a handler for the queue with the PCI device's interrupt */
+ err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
+ vp_dev->vdev.dev.bus_id, vp_dev);
+ if (err)
+ goto out_set_drvdata;
+
+ /* finally register the virtio device */
+ err = register_virtio_device(&vp_dev->vdev);
+ if (err)
+ goto out_req_irq;
+
+ return 0;
+
+out_req_irq:
+ free_irq(pci_dev->irq, vp_dev);
+out_set_drvdata:
+ pci_set_drvdata(pci_dev, NULL);
+ pci_iounmap(pci_dev, vp_dev->ioaddr);
+out_req_regions:
+ pci_release_regions(pci_dev);
+out_enable_device:
+ pci_disable_device(pci_dev);
+out:
+ kfree(vp_dev);
+ return err;
+}
+
+static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
+{
+ struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+
+ free_irq(pci_dev->irq, vp_dev);
+ pci_set_drvdata(pci_dev, NULL);
+ pci_iounmap(pci_dev, vp_dev->ioaddr);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+ kfree(vp_dev);
+}
+
+#ifdef CONFIG_PM
+static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ pci_save_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D3hot);
+ return 0;
+}
+
+static int virtio_pci_resume(struct pci_dev *pci_dev)
+{
+ pci_restore_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D0);
+ return 0;
+}
+#endif
+
+static struct pci_driver virtio_pci_driver = {
+ .name = "virtio-pci",
+ .id_table = virtio_pci_id_table,
+ .probe = virtio_pci_probe,
+ .remove = virtio_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = virtio_pci_suspend,
+ .resume = virtio_pci_resume,
+#endif
+};
+
+static int __init virtio_pci_init(void)
+{
+ int err;
+
+ err = device_register(&virtio_pci_root);
+ if (err)
+ return err;
+
+ err = pci_register_driver(&virtio_pci_driver);
+ if (err)
+ device_unregister(&virtio_pci_root);
+
+ return err;
+}
+
+module_init(virtio_pci_init);
+
+static void __exit virtio_pci_exit(void)
+{
+ device_unregister(&virtio_pci_root);
+ pci_unregister_driver(&virtio_pci_driver);
+}
+
+module_exit(virtio_pci_exit);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 1dc04b6..3a28c13 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -87,6 +87,8 @@
if (vq->num_free < out + in) {
pr_debug("Can't add buf len %i - avail = %i\n",
out + in, vq->num_free);
+ /* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */
+ vq->notify(&vq->vq);
END_USE(vq);
return -ENOSPC;
}
@@ -97,16 +99,14 @@
head = vq->free_head;
for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) {
vq->vring.desc[i].flags = VRING_DESC_F_NEXT;
- vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
- + sg->offset;
+ vq->vring.desc[i].addr = sg_phys(sg);
vq->vring.desc[i].len = sg->length;
prev = i;
sg++;
}
for (; in; i = vq->vring.desc[i].next, in--) {
vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
- vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
- + sg->offset;
+ vq->vring.desc[i].addr = sg_phys(sg);
vq->vring.desc[i].len = sg->length;
prev = i;
sg++;
@@ -171,16 +171,6 @@
vq->num_free++;
}
-/* FIXME: We need to tell other side about removal, to synchronize. */
-static void vring_shutdown(struct virtqueue *_vq)
-{
- struct vring_virtqueue *vq = to_vvq(_vq);
- unsigned int i;
-
- for (i = 0; i < vq->vring.num; i++)
- detach_buf(vq, i);
-}
-
static inline bool more_used(const struct vring_virtqueue *vq)
{
return vq->last_used_idx != vq->vring.used->idx;
@@ -220,7 +210,17 @@
return ret;
}
-static bool vring_restart(struct virtqueue *_vq)
+static void vring_disable_cb(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ START_USE(vq);
+ BUG_ON(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
+ vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+ END_USE(vq);
+}
+
+static bool vring_enable_cb(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
@@ -253,26 +253,34 @@
if (unlikely(vq->broken))
return IRQ_HANDLED;
+ /* Other side may have missed us turning off the interrupt,
+ * but we should preserve disable semantic for virtio users. */
+ if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
+ pr_debug("virtqueue interrupt after disable for %p\n", vq);
+ return IRQ_HANDLED;
+ }
+
pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
- if (vq->vq.callback && !vq->vq.callback(&vq->vq))
- vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+ if (vq->vq.callback)
+ vq->vq.callback(&vq->vq);
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(vring_interrupt);
static struct virtqueue_ops vring_vq_ops = {
.add_buf = vring_add_buf,
.get_buf = vring_get_buf,
.kick = vring_kick,
- .restart = vring_restart,
- .shutdown = vring_shutdown,
+ .disable_cb = vring_disable_cb,
+ .enable_cb = vring_enable_cb,
};
struct virtqueue *vring_new_virtqueue(unsigned int num,
struct virtio_device *vdev,
void *pages,
void (*notify)(struct virtqueue *),
- bool (*callback)(struct virtqueue *))
+ void (*callback)(struct virtqueue *))
{
struct vring_virtqueue *vq;
unsigned int i;
@@ -311,9 +319,12 @@
return &vq->vq;
}
+EXPORT_SYMBOL_GPL(vring_new_virtqueue);
void vring_del_virtqueue(struct virtqueue *vq)
{
kfree(to_vvq(vq));
}
+EXPORT_SYMBOL_GPL(vring_del_virtqueue);
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 8236d44..c449309 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -42,5 +42,15 @@
in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
hx4700.
+config W1_MASTER_GPIO
+ tristate "GPIO 1-wire busmaster"
+ depends on GENERIC_GPIO
+ help
+ Say Y here if you want to communicate with your 1-wire devices using
+ GPIO pins. This driver uses the GPIO API to control the wire.
+
+ This support is also available as a module. If so, the module
+ will be called w1-gpio.ko.
+
endmenu
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 11551b3..1420b5b 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
+obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
new file mode 100644
index 0000000..9e1138a
--- /dev/null
+++ b/drivers/w1/masters/w1-gpio.c
@@ -0,0 +1,124 @@
+/*
+ * w1-gpio - GPIO w1 bus master driver
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/w1-gpio.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#include <asm/gpio.h>
+
+static void w1_gpio_write_bit_dir(void *data, u8 bit)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ if (bit)
+ gpio_direction_input(pdata->pin);
+ else
+ gpio_direction_output(pdata->pin, 0);
+}
+
+static void w1_gpio_write_bit_val(void *data, u8 bit)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->pin, bit);
+}
+
+static u8 w1_gpio_read_bit(void *data)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->pin);
+}
+
+static int __init w1_gpio_probe(struct platform_device *pdev)
+{
+ struct w1_bus_master *master;
+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+ int err;
+
+ if (!pdata)
+ return -ENXIO;
+
+ master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ err = gpio_request(pdata->pin, "w1");
+ if (err)
+ goto free_master;
+
+ master->data = pdata;
+ master->read_bit = w1_gpio_read_bit;
+
+ if (pdata->is_open_drain) {
+ gpio_direction_output(pdata->pin, 1);
+ master->write_bit = w1_gpio_write_bit_val;
+ } else {
+ gpio_direction_input(pdata->pin);
+ master->write_bit = w1_gpio_write_bit_dir;
+ }
+
+ err = w1_add_master_device(master);
+ if (err)
+ goto free_gpio;
+
+ platform_set_drvdata(pdev, master);
+
+ return 0;
+
+ free_gpio:
+ gpio_free(pdata->pin);
+ free_master:
+ kfree(master);
+
+ return err;
+}
+
+static int __exit w1_gpio_remove(struct platform_device *pdev)
+{
+ struct w1_bus_master *master = platform_get_drvdata(pdev);
+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+ w1_remove_master_device(master);
+ gpio_free(pdata->pin);
+ kfree(master);
+
+ return 0;
+}
+
+static struct platform_driver w1_gpio_driver = {
+ .driver = {
+ .name = "w1-gpio",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(w1_gpio_remove),
+};
+
+static int __init w1_gpio_init(void)
+{
+ return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
+}
+
+static void __exit w1_gpio_exit(void)
+{
+ platform_driver_unregister(&w1_gpio_driver);
+}
+
+module_init(w1_gpio_init);
+module_exit(w1_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO w1 bus master driver");
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 112f4ec..fb28aca 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -92,6 +92,7 @@
int (*convert)(u8 rom[9]);
};
+/* The return value is millidegrees Centigrade. */
static inline int w1_DS18B20_convert_temp(u8 rom[9]);
static inline int w1_DS18S20_convert_temp(u8 rom[9]);
@@ -113,7 +114,7 @@
static inline int w1_DS18B20_convert_temp(u8 rom[9])
{
s16 t = (rom[1] << 8) | rom[0];
- t /= 16;
+ t = t*1000/16;
return t;
}
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 33e5031..7293c9b 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -675,7 +675,6 @@
struct w1_slave *sl;
struct list_head *ent;
struct w1_reg_num *tmp;
- int family_found = 0;
struct w1_master *dev;
u64 rn_le = cpu_to_le64(rn);
@@ -698,9 +697,6 @@
sl->reg_num.crc == tmp->crc) {
set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
break;
- } else if (sl->reg_num.family == tmp->family) {
- family_found = 1;
- break;
}
slave_count++;
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index cecbedd..61dde86 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -52,7 +52,7 @@
* overflow periods respectively.
*
* Also, since we can't really expect userspace to be responsive enough
- * before the overflow happens, we maintain two seperate timers .. One in
+ * before the overflow happens, we maintain two separate timers .. One in
* the kernel for clearing out WOVF every 2ms or so (again, this depends on
* HZ == 1000), and another for monitoring userspace writes to the WDT device.
*
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index b364da7..dfebdbe 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -175,7 +175,7 @@
if (!wnames)
return ERR_PTR(-ENOMEM);
- for (d = dentry, i = n; i >= 0; i--, d = d->d_parent)
+ for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent)
wnames[i] = (char *) d->d_name.name;
clone = 1;
@@ -183,7 +183,7 @@
while (i < n) {
l = min(n - i, P9_MAXWELEM);
fid = p9_client_walk(fid, l, &wnames[i], clone);
- if (!fid) {
+ if (IS_ERR(fid)) {
kfree(wnames);
return fid;
}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index fbb12da..9b0f022 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -3,7 +3,7 @@
*
* This file contains functions assisting in mapping VFS to 9P2000
*
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
* This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,6 @@
#include <linux/idr.h>
#include <net/9p/9p.h>
#include <net/9p/transport.h>
-#include <net/9p/conn.h>
#include <net/9p/client.h>
#include "v9fs.h"
#include "v9fs_vfs.h"
@@ -43,11 +42,11 @@
enum {
/* Options that take integer arguments */
- Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid,
+ Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
/* String options */
Opt_uname, Opt_remotename, Opt_trans,
/* Options that take no arguments */
- Opt_legacy, Opt_nodevmap,
+ Opt_nodevmap,
/* Cache options */
Opt_cache_loose,
/* Access options */
@@ -58,14 +57,11 @@
static match_table_t tokens = {
{Opt_debug, "debug=%x"},
- {Opt_msize, "msize=%u"},
{Opt_dfltuid, "dfltuid=%u"},
{Opt_dfltgid, "dfltgid=%u"},
{Opt_afid, "afid=%u"},
{Opt_uname, "uname=%s"},
{Opt_remotename, "aname=%s"},
- {Opt_trans, "trans=%s"},
- {Opt_legacy, "noextend"},
{Opt_nodevmap, "nodevmap"},
{Opt_cache_loose, "cache=loose"},
{Opt_cache_loose, "loose"},
@@ -85,16 +81,14 @@
char *options;
substring_t args[MAX_OPT_ARGS];
char *p;
- int option;
- int ret;
+ int option = 0;
char *s, *e;
+ int ret;
/* setup defaults */
- v9ses->maxdata = 8192;
v9ses->afid = ~0;
v9ses->debug = 0;
v9ses->cache = 0;
- v9ses->trans = v9fs_default_trans();
if (!v9ses->options)
return;
@@ -106,7 +100,8 @@
continue;
token = match_token(p, tokens, args);
if (token < Opt_uname) {
- if ((ret = match_int(&args[0], &option)) < 0) {
+ ret = match_int(&args[0], &option);
+ if (ret < 0) {
P9_DPRINTK(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
continue;
@@ -119,9 +114,7 @@
p9_debug_level = option;
#endif
break;
- case Opt_msize:
- v9ses->maxdata = option;
- break;
+
case Opt_dfltuid:
v9ses->dfltuid = option;
break;
@@ -131,18 +124,12 @@
case Opt_afid:
v9ses->afid = option;
break;
- case Opt_trans:
- v9ses->trans = v9fs_match_trans(&args[0]);
- break;
case Opt_uname:
match_strcpy(v9ses->uname, &args[0]);
break;
case Opt_remotename:
match_strcpy(v9ses->aname, &args[0]);
break;
- case Opt_legacy:
- v9ses->flags &= ~V9FS_EXTENDED;
- break;
case Opt_nodevmap:
v9ses->nodev = 1;
break;
@@ -185,7 +172,6 @@
const char *dev_name, char *data)
{
int retval = -EINVAL;
- struct p9_trans *trans = NULL;
struct p9_fid *fid;
v9ses->uname = __getname();
@@ -207,24 +193,7 @@
v9ses->options = kstrdup(data, GFP_KERNEL);
v9fs_parse_options(v9ses);
- if (v9ses->trans == NULL) {
- retval = -EPROTONOSUPPORT;
- P9_DPRINTK(P9_DEBUG_ERROR,
- "No transport defined or default transport\n");
- goto error;
- }
-
- trans = v9ses->trans->create(dev_name, v9ses->options);
- if (IS_ERR(trans)) {
- retval = PTR_ERR(trans);
- trans = NULL;
- goto error;
- }
- if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize)
- v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ;
-
- v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ,
- v9fs_extended(v9ses));
+ v9ses->clnt = p9_client_create(dev_name, v9ses->options);
if (IS_ERR(v9ses->clnt)) {
retval = PTR_ERR(v9ses->clnt);
@@ -236,6 +205,8 @@
if (!v9ses->clnt->dotu)
v9ses->flags &= ~V9FS_EXTENDED;
+ v9ses->maxdata = v9ses->clnt->msize;
+
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
if (!v9fs_extended(v9ses) &&
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index db4b419..7d3a101 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -1,7 +1,7 @@
/*
* V9FS definitions.
*
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,6 @@
struct v9fs_session_info {
/* options */
- unsigned int maxdata;
unsigned char flags; /* session flags */
unsigned char nodev; /* set to 1 if no disable device mapping */
unsigned short debug; /* debug level */
@@ -38,10 +37,10 @@
char *options; /* copy of mount options */
char *uname; /* user name to mount as */
char *aname; /* name of remote hierarchy being mounted */
+ unsigned int maxdata; /* max data for client interface */
unsigned int dfltuid; /* default uid/muid for legacy support */
unsigned int dfltgid; /* default gid for legacy support */
u32 uid; /* if ACCESS_SINGLE, the uid that has access */
- struct p9_trans_module *trans; /* 9p transport */
struct p9_client *clnt; /* 9p client */
struct dentry *debugfs_dir;
};
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index ba4b1ca..a616fff 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -184,7 +184,7 @@
.open = v9fs_file_open,
.release = v9fs_dir_release,
.lock = v9fs_file_lock,
- .mmap = generic_file_mmap,
+ .mmap = generic_file_readonly_mmap,
};
const struct file_operations v9fs_file_operations = {
@@ -194,5 +194,5 @@
.open = v9fs_file_open,
.release = v9fs_dir_release,
.lock = v9fs_file_lock,
- .mmap = generic_file_mmap,
+ .mmap = generic_file_readonly_mmap,
};
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 23581bc..5c5137c1 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -77,6 +77,8 @@
res |= P9_DMSETUID;
if ((mode & S_ISGID) == S_ISGID)
res |= P9_DMSETGID;
+ if ((mode & S_ISVTX) == S_ISVTX)
+ res |= P9_DMSETVTX;
if ((mode & P9_DMLINK))
res |= P9_DMLINK;
}
@@ -119,6 +121,9 @@
if ((mode & P9_DMSETGID) == P9_DMSETGID)
res |= S_ISGID;
+
+ if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
+ res |= S_ISVTX;
}
return res;
diff --git a/fs/Kconfig b/fs/Kconfig
index 219ec06..ea5b359 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1152,7 +1152,7 @@
depends on BEFS_FS
help
If you say Y here, you can use the 'debug' mount option to enable
- debugging output from the driver.
+ debugging output from the driver.
config BFS_FS
tristate "BFS file system support (EXPERIMENTAL)"
@@ -1263,7 +1263,7 @@
Extended attributes are name:value pairs associated with inodes by
the kernel or by users (see the attr(5) manual page, or visit
<http://acl.bestbits.at/> for details).
-
+
If unsure, say N.
config JFFS2_FS_POSIX_ACL
@@ -1274,10 +1274,10 @@
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
-
+
To learn more about Access Control Lists, visit the Posix ACLs for
Linux website <http://acl.bestbits.at/>.
-
+
If you don't know what Access Control Lists are, say N
config JFFS2_FS_SECURITY
@@ -1289,7 +1289,7 @@
implemented by security modules like SELinux. This option
enables an extended attribute handler for file security
labels in the jffs2 filesystem.
-
+
If you are not using a security module that requires using
extended attributes for file security labels, say N.
@@ -1674,6 +1674,8 @@
select CRYPTO_MD5 if NFSD_V4
select CRYPTO if NFSD_V4
select FS_POSIX_ACL if NFSD_V4
+ select PROC_FS if NFSD_V4
+ select PROC_FS if SUNRPC_GSS
help
If you want your Linux box to act as an NFS *server*, so that other
computers on your local network which support NFS can access certain
@@ -1833,7 +1835,7 @@
If unsure, say N.
config SMB_FS
- tristate "SMB file system support (to mount Windows shares etc.)"
+ tristate "SMB file system support (OBSOLETE, please use CIFS)"
depends on INET
select NLS
help
@@ -1856,8 +1858,8 @@
General information about how to connect Linux, Windows machines and
Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
- To compile the SMB support as a module, choose M here: the module will
- be called smbfs. Most people say N, however.
+ To compile the SMB support as a module, choose M here:
+ the module will be called smbfs. Most people say N, however.
config SMB_NLS_DEFAULT
bool "Use a default NLS"
@@ -1889,7 +1891,7 @@
smbmount from samba 2.2.0 or later supports this.
config CIFS
- tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)"
+ tristate "CIFS support (advanced network filesystem, SMBFS successor)"
depends on INET
select NLS
help
@@ -1947,16 +1949,16 @@
LANMAN based servers such as OS/2 and Windows 95, but such
mounts may be less secure than mounts using NTLM or more recent
security mechanisms if you are on a public network. Unless you
- have a need to access old SMB servers (and are on a private
+ have a need to access old SMB servers (and are on a private
network) you probably want to say N. Even if this support
is enabled in the kernel build, LANMAN authentication will not be
used automatically. At runtime LANMAN mounts are disabled but
can be set to required (or optional) either in
/proc/fs/cifs (see fs/cifs/README for more detail) or via an
- option on the mount command. This support is disabled by
+ option on the mount command. This support is disabled by
default in order to reduce the possibility of a downgrade
attack.
-
+
If unsure, say N.
config CIFS_XATTR
@@ -1997,7 +1999,7 @@
messages in some error paths, slowing performance. This
option can be turned off unless you are debugging
cifs problems. If unsure, say N.
-
+
config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL
@@ -2088,7 +2090,7 @@
However this new API is not backward compatible with older
clients. If you really need to run the old Coda userspace
cache manager then say Y.
-
+
For most cases you probably want to say N.
config AFS_FS
diff --git a/fs/befs/btree.c b/fs/befs/btree.c
index af5bb93..4202db7 100644
--- a/fs/befs/btree.c
+++ b/fs/befs/btree.c
@@ -232,7 +232,7 @@
* @key: Key string to lookup in btree
* @value: Value stored with @key
*
- * On sucess, returns BEFS_OK and sets *@value to the value stored
+ * On success, returns BEFS_OK and sets *@value to the value stored
* with @key (usually the disk block number of an inode).
*
* On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND.
diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c
index aacb4da..e3287d0 100644
--- a/fs/befs/datastream.c
+++ b/fs/befs/datastream.c
@@ -236,7 +236,7 @@
as in the indirect region code).
When/if blockno is found, if blockno is inside of a block
- run as stored on disk, we offset the start and lenght members
+ run as stored on disk, we offset the start and length members
of the block run, so that blockno is the start and len is
still valid (the run ends in the same place).
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 18ed6dd..111771d 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -117,7 +117,7 @@
return 0;
}
-/* Let's use some macros to make this stack manipulation a litle clearer */
+/* Let's use some macros to make this stack manipulation a little clearer */
#ifdef CONFIG_STACK_GROWSUP
#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))
#define STACK_ROUND(sp, items) \
@@ -1077,7 +1077,7 @@
current->mm->start_stack = bprm->p;
#ifdef arch_randomize_brk
- if (current->flags & PF_RANDOMIZE)
+ if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1))
current->mm->brk = current->mm->start_brk =
arch_randomize_brk(current->mm);
#endif
diff --git a/fs/block_dev.c b/fs/block_dev.c
index e48a630..e63067d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -534,7 +534,6 @@
if (err)
panic("Cannot register bdev pseudo-fs");
bd_mnt = kern_mount(&bd_type);
- err = PTR_ERR(bd_mnt);
if (IS_ERR(bd_mnt))
panic("Cannot create bdev pseudo-fs");
blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */
diff --git a/fs/buffer.c b/fs/buffer.c
index 456c9ab..826baf4f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1798,7 +1798,7 @@
start = max(from, block_start);
size = min(to, block_end) - start;
- zero_user_page(page, start, size, KM_USER0);
+ zero_user(page, start, size);
set_buffer_uptodate(bh);
}
@@ -1861,19 +1861,10 @@
mark_buffer_dirty(bh);
continue;
}
- if (block_end > to || block_start < from) {
- void *kaddr;
-
- kaddr = kmap_atomic(page, KM_USER0);
- if (block_end > to)
- memset(kaddr+to, 0,
- block_end-to);
- if (block_start < from)
- memset(kaddr+block_start,
- 0, from-block_start);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
- }
+ if (block_end > to || block_start < from)
+ zero_user_segments(page,
+ to, block_end,
+ block_start, from);
continue;
}
}
@@ -2104,8 +2095,7 @@
SetPageError(page);
}
if (!buffer_mapped(bh)) {
- zero_user_page(page, i * blocksize, blocksize,
- KM_USER0);
+ zero_user(page, i * blocksize, blocksize);
if (!err)
set_buffer_uptodate(bh);
continue;
@@ -2218,7 +2208,7 @@
&page, &fsdata);
if (err)
goto out;
- zero_user_page(page, zerofrom, len, KM_USER0);
+ zero_user(page, zerofrom, len);
err = pagecache_write_end(file, mapping, curpos, len, len,
page, fsdata);
if (err < 0)
@@ -2245,7 +2235,7 @@
&page, &fsdata);
if (err)
goto out;
- zero_user_page(page, zerofrom, len, KM_USER0);
+ zero_user(page, zerofrom, len);
err = pagecache_write_end(file, mapping, curpos, len, len,
page, fsdata);
if (err < 0)
@@ -2422,7 +2412,6 @@
unsigned block_in_page;
unsigned block_start, block_end;
sector_t block_in_file;
- char *kaddr;
int nr_reads = 0;
int ret = 0;
int is_mapped_to_disk = 1;
@@ -2493,13 +2482,8 @@
continue;
}
if (buffer_new(bh) || !buffer_mapped(bh)) {
- kaddr = kmap_atomic(page, KM_USER0);
- if (block_start < from)
- memset(kaddr+block_start, 0, from-block_start);
- if (block_end > to)
- memset(kaddr + to, 0, block_end - to);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_segments(page, block_start, from,
+ to, block_end);
continue;
}
if (buffer_uptodate(bh))
@@ -2636,7 +2620,7 @@
* the page size, the remaining memory is zeroed when mapped, and
* writes to that region are not written out to the file."
*/
- zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
+ zero_user_segment(page, offset, PAGE_CACHE_SIZE);
out:
ret = mpage_writepage(page, get_block, wbc);
if (ret == -EAGAIN)
@@ -2709,7 +2693,7 @@
if (page_has_buffers(page))
goto has_buffers;
}
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
set_page_dirty(page);
err = 0;
@@ -2785,7 +2769,7 @@
goto unlock;
}
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
mark_buffer_dirty(bh);
err = 0;
@@ -2831,7 +2815,7 @@
* the page size, the remaining memory is zeroed when mapped, and
* writes to that region are not written out to the file."
*/
- zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
+ zero_user_segment(page, offset, PAGE_CACHE_SIZE);
return __block_write_full_page(inode, page, get_block, wbc);
}
@@ -3169,7 +3153,7 @@
struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
{
- struct buffer_head *ret = kmem_cache_zalloc(bh_cachep,
+ struct buffer_head *ret = kmem_cache_alloc(bh_cachep,
set_migrateflags(gfp_flags, __GFP_RECLAIMABLE));
if (ret) {
INIT_LIST_HEAD(&ret->b_assoc_buffers);
@@ -3257,12 +3241,24 @@
}
EXPORT_SYMBOL(bh_submit_read);
+static void
+init_buffer_head(struct kmem_cache *cachep, void *data)
+{
+ struct buffer_head *bh = data;
+
+ memset(bh, 0, sizeof(*bh));
+ INIT_LIST_HEAD(&bh->b_assoc_buffers);
+}
+
void __init buffer_init(void)
{
int nrpages;
- bh_cachep = KMEM_CACHE(buffer_head,
- SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
+ bh_cachep = kmem_cache_create("buffer_head",
+ sizeof(struct buffer_head), 0,
+ (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
+ SLAB_MEM_SPREAD),
+ init_buffer_head);
/*
* Limit the bh occupancy to 10% of ZONE_NORMAL
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d9567ba..47f2621 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1386,7 +1386,7 @@
if (!page)
return -ENOMEM;
- zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
+ zero_user_segment(page, offset, PAGE_CACHE_SIZE);
unlock_page(page);
page_cache_release(page);
return rc;
diff --git a/fs/compat.c b/fs/compat.c
index 5216c3f..ee80ff3 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -2083,51 +2083,6 @@
#ifdef CONFIG_EPOLL
-#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
-asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
- struct compat_epoll_event __user *event)
-{
- long err = 0;
- struct compat_epoll_event user;
- struct epoll_event __user *kernel = NULL;
-
- if (event) {
- if (copy_from_user(&user, event, sizeof(user)))
- return -EFAULT;
- kernel = compat_alloc_user_space(sizeof(struct epoll_event));
- err |= __put_user(user.events, &kernel->events);
- err |= __put_user(user.data, &kernel->data);
- }
-
- return err ? err : sys_epoll_ctl(epfd, op, fd, kernel);
-}
-
-
-asmlinkage long compat_sys_epoll_wait(int epfd,
- struct compat_epoll_event __user *events,
- int maxevents, int timeout)
-{
- long i, ret, err = 0;
- struct epoll_event __user *kbuf;
- struct epoll_event ev;
-
- if ((maxevents <= 0) ||
- (maxevents > (INT_MAX / sizeof(struct epoll_event))))
- return -EINVAL;
- kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents);
- ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
- for (i = 0; i < ret; i++) {
- err |= __get_user(ev.events, &kbuf[i].events);
- err |= __get_user(ev.data, &kbuf[i].data);
- err |= __put_user(ev.events, &events->events);
- err |= __put_user_unaligned(ev.data, &events->data);
- events++;
- }
-
- return err ? -EFAULT: ret;
-}
-#endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */
-
#ifdef TIF_RESTORE_SIGMASK
asmlinkage long compat_sys_epoll_pwait(int epfd,
struct compat_epoll_event __user *events,
@@ -2153,11 +2108,7 @@
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}
-#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
- err = compat_sys_epoll_wait(epfd, events, maxevents, timeout);
-#else
err = sys_epoll_wait(epfd, events, maxevents, timeout);
-#endif
/*
* If we changed the signal mask, we need to restore the original one.
@@ -2206,19 +2157,41 @@
#ifdef CONFIG_TIMERFD
-asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
- const struct compat_itimerspec __user *utmr)
+asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
+ const struct compat_itimerspec __user *utmr,
+ struct compat_itimerspec __user *otmr)
{
+ int error;
struct itimerspec t;
struct itimerspec __user *ut;
if (get_compat_itimerspec(&t, utmr))
return -EFAULT;
- ut = compat_alloc_user_space(sizeof(*ut));
- if (copy_to_user(ut, &t, sizeof(t)))
+ ut = compat_alloc_user_space(2 * sizeof(struct itimerspec));
+ if (copy_to_user(&ut[0], &t, sizeof(t)))
return -EFAULT;
+ error = sys_timerfd_settime(ufd, flags, &ut[0], &ut[1]);
+ if (!error && otmr)
+ error = (copy_from_user(&t, &ut[1], sizeof(struct itimerspec)) ||
+ put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
- return sys_timerfd(ufd, clockid, flags, ut);
+ return error;
+}
+
+asmlinkage long compat_sys_timerfd_gettime(int ufd,
+ struct compat_itimerspec __user *otmr)
+{
+ int error;
+ struct itimerspec t;
+ struct itimerspec __user *ut;
+
+ ut = compat_alloc_user_space(sizeof(struct itimerspec));
+ error = sys_timerfd_gettime(ufd, ut);
+ if (!error)
+ error = (copy_from_user(&t, ut, sizeof(struct itimerspec)) ||
+ put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
+
+ return error;
}
#endif /* CONFIG_TIMERFD */
diff --git a/fs/dcache.c b/fs/dcache.c
index d9ca1e5..44f6cf2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -89,7 +89,7 @@
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
/* if dentry was never inserted into hash, immediate free is OK */
- if (dentry->d_hash.pprev == NULL)
+ if (hlist_unhashed(&dentry->d_hash))
__d_free(dentry);
else
call_rcu(&dentry->d_u.d_rcu, d_callback);
@@ -1408,9 +1408,6 @@
if (atomic_read(&dentry->d_count) == 1) {
dentry_iput(dentry);
fsnotify_nameremove(dentry, isdir);
-
- /* remove this and other inotify debug checks after 2.6.18 */
- dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
return;
}
diff --git a/fs/direct-io.c b/fs/direct-io.c
index acf0da1..9e81add 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -878,8 +878,8 @@
page_cache_release(page);
goto out;
}
- zero_user_page(page, block_in_page << blkbits,
- 1 << blkbits, KM_USER0);
+ zero_user(page, block_in_page << blkbits,
+ 1 << blkbits);
dio->block_in_file++;
block_in_page++;
goto next_block;
diff --git a/fs/dquot.c b/fs/dquot.c
index cee7c6f..def4e96 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -696,9 +696,8 @@
/* This routine is guarded by dqonoff_mutex mutex */
static void add_dquot_ref(struct super_block *sb, int type)
{
- struct inode *inode;
+ struct inode *inode, *old_inode = NULL;
-restart:
spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (!atomic_read(&inode->i_writecount))
@@ -711,12 +710,18 @@
__iget(inode);
spin_unlock(&inode_lock);
+ iput(old_inode);
sb->dq_op->initialize(inode, type);
- iput(inode);
- /* As we may have blocked we had better restart... */
- goto restart;
+ /* We hold a reference to 'inode' so it couldn't have been
+ * removed from s_inodes list while we dropped the inode_lock.
+ * We cannot iput the inode now as we can be holding the last
+ * reference and we cannot iput it under inode_lock. So we
+ * keep the reference and iput it later. */
+ old_inode = inode;
+ spin_lock(&inode_lock);
}
spin_unlock(&inode_lock);
+ iput(old_inode);
}
/* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index f8ef0af..a066e10 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -355,8 +355,11 @@
}
/* Consider doing this once, when the file is opened */
mutex_lock(&crypt_stat->cs_tfm_mutex);
- rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
- crypt_stat->key_size);
+ if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
+ rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
+ crypt_stat->key_size);
+ crypt_stat->flags |= ECRYPTFS_KEY_SET;
+ }
if (rc) {
ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
rc);
@@ -376,11 +379,10 @@
*
* Convert an eCryptfs page index into a lower byte offset
*/
-void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
- struct ecryptfs_crypt_stat *crypt_stat)
+static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
+ struct ecryptfs_crypt_stat *crypt_stat)
{
- (*offset) = ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
+ (*offset) = (crypt_stat->num_header_bytes_at_front
+ (crypt_stat->extent_size * extent_num));
}
@@ -842,15 +844,13 @@
set_extent_mask_and_shift(crypt_stat);
crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- crypt_stat->num_header_extents_at_front = 0;
+ crypt_stat->num_header_bytes_at_front = 0;
else {
if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
- crypt_stat->num_header_extents_at_front =
- (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE
- / crypt_stat->extent_size);
+ crypt_stat->num_header_bytes_at_front =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
else
- crypt_stat->num_header_extents_at_front =
- (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+ crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
}
}
@@ -1128,7 +1128,7 @@
struct ecryptfs_cipher_code_str_map_elem {
char cipher_str[16];
- u16 cipher_code;
+ u8 cipher_code;
};
/* Add support for additional ciphers by adding elements here. The
@@ -1152,10 +1152,10 @@
*
* Returns zero on no match, or the cipher code on match
*/
-u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
+u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
{
int i;
- u16 code = 0;
+ u8 code = 0;
struct ecryptfs_cipher_code_str_map_elem *map =
ecryptfs_cipher_code_str_map;
@@ -1187,7 +1187,7 @@
*
* Returns zero on success
*/
-int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code)
{
int rc = 0;
int i;
@@ -1236,7 +1236,8 @@
header_extent_size = (u32)crypt_stat->extent_size;
num_header_extents_at_front =
- (u16)crypt_stat->num_header_extents_at_front;
+ (u16)(crypt_stat->num_header_bytes_at_front
+ / crypt_stat->extent_size);
header_extent_size = cpu_to_be32(header_extent_size);
memcpy(virt, &header_extent_size, 4);
virt += 4;
@@ -1311,40 +1312,16 @@
static int
ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
struct dentry *ecryptfs_dentry,
- char *page_virt)
+ char *virt)
{
- int current_header_page;
- int header_pages;
int rc;
- rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
- 0, PAGE_CACHE_SIZE);
- if (rc) {
+ rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
+ 0, crypt_stat->num_header_bytes_at_front);
+ if (rc)
printk(KERN_ERR "%s: Error attempting to write header "
"information to lower file; rc = [%d]\n", __FUNCTION__,
rc);
- goto out;
- }
- header_pages = ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
- / PAGE_CACHE_SIZE);
- memset(page_virt, 0, PAGE_CACHE_SIZE);
- current_header_page = 1;
- while (current_header_page < header_pages) {
- loff_t offset;
-
- offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
- if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
- page_virt, offset,
- PAGE_CACHE_SIZE))) {
- printk(KERN_ERR "%s: Error attempting to write header "
- "information to lower file; rc = [%d]\n",
- __FUNCTION__, rc);
- goto out;
- }
- current_header_page++;
- }
-out:
return rc;
}
@@ -1370,15 +1347,13 @@
* retrieved via a prompt. Exactly what happens at this point should
* be policy-dependent.
*
- * TODO: Support header information spanning multiple pages
- *
* Returns zero on success; non-zero on error
*/
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
{
struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
- char *page_virt;
+ char *virt;
size_t size = 0;
int rc = 0;
@@ -1389,40 +1364,39 @@
goto out;
}
} else {
+ printk(KERN_WARNING "%s: Encrypted flag not set\n",
+ __FUNCTION__);
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING,
- "Called with crypt_stat->encrypted == 0\n");
goto out;
}
/* Released in this function */
- page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER);
- if (!page_virt) {
- ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
+ if (!virt) {
+ printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
rc = -ENOMEM;
goto out;
}
- rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat,
- ecryptfs_dentry);
+ rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat,
+ ecryptfs_dentry);
if (unlikely(rc)) {
- ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
- memset(page_virt, 0, PAGE_CACHE_SIZE);
+ printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
+ __FUNCTION__, rc);
goto out_free;
}
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
- crypt_stat, page_virt,
- size);
+ crypt_stat, virt, size);
else
rc = ecryptfs_write_metadata_to_contents(crypt_stat,
- ecryptfs_dentry,
- page_virt);
+ ecryptfs_dentry, virt);
if (rc) {
- printk(KERN_ERR "Error writing metadata out to lower file; "
- "rc = [%d]\n", rc);
+ printk(KERN_ERR "%s: Error writing metadata out to lower file; "
+ "rc = [%d]\n", __FUNCTION__, rc);
goto out_free;
}
out_free:
- kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+ memset(virt, 0, crypt_stat->num_header_bytes_at_front);
+ kfree(virt);
out:
return rc;
}
@@ -1442,16 +1416,16 @@
virt += sizeof(u32);
memcpy(&num_header_extents_at_front, virt, sizeof(u16));
num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
- crypt_stat->num_header_extents_at_front =
- (int)num_header_extents_at_front;
+ crypt_stat->num_header_bytes_at_front =
+ (((size_t)num_header_extents_at_front
+ * (size_t)header_extent_size));
(*bytes_read) = (sizeof(u32) + sizeof(u16));
if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
- && ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
+ && (crypt_stat->num_header_bytes_at_front
< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
rc = -EINVAL;
- printk(KERN_WARNING "Invalid number of header extents: [%zd]\n",
- crypt_stat->num_header_extents_at_front);
+ printk(KERN_WARNING "Invalid header size: [%zd]\n",
+ crypt_stat->num_header_bytes_at_front);
}
return rc;
}
@@ -1466,7 +1440,8 @@
*/
static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
{
- crypt_stat->num_header_extents_at_front = 2;
+ crypt_stat->num_header_bytes_at_front =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
}
/**
@@ -1552,9 +1527,10 @@
size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,
page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
if (size < 0) {
- printk(KERN_ERR "Error attempting to read the [%s] "
- "xattr from the lower file; return value = [%zd]\n",
- ECRYPTFS_XATTR_NAME, size);
+ if (unlikely(ecryptfs_verbosity > 0))
+ printk(KERN_INFO "Error attempting to read the [%s] "
+ "xattr from the lower file; return value = "
+ "[%zd]\n", ECRYPTFS_XATTR_NAME, size);
rc = -EINVAL;
goto out;
}
@@ -1802,7 +1778,7 @@
}
struct kmem_cache *ecryptfs_key_tfm_cache;
-struct list_head key_tfm_list;
+static struct list_head key_tfm_list;
struct mutex key_tfm_list_mutex;
int ecryptfs_init_crypto(void)
@@ -1812,6 +1788,11 @@
return 0;
}
+/**
+ * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list
+ *
+ * Called only at module unload time
+ */
int ecryptfs_destroy_crypto(void)
{
struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp;
@@ -1835,6 +1816,8 @@
struct ecryptfs_key_tfm *tmp_tfm;
int rc = 0;
+ BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
+
tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL);
if (key_tfm != NULL)
(*key_tfm) = tmp_tfm;
@@ -1861,13 +1844,50 @@
(*key_tfm) = NULL;
goto out;
}
- mutex_lock(&key_tfm_list_mutex);
list_add(&tmp_tfm->key_tfm_list, &key_tfm_list);
- mutex_unlock(&key_tfm_list_mutex);
out:
return rc;
}
+/**
+ * ecryptfs_tfm_exists - Search for existing tfm for cipher_name.
+ * @cipher_name: the name of the cipher to search for
+ * @key_tfm: set to corresponding tfm if found
+ *
+ * Searches for cached key_tfm matching @cipher_name
+ * Must be called with &key_tfm_list_mutex held
+ * Returns 1 if found, with @key_tfm set
+ * Returns 0 if not found, with @key_tfm set to NULL
+ */
+int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm)
+{
+ struct ecryptfs_key_tfm *tmp_key_tfm;
+
+ BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
+
+ list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) {
+ if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) {
+ if (key_tfm)
+ (*key_tfm) = tmp_key_tfm;
+ return 1;
+ }
+ }
+ if (key_tfm)
+ (*key_tfm) = NULL;
+ return 0;
+}
+
+/**
+ * ecryptfs_get_tfm_and_mutex_for_cipher_name
+ *
+ * @tfm: set to cached tfm found, or new tfm created
+ * @tfm_mutex: set to mutex for cached tfm found, or new tfm created
+ * @cipher_name: the name of the cipher to search for and/or add
+ *
+ * Sets pointers to @tfm & @tfm_mutex matching @cipher_name.
+ * Searches for cached item first, and creates new if not found.
+ * Returns 0 on success, non-zero if adding new cipher failed
+ */
int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
struct mutex **tfm_mutex,
char *cipher_name)
@@ -1877,22 +1897,17 @@
(*tfm) = NULL;
(*tfm_mutex) = NULL;
+
mutex_lock(&key_tfm_list_mutex);
- list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) {
- if (strcmp(key_tfm->cipher_name, cipher_name) == 0) {
- (*tfm) = key_tfm->key_tfm;
- (*tfm_mutex) = &key_tfm->key_tfm_mutex;
- mutex_unlock(&key_tfm_list_mutex);
+ if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) {
+ rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
+ if (rc) {
+ printk(KERN_ERR "Error adding new key_tfm to list; "
+ "rc = [%d]\n", rc);
goto out;
}
}
mutex_unlock(&key_tfm_list_mutex);
- rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
- if (rc) {
- printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n",
- rc);
- goto out;
- }
(*tfm) = key_tfm->key_tfm;
(*tfm_mutex) = &key_tfm->key_tfm_mutex;
out:
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index ce7a5d4..5007f78 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -234,10 +234,11 @@
#define ECRYPTFS_KEY_VALID 0x00000080
#define ECRYPTFS_METADATA_IN_XATTR 0x00000100
#define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200
+#define ECRYPTFS_KEY_SET 0x00000400
u32 flags;
unsigned int file_version;
size_t iv_bytes;
- size_t num_header_extents_at_front;
+ size_t num_header_bytes_at_front;
size_t extent_size; /* Data extent size; default is 4096 */
size_t key_size;
size_t extent_shift;
@@ -322,7 +323,6 @@
unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
};
-extern struct list_head key_tfm_list;
extern struct mutex key_tfm_list_mutex;
/**
@@ -521,11 +521,9 @@
extern struct kmem_cache *ecryptfs_dentry_info_cache;
extern struct kmem_cache *ecryptfs_inode_info_cache;
extern struct kmem_cache *ecryptfs_sb_info_cache;
-extern struct kmem_cache *ecryptfs_header_cache_0;
extern struct kmem_cache *ecryptfs_header_cache_1;
extern struct kmem_cache *ecryptfs_header_cache_2;
extern struct kmem_cache *ecryptfs_xattr_cache;
-extern struct kmem_cache *ecryptfs_lower_page_cache;
extern struct kmem_cache *ecryptfs_key_record_cache;
extern struct kmem_cache *ecryptfs_key_sig_cache;
extern struct kmem_cache *ecryptfs_global_auth_tok_cache;
@@ -562,8 +560,8 @@
struct inode *ecryptfs_inode);
int ecryptfs_read_and_validate_xattr_region(char *page_virt,
struct dentry *ecryptfs_dentry);
-u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
-int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code);
void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_generate_key_packet_set(char *dest_base,
struct ecryptfs_crypt_stat *crypt_stat,
@@ -576,8 +574,6 @@
int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
-ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
- size_t size);
ssize_t
ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
void *value, size_t size);
@@ -623,6 +619,7 @@
size_t key_size);
int ecryptfs_init_crypto(void);
int ecryptfs_destroy_crypto(void);
+int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm);
int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
struct mutex **tfm_mutex,
char *cipher_name);
@@ -631,8 +628,6 @@
char *sig);
int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
int num_zeros);
-void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
- struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
loff_t offset, size_t size);
int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
@@ -646,8 +641,6 @@
pgoff_t page_index,
size_t offset_in_page, size_t size,
struct inode *ecryptfs_inode);
-int ecryptfs_read(char *data, loff_t offset, size_t size,
- struct file *ecryptfs_file);
struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index c98c469..2b8f5ed 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -209,9 +209,10 @@
if (!(mount_crypt_stat->flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
rc = -EIO;
- printk(KERN_WARNING "Attempt to read file that "
+ printk(KERN_WARNING "Either the lower file "
"is not in a valid eCryptfs format, "
- "and plaintext passthrough mode is not "
+ "or the key could not be retrieved. "
+ "Plaintext passthrough mode is not "
"enabled; returning -EIO\n");
mutex_unlock(&crypt_stat->cs_mutex);
goto out_free;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 5a71918..edd1e44 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -365,8 +365,7 @@
dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- file_size = ((crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front)
+ file_size = (crypt_stat->num_header_bytes_at_front
+ i_size_read(lower_dentry->d_inode));
else
file_size = i_size_read(lower_dentry->d_inode);
@@ -685,7 +684,7 @@
* @crypt_stat: Crypt_stat associated with file
* @upper_size: Size of the upper file
*
- * Calculate the requried size of the lower file based on the
+ * Calculate the required size of the lower file based on the
* specified size of the upper file. This calculation is based on the
* number of headers in the underlying file and the extent size.
*
@@ -697,8 +696,7 @@
{
loff_t lower_size;
- lower_size = (crypt_stat->extent_size
- * crypt_stat->num_header_extents_at_front);
+ lower_size = crypt_stat->num_header_bytes_at_front;
if (upper_size != 0) {
loff_t num_extents;
@@ -875,11 +873,11 @@
if (!(mount_crypt_stat->flags
& ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
rc = -EIO;
- printk(KERN_WARNING "Attempt to read file that "
+ printk(KERN_WARNING "Either the lower file "
"is not in a valid eCryptfs format, "
- "and plaintext passthrough mode is not "
+ "or the key could not be retrieved. "
+ "Plaintext passthrough mode is not "
"enabled; returning -EIO\n");
-
mutex_unlock(&crypt_stat->cs_mutex);
goto out;
}
@@ -954,7 +952,7 @@
return rc;
}
-ssize_t
+static ssize_t
ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
size_t size)
{
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index f458c1f..682b1b2 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -189,7 +189,7 @@
}
static int
-parse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code,
+parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
struct ecryptfs_message *msg)
{
size_t i = 0;
@@ -275,7 +275,7 @@
static int
-write_tag_66_packet(char *signature, size_t cipher_code,
+write_tag_66_packet(char *signature, u8 cipher_code,
struct ecryptfs_crypt_stat *crypt_stat, char **packet,
size_t *packet_len)
{
@@ -428,7 +428,7 @@
decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_crypt_stat *crypt_stat)
{
- u16 cipher_code = 0;
+ u8 cipher_code = 0;
struct ecryptfs_msg_ctx *msg_ctx;
struct ecryptfs_message *msg = NULL;
char *auth_tok_sig;
@@ -1537,7 +1537,7 @@
struct scatterlist dst_sg;
struct scatterlist src_sg;
struct mutex *tfm_mutex = NULL;
- size_t cipher_code;
+ u8 cipher_code;
size_t packet_size_length;
size_t max_packet_size;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 0249aa4..778c420 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -117,7 +117,7 @@
*
* Returns zero on success; non-zero otherwise
*/
-int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
+static int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
{
struct ecryptfs_inode_info *inode_info =
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
@@ -226,17 +226,15 @@
return rc;
}
-enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
- ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
- ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
+enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
+ ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher,
+ ecryptfs_opt_ecryptfs_key_bytes,
ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
static match_table_t tokens = {
{ecryptfs_opt_sig, "sig=%s"},
{ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
- {ecryptfs_opt_debug, "debug=%u"},
- {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
{ecryptfs_opt_cipher, "cipher=%s"},
{ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
{ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
@@ -313,7 +311,6 @@
substring_t args[MAX_OPT_ARGS];
int token;
char *sig_src;
- char *debug_src;
char *cipher_name_dst;
char *cipher_name_src;
char *cipher_key_bytes_src;
@@ -341,16 +338,6 @@
}
sig_set = 1;
break;
- case ecryptfs_opt_debug:
- case ecryptfs_opt_ecryptfs_debug:
- debug_src = args[0].from;
- ecryptfs_verbosity =
- (int)simple_strtol(debug_src, &debug_src,
- 0);
- ecryptfs_printk(KERN_DEBUG,
- "Verbosity set to [%d]" "\n",
- ecryptfs_verbosity);
- break;
case ecryptfs_opt_cipher:
case ecryptfs_opt_ecryptfs_cipher:
cipher_name_src = args[0].from;
@@ -423,9 +410,13 @@
if (!cipher_key_bytes_set) {
mount_crypt_stat->global_default_cipher_key_size = 0;
}
- rc = ecryptfs_add_new_key_tfm(
- NULL, mount_crypt_stat->global_default_cipher_name,
- mount_crypt_stat->global_default_cipher_key_size);
+ mutex_lock(&key_tfm_list_mutex);
+ if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,
+ NULL))
+ rc = ecryptfs_add_new_key_tfm(
+ NULL, mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_key_size);
+ mutex_unlock(&key_tfm_list_mutex);
if (rc) {
printk(KERN_ERR "Error attempting to initialize cipher with "
"name = [%s] and key size = [%td]; rc = [%d]\n",
@@ -654,11 +645,6 @@
.size = sizeof(struct ecryptfs_sb_info),
},
{
- .cache = &ecryptfs_header_cache_0,
- .name = "ecryptfs_headers_0",
- .size = PAGE_CACHE_SIZE,
- },
- {
.cache = &ecryptfs_header_cache_1,
.name = "ecryptfs_headers_1",
.size = PAGE_CACHE_SIZE,
@@ -821,6 +807,10 @@
"rc = [%d]\n", rc);
goto out_release_messaging;
}
+ if (ecryptfs_verbosity > 0)
+ printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values "
+ "will be written to the syslog!\n", ecryptfs_verbosity);
+
goto out;
out_release_messaging:
ecryptfs_release_messaging(ecryptfs_transport);
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 32c5711..dc74b18 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -34,8 +34,6 @@
#include <linux/scatterlist.h>
#include "ecryptfs_kernel.h"
-struct kmem_cache *ecryptfs_lower_page_cache;
-
/**
* ecryptfs_get_locked_page
*
@@ -102,13 +100,14 @@
struct ecryptfs_crypt_stat *crypt_stat)
{
size_t written;
- int save_num_header_extents_at_front =
- crypt_stat->num_header_extents_at_front;
+ size_t save_num_header_bytes_at_front =
+ crypt_stat->num_header_bytes_at_front;
- crypt_stat->num_header_extents_at_front = 1;
+ crypt_stat->num_header_bytes_at_front =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
- crypt_stat->num_header_extents_at_front =
- save_num_header_extents_at_front;
+ crypt_stat->num_header_bytes_at_front =
+ save_num_header_bytes_at_front;
}
/**
@@ -134,8 +133,11 @@
loff_t view_extent_num = ((((loff_t)page->index)
* num_extents_per_page)
+ extent_num_in_page);
+ size_t num_header_extents_at_front =
+ (crypt_stat->num_header_bytes_at_front
+ / crypt_stat->extent_size);
- if (view_extent_num < crypt_stat->num_header_extents_at_front) {
+ if (view_extent_num < num_header_extents_at_front) {
/* This is a header extent */
char *page_virt;
@@ -157,9 +159,8 @@
} else {
/* This is an encrypted data extent */
loff_t lower_offset =
- ((view_extent_num -
- crypt_stat->num_header_extents_at_front)
- * crypt_stat->extent_size);
+ ((view_extent_num * crypt_stat->extent_size)
+ - crypt_stat->num_header_bytes_at_front);
rc = ecryptfs_read_lower_page_segment(
page, (lower_offset >> PAGE_CACHE_SHIFT),
@@ -257,8 +258,7 @@
end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
if (to > end_byte_in_page)
end_byte_in_page = to;
- zero_user_page(page, end_byte_in_page,
- PAGE_CACHE_SIZE - end_byte_in_page, KM_USER0);
+ zero_user_segment(page, end_byte_in_page, PAGE_CACHE_SIZE);
out:
return 0;
}
@@ -307,7 +307,7 @@
*/
if ((i_size_read(page->mapping->host) == prev_page_end_size) &&
(from != 0)) {
- zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_CACHE_SIZE);
}
out:
return rc;
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index 948f576..0c49286 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -293,6 +293,7 @@
return rc;
}
+#if 0
/**
* ecryptfs_read
* @data: The virtual address into which to write the data read (and
@@ -371,3 +372,4 @@
out:
return rc;
}
+#endif /* 0 */
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
index 4859c4e..c27ac2b 100644
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -156,32 +156,38 @@
/**
* ecryptfs_show_options
*
- * Prints the directory we are currently mounted over.
- * Returns zero on success; non-zero otherwise
+ * Prints the mount options for a given superblock.
+ * Returns zero; does not fail.
*/
static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
{
struct super_block *sb = mnt->mnt_sb;
- struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
- struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
- char *tmp_page;
- char *path;
- int rc = 0;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+ struct ecryptfs_global_auth_tok *walker;
- tmp_page = (char *)__get_free_page(GFP_KERNEL);
- if (!tmp_page) {
- rc = -ENOMEM;
- goto out;
+ mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
+ list_for_each_entry(walker,
+ &mount_crypt_stat->global_auth_tok_list,
+ mount_crypt_stat_list) {
+ seq_printf(m, ",ecryptfs_sig=%s", walker->sig);
}
- path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
- if (IS_ERR(path)) {
- rc = PTR_ERR(path);
- goto out;
- }
- seq_printf(m, ",dir=%s", path);
- free_page((unsigned long)tmp_page);
-out:
- return rc;
+ mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
+
+ seq_printf(m, ",ecryptfs_cipher=%s",
+ mount_crypt_stat->global_default_cipher_name);
+
+ if (mount_crypt_stat->global_default_cipher_key_size)
+ seq_printf(m, ",ecryptfs_key_bytes=%zd",
+ mount_crypt_stat->global_default_cipher_key_size);
+ if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)
+ seq_printf(m, ",ecryptfs_passthrough");
+ if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED)
+ seq_printf(m, ",ecryptfs_xattr_metadata");
+ if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)
+ seq_printf(m, ",ecryptfs_encrypted_view");
+
+ return 0;
}
const struct super_operations ecryptfs_sops = {
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 2ce19c0..a9f130c 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/anon_inodes.h>
#include <linux/eventfd.h>
+#include <linux/syscalls.h>
struct eventfd_ctx {
wait_queue_head_t wqh;
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 81c04ab..a415f42 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -353,7 +353,7 @@
spin_unlock_irqrestore(&psw->lock, flags);
/* Do really wake up now */
- wake_up(wq);
+ wake_up_nested(wq, 1 + wake_nests);
/* Remove the current task from the list */
spin_lock_irqsave(&psw->lock, flags);
diff --git a/fs/exec.c b/fs/exec.c
index 282240a..be923e4 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -760,7 +760,7 @@
*/
read_lock(&tasklist_lock);
spin_lock_irq(lock);
- if (sig->flags & SIGNAL_GROUP_EXIT) {
+ if (signal_group_exit(sig)) {
/*
* Another group action in progress, just
* return so that the signal is processed.
@@ -778,6 +778,7 @@
if (unlikely(tsk->group_leader == task_child_reaper(tsk)))
task_active_pid_ns(tsk)->child_reaper = tsk;
+ sig->group_exit_task = tsk;
zap_other_threads(tsk);
read_unlock(&tasklist_lock);
@@ -802,7 +803,6 @@
}
sig->notify_count = count;
- sig->group_exit_task = tsk;
while (atomic_read(&sig->count) > count) {
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(lock);
@@ -871,15 +871,10 @@
leader->exit_state = EXIT_DEAD;
write_unlock_irq(&tasklist_lock);
- }
+ }
sig->group_exit_task = NULL;
sig->notify_count = 0;
- /*
- * There may be one thread left which is just exiting,
- * but it's safe to stop telling the group to kill themselves.
- */
- sig->flags = 0;
no_thread_group:
exit_itimers(sig);
@@ -947,12 +942,13 @@
spin_unlock(&files->file_lock);
}
-void get_task_comm(char *buf, struct task_struct *tsk)
+char *get_task_comm(char *buf, struct task_struct *tsk)
{
/* buf must be at least sizeof(tsk->comm) in size */
task_lock(tsk);
strncpy(buf, tsk->comm, sizeof(tsk->comm));
task_unlock(tsk);
+ return buf;
}
void set_task_comm(struct task_struct *tsk, char *buf)
@@ -1548,7 +1544,7 @@
int err = -EAGAIN;
spin_lock_irq(&tsk->sighand->siglock);
- if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) {
+ if (!signal_group_exit(tsk->signal)) {
tsk->signal->group_exit_code = exit_code;
zap_process(tsk);
err = 0;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 377ad17..e7b2baf 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -69,9 +69,53 @@
return desc + offset;
}
+static int ext2_valid_block_bitmap(struct super_block *sb,
+ struct ext2_group_desc *desc,
+ unsigned int block_group,
+ struct buffer_head *bh)
+{
+ ext2_grpblk_t offset;
+ ext2_grpblk_t next_zero_bit;
+ ext2_fsblk_t bitmap_blk;
+ ext2_fsblk_t group_first_block;
+
+ group_first_block = ext2_group_first_block_no(sb, block_group);
+
+ /* check whether block bitmap block number is set */
+ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+ offset = bitmap_blk - group_first_block;
+ if (!ext2_test_bit(offset, bh->b_data))
+ /* bad block bitmap */
+ goto err_out;
+
+ /* check whether the inode bitmap block number is set */
+ bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
+ offset = bitmap_blk - group_first_block;
+ if (!ext2_test_bit(offset, bh->b_data))
+ /* bad block bitmap */
+ goto err_out;
+
+ /* check whether the inode table block number is set */
+ bitmap_blk = le32_to_cpu(desc->bg_inode_table);
+ offset = bitmap_blk - group_first_block;
+ next_zero_bit = ext2_find_next_zero_bit(bh->b_data,
+ offset + EXT2_SB(sb)->s_itb_per_group,
+ offset);
+ if (next_zero_bit >= offset + EXT2_SB(sb)->s_itb_per_group)
+ /* good bitmap for inode tables */
+ return 1;
+
+err_out:
+ ext2_error(sb, __FUNCTION__,
+ "Invalid block bitmap - "
+ "block_group = %d, block = %lu",
+ block_group, bitmap_blk);
+ return 0;
+}
+
/*
- * Read the bitmap for a given block_group, reading into the specified
- * slot in the superblock's bitmap cache.
+ * Read the bitmap for a given block_group,and validate the
+ * bits for block/inode/inode tables are set in the bitmaps
*
* Return buffer_head on success or NULL in case of failure.
*/
@@ -80,17 +124,36 @@
{
struct ext2_group_desc * desc;
struct buffer_head * bh = NULL;
-
- desc = ext2_get_group_desc (sb, block_group, NULL);
+ ext2_fsblk_t bitmap_blk;
+
+ desc = ext2_get_group_desc(sb, block_group, NULL);
if (!desc)
- goto error_out;
- bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
- if (!bh)
- ext2_error (sb, "read_block_bitmap",
+ return NULL;
+ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+ bh = sb_getblk(sb, bitmap_blk);
+ if (unlikely(!bh)) {
+ ext2_error(sb, __FUNCTION__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
-error_out:
+ return NULL;
+ }
+ if (likely(bh_uptodate_or_lock(bh)))
+ return bh;
+
+ if (bh_submit_read(bh) < 0) {
+ brelse(bh);
+ ext2_error(sb, __FUNCTION__,
+ "Cannot read block bitmap - "
+ "block_group = %d, block_bitmap = %u",
+ block_group, le32_to_cpu(desc->bg_block_bitmap));
+ return NULL;
+ }
+ if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) {
+ brelse(bh);
+ return NULL;
+ }
+
return bh;
}
@@ -474,11 +537,13 @@
in_range (block, le32_to_cpu(desc->bg_inode_table),
sbi->s_itb_per_group) ||
in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
- sbi->s_itb_per_group))
+ sbi->s_itb_per_group)) {
ext2_error (sb, "ext2_free_blocks",
"Freeing blocks in system zones - "
"Block = %lu, count = %lu",
block, count);
+ goto error_return;
+ }
for (i = 0, group_freed = 0; i < count; i++) {
if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
@@ -1250,8 +1315,8 @@
smp_rmb();
/*
- * Now search the rest of the groups. We assume that
- * i and gdp correctly point to the last group visited.
+ * Now search the rest of the groups. We assume that
+ * group_no and gdp correctly point to the last group visited.
*/
for (bgi = 0; bgi < ngroups; bgi++) {
group_no++;
@@ -1311,11 +1376,13 @@
in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
EXT2_SB(sb)->s_itb_per_group) ||
in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
- EXT2_SB(sb)->s_itb_per_group))
+ EXT2_SB(sb)->s_itb_per_group)) {
ext2_error(sb, "ext2_new_blocks",
"Allocating block in system zone - "
"blocks from "E2FSBLK", length %lu",
ret_block, num);
+ goto out;
+ }
performed_allocation = 1;
@@ -1466,9 +1533,6 @@
*/
unsigned long ext2_bg_num_gdb(struct super_block *sb, int group)
{
- if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
- !ext2_group_sparse(group))
- return 0;
- return EXT2_SB(sb)->s_gdb_count;
+ return ext2_bg_has_super(sb, group) ? EXT2_SB(sb)->s_gdb_count : 0;
}
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index d868e26..8dededd 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -703,7 +703,7 @@
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = ext2_readdir,
- .ioctl = ext2_ioctl,
+ .unlocked_ioctl = ext2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext2_compat_ioctl,
#endif
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index c87ae29..bb9948c 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -139,8 +139,7 @@
struct page **pagep, void **fsdata);
/* ioctl.c */
-extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
- unsigned long);
+extern long ext2_ioctl(struct file *, unsigned int, unsigned long);
extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long);
/* namei.c */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index c051798..5f2fa9c 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -48,7 +48,7 @@
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
- .ioctl = ext2_ioctl,
+ .unlocked_ioctl = ext2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext2_compat_ioctl,
#endif
@@ -65,7 +65,7 @@
.llseek = generic_file_llseek,
.read = xip_file_read,
.write = xip_file_write,
- .ioctl = ext2_ioctl,
+ .unlocked_ioctl = ext2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext2_compat_ioctl,
#endif
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index b1ab32a..03978ec 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -286,15 +286,12 @@
* ext2_find_goal - find a prefered place for allocation.
* @inode: owner
* @block: block we want
- * @chain: chain of indirect blocks
* @partial: pointer to the last triple within a chain
*
* Returns preferred place for a block (the goal).
*/
-static inline int ext2_find_goal(struct inode *inode,
- long block,
- Indirect chain[4],
+static inline int ext2_find_goal(struct inode *inode, long block,
Indirect *partial)
{
struct ext2_block_alloc_info *block_i;
@@ -569,7 +566,6 @@
*
* `handle' can be NULL if create == 0.
*
- * The BKL may not be held on entry here. Be sure to take it early.
* return > 0, # of blocks mapped or allocated.
* return = 0, if plain lookup failed.
* return < 0, error case.
@@ -639,7 +635,7 @@
if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
ext2_init_block_alloc_info(inode);
- goal = ext2_find_goal(inode, iblock, chain, partial);
+ goal = ext2_find_goal(inode, iblock, partial);
/* the number of blocks need to allocate for [d,t]indirect blocks */
indirect_blks = (chain + depth) - partial - 1;
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 320b2cb..b8ea11f 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -17,9 +17,9 @@
#include <asm/uaccess.h>
-int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
- unsigned long arg)
+long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_dentry->d_inode;
struct ext2_inode_info *ei = EXT2_I(inode);
unsigned int flags;
unsigned short rsv_window_size;
@@ -141,9 +141,6 @@
#ifdef CONFIG_COMPAT
long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- int ret;
-
/* These are just misnamed, they actually get/put from/to user an int */
switch (cmd) {
case EXT2_IOC32_GETFLAGS:
@@ -161,9 +158,6 @@
default:
return -ENOIOCTLCMD;
}
- lock_kernel();
- ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
- unlock_kernel();
- return ret;
+ return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
}
#endif
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 6abaf75..1ba18b7 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -234,16 +234,16 @@
le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {
seq_printf(seq, ",resgid=%u", sbi->s_resgid);
}
- if (test_opt(sb, ERRORS_CONT)) {
+ if (test_opt(sb, ERRORS_RO)) {
int def_errors = le16_to_cpu(es->s_errors);
if (def_errors == EXT2_ERRORS_PANIC ||
- def_errors == EXT2_ERRORS_RO) {
- seq_puts(seq, ",errors=continue");
+ def_errors == EXT2_ERRORS_CONTINUE) {
+ seq_puts(seq, ",errors=remount-ro");
}
}
- if (test_opt(sb, ERRORS_RO))
- seq_puts(seq, ",errors=remount-ro");
+ if (test_opt(sb, ERRORS_CONT))
+ seq_puts(seq, ",errors=continue");
if (test_opt(sb, ERRORS_PANIC))
seq_puts(seq, ",errors=panic");
if (test_opt(sb, NO_UID32))
@@ -617,27 +617,24 @@
return res;
}
-static int ext2_check_descriptors (struct super_block * sb)
+static int ext2_check_descriptors(struct super_block *sb)
{
int i;
- int desc_block = 0;
struct ext2_sb_info *sbi = EXT2_SB(sb);
unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
unsigned long last_block;
- struct ext2_group_desc * gdp = NULL;
ext2_debug ("Checking group descriptors");
- for (i = 0; i < sbi->s_groups_count; i++)
- {
+ for (i = 0; i < sbi->s_groups_count; i++) {
+ struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL);
+
if (i == sbi->s_groups_count - 1)
last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
else
last_block = first_block +
(EXT2_BLOCKS_PER_GROUP(sb) - 1);
- if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
- gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data;
if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
le32_to_cpu(gdp->bg_block_bitmap) > last_block)
{
@@ -667,7 +664,6 @@
return 0;
}
first_block += EXT2_BLOCKS_PER_GROUP(sb);
- gdp++;
}
return 1;
}
@@ -820,10 +816,10 @@
if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
set_opt(sbi->s_mount_opt, ERRORS_PANIC);
- else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
- set_opt(sbi->s_mount_opt, ERRORS_RO);
- else
+ else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
set_opt(sbi->s_mount_opt, ERRORS_CONT);
+ else
+ set_opt(sbi->s_mount_opt, ERRORS_RO);
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -868,8 +864,7 @@
blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
- if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
- (sb->s_blocksize != blocksize))) {
+ if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) {
if (!silent)
printk("XIP: Unsupported blocksize\n");
goto failed_mount;
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index a8ba7e8..a757130 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -80,13 +80,57 @@
return desc + offset;
}
+static int ext3_valid_block_bitmap(struct super_block *sb,
+ struct ext3_group_desc *desc,
+ unsigned int block_group,
+ struct buffer_head *bh)
+{
+ ext3_grpblk_t offset;
+ ext3_grpblk_t next_zero_bit;
+ ext3_fsblk_t bitmap_blk;
+ ext3_fsblk_t group_first_block;
+
+ group_first_block = ext3_group_first_block_no(sb, block_group);
+
+ /* check whether block bitmap block number is set */
+ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+ offset = bitmap_blk - group_first_block;
+ if (!ext3_test_bit(offset, bh->b_data))
+ /* bad block bitmap */
+ goto err_out;
+
+ /* check whether the inode bitmap block number is set */
+ bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
+ offset = bitmap_blk - group_first_block;
+ if (!ext3_test_bit(offset, bh->b_data))
+ /* bad block bitmap */
+ goto err_out;
+
+ /* check whether the inode table block number is set */
+ bitmap_blk = le32_to_cpu(desc->bg_inode_table);
+ offset = bitmap_blk - group_first_block;
+ next_zero_bit = ext3_find_next_zero_bit(bh->b_data,
+ offset + EXT3_SB(sb)->s_itb_per_group,
+ offset);
+ if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group)
+ /* good bitmap for inode tables */
+ return 1;
+
+err_out:
+ ext3_error(sb, __FUNCTION__,
+ "Invalid block bitmap - "
+ "block_group = %d, block = %lu",
+ block_group, bitmap_blk);
+ return 0;
+}
+
/**
* read_block_bitmap()
* @sb: super block
* @block_group: given block group
*
- * Read the bitmap for a given block_group, reading into the specified
- * slot in the superblock's bitmap cache.
+ * Read the bitmap for a given block_group,and validate the
+ * bits for block/inode/inode tables are set in the bitmaps
*
* Return buffer_head on success or NULL in case of failure.
*/
@@ -95,17 +139,35 @@
{
struct ext3_group_desc * desc;
struct buffer_head * bh = NULL;
+ ext3_fsblk_t bitmap_blk;
- desc = ext3_get_group_desc (sb, block_group, NULL);
+ desc = ext3_get_group_desc(sb, block_group, NULL);
if (!desc)
- goto error_out;
- bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
- if (!bh)
- ext3_error (sb, "read_block_bitmap",
+ return NULL;
+ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+ bh = sb_getblk(sb, bitmap_blk);
+ if (unlikely(!bh)) {
+ ext3_error(sb, __FUNCTION__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
-error_out:
+ return NULL;
+ }
+ if (likely(bh_uptodate_or_lock(bh)))
+ return bh;
+
+ if (bh_submit_read(bh) < 0) {
+ brelse(bh);
+ ext3_error(sb, __FUNCTION__,
+ "Cannot read block bitmap - "
+ "block_group = %d, block_bitmap = %u",
+ block_group, le32_to_cpu(desc->bg_block_bitmap));
+ return NULL;
+ }
+ if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) {
+ brelse(bh);
+ return NULL;
+ }
return bh;
}
/*
@@ -468,11 +530,13 @@
in_range (block, le32_to_cpu(desc->bg_inode_table),
sbi->s_itb_per_group) ||
in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
- sbi->s_itb_per_group))
+ sbi->s_itb_per_group)) {
ext3_error (sb, "ext3_free_blocks",
"Freeing blocks in system zones - "
"Block = "E3FSBLK", count = %lu",
block, count);
+ goto error_return;
+ }
/*
* We are about to start releasing blocks in the bitmap,
@@ -1508,7 +1572,7 @@
/*
* Now search the rest of the groups. We assume that
- * i and gdp correctly point to the last group visited.
+ * group_no and gdp correctly point to the last group visited.
*/
for (bgi = 0; bgi < ngroups; bgi++) {
group_no++;
@@ -1575,11 +1639,13 @@
in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
EXT3_SB(sb)->s_itb_per_group) ||
in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
- EXT3_SB(sb)->s_itb_per_group))
+ EXT3_SB(sb)->s_itb_per_group)) {
ext3_error(sb, "ext3_new_block",
"Allocating block in system zone - "
"blocks from "E3FSBLK", length %lu",
ret_block, num);
+ goto out;
+ }
performed_allocation = 1;
@@ -1782,11 +1848,7 @@
static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group)
{
- if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
- EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
- !ext3_group_sparse(group))
- return 0;
- return EXT3_SB(sb)->s_gdb_count;
+ return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;
}
/**
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 9b162cd..8a9ce2d 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -439,16 +439,14 @@
* ext3_find_goal - find a prefered place for allocation.
* @inode: owner
* @block: block we want
- * @chain: chain of indirect blocks
* @partial: pointer to the last triple within a chain
- * @goal: place to store the result.
*
* Normally this function find the prefered place for block allocation,
- * stores it in *@goal and returns zero.
+ * returns it.
*/
static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
- Indirect chain[4], Indirect *partial)
+ Indirect *partial)
{
struct ext3_block_alloc_info *block_i;
@@ -884,7 +882,7 @@
if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
ext3_init_block_alloc_info(inode);
- goal = ext3_find_goal(inode, iblock, chain, partial);
+ goal = ext3_find_goal(inode, iblock, partial);
/* the number of blocks need to allocate for [d,t]indirect blocks */
indirect_blks = (chain + depth) - partial - 1;
@@ -941,55 +939,45 @@
return err;
}
-#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
+/* Maximum number of blocks we map for direct IO at once. */
+#define DIO_MAX_BLOCKS 4096
+/*
+ * Number of credits we need for writing DIO_MAX_BLOCKS:
+ * We need sb + group descriptor + bitmap + inode -> 4
+ * For B blocks with A block pointers per block we need:
+ * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect).
+ * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25.
+ */
+#define DIO_CREDITS 25
static int ext3_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
handle_t *handle = ext3_journal_current_handle();
- int ret = 0;
+ int ret = 0, started = 0;
unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
- if (!create)
- goto get_block; /* A read */
-
- if (max_blocks == 1)
- goto get_block; /* A single block get */
-
- if (handle->h_transaction->t_state == T_LOCKED) {
- /*
- * Huge direct-io writes can hold off commits for long
- * periods of time. Let this commit run.
- */
- ext3_journal_stop(handle);
- handle = ext3_journal_start(inode, DIO_CREDITS);
- if (IS_ERR(handle))
+ if (create && !handle) { /* Direct IO write... */
+ if (max_blocks > DIO_MAX_BLOCKS)
+ max_blocks = DIO_MAX_BLOCKS;
+ handle = ext3_journal_start(inode, DIO_CREDITS +
+ 2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
- goto get_block;
- }
-
- if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
- /*
- * Getting low on buffer credits...
- */
- ret = ext3_journal_extend(handle, DIO_CREDITS);
- if (ret > 0) {
- /*
- * Couldn't extend the transaction. Start a new one.
- */
- ret = ext3_journal_restart(handle, DIO_CREDITS);
+ goto out;
}
+ started = 1;
}
-get_block:
- if (ret == 0) {
- ret = ext3_get_blocks_handle(handle, inode, iblock,
+ ret = ext3_get_blocks_handle(handle, inode, iblock,
max_blocks, bh_result, create, 0);
- if (ret > 0) {
- bh_result->b_size = (ret << inode->i_blkbits);
- ret = 0;
- }
+ if (ret > 0) {
+ bh_result->b_size = (ret << inode->i_blkbits);
+ ret = 0;
}
+ if (started)
+ ext3_journal_stop(handle);
+out:
return ret;
}
@@ -1680,7 +1668,8 @@
* if the machine crashes during the write.
*
* If the O_DIRECT write is intantiating holes inside i_size and the machine
- * crashes then stale disk data _may_ be exposed inside the file.
+ * crashes then stale disk data _may_ be exposed inside the file. But current
+ * VFS code falls back into buffered path in that case so we are safe.
*/
static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset,
@@ -1689,7 +1678,7 @@
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
struct ext3_inode_info *ei = EXT3_I(inode);
- handle_t *handle = NULL;
+ handle_t *handle;
ssize_t ret;
int orphan = 0;
size_t count = iov_length(iov, nr_segs);
@@ -1697,17 +1686,21 @@
if (rw == WRITE) {
loff_t final_size = offset + count;
- handle = ext3_journal_start(inode, DIO_CREDITS);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- goto out;
- }
if (final_size > inode->i_size) {
+ /* Credits for sb + inode write */
+ handle = ext3_journal_start(inode, 2);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto out;
+ }
ret = ext3_orphan_add(handle, inode);
- if (ret)
- goto out_stop;
+ if (ret) {
+ ext3_journal_stop(handle);
+ goto out;
+ }
orphan = 1;
ei->i_disksize = inode->i_size;
+ ext3_journal_stop(handle);
}
}
@@ -1715,18 +1708,21 @@
offset, nr_segs,
ext3_get_block, NULL);
- /*
- * Reacquire the handle: ext3_get_block() can restart the transaction
- */
- handle = ext3_journal_current_handle();
-
-out_stop:
- if (handle) {
+ if (orphan) {
int err;
- if (orphan && inode->i_nlink)
+ /* Credits for sb + inode write */
+ handle = ext3_journal_start(inode, 2);
+ if (IS_ERR(handle)) {
+ /* This is really bad luck. We've written the data
+ * but cannot extend i_size. Bail out and pretend
+ * the write failed... */
+ ret = PTR_ERR(handle);
+ goto out;
+ }
+ if (inode->i_nlink)
ext3_orphan_del(handle, inode);
- if (orphan && ret > 0) {
+ if (ret > 0) {
loff_t end = offset + ret;
if (end > inode->i_size) {
ei->i_disksize = end;
@@ -1845,7 +1841,7 @@
*/
if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
ext3_should_writeback_data(inode) && PageUptodate(page)) {
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
set_page_dirty(page);
goto unlock;
}
@@ -1898,7 +1894,7 @@
goto unlock;
}
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
BUFFER_TRACE(bh, "zeroed end of block");
err = 0;
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 4ab6f76..92b83b0 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -860,14 +860,10 @@
int nblocks, i, err;
struct inode *dir = dentry->d_parent->d_inode;
int namelen;
- const u8 *name;
- unsigned blocksize;
*res_dir = NULL;
sb = dir->i_sb;
- blocksize = sb->s_blocksize;
namelen = dentry->d_name.len;
- name = dentry->d_name.name;
if (namelen > EXT3_NAME_LEN)
return NULL;
if (is_dx(dir)) {
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index f3675cc..343677e 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -575,16 +575,16 @@
le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) {
seq_printf(seq, ",resgid=%u", sbi->s_resgid);
}
- if (test_opt(sb, ERRORS_CONT)) {
+ if (test_opt(sb, ERRORS_RO)) {
int def_errors = le16_to_cpu(es->s_errors);
if (def_errors == EXT3_ERRORS_PANIC ||
- def_errors == EXT3_ERRORS_RO) {
- seq_puts(seq, ",errors=continue");
+ def_errors == EXT3_ERRORS_CONTINUE) {
+ seq_puts(seq, ",errors=remount-ro");
}
}
- if (test_opt(sb, ERRORS_RO))
- seq_puts(seq, ",errors=remount-ro");
+ if (test_opt(sb, ERRORS_CONT))
+ seq_puts(seq, ",errors=continue");
if (test_opt(sb, ERRORS_PANIC))
seq_puts(seq, ",errors=panic");
if (test_opt(sb, NO_UID32))
@@ -1252,28 +1252,24 @@
}
/* Called at mount-time, super-block is locked */
-static int ext3_check_descriptors (struct super_block * sb)
+static int ext3_check_descriptors(struct super_block *sb)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
ext3_fsblk_t last_block;
- struct ext3_group_desc * gdp = NULL;
- int desc_block = 0;
int i;
ext3_debug ("Checking group descriptors");
- for (i = 0; i < sbi->s_groups_count; i++)
- {
+ for (i = 0; i < sbi->s_groups_count; i++) {
+ struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL);
+
if (i == sbi->s_groups_count - 1)
last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
else
last_block = first_block +
(EXT3_BLOCKS_PER_GROUP(sb) - 1);
- if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
- gdp = (struct ext3_group_desc *)
- sbi->s_group_desc[desc_block++]->b_data;
if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
le32_to_cpu(gdp->bg_block_bitmap) > last_block)
{
@@ -1306,7 +1302,6 @@
return 0;
}
first_block += EXT3_BLOCKS_PER_GROUP(sb);
- gdp++;
}
sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb));
@@ -1583,10 +1578,10 @@
if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC)
set_opt(sbi->s_mount_opt, ERRORS_PANIC);
- else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
- set_opt(sbi->s_mount_opt, ERRORS_RO);
- else
+ else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_CONTINUE)
set_opt(sbi->s_mount_opt, ERRORS_CONT);
+ else
+ set_opt(sbi->s_mount_opt, ERRORS_RO);
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index ac75ea9..0737e05 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -1700,7 +1700,7 @@
/*
* Now search the rest of the groups. We assume that
- * i and gdp correctly point to the last group visited.
+ * group_no and gdp correctly point to the last group visited.
*/
for (bgi = 0; bgi < ngroups; bgi++) {
group_no++;
@@ -2011,11 +2011,7 @@
static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
ext4_group_t group)
{
- if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
- EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
- !ext4_group_sparse(group))
- return 0;
- return EXT4_SB(sb)->s_gdb_count;
+ return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0;
}
/**
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index bb717cb..0e9055c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -429,16 +429,13 @@
* ext4_find_goal - find a prefered place for allocation.
* @inode: owner
* @block: block we want
- * @chain: chain of indirect blocks
* @partial: pointer to the last triple within a chain
- * @goal: place to store the result.
*
* Normally this function find the prefered place for block allocation,
- * stores it in *@goal and returns zero.
+ * returns it.
*/
-
static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
- Indirect chain[4], Indirect *partial)
+ Indirect *partial)
{
struct ext4_block_alloc_info *block_i;
@@ -839,7 +836,7 @@
if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
ext4_init_block_alloc_info(inode);
- goal = ext4_find_goal(inode, iblock, chain, partial);
+ goal = ext4_find_goal(inode, iblock, partial);
/* the number of blocks need to allocate for [d,t]indirect blocks */
indirect_blks = (chain + depth) - partial - 1;
@@ -1840,7 +1837,7 @@
*/
if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
ext4_should_writeback_data(inode) && PageUptodate(page)) {
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
set_page_dirty(page);
goto unlock;
}
@@ -1893,7 +1890,7 @@
goto unlock;
}
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
BUFFER_TRACE(bh, "zeroed end of block");
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 055a0cd..c89bb87 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1458,7 +1458,7 @@
}
/* Called at mount-time, super-block is locked */
-static int ext4_check_descriptors (struct super_block * sb)
+static int ext4_check_descriptors(struct super_block *sb)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
@@ -1466,8 +1466,6 @@
ext4_fsblk_t block_bitmap;
ext4_fsblk_t inode_bitmap;
ext4_fsblk_t inode_table;
- struct ext4_group_desc * gdp = NULL;
- int desc_block = 0;
int flexbg_flag = 0;
ext4_group_t i;
@@ -1476,17 +1474,15 @@
ext4_debug ("Checking group descriptors");
- for (i = 0; i < sbi->s_groups_count; i++)
- {
+ for (i = 0; i < sbi->s_groups_count; i++) {
+ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
+
if (i == sbi->s_groups_count - 1 || flexbg_flag)
last_block = ext4_blocks_count(sbi->s_es) - 1;
else
last_block = first_block +
(EXT4_BLOCKS_PER_GROUP(sb) - 1);
- if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
- gdp = (struct ext4_group_desc *)
- sbi->s_group_desc[desc_block++]->b_data;
block_bitmap = ext4_block_bitmap(sb, gdp);
if (block_bitmap < first_block || block_bitmap > last_block)
{
@@ -1524,8 +1520,6 @@
}
if (!flexbg_flag)
first_block += EXT4_BLOCKS_PER_GROUP(sb);
- gdp = (struct ext4_group_desc *)
- ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
}
ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 69a83b5..c614175 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -155,6 +155,42 @@
return err;
}
+static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
+{
+ mode_t req = mode & ~S_IFMT;
+
+ /*
+ * Of the r and x bits, all (subject to umask) must be present. Of the
+ * w bits, either all (subject to umask) or none must be present.
+ */
+
+ if (S_ISREG(mode)) {
+ req &= ~sbi->options.fs_fmask;
+
+ if ((req & (S_IRUGO | S_IXUGO)) !=
+ ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
+ return -EPERM;
+
+ if ((req & S_IWUGO) != 0 &&
+ (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
+ return -EPERM;
+ } else if (S_ISDIR(mode)) {
+ req &= ~sbi->options.fs_dmask;
+
+ if ((req & (S_IRUGO | S_IXUGO)) !=
+ ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
+ return -EPERM;
+
+ if ((req & S_IWUGO) != 0 &&
+ (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
+ return -EPERM;
+ } else {
+ return -EPERM;
+ }
+
+ return 0;
+}
+
int fat_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -186,9 +222,7 @@
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != sbi->options.fs_uid)) ||
((attr->ia_valid & ATTR_GID) &&
- (attr->ia_gid != sbi->options.fs_gid)) ||
- ((attr->ia_valid & ATTR_MODE) &&
- (attr->ia_mode & ~MSDOS_VALID_MODE)))
+ (attr->ia_gid != sbi->options.fs_gid)))
error = -EPERM;
if (error) {
@@ -196,6 +230,13 @@
error = 0;
goto out;
}
+
+ if (attr->ia_valid & ATTR_MODE) {
+ error = check_mode(sbi, attr->ia_mode);
+ if (error != 0 && !sbi->options.quiet)
+ goto out;
+ }
+
error = inode_setattr(inode, attr);
if (error)
goto out;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 920a576e..24c0aaa 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1295,10 +1295,8 @@
fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
if (!IS_FSINFO(fsinfo)) {
- printk(KERN_WARNING
- "FAT: Did not find valid FSINFO signature.\n"
- " Found signature1 0x%08x signature2 0x%08x"
- " (sector = %lu)\n",
+ printk(KERN_WARNING "FAT: Invalid FSINFO signature: "
+ "0x%08x, 0x%08x (sector = %lu)\n",
le32_to_cpu(fsinfo->signature1),
le32_to_cpu(fsinfo->signature2),
sbi->fsinfo_sector);
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 308f2b6..61f2351 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -55,9 +55,8 @@
fsinfo = (struct fat_boot_fsinfo *)bh->b_data;
/* Sanity check */
if (!IS_FSINFO(fsinfo)) {
- printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n"
- " Found signature1 0x%08x signature2 0x%08x"
- " (sector = %lu)\n",
+ printk(KERN_ERR "FAT: Invalid FSINFO signature: "
+ "0x%08x, 0x%08x (sector = %lu)\n",
le32_to_cpu(fsinfo->signature1),
le32_to_cpu(fsinfo->signature2),
sbi->fsinfo_sector);
diff --git a/fs/file.c b/fs/file.c
index c5575de..5110acb1 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -24,6 +24,8 @@
struct fdtable *next;
};
+int sysctl_nr_open __read_mostly = 1024*1024;
+
/*
* We use this list to defer free fdtables that have vmalloced
* sets/arrays. By keeping a per-cpu list, we avoid having to embed
@@ -147,8 +149,8 @@
nr /= (1024 / sizeof(struct file *));
nr = roundup_pow_of_two(nr + 1);
nr *= (1024 / sizeof(struct file *));
- if (nr > NR_OPEN)
- nr = NR_OPEN;
+ if (nr > sysctl_nr_open)
+ nr = sysctl_nr_open;
fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
if (!fdt)
@@ -233,7 +235,7 @@
if (nr < fdt->max_fds)
return 0;
/* Can we expand? */
- if (nr >= NR_OPEN)
+ if (nr >= sysctl_nr_open)
return -EMFILE;
/* All good, so we try */
diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h
index 3c96d6e..aaf1fb09 100644
--- a/fs/freevxfs/vxfs_dir.h
+++ b/fs/freevxfs/vxfs_dir.h
@@ -41,7 +41,7 @@
* VxFS directory block header.
*
* This entry is the head of every filesystem block in a directory.
- * It is used for free space managment and additionally includes
+ * It is used for free space management and additionally includes
* a hash for speeding up directory search (lookup).
*
* The hash may be empty and in fact we do not use it all in the
diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c
index 24b5a77..8a5959a 100644
--- a/fs/freevxfs/vxfs_immed.c
+++ b/fs/freevxfs/vxfs_immed.c
@@ -54,7 +54,7 @@
};
/*
- * Adress space operations for immed files and directories.
+ * Address space operations for immed files and directories.
*/
const struct address_space_operations vxfs_immed_aops = {
.readpage = vxfs_immed_readpage,
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 300324b..db80ce9 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -284,7 +284,17 @@
* soon as the queue becomes uncongested.
*/
inode->i_state |= I_DIRTY_PAGES;
- requeue_io(inode);
+ if (wbc->nr_to_write <= 0) {
+ /*
+ * slice used up: queue for next turn
+ */
+ requeue_io(inode);
+ } else {
+ /*
+ * somehow blocked: retry later
+ */
+ redirty_tail(inode);
+ }
} else {
/*
* Otherwise fully redirty the inode so that
@@ -334,9 +344,6 @@
WARN_ON(inode->i_state & I_WILL_FREE);
if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) {
- struct address_space *mapping = inode->i_mapping;
- int ret;
-
/*
* We're skipping this inode because it's locked, and we're not
* doing writeback-for-data-integrity. Move it to s_more_io so
@@ -345,15 +352,7 @@
* completed a full scan of s_io.
*/
requeue_io(inode);
-
- /*
- * Even if we don't actually write the inode itself here,
- * we can at least start some of the data writeout..
- */
- spin_unlock(&inode_lock);
- ret = do_writepages(mapping, wbc);
- spin_lock(&inode_lock);
- return ret;
+ return 0;
}
/*
@@ -479,8 +478,12 @@
iput(inode);
cond_resched();
spin_lock(&inode_lock);
- if (wbc->nr_to_write <= 0)
+ if (wbc->nr_to_write <= 0) {
+ wbc->more_io = 1;
break;
+ }
+ if (!list_empty(&sb->s_more_io))
+ wbc->more_io = 1;
}
return; /* Leave any unwritten inodes on s_io */
}
@@ -512,8 +515,7 @@
might_sleep();
spin_lock(&sb_lock);
restart:
- sb = sb_entry(super_blocks.prev);
- for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+ list_for_each_entry_reverse(sb, &super_blocks, s_list) {
if (sb_has_dirty_inodes(sb)) {
/* we're making our own get_super here */
sb->s_count++;
@@ -578,10 +580,8 @@
{
struct super_block *sb;
spin_lock(&sb_lock);
- sb = sb_entry(super_blocks.prev);
- for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+ list_for_each_entry_reverse(sb, &super_blocks, s_list)
sb->s_syncing = val;
- }
spin_unlock(&sb_lock);
}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index db534bcde..af639807 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -201,6 +201,55 @@
}
}
+static unsigned len_args(unsigned numargs, struct fuse_arg *args)
+{
+ unsigned nbytes = 0;
+ unsigned i;
+
+ for (i = 0; i < numargs; i++)
+ nbytes += args[i].size;
+
+ return nbytes;
+}
+
+static u64 fuse_get_unique(struct fuse_conn *fc)
+{
+ fc->reqctr++;
+ /* zero is special */
+ if (fc->reqctr == 0)
+ fc->reqctr = 1;
+
+ return fc->reqctr;
+}
+
+static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
+{
+ req->in.h.unique = fuse_get_unique(fc);
+ req->in.h.len = sizeof(struct fuse_in_header) +
+ len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
+ list_add_tail(&req->list, &fc->pending);
+ req->state = FUSE_REQ_PENDING;
+ if (!req->waiting) {
+ req->waiting = 1;
+ atomic_inc(&fc->num_waiting);
+ }
+ wake_up(&fc->waitq);
+ kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+}
+
+static void flush_bg_queue(struct fuse_conn *fc)
+{
+ while (fc->active_background < FUSE_MAX_BACKGROUND &&
+ !list_empty(&fc->bg_queue)) {
+ struct fuse_req *req;
+
+ req = list_entry(fc->bg_queue.next, struct fuse_req, list);
+ list_del(&req->list);
+ fc->active_background++;
+ queue_request(fc, req);
+ }
+}
+
/*
* This function is called when a request is finished. Either a reply
* has arrived or it was aborted (and not yet sent) or some error
@@ -229,6 +278,8 @@
clear_bdi_congested(&fc->bdi, WRITE);
}
fc->num_background--;
+ fc->active_background--;
+ flush_bg_queue(fc);
}
spin_unlock(&fc->lock);
wake_up(&req->waitq);
@@ -320,42 +371,6 @@
}
}
-static unsigned len_args(unsigned numargs, struct fuse_arg *args)
-{
- unsigned nbytes = 0;
- unsigned i;
-
- for (i = 0; i < numargs; i++)
- nbytes += args[i].size;
-
- return nbytes;
-}
-
-static u64 fuse_get_unique(struct fuse_conn *fc)
- {
- fc->reqctr++;
- /* zero is special */
- if (fc->reqctr == 0)
- fc->reqctr = 1;
-
- return fc->reqctr;
-}
-
-static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
-{
- req->in.h.unique = fuse_get_unique(fc);
- req->in.h.len = sizeof(struct fuse_in_header) +
- len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
- list_add_tail(&req->list, &fc->pending);
- req->state = FUSE_REQ_PENDING;
- if (!req->waiting) {
- req->waiting = 1;
- atomic_inc(&fc->num_waiting);
- }
- wake_up(&fc->waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
-}
-
void request_send(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
@@ -375,20 +390,26 @@
spin_unlock(&fc->lock);
}
+static void request_send_nowait_locked(struct fuse_conn *fc,
+ struct fuse_req *req)
+{
+ req->background = 1;
+ fc->num_background++;
+ if (fc->num_background == FUSE_MAX_BACKGROUND)
+ fc->blocked = 1;
+ if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
+ set_bdi_congested(&fc->bdi, READ);
+ set_bdi_congested(&fc->bdi, WRITE);
+ }
+ list_add_tail(&req->list, &fc->bg_queue);
+ flush_bg_queue(fc);
+}
+
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
{
spin_lock(&fc->lock);
if (fc->connected) {
- req->background = 1;
- fc->num_background++;
- if (fc->num_background == FUSE_MAX_BACKGROUND)
- fc->blocked = 1;
- if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
- set_bdi_congested(&fc->bdi, READ);
- set_bdi_congested(&fc->bdi, WRITE);
- }
-
- queue_request(fc, req);
+ request_send_nowait_locked(fc, req);
spin_unlock(&fc->lock);
} else {
req->out.h.error = -ENOTCONN;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 80d2f52..f56f91b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -416,6 +416,7 @@
fuse_put_request(fc, forget_req);
d_instantiate(entry, inode);
fuse_change_entry_timeout(entry, &outentry);
+ fuse_invalidate_attr(dir);
file = lookup_instantiate_filp(nd, entry, generic_file_open);
if (IS_ERR(file)) {
ff->fh = outopen.fh;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index bb05d22..676b0bc 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -77,8 +77,8 @@
static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
{
- dput(req->dentry);
- mntput(req->vfsmount);
+ dput(req->misc.release.dentry);
+ mntput(req->misc.release.vfsmount);
fuse_put_request(fc, req);
}
@@ -86,7 +86,8 @@
{
if (atomic_dec_and_test(&ff->count)) {
struct fuse_req *req = ff->reserved_req;
- struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode);
+ struct inode *inode = req->misc.release.dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
req->end = fuse_release_end;
request_send_background(fc, req);
kfree(ff);
@@ -137,7 +138,7 @@
void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode)
{
struct fuse_req *req = ff->reserved_req;
- struct fuse_release_in *inarg = &req->misc.release_in;
+ struct fuse_release_in *inarg = &req->misc.release.in;
inarg->fh = ff->fh;
inarg->flags = flags;
@@ -153,13 +154,14 @@
struct fuse_file *ff = file->private_data;
if (ff) {
struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_req *req = ff->reserved_req;
fuse_release_fill(ff, get_node_id(inode), file->f_flags,
isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
/* Hold vfsmount and dentry until release is finished */
- ff->reserved_req->vfsmount = mntget(file->f_path.mnt);
- ff->reserved_req->dentry = dget(file->f_path.dentry);
+ req->misc.release.vfsmount = mntget(file->f_path.mnt);
+ req->misc.release.dentry = dget(file->f_path.dentry);
spin_lock(&fc->lock);
list_del(&ff->write_entry);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 3ab8a30..67aaf6e 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -215,7 +215,11 @@
/** Data for asynchronous requests */
union {
struct fuse_forget_in forget_in;
- struct fuse_release_in release_in;
+ struct {
+ struct fuse_release_in in;
+ struct vfsmount *vfsmount;
+ struct dentry *dentry;
+ } release;
struct fuse_init_in init_in;
struct fuse_init_out init_out;
struct fuse_read_in read_in;
@@ -238,12 +242,6 @@
/** File used in the request (or NULL) */
struct fuse_file *ff;
- /** vfsmount used in release */
- struct vfsmount *vfsmount;
-
- /** dentry used in release */
- struct dentry *dentry;
-
/** Request completion callback */
void (*end)(struct fuse_conn *, struct fuse_req *);
@@ -298,6 +296,12 @@
/** Number of requests currently in the background */
unsigned num_background;
+ /** Number of background requests currently queued for userspace */
+ unsigned active_background;
+
+ /** The list of background requests set aside for later queuing */
+ struct list_head bg_queue;
+
/** Pending interrupts */
struct list_head interrupts;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e5e80d1..c90f633 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -465,6 +465,7 @@
INIT_LIST_HEAD(&fc->processing);
INIT_LIST_HEAD(&fc->io);
INIT_LIST_HEAD(&fc->interrupts);
+ INIT_LIST_HEAD(&fc->bg_queue);
atomic_set(&fc->num_waiting, 0);
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index e4effc4..e9456eb 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -932,7 +932,7 @@
if (!gfs2_is_writeback(ip))
gfs2_trans_add_bh(ip->i_gl, bh, 0);
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
unlock:
unlock_page(page);
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 38dbe99..ac772b6 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -446,7 +446,7 @@
* so we need to supply one here. It doesn't happen often.
*/
if (unlikely(page->index)) {
- zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_CACHE_SIZE);
return 0;
}
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index b249e29..6fb07d6 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -450,7 +450,7 @@
fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
jd->jd_jid);
- /* Aquire the journal lock so we can do recovery */
+ /* Acquire the journal lock so we can do recovery */
error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
LM_ST_EXCLUSIVE,
diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c
index f8452a0..4129cdb 100644
--- a/fs/hfs/bfind.c
+++ b/fs/hfs/bfind.c
@@ -52,9 +52,9 @@
rec = (e + b) / 2;
len = hfs_brec_lenoff(bnode, rec, &off);
keylen = hfs_brec_keylen(bnode, rec);
- if (keylen == HFS_BAD_KEYLEN) {
+ if (keylen == 0) {
res = -EINVAL;
- goto done;
+ goto fail;
}
hfs_bnode_read(bnode, fd->key, off, keylen);
cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
@@ -71,9 +71,9 @@
if (rec != e && e >= 0) {
len = hfs_brec_lenoff(bnode, e, &off);
keylen = hfs_brec_keylen(bnode, e);
- if (keylen == HFS_BAD_KEYLEN) {
+ if (keylen == 0) {
res = -EINVAL;
- goto done;
+ goto fail;
}
hfs_bnode_read(bnode, fd->key, off, keylen);
}
@@ -83,6 +83,7 @@
fd->keylength = keylen;
fd->entryoffset = off + keylen;
fd->entrylength = len - keylen;
+fail:
return res;
}
@@ -206,7 +207,7 @@
len = hfs_brec_lenoff(bnode, fd->record, &off);
keylen = hfs_brec_keylen(bnode, fd->record);
- if (keylen == HFS_BAD_KEYLEN) {
+ if (keylen == 0) {
res = -EINVAL;
goto out;
}
diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c
index 8626ee3..878bf25 100644
--- a/fs/hfs/brec.c
+++ b/fs/hfs/brec.c
@@ -49,14 +49,14 @@
if (retval > node->tree->max_key_len + 2) {
printk(KERN_ERR "hfs: keylen %d too large\n",
retval);
- retval = HFS_BAD_KEYLEN;
+ retval = 0;
}
} else {
retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
if (retval > node->tree->max_key_len + 1) {
printk(KERN_ERR "hfs: keylen %d too large\n",
retval);
- retval = HFS_BAD_KEYLEN;
+ retval = 0;
}
}
}
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 110dd35..24cf6fc 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -81,15 +81,23 @@
goto fail_page;
if (!tree->node_count)
goto fail_page;
- if ((id == HFS_EXT_CNID) && (tree->max_key_len != HFS_MAX_EXT_KEYLEN)) {
- printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
- tree->max_key_len);
- goto fail_page;
- }
- if ((id == HFS_CAT_CNID) && (tree->max_key_len != HFS_MAX_CAT_KEYLEN)) {
- printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
- tree->max_key_len);
- goto fail_page;
+ switch (id) {
+ case HFS_EXT_CNID:
+ if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
+ printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
+ tree->max_key_len);
+ goto fail_page;
+ }
+ break;
+ case HFS_CAT_CNID:
+ if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
+ printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
+ tree->max_key_len);
+ goto fail_page;
+ }
+ break;
+ default:
+ BUG();
}
tree->node_size_shift = ffs(size) - 1;
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h
index c6aae61..6f194d0 100644
--- a/fs/hfs/hfs.h
+++ b/fs/hfs/hfs.h
@@ -28,8 +28,6 @@
#define HFS_MAX_NAMELEN 128
#define HFS_MAX_VALENCE 32767U
-#define HFS_BAD_KEYLEN 0xFF
-
/* Meanings of the drAtrb field of the MDB,
* Reference: _Inside Macintosh: Files_ p. 2-61
*/
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 16cbd90..32de44e 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -6,7 +6,7 @@
* This file may be distributed under the terms of the GNU General Public License.
*
* This file contains hfs_read_super(), some of the super_ops and
- * init_module() and cleanup_module(). The remaining super_ops are in
+ * init_hfs_fs() and exit_hfs_fs(). The remaining super_ops are in
* inode.c since they deal with inodes.
*
* Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 35c1a9f..53fd0a6 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -285,17 +285,17 @@
return err;
times[0].tv_sec = atime_ts.tv_sec;
- times[0].tv_usec = atime_ts.tv_nsec * 1000;
+ times[0].tv_usec = atime_ts.tv_nsec / 1000;
times[1].tv_sec = mtime_ts.tv_sec;
- times[1].tv_usec = mtime_ts.tv_nsec * 1000;
+ times[1].tv_usec = mtime_ts.tv_nsec / 1000;
if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
times[0].tv_sec = attrs->ia_atime.tv_sec;
- times[0].tv_usec = attrs->ia_atime.tv_nsec * 1000;
+ times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000;
}
if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
times[1].tv_sec = attrs->ia_mtime.tv_sec;
- times[1].tv_usec = attrs->ia_mtime.tv_nsec * 1000;
+ times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000;
}
if (fd >= 0) {
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 09ee07f..3b3cc28 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -768,7 +768,7 @@
case Opt_mode:
if (match_octal(&args[0], &option))
goto bad_val;
- pconfig->mode = option & 0777U;
+ pconfig->mode = option & 01777U;
break;
case Opt_size: {
diff --git a/fs/inotify.c b/fs/inotify.c
index 2c5b921..690e725 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -168,20 +168,14 @@
struct dentry *child;
list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
- if (!child->d_inode) {
- WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
+ if (!child->d_inode)
continue;
- }
+
spin_lock(&child->d_lock);
- if (watched) {
- WARN_ON(child->d_flags &
- DCACHE_INOTIFY_PARENT_WATCHED);
+ if (watched)
child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
- } else {
- WARN_ON(!(child->d_flags &
- DCACHE_INOTIFY_PARENT_WATCHED));
- child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED;
- }
+ else
+ child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED;
spin_unlock(&child->d_lock);
}
}
@@ -253,7 +247,6 @@
if (!inode)
return;
- WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
spin_lock(&entry->d_lock);
parent = entry->d_parent;
if (parent->d_inode && inotify_inode_watched(parent->d_inode))
@@ -627,6 +620,7 @@
struct inode *inode, u32 mask)
{
int ret = 0;
+ int newly_watched;
/* don't allow invalid bits: we don't want flags set */
mask &= IN_ALL_EVENTS | IN_ONESHOT;
@@ -653,12 +647,18 @@
*/
watch->inode = igrab(inode);
- if (!inotify_inode_watched(inode))
- set_dentry_child_flags(inode, 1);
-
/* Add the watch to the handle's and the inode's list */
+ newly_watched = !inotify_inode_watched(inode);
list_add(&watch->h_list, &ih->watches);
list_add(&watch->i_list, &inode->inotify_watches);
+ /*
+ * Set child flags _after_ adding the watch, so there is no race
+ * windows where newly instantiated children could miss their parent's
+ * watched flag.
+ */
+ if (newly_watched)
+ set_dentry_child_flags(inode, 1);
+
out:
mutex_unlock(&ih->mutex);
mutex_unlock(&inode->inotify_mutex);
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 5e00933..a336c97 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -79,6 +79,7 @@
atomic_t count; /* reference count */
struct user_struct *user; /* user who opened this dev */
struct inotify_handle *ih; /* inotify handle */
+ struct fasync_struct *fa; /* async notification */
unsigned int queue_size; /* size of the queue (bytes) */
unsigned int event_count; /* number of pending events */
unsigned int max_events; /* maximum number of events */
@@ -248,6 +249,19 @@
}
/*
+ * inotify_dev_get_last_event - return the last event in the given dev's queue
+ *
+ * Caller must hold dev->ev_mutex.
+ */
+static inline struct inotify_kernel_event *
+inotify_dev_get_last_event(struct inotify_device *dev)
+{
+ if (list_empty(&dev->events))
+ return NULL;
+ return list_entry(dev->events.prev, struct inotify_kernel_event, list);
+}
+
+/*
* inotify_dev_queue_event - event handler registered with core inotify, adds
* a new event to the given device
*
@@ -273,7 +287,7 @@
put_inotify_watch(w); /* final put */
/* coalescing: drop this event if it is a dupe of the previous */
- last = inotify_dev_get_event(dev);
+ last = inotify_dev_get_last_event(dev);
if (last && last->event.mask == mask && last->event.wd == wd &&
last->event.cookie == cookie) {
const char *lastname = last->name;
@@ -302,6 +316,7 @@
dev->queue_size += sizeof(struct inotify_event) + kevent->event.len;
list_add_tail(&kevent->list, &dev->events);
wake_up_interruptible(&dev->wq);
+ kill_fasync(&dev->fa, SIGIO, POLL_IN);
out:
mutex_unlock(&dev->ev_mutex);
@@ -490,6 +505,13 @@
return ret;
}
+static int inotify_fasync(int fd, struct file *file, int on)
+{
+ struct inotify_device *dev = file->private_data;
+
+ return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO;
+}
+
static int inotify_release(struct inode *ignored, struct file *file)
{
struct inotify_device *dev = file->private_data;
@@ -502,6 +524,9 @@
inotify_dev_event_dequeue(dev);
mutex_unlock(&dev->ev_mutex);
+ if (file->f_flags & FASYNC)
+ inotify_fasync(-1, file, 0);
+
/* free this device: the put matching the get in inotify_init() */
put_inotify_dev(dev);
@@ -530,6 +555,7 @@
static const struct file_operations inotify_fops = {
.poll = inotify_poll,
.read = inotify_read,
+ .fasync = inotify_fasync,
.release = inotify_release,
.unlocked_ioctl = inotify_ioctl,
.compat_ioctl = inotify_ioctl,
@@ -577,6 +603,7 @@
goto out_free_dev;
}
dev->ih = ih;
+ dev->fa = NULL;
filp->f_op = &inotify_fops;
filp->f_path.mnt = mntget(inotify_mnt);
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 5d14243..3943a89 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1457,7 +1457,7 @@
* Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
* and don't attempt to make any other journal updates.
*/
-void __journal_abort_hard(journal_t *journal)
+static void __journal_abort_hard(journal_t *journal)
{
transaction_t *transaction;
char b[BDEVNAME_SIZE];
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index c5d9694..2b8edf4 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -354,7 +354,7 @@
struct buffer_head * obh;
struct buffer_head * nbh;
- cond_resched(); /* We're under lock_kernel() */
+ cond_resched();
/* If we already know where to stop the log traversal,
* check right now that we haven't gone past the end of
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 92168066..d36356f 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -397,7 +397,7 @@
struct buffer_head * obh;
struct buffer_head * nbh;
- cond_resched(); /* We're under lock_kernel() */
+ cond_resched();
/* If we already know where to stop the log traversal,
* check right now that we haven't gone past the end of
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 2eae5d2..6c1ba35 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -741,7 +741,7 @@
* are not obsolete.
*
* Of course, this optimization only makes sense in case
- * of NAND flashes (or other flashes whith
+ * of NAND flashes (or other flashes with
* !jffs2_can_mark_obsolete()), since on NOR flashes
* nodes are marked obsolete physically.
*
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index 1543906..a000aaa 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -3965,7 +3965,7 @@
* xtTruncate_pmap()
*
* function:
- * Perform truncate to zero lenghth for deleted file, leaving the
+ * Perform truncate to zero length for deleted file, leaving the
* the xtree and working map untouched. This allows the file to
* be accessed via open file handles, while the delete of the file
* is committed to disk.
diff --git a/fs/libfs.c b/fs/libfs.c
index 6e68b70..5523bde 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -341,13 +341,10 @@
unsigned from, unsigned to)
{
if (!PageUptodate(page)) {
- if (to - from != PAGE_CACHE_SIZE) {
- void *kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr, 0, from);
- memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
- }
+ if (to - from != PAGE_CACHE_SIZE)
+ zero_user_segments(page,
+ 0, from,
+ to, PAGE_CACHE_SIZE);
}
return 0;
}
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 572601e9..ca6b16f 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -34,10 +34,10 @@
static void nlm_gc_hosts(void);
static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
- const char *, int, int);
+ const char *, unsigned int, int);
static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
const char *hostname,
- int hostname_len);
+ unsigned int hostname_len);
/*
* Common host lookup routine for server & client
@@ -45,7 +45,8 @@
static struct nlm_host *
nlm_lookup_host(int server, const struct sockaddr_in *sin,
int proto, int version, const char *hostname,
- int hostname_len, const struct sockaddr_in *ssin)
+ unsigned int hostname_len,
+ const struct sockaddr_in *ssin)
{
struct hlist_head *chain;
struct hlist_node *pos;
@@ -176,7 +177,7 @@
*/
struct nlm_host *
nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
- const char *hostname, int hostname_len)
+ const char *hostname, unsigned int hostname_len)
{
struct sockaddr_in ssin = {0};
@@ -189,7 +190,7 @@
*/
struct nlm_host *
nlmsvc_lookup_host(struct svc_rqst *rqstp,
- const char *hostname, int hostname_len)
+ const char *hostname, unsigned int hostname_len)
{
struct sockaddr_in ssin = {0};
@@ -307,7 +308,8 @@
* Release all resources held by that peer.
*/
void nlm_host_rebooted(const struct sockaddr_in *sin,
- const char *hostname, int hostname_len,
+ const char *hostname,
+ unsigned int hostname_len,
u32 new_state)
{
struct hlist_head *chain;
@@ -377,8 +379,13 @@
/* First, make all hosts eligible for gc */
dprintk("lockd: nuking all hosts...\n");
for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
- hlist_for_each_entry(host, pos, chain, h_hash)
+ hlist_for_each_entry(host, pos, chain, h_hash) {
host->h_expires = jiffies - 1;
+ if (host->h_rpcclnt) {
+ rpc_shutdown_client(host->h_rpcclnt);
+ host->h_rpcclnt = NULL;
+ }
+ }
}
/* Then, perform a garbage collection pass */
@@ -449,7 +456,7 @@
static struct nsm_handle *
__nsm_find(const struct sockaddr_in *sin,
- const char *hostname, int hostname_len,
+ const char *hostname, unsigned int hostname_len,
int create)
{
struct nsm_handle *nsm = NULL;
@@ -503,7 +510,8 @@
}
static struct nsm_handle *
-nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
+nsm_find(const struct sockaddr_in *sin, const char *hostname,
+ unsigned int hostname_len)
{
return __nsm_find(sin, hostname, hostname_len, 1);
}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 82e2192..0822646 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -219,19 +219,6 @@
module_put_and_exit(0);
}
-
-static int find_socket(struct svc_serv *serv, int proto)
-{
- struct svc_sock *svsk;
- int found = 0;
- list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
- if (svsk->sk_sk->sk_protocol == proto) {
- found = 1;
- break;
- }
- return found;
-}
-
/*
* Make any sockets that are needed but not present.
* If nlm_udpport or nlm_tcpport were set as module
@@ -240,17 +227,25 @@
static int make_socks(struct svc_serv *serv, int proto)
{
static int warned;
+ struct svc_xprt *xprt;
int err = 0;
- if (proto == IPPROTO_UDP || nlm_udpport)
- if (!find_socket(serv, IPPROTO_UDP))
- err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport,
- SVC_SOCK_DEFAULTS);
- if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport))
- if (!find_socket(serv, IPPROTO_TCP))
- err = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport,
- SVC_SOCK_DEFAULTS);
-
+ if (proto == IPPROTO_UDP || nlm_udpport) {
+ xprt = svc_find_xprt(serv, "udp", 0, 0);
+ if (!xprt)
+ err = svc_create_xprt(serv, "udp", nlm_udpport,
+ SVC_SOCK_DEFAULTS);
+ else
+ svc_xprt_put(xprt);
+ }
+ if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
+ xprt = svc_find_xprt(serv, "tcp", 0, 0);
+ if (!xprt)
+ err = svc_create_xprt(serv, "tcp", nlm_tcpport,
+ SVC_SOCK_DEFAULTS);
+ else
+ svc_xprt_put(xprt);
+ }
if (err >= 0) {
warned = 0;
err = 0;
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index bf27b6c..385437e 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -84,6 +84,7 @@
{
struct nlm_host *host;
struct nlm_file *file;
+ int rc = rpc_success;
dprintk("lockd: TEST4 called\n");
resp->cookie = argp->cookie;
@@ -91,7 +92,7 @@
/* Don't accept test requests during grace period */
if (nlmsvc_grace_period) {
resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
+ return rc;
}
/* Obtain client and file */
@@ -101,12 +102,13 @@
/* Now check for conflicting locks */
resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
if (resp->status == nlm_drop_reply)
- return rpc_drop_reply;
+ rc = rpc_drop_reply;
+ else
+ dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
- dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
nlm_release_host(host);
nlm_release_file(file);
- return rpc_success;
+ return rc;
}
static __be32
@@ -115,6 +117,7 @@
{
struct nlm_host *host;
struct nlm_file *file;
+ int rc = rpc_success;
dprintk("lockd: LOCK called\n");
@@ -123,7 +126,7 @@
/* Don't accept new lock requests during grace period */
if (nlmsvc_grace_period && !argp->reclaim) {
resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
+ return rc;
}
/* Obtain client and file */
@@ -146,12 +149,13 @@
resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
argp->block, &argp->cookie);
if (resp->status == nlm_drop_reply)
- return rpc_drop_reply;
+ rc = rpc_drop_reply;
+ else
+ dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
- dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
nlm_release_file(file);
- return rpc_success;
+ return rc;
}
static __be32
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index d120ec39..2f4d8fa 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -501,25 +501,29 @@
block, block->b_flags, block->b_fl);
if (block->b_flags & B_TIMED_OUT) {
nlmsvc_unlink_block(block);
- return nlm_lck_denied;
+ ret = nlm_lck_denied;
+ goto out;
}
if (block->b_flags & B_GOT_CALLBACK) {
+ nlmsvc_unlink_block(block);
if (block->b_fl != NULL
&& block->b_fl->fl_type != F_UNLCK) {
lock->fl = *block->b_fl;
goto conf_lock;
- }
- else {
- nlmsvc_unlink_block(block);
- return nlm_granted;
+ } else {
+ ret = nlm_granted;
+ goto out;
}
}
- return nlm_drop_reply;
+ ret = nlm_drop_reply;
+ goto out;
}
error = vfs_test_lock(file->f_file, &lock->fl);
- if (error == -EINPROGRESS)
- return nlmsvc_defer_lock_rqst(rqstp, block);
+ if (error == -EINPROGRESS) {
+ ret = nlmsvc_defer_lock_rqst(rqstp, block);
+ goto out;
+ }
if (error) {
ret = nlm_lck_denied_nolocks;
goto out;
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 9cd5c8b..88379cc 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -113,6 +113,7 @@
{
struct nlm_host *host;
struct nlm_file *file;
+ int rc = rpc_success;
dprintk("lockd: TEST called\n");
resp->cookie = argp->cookie;
@@ -120,7 +121,7 @@
/* Don't accept test requests during grace period */
if (nlmsvc_grace_period) {
resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
+ return rc;
}
/* Obtain client and file */
@@ -130,13 +131,14 @@
/* Now check for conflicting locks */
resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
if (resp->status == nlm_drop_reply)
- return rpc_drop_reply;
+ rc = rpc_drop_reply;
+ else
+ dprintk("lockd: TEST status %d vers %d\n",
+ ntohl(resp->status), rqstp->rq_vers);
- dprintk("lockd: TEST status %d vers %d\n",
- ntohl(resp->status), rqstp->rq_vers);
nlm_release_host(host);
nlm_release_file(file);
- return rpc_success;
+ return rc;
}
static __be32
@@ -145,6 +147,7 @@
{
struct nlm_host *host;
struct nlm_file *file;
+ int rc = rpc_success;
dprintk("lockd: LOCK called\n");
@@ -153,7 +156,7 @@
/* Don't accept new lock requests during grace period */
if (nlmsvc_grace_period && !argp->reclaim) {
resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
+ return rc;
}
/* Obtain client and file */
@@ -176,12 +179,13 @@
resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
argp->block, &argp->cookie));
if (resp->status == nlm_drop_reply)
- return rpc_drop_reply;
+ rc = rpc_drop_reply;
+ else
+ dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
- dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
nlm_release_file(file);
- return rpc_success;
+ return rc;
}
static __be32
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 84ebba3..dbbefbc 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -87,7 +87,7 @@
unsigned int hash;
__be32 nfserr;
- nlm_debug_print_fh("nlm_file_lookup", f);
+ nlm_debug_print_fh("nlm_lookup_file", f);
hash = file_hash(f);
diff --git a/fs/locks.c b/fs/locks.c
index 8b8388e..49354b9 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -125,6 +125,7 @@
#include <linux/syscalls.h>
#include <linux/time.h>
#include <linux/rcupdate.h>
+#include <linux/pid_namespace.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -185,6 +186,7 @@
fl->fl_fasync = NULL;
fl->fl_owner = NULL;
fl->fl_pid = 0;
+ fl->fl_nspid = NULL;
fl->fl_file = NULL;
fl->fl_flags = 0;
fl->fl_type = 0;
@@ -553,6 +555,8 @@
{
list_add(&fl->fl_link, &file_lock_list);
+ fl->fl_nspid = get_pid(task_tgid(current));
+
/* insert into file's list */
fl->fl_next = *pos;
*pos = fl;
@@ -584,6 +588,11 @@
if (fl->fl_ops && fl->fl_ops->fl_remove)
fl->fl_ops->fl_remove(fl);
+ if (fl->fl_nspid) {
+ put_pid(fl->fl_nspid);
+ fl->fl_nspid = NULL;
+ }
+
locks_wake_up_blocks(fl);
locks_free_lock(fl);
}
@@ -634,33 +643,6 @@
return (locks_conflict(caller_fl, sys_fl));
}
-static int interruptible_sleep_on_locked(wait_queue_head_t *fl_wait, int timeout)
-{
- int result = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- __set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(fl_wait, &wait);
- if (timeout == 0)
- schedule();
- else
- result = schedule_timeout(timeout);
- if (signal_pending(current))
- result = -ERESTARTSYS;
- remove_wait_queue(fl_wait, &wait);
- __set_current_state(TASK_RUNNING);
- return result;
-}
-
-static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *waiter, int time)
-{
- int result;
- locks_insert_block(blocker, waiter);
- result = interruptible_sleep_on_locked(&waiter->fl_wait, time);
- __locks_delete_block(waiter);
- return result;
-}
-
void
posix_test_lock(struct file *filp, struct file_lock *fl)
{
@@ -673,55 +655,67 @@
if (posix_locks_conflict(fl, cfl))
break;
}
- if (cfl)
+ if (cfl) {
__locks_copy_lock(fl, cfl);
- else
+ if (cfl->fl_nspid)
+ fl->fl_pid = pid_nr_ns(cfl->fl_nspid,
+ task_active_pid_ns(current));
+ } else
fl->fl_type = F_UNLCK;
unlock_kernel();
return;
}
-
EXPORT_SYMBOL(posix_test_lock);
-/* This function tests for deadlock condition before putting a process to
- * sleep. The detection scheme is no longer recursive. Recursive was neat,
- * but dangerous - we risked stack corruption if the lock data was bad, or
- * if the recursion was too deep for any other reason.
+/*
+ * Deadlock detection:
*
- * We rely on the fact that a task can only be on one lock's wait queue
- * at a time. When we find blocked_task on a wait queue we can re-search
- * with blocked_task equal to that queue's owner, until either blocked_task
- * isn't found, or blocked_task is found on a queue owned by my_task.
+ * We attempt to detect deadlocks that are due purely to posix file
+ * locks.
*
- * Note: the above assumption may not be true when handling lock requests
- * from a broken NFS client. But broken NFS clients have a lot more to
- * worry about than proper deadlock detection anyway... --okir
+ * We assume that a task can be waiting for at most one lock at a time.
+ * So for any acquired lock, the process holding that lock may be
+ * waiting on at most one other lock. That lock in turns may be held by
+ * someone waiting for at most one other lock. Given a requested lock
+ * caller_fl which is about to wait for a conflicting lock block_fl, we
+ * follow this chain of waiters to ensure we are not about to create a
+ * cycle.
*
- * However, the failure of this assumption (also possible in the case of
- * multiple tasks sharing the same open file table) also means there's no
- * guarantee that the loop below will terminate. As a hack, we give up
- * after a few iterations.
+ * Since we do this before we ever put a process to sleep on a lock, we
+ * are ensured that there is never a cycle; that is what guarantees that
+ * the while() loop in posix_locks_deadlock() eventually completes.
+ *
+ * Note: the above assumption may not be true when handling lock
+ * requests from a broken NFS client. It may also fail in the presence
+ * of tasks (such as posix threads) sharing the same open file table.
+ *
+ * To handle those cases, we just bail out after a few iterations.
*/
#define MAX_DEADLK_ITERATIONS 10
+/* Find a lock that the owner of the given block_fl is blocking on. */
+static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
+{
+ struct file_lock *fl;
+
+ list_for_each_entry(fl, &blocked_list, fl_link) {
+ if (posix_same_owner(fl, block_fl))
+ return fl->fl_next;
+ }
+ return NULL;
+}
+
static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
- struct file_lock *fl;
int i = 0;
-next_task:
- if (posix_same_owner(caller_fl, block_fl))
- return 1;
- list_for_each_entry(fl, &blocked_list, fl_link) {
- if (posix_same_owner(fl, block_fl)) {
- if (i++ > MAX_DEADLK_ITERATIONS)
- return 0;
- fl = fl->fl_next;
- block_fl = fl;
- goto next_task;
- }
+ while ((block_fl = what_owner_is_waiting_for(block_fl))) {
+ if (i++ > MAX_DEADLK_ITERATIONS)
+ return 0;
+ if (posix_same_owner(caller_fl, block_fl))
+ return 1;
}
return 0;
}
@@ -1256,7 +1250,10 @@
if (break_time == 0)
break_time++;
}
- error = locks_block_on_timeout(flock, new_fl, break_time);
+ locks_insert_block(flock, new_fl);
+ error = wait_event_interruptible_timeout(new_fl->fl_wait,
+ !new_fl->fl_next, break_time);
+ __locks_delete_block(new_fl);
if (error >= 0) {
if (error == 0)
time_out_leases(inode);
@@ -2084,6 +2081,12 @@
int id, char *pfx)
{
struct inode *inode = NULL;
+ unsigned int fl_pid;
+
+ if (fl->fl_nspid)
+ fl_pid = pid_nr_ns(fl->fl_nspid, task_active_pid_ns(current));
+ else
+ fl_pid = fl->fl_pid;
if (fl->fl_file != NULL)
inode = fl->fl_file->f_path.dentry->d_inode;
@@ -2124,16 +2127,16 @@
}
if (inode) {
#ifdef WE_CAN_BREAK_LSLK_NOW
- seq_printf(f, "%d %s:%ld ", fl->fl_pid,
+ seq_printf(f, "%d %s:%ld ", fl_pid,
inode->i_sb->s_id, inode->i_ino);
#else
/* userspace relies on this representation of dev_t ;-( */
- seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid,
+ seq_printf(f, "%d %02x:%02x:%ld ", fl_pid,
MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev), inode->i_ino);
#endif
} else {
- seq_printf(f, "%d <none>:0 ", fl->fl_pid);
+ seq_printf(f, "%d <none>:0 ", fl_pid);
}
if (IS_POSIX(fl)) {
if (fl->fl_end == OFFSET_MAX)
diff --git a/fs/mpage.c b/fs/mpage.c
index d54f8f8..5df5643 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -276,9 +276,7 @@
}
if (first_hole != blocks_per_page) {
- zero_user_page(page, first_hole << blkbits,
- PAGE_CACHE_SIZE - (first_hole << blkbits),
- KM_USER0);
+ zero_user_segment(page, first_hole << blkbits, PAGE_CACHE_SIZE);
if (first_hole == 0) {
SetPageUptodate(page);
unlock_page(page);
@@ -571,8 +569,7 @@
if (page->index > end_index || !offset)
goto confused;
- zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
- KM_USER0);
+ zero_user_segment(page, offset, PAGE_CACHE_SIZE);
}
/*
diff --git a/fs/namei.c b/fs/namei.c
index 73e2e66..241cff4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2188,6 +2188,7 @@
/* We don't d_delete() NFS sillyrenamed files--they still exist. */
if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+ fsnotify_link_count(dentry->d_inode);
d_delete(dentry);
}
@@ -2360,7 +2361,7 @@
error = dir->i_op->link(old_dentry, dir, new_dentry);
mutex_unlock(&old_dentry->d_inode->i_mutex);
if (!error)
- fsnotify_create(dir, new_dentry);
+ fsnotify_link(dir, old_dentry->d_inode, new_dentry);
return error;
}
diff --git a/fs/namespace.c b/fs/namespace.c
index 61bf376..e9c10cd 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -25,18 +25,21 @@
#include <linux/security.h>
#include <linux/mount.h>
#include <linux/ramfs.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include "pnode.h"
#include "internal.h"
+#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
+#define HASH_SIZE (1UL << HASH_SHIFT)
+
/* spinlock for vfsmount related operations, inplace of dcache_lock */
__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
static int event;
static struct list_head *mount_hashtable __read_mostly;
-static int hash_mask __read_mostly, hash_bits __read_mostly;
static struct kmem_cache *mnt_cache __read_mostly;
static struct rw_semaphore namespace_sem;
@@ -48,8 +51,8 @@
{
unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
- tmp = tmp + (tmp >> hash_bits);
- return tmp & hash_mask;
+ tmp = tmp + (tmp >> HASH_SHIFT);
+ return tmp & (HASH_SIZE - 1);
}
struct vfsmount *alloc_vfsmnt(const char *name)
@@ -1813,9 +1816,7 @@
void __init mnt_init(void)
{
- struct list_head *d;
- unsigned int nr_hash;
- int i;
+ unsigned u;
int err;
init_rwsem(&namespace_sem);
@@ -1828,35 +1829,11 @@
if (!mount_hashtable)
panic("Failed to allocate mount hash table\n");
- /*
- * Find the power-of-two list-heads that can fit into the allocation..
- * We don't guarantee that "sizeof(struct list_head)" is necessarily
- * a power-of-two.
- */
- nr_hash = PAGE_SIZE / sizeof(struct list_head);
- hash_bits = 0;
- do {
- hash_bits++;
- } while ((nr_hash >> hash_bits) != 0);
- hash_bits--;
+ printk("Mount-cache hash table entries: %lu\n", HASH_SIZE);
- /*
- * Re-calculate the actual number of entries and the mask
- * from the number of bits we can fit.
- */
- nr_hash = 1UL << hash_bits;
- hash_mask = nr_hash - 1;
+ for (u = 0; u < HASH_SIZE; u++)
+ INIT_LIST_HEAD(&mount_hashtable[u]);
- printk("Mount-cache hash table entries: %d\n", nr_hash);
-
- /* And initialize the newly allocated array */
- d = mount_hashtable;
- i = nr_hash;
- do {
- INIT_LIST_HEAD(d);
- d++;
- i--;
- } while (i);
err = sysfs_init();
if (err)
printk(KERN_WARNING "%s: sysfs_init error: %d\n",
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index e1cb70c..eff1f18 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -987,7 +987,7 @@
static int __init init_ncp_fs(void)
{
int err;
- DPRINTK("ncpfs: init_module called\n");
+ DPRINTK("ncpfs: init_ncp_fs called\n");
err = init_inodecache();
if (err)
@@ -1004,7 +1004,7 @@
static void __exit exit_ncp_fs(void)
{
- DPRINTK("ncpfs: cleanup_module called\n");
+ DPRINTK("ncpfs: exit_ncp_fs called\n");
unregister_filesystem(&ncp_fs_type);
destroy_inodecache();
}
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index a94473d3..5d8dcb9 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -50,10 +50,6 @@
pos = vmf->pgoff << PAGE_SHIFT;
count = PAGE_SIZE;
- if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
- WARN_ON(1); /* shouldn't happen? */
- count = area->vm_end - (unsigned long)vmf->virtual_address;
- }
/* what we can read in one go */
bufsize = NCP_SERVER(inode)->buffer_size;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 9b6bbf1..bd185a5 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -119,8 +119,8 @@
if (!serv)
goto out_err;
- ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport,
- SVC_SOCK_ANONYMOUS);
+ ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
+ SVC_SOCK_ANONYMOUS);
if (ret <= 0)
goto out_destroy;
nfs_callback_tcpport = ret;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 8fd6dfb..3d7d963 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -79,7 +79,7 @@
static
int nfs_return_empty_page(struct page *page)
{
- zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page);
unlock_page(page);
return 0;
@@ -103,10 +103,10 @@
pglen = PAGE_CACHE_SIZE - base;
for (;;) {
if (remainder <= pglen) {
- zero_user_page(*pages, base, remainder, KM_USER0);
+ zero_user(*pages, base, remainder);
break;
}
- zero_user_page(*pages, base, pglen, KM_USER0);
+ zero_user(*pages, base, pglen);
pages++;
remainder -= pglen;
pglen = PAGE_CACHE_SIZE;
@@ -130,7 +130,7 @@
return PTR_ERR(new);
}
if (len < PAGE_CACHE_SIZE)
- zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0);
+ zero_user_segment(page, len, PAGE_CACHE_SIZE);
nfs_list_add_request(new, &one_request);
if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
@@ -532,7 +532,7 @@
goto out_error;
if (len < PAGE_CACHE_SIZE)
- zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0);
+ zero_user_segment(page, len, PAGE_CACHE_SIZE);
nfs_pageio_add_request(desc->pgio, new);
return 0;
out_error:
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 522efff..b144b19 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -665,9 +665,7 @@
* then we need to zero any uninitalised data. */
if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
&& !PageUptodate(req->wb_page))
- zero_user_page(req->wb_page, req->wb_bytes,
- PAGE_CACHE_SIZE - req->wb_bytes,
- KM_USER0);
+ zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE);
return req;
}
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 2192805..d13403e 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -11,8 +11,6 @@
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/export.h>
-#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
-
int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
{
struct exp_flavor_info *f;
@@ -69,10 +67,12 @@
ret = set_current_groups(cred.cr_group_info);
put_group_info(cred.cr_group_info);
if ((cred.cr_uid)) {
- cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
+ current->cap_effective =
+ cap_drop_nfsd_set(current->cap_effective);
} else {
- cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
- current->cap_permitted);
+ current->cap_effective =
+ cap_raise_nfsd_set(current->cap_effective,
+ current->cap_permitted);
}
return ret;
}
diff --git a/include/linux/nfsd/auth.h b/fs/nfsd/auth.h
similarity index 87%
rename from include/linux/nfsd/auth.h
rename to fs/nfsd/auth.h
index 0fb9f72..78b3c0e 100644
--- a/include/linux/nfsd/auth.h
+++ b/fs/nfsd/auth.h
@@ -1,6 +1,4 @@
/*
- * include/linux/nfsd/auth.h
- *
* nfsd-specific authentication stuff.
* uid/gid mapping not yet implemented.
*
@@ -10,8 +8,6 @@
#ifndef LINUX_NFSD_AUTH_H
#define LINUX_NFSD_AUTH_H
-#ifdef __KERNEL__
-
#define nfsd_luid(rq, uid) ((u32)(uid))
#define nfsd_lgid(rq, gid) ((u32)(gid))
#define nfsd_ruid(rq, uid) ((u32)(uid))
@@ -23,5 +19,4 @@
*/
int nfsd_setuser(struct svc_rqst *, struct svc_export *);
-#endif /* __KERNEL__ */
#endif /* LINUX_NFSD_AUTH_H */
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 66d0aeb..79b4bf8 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1357,8 +1357,6 @@
mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
- if (PTR_ERR(exp) == -ENOENT)
- return nfserr_perm;
if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));
rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
@@ -1637,13 +1635,19 @@
/*
* Initialize the exports module.
*/
-void
+int
nfsd_export_init(void)
{
+ int rv;
dprintk("nfsd: initializing export module.\n");
- cache_register(&svc_export_cache);
- cache_register(&svc_expkey_cache);
+ rv = cache_register(&svc_export_cache);
+ if (rv)
+ return rv;
+ rv = cache_register(&svc_expkey_cache);
+ if (rv)
+ cache_unregister(&svc_export_cache);
+ return rv;
}
@@ -1670,10 +1674,8 @@
exp_writelock();
- if (cache_unregister(&svc_expkey_cache))
- printk(KERN_ERR "nfsd: failed to unregister expkey cache\n");
- if (cache_unregister(&svc_export_cache))
- printk(KERN_ERR "nfsd: failed to unregister export cache\n");
+ cache_unregister(&svc_expkey_cache);
+ cache_unregister(&svc_export_cache);
svcauth_unix_purge();
exp_writeunlock();
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 0e5fa11..1c3b765 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -221,12 +221,17 @@
struct nfsd3_getaclres *resp)
{
struct dentry *dentry = resp->fh.fh_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode;
struct kvec *head = rqstp->rq_res.head;
unsigned int base;
int n;
int w;
+ /*
+ * Since this is version 2, the check for nfserr in
+ * nfsd_dispatch actually ensures the following cannot happen.
+ * However, it seems fragile to depend on that.
+ */
if (dentry == NULL || dentry->d_inode == NULL)
return 0;
inode = dentry->d_inode;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index f917fd2..d7647f7 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -21,6 +21,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/xdr3.h>
+#include "auth.h"
#define NFSDDBG_FACILITY NFSDDBG_XDR
@@ -88,10 +89,10 @@
* no slashes or null bytes.
*/
static __be32 *
-decode_filename(__be32 *p, char **namp, int *lenp)
+decode_filename(__be32 *p, char **namp, unsigned int *lenp)
{
char *name;
- int i;
+ unsigned int i;
if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
for (i = 0, name = *namp; i < *lenp; i++, name++) {
@@ -452,8 +453,7 @@
nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_symlinkargs *args)
{
- unsigned int len;
- int avail;
+ unsigned int len, avail;
char *old, *new;
struct kvec *vec;
@@ -486,7 +486,8 @@
/* now copy next page if there is one */
if (len && !avail && rqstp->rq_arg.page_len) {
avail = rqstp->rq_arg.page_len;
- if (avail > PAGE_SIZE) avail = PAGE_SIZE;
+ if (avail > PAGE_SIZE)
+ avail = PAGE_SIZE;
old = page_address(rqstp->rq_arg.pages[0]);
}
while (len && avail && *old) {
@@ -816,11 +817,11 @@
encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
struct svc_fh *fhp)
{
- p = encode_post_op_attr(cd->rqstp, p, fhp);
- *p++ = xdr_one; /* yes, a file handle follows */
- p = encode_fh(p, fhp);
- fh_put(fhp);
- return p;
+ p = encode_post_op_attr(cd->rqstp, p, fhp);
+ *p++ = xdr_one; /* yes, a file handle follows */
+ p = encode_fh(p, fhp);
+ fh_put(fhp);
+ return p;
}
static int
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 9d536a8..aae2b29 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -350,30 +350,6 @@
static int do_probe_callback(void *data)
{
struct nfs4_client *clp = data;
- struct nfs4_callback *cb = &clp->cl_callback;
- struct rpc_message msg = {
- .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
- .rpc_argp = clp,
- };
- int status;
-
- status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
-
- if (status) {
- rpc_shutdown_client(cb->cb_client);
- cb->cb_client = NULL;
- } else
- atomic_set(&cb->cb_set, 1);
- put_nfs4_client(clp);
- return 0;
-}
-
-/*
- * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
- */
-void
-nfsd4_probe_callback(struct nfs4_client *clp)
-{
struct sockaddr_in addr;
struct nfs4_callback *cb = &clp->cl_callback;
struct rpc_timeout timeparms = {
@@ -390,13 +366,15 @@
.timeout = &timeparms,
.program = program,
.version = nfs_cb_version[1]->number,
- .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
+ .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
.flags = (RPC_CLNT_CREATE_NOPING),
};
- struct task_struct *t;
-
- if (atomic_read(&cb->cb_set))
- return;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+ .rpc_argp = clp,
+ };
+ struct rpc_clnt *client;
+ int status;
/* Initialize address */
memset(&addr, 0, sizeof(addr));
@@ -416,29 +394,50 @@
program->stats->program = program;
/* Create RPC client */
- cb->cb_client = rpc_create(&args);
- if (IS_ERR(cb->cb_client)) {
+ client = rpc_create(&args);
+ if (IS_ERR(client)) {
dprintk("NFSD: couldn't create callback client\n");
+ status = PTR_ERR(client);
goto out_err;
}
+ status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
+
+ if (status)
+ goto out_release_client;
+
+ cb->cb_client = client;
+ atomic_set(&cb->cb_set, 1);
+ put_nfs4_client(clp);
+ return 0;
+out_release_client:
+ rpc_shutdown_client(client);
+out_err:
+ put_nfs4_client(clp);
+ dprintk("NFSD: warning: no callback path to client %.*s\n",
+ (int)clp->cl_name.len, clp->cl_name.data);
+ return status;
+}
+
+/*
+ * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
+ */
+void
+nfsd4_probe_callback(struct nfs4_client *clp)
+{
+ struct task_struct *t;
+
+ BUG_ON(atomic_read(&clp->cl_callback.cb_set));
+
/* the task holds a reference to the nfs4_client struct */
atomic_inc(&clp->cl_count);
t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
if (IS_ERR(t))
- goto out_release_clp;
+ atomic_dec(&clp->cl_count);
return;
-
-out_release_clp:
- atomic_dec(&clp->cl_count);
- rpc_shutdown_client(cb->cb_client);
-out_err:
- cb->cb_client = NULL;
- dprintk("NFSD: warning: no callback path to client %.*s\n",
- (int)clp->cl_name.len, clp->cl_name.data);
}
/*
@@ -458,9 +457,6 @@
int retries = 1;
int status = 0;
- if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
- return;
-
cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
cbr->cbr_dp = dp;
@@ -469,6 +465,7 @@
switch (status) {
case -EIO:
/* Network partition? */
+ atomic_set(&clp->cl_callback.cb_set, 0);
case -EBADHANDLE:
case -NFS4ERR_BAD_STATEID:
/* Race: client probably got cb_recall
@@ -481,11 +478,10 @@
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
}
out_put_cred:
- if (status == -EIO)
- atomic_set(&clp->cl_callback.cb_set, 0);
- /* Success or failure, now we're either waiting for lease expiration
- * or deleg_return. */
- dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
+ /*
+ * Success or failure, now we're either waiting for lease expiration
+ * or deleg_return.
+ */
put_nfs4_client(clp);
nfs4_put_delegation(dp);
return;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 4c0c683..996bd88 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -255,13 +255,10 @@
goto out;
if (len == 0)
set_bit(CACHE_NEGATIVE, &ent.h.flags);
- else {
- if (error >= IDMAP_NAMESZ) {
- error = -EINVAL;
- goto out;
- }
+ else if (len >= IDMAP_NAMESZ)
+ goto out;
+ else
memcpy(ent.name, buf1, sizeof(ent.name));
- }
error = -ENOMEM;
res = idtoname_update(&ent, res);
if (res == NULL)
@@ -467,20 +464,25 @@
* Exported API
*/
-void
+int
nfsd_idmap_init(void)
{
- cache_register(&idtoname_cache);
- cache_register(&nametoid_cache);
+ int rv;
+
+ rv = cache_register(&idtoname_cache);
+ if (rv)
+ return rv;
+ rv = cache_register(&nametoid_cache);
+ if (rv)
+ cache_unregister(&idtoname_cache);
+ return rv;
}
void
nfsd_idmap_shutdown(void)
{
- if (cache_unregister(&idtoname_cache))
- printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n");
- if (cache_unregister(&nametoid_cache))
- printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
+ cache_unregister(&idtoname_cache);
+ cache_unregister(&nametoid_cache);
}
/*
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 18ead17..c593db0 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -750,7 +750,7 @@
cstate->current_fh.fh_export,
cstate->current_fh.fh_dentry, buf,
&count, verify->ve_bmval,
- rqstp);
+ rqstp, 0);
/* this means that nfsd4_encode_fattr() ran out of space */
if (status == nfserr_resource && count == 0)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 31673cd..f6744bc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -61,7 +61,6 @@
static time_t user_lease_time = 90;
static time_t boot_time;
static int in_grace = 1;
-static u32 current_clientid = 1;
static u32 current_ownerid = 1;
static u32 current_fileid = 1;
static u32 current_delegid = 1;
@@ -340,21 +339,20 @@
* This type of memory management is somewhat inefficient, but we use it
* anyway since SETCLIENTID is not a common operation.
*/
-static inline struct nfs4_client *
-alloc_client(struct xdr_netobj name)
+static struct nfs4_client *alloc_client(struct xdr_netobj name)
{
struct nfs4_client *clp;
- if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
- if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
- memcpy(clp->cl_name.data, name.data, name.len);
- clp->cl_name.len = name.len;
- }
- else {
- kfree(clp);
- clp = NULL;
- }
+ clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
+ if (clp == NULL)
+ return NULL;
+ clp->cl_name.data = kmalloc(name.len, GFP_KERNEL);
+ if (clp->cl_name.data == NULL) {
+ kfree(clp);
+ return NULL;
}
+ memcpy(clp->cl_name.data, name.data, name.len);
+ clp->cl_name.len = name.len;
return clp;
}
@@ -363,8 +361,11 @@
{
struct rpc_clnt *clnt = clp->cl_callback.cb_client;
- /* shutdown rpc client, ending any outstanding recall rpcs */
if (clnt) {
+ /*
+ * Callback threads take a reference on the client, so there
+ * should be no outstanding callbacks at this point.
+ */
clp->cl_callback.cb_client = NULL;
rpc_shutdown_client(clnt);
}
@@ -422,12 +423,13 @@
put_nfs4_client(clp);
}
-static struct nfs4_client *
-create_client(struct xdr_netobj name, char *recdir) {
+static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir)
+{
struct nfs4_client *clp;
- if (!(clp = alloc_client(name)))
- goto out;
+ clp = alloc_client(name);
+ if (clp == NULL)
+ return NULL;
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_count, 1);
atomic_set(&clp->cl_callback.cb_set, 0);
@@ -436,32 +438,30 @@
INIT_LIST_HEAD(&clp->cl_openowners);
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
-out:
return clp;
}
-static void
-copy_verf(struct nfs4_client *target, nfs4_verifier *source) {
- memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data));
+static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
+{
+ memcpy(target->cl_verifier.data, source->data,
+ sizeof(target->cl_verifier.data));
}
-static void
-copy_clid(struct nfs4_client *target, struct nfs4_client *source) {
+static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
+{
target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
target->cl_clientid.cl_id = source->cl_clientid.cl_id;
}
-static void
-copy_cred(struct svc_cred *target, struct svc_cred *source) {
-
+static void copy_cred(struct svc_cred *target, struct svc_cred *source)
+{
target->cr_uid = source->cr_uid;
target->cr_gid = source->cr_gid;
target->cr_group_info = source->cr_group_info;
get_group_info(target->cr_group_info);
}
-static inline int
-same_name(const char *n1, const char *n2)
+static int same_name(const char *n1, const char *n2)
{
return 0 == memcmp(n1, n2, HEXDIR_LEN);
}
@@ -485,26 +485,26 @@
return cr1->cr_uid == cr2->cr_uid;
}
-static void
-gen_clid(struct nfs4_client *clp) {
+static void gen_clid(struct nfs4_client *clp)
+{
+ static u32 current_clientid = 1;
+
clp->cl_clientid.cl_boot = boot_time;
clp->cl_clientid.cl_id = current_clientid++;
}
-static void
-gen_confirm(struct nfs4_client *clp) {
- struct timespec tv;
- u32 * p;
+static void gen_confirm(struct nfs4_client *clp)
+{
+ static u32 i;
+ u32 *p;
- tv = CURRENT_TIME;
p = (u32 *)clp->cl_confirm.data;
- *p++ = tv.tv_sec;
- *p++ = tv.tv_nsec;
+ *p++ = get_seconds();
+ *p++ = i++;
}
-static int
-check_name(struct xdr_netobj name) {
-
+static int check_name(struct xdr_netobj name)
+{
if (name.len == 0)
return 0;
if (name.len > NFS4_OPAQUE_LIMIT) {
@@ -683,39 +683,6 @@
return;
}
-/*
- * RFC 3010 has a complex implmentation description of processing a
- * SETCLIENTID request consisting of 5 bullets, labeled as
- * CASE0 - CASE4 below.
- *
- * NOTES:
- * callback information will be processed in a future patch
- *
- * an unconfirmed record is added when:
- * NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record.
- * CASE 1: confirmed record found with matching name, principal,
- * verifier, and clientid.
- * CASE 2: confirmed record found with matching name, principal,
- * and there is no unconfirmed record with matching
- * name and principal
- *
- * an unconfirmed record is replaced when:
- * CASE 3: confirmed record found with matching name, principal,
- * and an unconfirmed record is found with matching
- * name, principal, and with clientid and
- * confirm that does not match the confirmed record.
- * CASE 4: there is no confirmed record with matching name and
- * principal. there is an unconfirmed record with
- * matching name, principal.
- *
- * an unconfirmed record is deleted when:
- * CASE 1: an unconfirmed record that matches input name, verifier,
- * and confirmed clientid.
- * CASE 4: any unconfirmed records with matching name and principal
- * that exist after an unconfirmed record has been replaced
- * as described above.
- *
- */
__be32
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_setclientid *setclid)
@@ -748,11 +715,7 @@
nfs4_lock_state();
conf = find_confirmed_client_by_str(dname, strhashval);
if (conf) {
- /*
- * CASE 0:
- * clname match, confirmed, different principal
- * or different ip_address
- */
+ /* RFC 3530 14.2.33 CASE 0: */
status = nfserr_clid_inuse;
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
|| conf->cl_addr != sin->sin_addr.s_addr) {
@@ -761,12 +724,17 @@
goto out;
}
}
+ /*
+ * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
+ * has a description of SETCLIENTID request processing consisting
+ * of 5 bullet points, labeled as CASE0 - CASE4 below.
+ */
unconf = find_unconfirmed_client_by_str(dname, strhashval);
status = nfserr_resource;
if (!conf) {
- /*
- * CASE 4:
- * placed first, because it is the normal case.
+ /*
+ * RFC 3530 14.2.33 CASE 4:
+ * placed first, because it is the normal case
*/
if (unconf)
expire_client(unconf);
@@ -776,17 +744,8 @@
gen_clid(new);
} else if (same_verf(&conf->cl_verifier, &clverifier)) {
/*
- * CASE 1:
- * cl_name match, confirmed, principal match
- * verifier match: probable callback update
- *
- * remove any unconfirmed nfs4_client with
- * matching cl_name, cl_verifier, and cl_clientid
- *
- * create and insert an unconfirmed nfs4_client with same
- * cl_name, cl_verifier, and cl_clientid as existing
- * nfs4_client, but with the new callback info and a
- * new cl_confirm
+ * RFC 3530 14.2.33 CASE 1:
+ * probable callback update
*/
if (unconf) {
/* Note this is removing unconfirmed {*x***},
@@ -802,43 +761,25 @@
copy_clid(new, conf);
} else if (!unconf) {
/*
- * CASE 2:
- * clname match, confirmed, principal match
- * verfier does not match
- * no unconfirmed. create a new unconfirmed nfs4_client
- * using input clverifier, clname, and callback info
- * and generate a new cl_clientid and cl_confirm.
+ * RFC 3530 14.2.33 CASE 2:
+ * probable client reboot; state will be removed if
+ * confirmed.
*/
new = create_client(clname, dname);
if (new == NULL)
goto out;
gen_clid(new);
- } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
- /*
- * CASE3:
- * confirmed found (name, principal match)
- * confirmed verifier does not match input clverifier
- *
- * unconfirmed found (name match)
- * confirmed->cl_confirm != unconfirmed->cl_confirm
- *
- * remove unconfirmed.
- *
- * create an unconfirmed nfs4_client
- * with same cl_name as existing confirmed nfs4_client,
- * but with new callback info, new cl_clientid,
- * new cl_verifier and a new cl_confirm
+ } else {
+ /*
+ * RFC 3530 14.2.33 CASE 3:
+ * probable client reboot; state will be removed if
+ * confirmed.
*/
expire_client(unconf);
new = create_client(clname, dname);
if (new == NULL)
goto out;
gen_clid(new);
- } else {
- /* No cases hit !!! */
- status = nfserr_inval;
- goto out;
-
}
copy_verf(new, &clverifier);
new->cl_addr = sin->sin_addr.s_addr;
@@ -857,11 +798,9 @@
/*
- * RFC 3010 has a complex implmentation description of processing a
- * SETCLIENTID_CONFIRM request consisting of 4 bullets describing
- * processing on a DRC miss, labeled as CASE1 - CASE4 below.
- *
- * NOTE: callback information will be processed here in a future patch
+ * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
+ * a description of SETCLIENTID_CONFIRM request processing consisting of 4
+ * bullets, labeled as CASE1 - CASE4 below.
*/
__be32
nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
@@ -892,16 +831,16 @@
if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)
goto out;
- if ((conf && unconf) &&
- (same_verf(&unconf->cl_confirm, &confirm)) &&
- (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
- (same_name(conf->cl_recdir,unconf->cl_recdir)) &&
- (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
- /* CASE 1:
- * unconf record that matches input clientid and input confirm.
- * conf record that matches input clientid.
- * conf and unconf records match names, verifiers
- */
+ /*
+ * section 14.2.34 of RFC 3530 has a description of
+ * SETCLIENTID_CONFIRM request processing consisting
+ * of 4 bullet points, labeled as CASE1 - CASE4 below.
+ */
+ if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
+ /*
+ * RFC 3530 14.2.34 CASE 1:
+ * callback update
+ */
if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
else {
@@ -914,15 +853,11 @@
status = nfs_ok;
}
- } else if ((conf && !unconf) ||
- ((conf && unconf) &&
- (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
- !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
- /* CASE 2:
- * conf record that matches input clientid.
- * if unconf record matches input clientid, then
- * unconf->cl_name or unconf->cl_verifier don't match the
- * conf record.
+ } else if (conf && !unconf) {
+ /*
+ * RFC 3530 14.2.34 CASE 2:
+ * probable retransmitted request; play it safe and
+ * do nothing.
*/
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
status = nfserr_clid_inuse;
@@ -930,10 +865,9 @@
status = nfs_ok;
} else if (!conf && unconf
&& same_verf(&unconf->cl_confirm, &confirm)) {
- /* CASE 3:
- * conf record not found.
- * unconf record found.
- * unconf->cl_confirm matches input confirm
+ /*
+ * RFC 3530 14.2.34 CASE 3:
+ * Normal case; new or rebooted client:
*/
if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
status = nfserr_clid_inuse;
@@ -948,16 +882,15 @@
}
move_to_confirmed(unconf);
conf = unconf;
+ nfsd4_probe_callback(conf);
status = nfs_ok;
}
} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
&& (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
&confirm)))) {
- /* CASE 4:
- * conf record not found, or if conf, conf->cl_confirm does not
- * match input confirm.
- * unconf record not found, or if unconf, unconf->cl_confirm
- * does not match input confirm.
+ /*
+ * RFC 3530 14.2.34 CASE 4:
+ * Client probably hasn't noticed that we rebooted yet.
*/
status = nfserr_stale_clientid;
} else {
@@ -965,8 +898,6 @@
status = nfserr_clid_inuse;
}
out:
- if (!status)
- nfsd4_probe_callback(conf);
nfs4_unlock_state();
return status;
}
@@ -1226,14 +1157,19 @@
return NULL;
}
-static int access_valid(u32 x)
+static inline int access_valid(u32 x)
{
- return (x > 0 && x < 4);
+ if (x < NFS4_SHARE_ACCESS_READ)
+ return 0;
+ if (x > NFS4_SHARE_ACCESS_BOTH)
+ return 0;
+ return 1;
}
-static int deny_valid(u32 x)
+static inline int deny_valid(u32 x)
{
- return (x >= 0 && x < 5);
+ /* Note: unlike access bits, deny bits may be zero. */
+ return x <= NFS4_SHARE_DENY_BOTH;
}
static void
@@ -2162,8 +2098,10 @@
goto check_replay;
}
+ *stpp = stp;
+ *sopp = sop = stp->st_stateowner;
+
if (lock) {
- struct nfs4_stateowner *sop = stp->st_stateowner;
clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
int lkflg = 0;
@@ -2193,9 +2131,6 @@
return nfserr_bad_stateid;
}
- *stpp = stp;
- *sopp = sop = stp->st_stateowner;
-
/*
* We now validate the seqid and stateid generation numbers.
* For the moment, we ignore the possibility of
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5733394..b0592e7 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -148,12 +148,12 @@
} \
} while (0)
-static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
{
/* We want more bytes than seem to be available.
* Maybe we need a new page, maybe we have just run out
*/
- int avail = (char*)argp->end - (char*)argp->p;
+ unsigned int avail = (char *)argp->end - (char *)argp->p;
__be32 *p;
if (avail + argp->pagelen < nbytes)
return NULL;
@@ -169,6 +169,11 @@
return NULL;
}
+ /*
+ * The following memcpy is safe because read_buf is always
+ * called with nbytes > avail, and the two cases above both
+ * guarantee p points to at least nbytes bytes.
+ */
memcpy(p, argp->p, avail);
/* step to next page */
argp->p = page_address(argp->pagelist[0]);
@@ -1448,7 +1453,7 @@
__be32
nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
- struct svc_rqst *rqstp)
+ struct svc_rqst *rqstp, int ignore_crossmnt)
{
u32 bmval0 = bmval[0];
u32 bmval1 = bmval[1];
@@ -1828,7 +1833,12 @@
if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
if ((buflen -= 8) < 0)
goto out_resource;
- if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
+ /*
+ * Get parent's attributes if not ignoring crossmount
+ * and this is the root of a cross-mounted filesystem.
+ */
+ if (ignore_crossmnt == 0 &&
+ exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
err = vfs_getattr(exp->ex_mnt->mnt_parent,
exp->ex_mnt->mnt_mountpoint, &stat);
if (err)
@@ -1864,13 +1874,25 @@
struct svc_export *exp = cd->rd_fhp->fh_export;
struct dentry *dentry;
__be32 nfserr;
+ int ignore_crossmnt = 0;
dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
if (IS_ERR(dentry))
return nfserrno(PTR_ERR(dentry));
exp_get(exp);
- if (d_mountpoint(dentry)) {
+ /*
+ * In the case of a mountpoint, the client may be asking for
+ * attributes that are only properties of the underlying filesystem
+ * as opposed to the cross-mounted file system. In such a case,
+ * we will not follow the cross mount and will fill the attribtutes
+ * directly from the mountpoint dentry.
+ */
+ if (d_mountpoint(dentry) &&
+ (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
+ (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
+ ignore_crossmnt = 1;
+ else if (d_mountpoint(dentry)) {
int err;
/*
@@ -1889,7 +1911,7 @@
}
nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
- cd->rd_rqstp);
+ cd->rd_rqstp, ignore_crossmnt);
out_put:
dput(dentry);
exp_put(exp);
@@ -2043,7 +2065,7 @@
buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
resp->p, &buflen, getattr->ga_bmval,
- resp->rqstp);
+ resp->rqstp, 0);
if (!nfserr)
resp->p += buflen;
return nfserr;
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 578f2c9..5bfc2ac 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -44,17 +44,17 @@
*/
static DEFINE_SPINLOCK(cache_lock);
-void
-nfsd_cache_init(void)
+int nfsd_reply_cache_init(void)
{
struct svc_cacherep *rp;
int i;
INIT_LIST_HEAD(&lru_head);
i = CACHESIZE;
- while(i) {
+ while (i) {
rp = kmalloc(sizeof(*rp), GFP_KERNEL);
- if (!rp) break;
+ if (!rp)
+ goto out_nomem;
list_add(&rp->c_lru, &lru_head);
rp->c_state = RC_UNUSED;
rp->c_type = RC_NOCACHE;
@@ -62,23 +62,19 @@
i--;
}
- if (i)
- printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
- CACHESIZE, CACHESIZE-i);
-
hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
- if (!hash_list) {
- nfsd_cache_shutdown();
- printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
- HASHSIZE * sizeof(struct hlist_head));
- return;
- }
+ if (!hash_list)
+ goto out_nomem;
cache_disabled = 0;
+ return 0;
+out_nomem:
+ printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
+ nfsd_reply_cache_shutdown();
+ return -ENOMEM;
}
-void
-nfsd_cache_shutdown(void)
+void nfsd_reply_cache_shutdown(void)
{
struct svc_cacherep *rp;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 77dc989..8516137 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -304,6 +304,9 @@
struct auth_domain *dom;
struct knfsd_fh fh;
+ if (size == 0)
+ return -EINVAL;
+
if (buf[size-1] != '\n')
return -EINVAL;
buf[size-1] = 0;
@@ -503,7 +506,7 @@
int len = 0;
lock_kernel();
if (nfsd_serv)
- len = svc_sock_names(buf, nfsd_serv, NULL);
+ len = svc_xprt_names(nfsd_serv, buf, 0);
unlock_kernel();
return len;
}
@@ -540,7 +543,7 @@
}
return err < 0 ? err : 0;
}
- if (buf[0] == '-') {
+ if (buf[0] == '-' && isdigit(buf[1])) {
char *toclose = kstrdup(buf+1, GFP_KERNEL);
int len = 0;
if (!toclose)
@@ -554,6 +557,53 @@
kfree(toclose);
return len;
}
+ /*
+ * Add a transport listener by writing it's transport name
+ */
+ if (isalpha(buf[0])) {
+ int err;
+ char transport[16];
+ int port;
+ if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
+ err = nfsd_create_serv();
+ if (!err) {
+ err = svc_create_xprt(nfsd_serv,
+ transport, port,
+ SVC_SOCK_ANONYMOUS);
+ if (err == -ENOENT)
+ /* Give a reasonable perror msg for
+ * bad transport string */
+ err = -EPROTONOSUPPORT;
+ }
+ return err < 0 ? err : 0;
+ }
+ }
+ /*
+ * Remove a transport by writing it's transport name and port number
+ */
+ if (buf[0] == '-' && isalpha(buf[1])) {
+ struct svc_xprt *xprt;
+ int err = -EINVAL;
+ char transport[16];
+ int port;
+ if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
+ if (port == 0)
+ return -EINVAL;
+ lock_kernel();
+ if (nfsd_serv) {
+ xprt = svc_find_xprt(nfsd_serv, transport,
+ AF_UNSPEC, port);
+ if (xprt) {
+ svc_close_xprt(xprt);
+ svc_xprt_put(xprt);
+ err = 0;
+ } else
+ err = -ENOTCONN;
+ }
+ unlock_kernel();
+ return err < 0 ? err : 0;
+ }
+ }
return -EINVAL;
}
@@ -616,7 +666,7 @@
char *recdir;
int len, status;
- if (size > PATH_MAX || buf[size-1] != '\n')
+ if (size == 0 || size > PATH_MAX || buf[size-1] != '\n')
return -EINVAL;
buf[size-1] = 0;
@@ -674,6 +724,27 @@
.kill_sb = kill_litter_super,
};
+#ifdef CONFIG_PROC_FS
+static int create_proc_exports_entry(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = proc_mkdir("fs/nfs", NULL);
+ if (!entry)
+ return -ENOMEM;
+ entry = create_proc_entry("fs/nfs/exports", 0, NULL);
+ if (!entry)
+ return -ENOMEM;
+ entry->proc_fops = &exports_operations;
+ return 0;
+}
+#else /* CONFIG_PROC_FS */
+static int create_proc_exports_entry(void)
+{
+ return 0;
+}
+#endif
+
static int __init init_nfsd(void)
{
int retval;
@@ -683,32 +754,43 @@
if (retval)
return retval;
nfsd_stat_init(); /* Statistics */
- nfsd_cache_init(); /* RPC reply cache */
- nfsd_export_init(); /* Exports table */
+ retval = nfsd_reply_cache_init();
+ if (retval)
+ goto out_free_stat;
+ retval = nfsd_export_init();
+ if (retval)
+ goto out_free_cache;
nfsd_lockd_init(); /* lockd->nfsd callbacks */
- nfsd_idmap_init(); /* Name to ID mapping */
- if (proc_mkdir("fs/nfs", NULL)) {
- struct proc_dir_entry *entry;
- entry = create_proc_entry("fs/nfs/exports", 0, NULL);
- if (entry)
- entry->proc_fops = &exports_operations;
- }
+ retval = nfsd_idmap_init();
+ if (retval)
+ goto out_free_lockd;
+ retval = create_proc_exports_entry();
+ if (retval)
+ goto out_free_idmap;
retval = register_filesystem(&nfsd_fs_type);
- if (retval) {
- nfsd_export_shutdown();
- nfsd_cache_shutdown();
- remove_proc_entry("fs/nfs/exports", NULL);
- remove_proc_entry("fs/nfs", NULL);
- nfsd_stat_shutdown();
- nfsd_lockd_shutdown();
- }
+ if (retval)
+ goto out_free_all;
+ return 0;
+out_free_all:
+ remove_proc_entry("fs/nfs/exports", NULL);
+ remove_proc_entry("fs/nfs", NULL);
+out_free_idmap:
+ nfsd_idmap_shutdown();
+out_free_lockd:
+ nfsd_lockd_shutdown();
+ nfsd_export_shutdown();
+out_free_cache:
+ nfsd_reply_cache_shutdown();
+out_free_stat:
+ nfsd_stat_shutdown();
+ nfsd4_free_slabs();
return retval;
}
static void __exit exit_nfsd(void)
{
nfsd_export_shutdown();
- nfsd_cache_shutdown();
+ nfsd_reply_cache_shutdown();
remove_proc_entry("fs/nfs/exports", NULL);
remove_proc_entry("fs/nfs", NULL);
nfsd_stat_shutdown();
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 468f17a..8fbd2dc 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -22,6 +22,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/nfsd/nfsd.h>
+#include "auth.h"
#define NFSDDBG_FACILITY NFSDDBG_FH
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 1190aea..9647b0f 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -155,8 +155,8 @@
static void nfsd_last_thread(struct svc_serv *serv)
{
/* When last nfsd thread exits we need to do some clean-up */
- struct svc_sock *svsk;
- list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
+ struct svc_xprt *xprt;
+ list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
lockd_down();
nfsd_serv = NULL;
nfsd_racache_shutdown();
@@ -236,7 +236,7 @@
error = lockd_up(IPPROTO_UDP);
if (error >= 0) {
- error = svc_makesock(nfsd_serv, IPPROTO_UDP, port,
+ error = svc_create_xprt(nfsd_serv, "udp", port,
SVC_SOCK_DEFAULTS);
if (error < 0)
lockd_down();
@@ -247,7 +247,7 @@
#ifdef CONFIG_NFSD_TCP
error = lockd_up(IPPROTO_TCP);
if (error >= 0) {
- error = svc_makesock(nfsd_serv, IPPROTO_TCP, port,
+ error = svc_create_xprt(nfsd_serv, "tcp", port,
SVC_SOCK_DEFAULTS);
if (error < 0)
lockd_down();
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index b86e365..61ad617 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -15,6 +15,7 @@
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/xdr.h>
#include <linux/mm.h>
+#include "auth.h"
#define NFSDDBG_FACILITY NFSDDBG_XDR
@@ -62,10 +63,10 @@
* no slashes or null bytes.
*/
static __be32 *
-decode_filename(__be32 *p, char **namp, int *lenp)
+decode_filename(__be32 *p, char **namp, unsigned int *lenp)
{
char *name;
- int i;
+ unsigned int i;
if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
for (i = 0, name = *namp; i < *lenp; i++, name++) {
@@ -78,10 +79,10 @@
}
static __be32 *
-decode_pathname(__be32 *p, char **namp, int *lenp)
+decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
{
char *name;
- int i;
+ unsigned int i;
if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
for (i = 0, name = *namp; i < *lenp; i++, name++) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index d019918..cc75e4f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -132,7 +132,7 @@
__be32
nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
- const char *name, int len,
+ const char *name, unsigned int len,
struct svc_export **exp_ret, struct dentry **dentry_ret)
{
struct svc_export *exp;
@@ -226,7 +226,7 @@
*/
__be32
nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
- int len, struct svc_fh *resfh)
+ unsigned int len, struct svc_fh *resfh)
{
struct svc_export *exp;
struct dentry *dentry;
@@ -1151,6 +1151,26 @@
}
#endif /* CONFIG_NFSD_V3 */
+__be32
+nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
+ struct iattr *iap)
+{
+ /*
+ * Mode has already been set earlier in create:
+ */
+ iap->ia_valid &= ~ATTR_MODE;
+ /*
+ * Setting uid/gid works only for root. Irix appears to
+ * send along the gid on create when it tries to implement
+ * setgid directories via NFS:
+ */
+ if (current->fsuid != 0)
+ iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
+ if (iap->ia_valid)
+ return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ return 0;
+}
+
/*
* Create a file (regular, directory, device, fifo); UNIX sockets
* not yet implemented.
@@ -1167,6 +1187,7 @@
struct dentry *dentry, *dchild = NULL;
struct inode *dirp;
__be32 err;
+ __be32 err2;
int host_err;
err = nfserr_perm;
@@ -1257,16 +1278,9 @@
}
- /* Set file attributes. Mode has already been set and
- * setting uid/gid works only for root. Irix appears to
- * send along the gid when it tries to implement setgid
- * directories via NFS.
- */
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
- __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
- if (err2)
- err = err2;
- }
+ err2 = nfsd_create_setattr(rqstp, resfhp, iap);
+ if (err2)
+ err = err2;
/*
* Update the file handle to get the new inode info.
*/
@@ -1295,6 +1309,7 @@
struct dentry *dentry, *dchild = NULL;
struct inode *dirp;
__be32 err;
+ __be32 err2;
int host_err;
__u32 v_mtime=0, v_atime=0;
@@ -1399,16 +1414,10 @@
iap->ia_atime.tv_nsec = 0;
}
- /* Set file attributes.
- * Irix appears to send along the gid when it tries to
- * implement setgid directories via NFS. Clear out all that cruft.
- */
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
- __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
- if (err2)
- err = err2;
- }
+ err2 = nfsd_create_setattr(rqstp, resfhp, iap);
+ if (err2)
+ err = err2;
/*
* Update the filehandle to get the new inode info.
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index ad87cb0..00e9ccd 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -87,13 +87,17 @@
/* Check for the current buffer head overflowing. */
if (unlikely(file_ofs + bh->b_size > init_size)) {
int ofs;
+ void *kaddr;
ofs = 0;
if (file_ofs < init_size)
ofs = init_size - file_ofs;
local_irq_save(flags);
- zero_user_page(page, bh_offset(bh) + ofs,
- bh->b_size - ofs, KM_BIO_SRC_IRQ);
+ kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ);
+ memset(kaddr + bh_offset(bh) + ofs, 0,
+ bh->b_size - ofs);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_BIO_SRC_IRQ);
local_irq_restore(flags);
}
} else {
@@ -334,7 +338,7 @@
bh->b_blocknr = -1UL;
clear_buffer_mapped(bh);
handle_zblock:
- zero_user_page(page, i * blocksize, blocksize, KM_USER0);
+ zero_user(page, i * blocksize, blocksize);
if (likely(!err))
set_buffer_uptodate(bh);
} while (i++, iblock++, (bh = bh->b_this_page) != head);
@@ -410,7 +414,7 @@
/* Is the page fully outside i_size? (truncate in progress) */
if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT)) {
- zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_CACHE_SIZE);
ntfs_debug("Read outside i_size - truncated?");
goto done;
}
@@ -459,7 +463,7 @@
* ok to ignore the compressed flag here.
*/
if (unlikely(page->index > 0)) {
- zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_CACHE_SIZE);
goto done;
}
if (!NInoAttr(ni))
@@ -788,8 +792,7 @@
if (err == -ENOENT || lcn == LCN_ENOENT) {
bh->b_blocknr = -1;
clear_buffer_dirty(bh);
- zero_user_page(page, bh_offset(bh), blocksize,
- KM_USER0);
+ zero_user(page, bh_offset(bh), blocksize);
set_buffer_uptodate(bh);
err = 0;
continue;
@@ -1414,8 +1417,7 @@
if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) {
/* The page straddles i_size. */
unsigned int ofs = i_size & ~PAGE_CACHE_MASK;
- zero_user_page(page, ofs, PAGE_CACHE_SIZE - ofs,
- KM_USER0);
+ zero_user_segment(page, ofs, PAGE_CACHE_SIZE);
}
/* Handle mst protected attributes. */
if (NInoMstProtected(ni))
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index d1619d0..33ff314 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -565,7 +565,7 @@
if (xpage >= max_page) {
kfree(bhs);
kfree(pages);
- zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_CACHE_SIZE);
ntfs_debug("Compressed read outside i_size - truncated?");
SetPageUptodate(page);
unlock_page(page);
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 6cd08df..3c5550c 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -607,8 +607,8 @@
ntfs_submit_bh_for_read(bh);
*wait_bh++ = bh;
} else {
- zero_user_page(page, bh_offset(bh),
- blocksize, KM_USER0);
+ zero_user(page, bh_offset(bh),
+ blocksize);
set_buffer_uptodate(bh);
}
}
@@ -683,9 +683,8 @@
ntfs_submit_bh_for_read(bh);
*wait_bh++ = bh;
} else {
- zero_user_page(page,
- bh_offset(bh),
- blocksize, KM_USER0);
+ zero_user(page, bh_offset(bh),
+ blocksize);
set_buffer_uptodate(bh);
}
}
@@ -703,8 +702,8 @@
*/
if (bh_end <= pos || bh_pos >= end) {
if (!buffer_uptodate(bh)) {
- zero_user_page(page, bh_offset(bh),
- blocksize, KM_USER0);
+ zero_user(page, bh_offset(bh),
+ blocksize);
set_buffer_uptodate(bh);
}
mark_buffer_dirty(bh);
@@ -743,8 +742,7 @@
if (!buffer_uptodate(bh))
set_buffer_uptodate(bh);
} else if (!buffer_uptodate(bh)) {
- zero_user_page(page, bh_offset(bh), blocksize,
- KM_USER0);
+ zero_user(page, bh_offset(bh), blocksize);
set_buffer_uptodate(bh);
}
continue;
@@ -868,8 +866,8 @@
if (!buffer_uptodate(bh))
set_buffer_uptodate(bh);
} else if (!buffer_uptodate(bh)) {
- zero_user_page(page, bh_offset(bh),
- blocksize, KM_USER0);
+ zero_user(page, bh_offset(bh),
+ blocksize);
set_buffer_uptodate(bh);
}
continue;
@@ -1128,8 +1126,8 @@
if (likely(bh_pos < initialized_size))
ofs = initialized_size - bh_pos;
- zero_user_page(page, bh_offset(bh) + ofs,
- blocksize - ofs, KM_USER0);
+ zero_user_segment(page, bh_offset(bh) + ofs,
+ blocksize);
}
} else /* if (unlikely(!buffer_uptodate(bh))) */
err = -EIO;
@@ -1269,8 +1267,8 @@
if (PageUptodate(page))
set_buffer_uptodate(bh);
else {
- zero_user_page(page, bh_offset(bh),
- blocksize, KM_USER0);
+ zero_user(page, bh_offset(bh),
+ blocksize);
set_buffer_uptodate(bh);
}
}
@@ -1330,7 +1328,7 @@
len = PAGE_CACHE_SIZE;
if (len > bytes)
len = bytes;
- zero_user_page(*pages, 0, len, KM_USER0);
+ zero_user(*pages, 0, len);
}
goto out;
}
@@ -1451,7 +1449,7 @@
len = PAGE_CACHE_SIZE;
if (len > bytes)
len = bytes;
- zero_user_page(*pages, 0, len, KM_USER0);
+ zero_user(*pages, 0, len);
}
goto out;
}
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h
index e38e402..cd0be3f 100644
--- a/fs/ntfs/malloc.h
+++ b/fs/ntfs/malloc.h
@@ -85,8 +85,7 @@
static inline void ntfs_free(void *addr)
{
- if (likely(((unsigned long)addr < VMALLOC_START) ||
- ((unsigned long)addr >= VMALLOC_END ))) {
+ if (!is_vmalloc_addr(addr)) {
kfree(addr);
/* free_page((unsigned long)addr); */
return;
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index e6df06a..447206eb 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -3338,7 +3338,7 @@
if (insert->ins_split != SPLIT_NONE) {
/*
* We could call ocfs2_insert_at_leaf() for some types
- * of splits, but it's easier to just let one seperate
+ * of splits, but it's easier to just let one separate
* function sort it all out.
*/
ocfs2_split_record(inode, left_path, right_path,
@@ -5670,7 +5670,7 @@
mlog_errno(ret);
if (zero)
- zero_user_page(page, from, to - from, KM_USER0);
+ zero_user_segment(page, from, to);
/*
* Need to set the buffers we zero'd into uptodate
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index bc7b4cb..8224312 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -307,7 +307,7 @@
* XXX sys_readahead() seems to get that wrong?
*/
if (start >= i_size_read(inode)) {
- zero_user_page(page, 0, PAGE_SIZE, KM_USER0);
+ zero_user(page, 0, PAGE_SIZE);
SetPageUptodate(page);
ret = 0;
goto out_alloc;
@@ -869,7 +869,7 @@
if (block_start >= to)
break;
- zero_user_page(page, block_start, bh->b_size, KM_USER0);
+ zero_user(page, block_start, bh->b_size);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
@@ -1034,7 +1034,7 @@
start = max(from, block_start);
end = min(to, block_end);
- zero_user_page(page, start, end - start, KM_USER0);
+ zero_user_segment(page, start, end);
set_buffer_uptodate(bh);
}
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 6b0107f..e280833 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -1215,7 +1215,7 @@
down_write(&oi->ip_alloc_sem);
/*
- * Prepare for worst case allocation scenario of two seperate
+ * Prepare for worst case allocation scenario of two separate
* extents.
*/
if (alloc == 2)
diff --git a/fs/ocfs2/ocfs1_fs_compat.h b/fs/ocfs2/ocfs1_fs_compat.h
index 0b499bc..dfb313b 100644
--- a/fs/ocfs2/ocfs1_fs_compat.h
+++ b/fs/ocfs2/ocfs1_fs_compat.h
@@ -77,7 +77,7 @@
{
/*00*/ __u32 curr_master;
__u8 file_lock;
- __u8 compat_pad[3]; /* Not in orignal definition. Used to
+ __u8 compat_pad[3]; /* Not in original definition. Used to
make the already existing alignment
explicit */
__u64 last_write_time;
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index 7e397e2..72c198a 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -646,7 +646,7 @@
* sync-data inodes."
*
* Note: OCFS2 already does this differently for metadata vs data
- * allocations, as those bitmaps are seperate and undo access is never
+ * allocations, as those bitmaps are separate and undo access is never
* called on a metadata group descriptor.
*/
static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index a99acd8..cb5f0a3 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -198,7 +198,7 @@
config SGI_PARTITION
bool "SGI partition support" if PARTITION_ADVANCED
- default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
+ default y if DEFAULT_SGI_PARTITION
help
Say Y here if you would like to be able to read the hard disk
partition table format used by SGI machines.
diff --git a/fs/pnode.c b/fs/pnode.c
index 89940f2..05ba692 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -83,6 +83,8 @@
mnt->mnt_master = NULL;
if (type == MS_UNBINDABLE)
mnt->mnt_flags |= MNT_UNBINDABLE;
+ else
+ mnt->mnt_flags &= ~MNT_UNBINDABLE;
}
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index b380313..6ba2746 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -281,14 +281,23 @@
return buffer;
}
+static char *render_cap_t(const char *header, kernel_cap_t *a, char *buffer)
+{
+ unsigned __capi;
+
+ buffer += sprintf(buffer, "%s", header);
+ CAP_FOR_EACH_U32(__capi) {
+ buffer += sprintf(buffer, "%08x",
+ a->cap[(_LINUX_CAPABILITY_U32S-1) - __capi]);
+ }
+ return buffer + sprintf(buffer, "\n");
+}
+
static inline char *task_cap(struct task_struct *p, char *buffer)
{
- return buffer + sprintf(buffer, "CapInh:\t%016x\n"
- "CapPrm:\t%016x\n"
- "CapEff:\t%016x\n",
- cap_t(p->cap_inheritable),
- cap_t(p->cap_permitted),
- cap_t(p->cap_effective));
+ buffer = render_cap_t("CapInh:\t", &p->cap_inheritable, buffer);
+ buffer = render_cap_t("CapPrm:\t", &p->cap_permitted, buffer);
+ return render_cap_t("CapEff:\t", &p->cap_effective, buffer);
}
static inline char *task_context_switch_counts(struct task_struct *p,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 3353748..c59852b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -88,10 +88,6 @@
* in /proc for a task before it execs a suid executable.
*/
-
-/* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 13
-
struct pid_entry {
char *name;
int len;
@@ -787,7 +783,7 @@
}
#endif
-static loff_t mem_lseek(struct file * file, loff_t offset, int orig)
+loff_t mem_lseek(struct file *file, loff_t offset, int orig)
{
switch (orig) {
case 0:
@@ -935,42 +931,6 @@
.write = oom_adjust_write,
};
-#ifdef CONFIG_MMU
-static ssize_t clear_refs_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct task_struct *task;
- char buffer[PROC_NUMBUF], *end;
- struct mm_struct *mm;
-
- memset(buffer, 0, sizeof(buffer));
- if (count > sizeof(buffer) - 1)
- count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
- return -EFAULT;
- if (!simple_strtol(buffer, &end, 0))
- return -EINVAL;
- if (*end == '\n')
- end++;
- task = get_proc_task(file->f_path.dentry->d_inode);
- if (!task)
- return -ESRCH;
- mm = get_task_mm(task);
- if (mm) {
- clear_refs_smap(mm);
- mmput(mm);
- }
- put_task_struct(task);
- if (end - buffer == 0)
- return -EIO;
- return end - buffer;
-}
-
-static struct file_operations proc_clear_refs_operations = {
- .write = clear_refs_write,
-};
-#endif
-
#ifdef CONFIG_AUDITSYSCALL
#define TMPBUFLEN 21
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -2289,9 +2249,10 @@
LNK("exe", exe),
REG("mounts", S_IRUGO, mounts),
REG("mountstats", S_IRUSR, mountstats),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, clear_refs),
REG("smaps", S_IRUGO, smaps),
+ REG("pagemap", S_IRUSR, pagemap),
#endif
#ifdef CONFIG_SECURITY
DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
@@ -2360,7 +2321,8 @@
name.len = snprintf(buf, sizeof(buf), "%d", pid);
dentry = d_hash_and_lookup(mnt->mnt_root, &name);
if (dentry) {
- shrink_dcache_parent(dentry);
+ if (!(current->flags & PF_EXITING))
+ shrink_dcache_parent(dentry);
d_drop(dentry);
dput(dentry);
}
@@ -2617,9 +2579,10 @@
LNK("root", root),
LNK("exe", exe),
REG("mounts", S_IRUGO, mounts),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, clear_refs),
REG("smaps", S_IRUGO, smaps),
+ REG("pagemap", S_IRUSR, pagemap),
#endif
#ifdef CONFIG_SECURITY
DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 05b3e90..7d57e80 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -52,15 +52,13 @@
extern int proc_tgid_stat(struct task_struct *, char *);
extern int proc_pid_status(struct task_struct *, char *);
extern int proc_pid_statm(struct task_struct *, char *);
+extern loff_t mem_lseek(struct file *file, loff_t offset, int orig);
extern const struct file_operations proc_maps_operations;
extern const struct file_operations proc_numa_maps_operations;
extern const struct file_operations proc_smaps_operations;
-
-extern const struct file_operations proc_maps_operations;
-extern const struct file_operations proc_numa_maps_operations;
-extern const struct file_operations proc_smaps_operations;
-
+extern const struct file_operations proc_clear_refs_operations;
+extern const struct file_operations proc_pagemap_operations;
void free_proc_entry(struct proc_dir_entry *de);
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 1be7308..7dd26e1 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -325,7 +325,7 @@
if (m == NULL) {
if (clear_user(buffer, tsz))
return -EFAULT;
- } else if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
+ } else if (is_vmalloc_addr((void *)start)) {
char * elf_buf;
struct vm_struct *m;
unsigned long curstart = start;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 3462bfd..2686592 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -29,6 +29,7 @@
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <linux/pagemap.h>
+#include <linux/interrupt.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/smp.h>
@@ -46,6 +47,7 @@
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
#include <linux/pid_namespace.h>
+#include <linux/bootmem.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -63,7 +65,6 @@
*/
extern int get_hardware_list(char *);
extern int get_stram_list(char *);
-extern int get_filesystem_list(char *);
extern int get_exec_domain_list(char *);
extern int get_dma_list(char *);
@@ -83,10 +84,15 @@
{
int a, b, c;
int len;
+ unsigned long seq;
- a = avenrun[0] + (FIXED_1/200);
- b = avenrun[1] + (FIXED_1/200);
- c = avenrun[2] + (FIXED_1/200);
+ do {
+ seq = read_seqbegin(&xtime_lock);
+ a = avenrun[0] + (FIXED_1/200);
+ b = avenrun[1] + (FIXED_1/200);
+ c = avenrun[2] + (FIXED_1/200);
+ } while (read_seqretry(&xtime_lock, seq));
+
len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
@@ -598,7 +604,6 @@
}
-extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */
static struct seq_operations int_seq_ops = {
.start = int_seq_start,
.next = int_seq_next,
@@ -675,6 +680,137 @@
};
#endif
+#ifdef CONFIG_PROC_PAGE_MONITOR
+#define KPMSIZE sizeof(u64)
+#define KPMMASK (KPMSIZE - 1)
+/* /proc/kpagecount - an array exposing page counts
+ *
+ * Each entry is a u64 representing the corresponding
+ * physical page count.
+ */
+static ssize_t kpagecount_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u64 __user *out = (u64 __user *)buf;
+ struct page *ppage;
+ unsigned long src = *ppos;
+ unsigned long pfn;
+ ssize_t ret = 0;
+ u64 pcount;
+
+ pfn = src / KPMSIZE;
+ count = min_t(size_t, count, (max_pfn * KPMSIZE) - src);
+ if (src & KPMMASK || count & KPMMASK)
+ return -EIO;
+
+ while (count > 0) {
+ ppage = NULL;
+ if (pfn_valid(pfn))
+ ppage = pfn_to_page(pfn);
+ pfn++;
+ if (!ppage)
+ pcount = 0;
+ else
+ pcount = atomic_read(&ppage->_count);
+
+ if (put_user(pcount, out++)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ count -= KPMSIZE;
+ }
+
+ *ppos += (char __user *)out - buf;
+ if (!ret)
+ ret = (char __user *)out - buf;
+ return ret;
+}
+
+static struct file_operations proc_kpagecount_operations = {
+ .llseek = mem_lseek,
+ .read = kpagecount_read,
+};
+
+/* /proc/kpageflags - an array exposing page flags
+ *
+ * Each entry is a u64 representing the corresponding
+ * physical page flags.
+ */
+
+/* These macros are used to decouple internal flags from exported ones */
+
+#define KPF_LOCKED 0
+#define KPF_ERROR 1
+#define KPF_REFERENCED 2
+#define KPF_UPTODATE 3
+#define KPF_DIRTY 4
+#define KPF_LRU 5
+#define KPF_ACTIVE 6
+#define KPF_SLAB 7
+#define KPF_WRITEBACK 8
+#define KPF_RECLAIM 9
+#define KPF_BUDDY 10
+
+#define kpf_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos)
+
+static ssize_t kpageflags_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u64 __user *out = (u64 __user *)buf;
+ struct page *ppage;
+ unsigned long src = *ppos;
+ unsigned long pfn;
+ ssize_t ret = 0;
+ u64 kflags, uflags;
+
+ pfn = src / KPMSIZE;
+ count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
+ if (src & KPMMASK || count & KPMMASK)
+ return -EIO;
+
+ while (count > 0) {
+ ppage = NULL;
+ if (pfn_valid(pfn))
+ ppage = pfn_to_page(pfn);
+ pfn++;
+ if (!ppage)
+ kflags = 0;
+ else
+ kflags = ppage->flags;
+
+ uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) |
+ kpf_copy_bit(kflags, KPF_ERROR, PG_error) |
+ kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) |
+ kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) |
+ kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) |
+ kpf_copy_bit(kflags, KPF_LRU, PG_lru) |
+ kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) |
+ kpf_copy_bit(kflags, KPF_SLAB, PG_slab) |
+ kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) |
+ kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) |
+ kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy);
+
+ if (put_user(uflags, out++)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ count -= KPMSIZE;
+ }
+
+ *ppos += (char __user *)out - buf;
+ if (!ret)
+ ret = (char __user *)out - buf;
+ return ret;
+}
+
+static struct file_operations proc_kpageflags_operations = {
+ .llseek = mem_lseek,
+ .read = kpageflags_read,
+};
+#endif /* CONFIG_PROC_PAGE_MONITOR */
+
struct proc_dir_entry *proc_root_kcore;
void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
@@ -755,6 +891,10 @@
(size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
}
#endif
+#ifdef CONFIG_PROC_PAGE_MONITOR
+ create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations);
+ create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations);
+#endif
#ifdef CONFIG_PROC_VMCORE
proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
if (proc_vmcore)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 8043a3e..38338ed 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -5,7 +5,10 @@
#include <linux/highmem.h>
#include <linux/ptrace.h>
#include <linux/pagemap.h>
+#include <linux/ptrace.h>
#include <linux/mempolicy.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
@@ -114,24 +117,124 @@
seq_printf(m, "%*c", len, ' ');
}
-struct mem_size_stats
+static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
{
- unsigned long resident;
- unsigned long shared_clean;
- unsigned long shared_dirty;
- unsigned long private_clean;
- unsigned long private_dirty;
- unsigned long referenced;
-};
+ if (vma && vma != priv->tail_vma) {
+ struct mm_struct *mm = vma->vm_mm;
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ }
+}
-struct pmd_walker {
- struct vm_area_struct *vma;
- void *private;
- void (*action)(struct vm_area_struct *, pmd_t *, unsigned long,
- unsigned long, void *);
-};
+static void *m_start(struct seq_file *m, loff_t *pos)
+{
+ struct proc_maps_private *priv = m->private;
+ unsigned long last_addr = m->version;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma, *tail_vma = NULL;
+ loff_t l = *pos;
-static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
+ /* Clear the per syscall fields in priv */
+ priv->task = NULL;
+ priv->tail_vma = NULL;
+
+ /*
+ * We remember last_addr rather than next_addr to hit with
+ * mmap_cache most of the time. We have zero last_addr at
+ * the beginning and also after lseek. We will have -1 last_addr
+ * after the end of the vmas.
+ */
+
+ if (last_addr == -1UL)
+ return NULL;
+
+ priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
+ if (!priv->task)
+ return NULL;
+
+ mm = mm_for_maps(priv->task);
+ if (!mm)
+ return NULL;
+
+ tail_vma = get_gate_vma(priv->task);
+ priv->tail_vma = tail_vma;
+
+ /* Start with last addr hint */
+ vma = find_vma(mm, last_addr);
+ if (last_addr && vma) {
+ vma = vma->vm_next;
+ goto out;
+ }
+
+ /*
+ * Check the vma index is within the range and do
+ * sequential scan until m_index.
+ */
+ vma = NULL;
+ if ((unsigned long)l < mm->map_count) {
+ vma = mm->mmap;
+ while (l-- && vma)
+ vma = vma->vm_next;
+ goto out;
+ }
+
+ if (l != mm->map_count)
+ tail_vma = NULL; /* After gate vma */
+
+out:
+ if (vma)
+ return vma;
+
+ /* End of vmas has been reached */
+ m->version = (tail_vma != NULL)? 0: -1UL;
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ return tail_vma;
+}
+
+static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct proc_maps_private *priv = m->private;
+ struct vm_area_struct *vma = v;
+ struct vm_area_struct *tail_vma = priv->tail_vma;
+
+ (*pos)++;
+ if (vma && (vma != tail_vma) && vma->vm_next)
+ return vma->vm_next;
+ vma_stop(priv, vma);
+ return (vma != tail_vma)? tail_vma: NULL;
+}
+
+static void m_stop(struct seq_file *m, void *v)
+{
+ struct proc_maps_private *priv = m->private;
+ struct vm_area_struct *vma = v;
+
+ vma_stop(priv, vma);
+ if (priv->task)
+ put_task_struct(priv->task);
+}
+
+static int do_maps_open(struct inode *inode, struct file *file,
+ struct seq_operations *ops)
+{
+ struct proc_maps_private *priv;
+ int ret = -ENOMEM;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv) {
+ priv->pid = proc_pid(inode);
+ ret = seq_open(file, ops);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = priv;
+ } else {
+ kfree(priv);
+ }
+ }
+ return ret;
+}
+
+static int show_map(struct seq_file *m, void *v)
{
struct proc_maps_private *priv = m->private;
struct task_struct *task = priv->task;
@@ -191,41 +294,71 @@
}
seq_putc(m, '\n');
- if (mss)
- seq_printf(m,
- "Size: %8lu kB\n"
- "Rss: %8lu kB\n"
- "Shared_Clean: %8lu kB\n"
- "Shared_Dirty: %8lu kB\n"
- "Private_Clean: %8lu kB\n"
- "Private_Dirty: %8lu kB\n"
- "Referenced: %8lu kB\n",
- (vma->vm_end - vma->vm_start) >> 10,
- mss->resident >> 10,
- mss->shared_clean >> 10,
- mss->shared_dirty >> 10,
- mss->private_clean >> 10,
- mss->private_dirty >> 10,
- mss->referenced >> 10);
-
if (m->count < m->size) /* vma is copied successfully */
m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
return 0;
}
-static int show_map(struct seq_file *m, void *v)
+static struct seq_operations proc_pid_maps_op = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+ .show = show_map
+};
+
+static int maps_open(struct inode *inode, struct file *file)
{
- return show_map_internal(m, v, NULL);
+ return do_maps_open(inode, file, &proc_pid_maps_op);
}
-static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
- unsigned long addr, unsigned long end,
- void *private)
+const struct file_operations proc_maps_operations = {
+ .open = maps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+/*
+ * Proportional Set Size(PSS): my share of RSS.
+ *
+ * PSS of a process is the count of pages it has in memory, where each
+ * page is divided by the number of processes sharing it. So if a
+ * process has 1000 pages all to itself, and 1000 shared with one other
+ * process, its PSS will be 1500.
+ *
+ * To keep (accumulated) division errors low, we adopt a 64bit
+ * fixed-point pss counter to minimize division errors. So (pss >>
+ * PSS_SHIFT) would be the real byte count.
+ *
+ * A shift of 12 before division means (assuming 4K page size):
+ * - 1M 3-user-pages add up to 8KB errors;
+ * - supports mapcount up to 2^24, or 16M;
+ * - supports PSS up to 2^52 bytes, or 4PB.
+ */
+#define PSS_SHIFT 12
+
+#ifdef CONFIG_PROC_PAGE_MONITOR
+struct mem_size_stats
+{
+ struct vm_area_struct *vma;
+ unsigned long resident;
+ unsigned long shared_clean;
+ unsigned long shared_dirty;
+ unsigned long private_clean;
+ unsigned long private_dirty;
+ unsigned long referenced;
+ u64 pss;
+};
+
+static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+ void *private)
{
struct mem_size_stats *mss = private;
+ struct vm_area_struct *vma = mss->vma;
pte_t *pte, ptent;
spinlock_t *ptl;
struct page *page;
+ int mapcount;
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
for (; addr != end; pte++, addr += PAGE_SIZE) {
@@ -242,26 +375,88 @@
/* Accumulate the size in pages that have been accessed. */
if (pte_young(ptent) || PageReferenced(page))
mss->referenced += PAGE_SIZE;
- if (page_mapcount(page) >= 2) {
+ mapcount = page_mapcount(page);
+ if (mapcount >= 2) {
if (pte_dirty(ptent))
mss->shared_dirty += PAGE_SIZE;
else
mss->shared_clean += PAGE_SIZE;
+ mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
} else {
if (pte_dirty(ptent))
mss->private_dirty += PAGE_SIZE;
else
mss->private_clean += PAGE_SIZE;
+ mss->pss += (PAGE_SIZE << PSS_SHIFT);
}
}
pte_unmap_unlock(pte - 1, ptl);
cond_resched();
+ return 0;
}
-static void clear_refs_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
- unsigned long addr, unsigned long end,
- void *private)
+static struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range };
+
+static int show_smap(struct seq_file *m, void *v)
{
+ struct vm_area_struct *vma = v;
+ struct mem_size_stats mss;
+ int ret;
+
+ memset(&mss, 0, sizeof mss);
+ mss.vma = vma;
+ if (vma->vm_mm && !is_vm_hugetlb_page(vma))
+ walk_page_range(vma->vm_mm, vma->vm_start, vma->vm_end,
+ &smaps_walk, &mss);
+
+ ret = show_map(m, v);
+ if (ret)
+ return ret;
+
+ seq_printf(m,
+ "Size: %8lu kB\n"
+ "Rss: %8lu kB\n"
+ "Pss: %8lu kB\n"
+ "Shared_Clean: %8lu kB\n"
+ "Shared_Dirty: %8lu kB\n"
+ "Private_Clean: %8lu kB\n"
+ "Private_Dirty: %8lu kB\n"
+ "Referenced: %8lu kB\n",
+ (vma->vm_end - vma->vm_start) >> 10,
+ mss.resident >> 10,
+ (unsigned long)(mss.pss >> (10 + PSS_SHIFT)),
+ mss.shared_clean >> 10,
+ mss.shared_dirty >> 10,
+ mss.private_clean >> 10,
+ mss.private_dirty >> 10,
+ mss.referenced >> 10);
+
+ return ret;
+}
+
+static struct seq_operations proc_pid_smaps_op = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+ .show = show_smap
+};
+
+static int smaps_open(struct inode *inode, struct file *file)
+{
+ return do_maps_open(inode, file, &proc_pid_smaps_op);
+}
+
+const struct file_operations proc_smaps_operations = {
+ .open = smaps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
+ unsigned long end, void *private)
+{
+ struct vm_area_struct *vma = private;
pte_t *pte, ptent;
spinlock_t *ptl;
struct page *page;
@@ -282,235 +477,248 @@
}
pte_unmap_unlock(pte - 1, ptl);
cond_resched();
+ return 0;
}
-static inline void walk_pmd_range(struct pmd_walker *walker, pud_t *pud,
- unsigned long addr, unsigned long end)
+static struct mm_walk clear_refs_walk = { .pmd_entry = clear_refs_pte_range };
+
+static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
- pmd_t *pmd;
- unsigned long next;
-
- for (pmd = pmd_offset(pud, addr); addr != end;
- pmd++, addr = next) {
- next = pmd_addr_end(addr, end);
- if (pmd_none_or_clear_bad(pmd))
- continue;
- walker->action(walker->vma, pmd, addr, next, walker->private);
- }
-}
-
-static inline void walk_pud_range(struct pmd_walker *walker, pgd_t *pgd,
- unsigned long addr, unsigned long end)
-{
- pud_t *pud;
- unsigned long next;
-
- for (pud = pud_offset(pgd, addr); addr != end;
- pud++, addr = next) {
- next = pud_addr_end(addr, end);
- if (pud_none_or_clear_bad(pud))
- continue;
- walk_pmd_range(walker, pud, addr, next);
- }
-}
-
-/*
- * walk_page_range - walk the page tables of a VMA with a callback
- * @vma - VMA to walk
- * @action - callback invoked for every bottom-level (PTE) page table
- * @private - private data passed to the callback function
- *
- * Recursively walk the page table for the memory area in a VMA, calling
- * a callback for every bottom-level (PTE) page table.
- */
-static inline void walk_page_range(struct vm_area_struct *vma,
- void (*action)(struct vm_area_struct *,
- pmd_t *, unsigned long,
- unsigned long, void *),
- void *private)
-{
- unsigned long addr = vma->vm_start;
- unsigned long end = vma->vm_end;
- struct pmd_walker walker = {
- .vma = vma,
- .private = private,
- .action = action,
- };
- pgd_t *pgd;
- unsigned long next;
-
- for (pgd = pgd_offset(vma->vm_mm, addr); addr != end;
- pgd++, addr = next) {
- next = pgd_addr_end(addr, end);
- if (pgd_none_or_clear_bad(pgd))
- continue;
- walk_pud_range(&walker, pgd, addr, next);
- }
-}
-
-static int show_smap(struct seq_file *m, void *v)
-{
- struct vm_area_struct *vma = v;
- struct mem_size_stats mss;
-
- memset(&mss, 0, sizeof mss);
- if (vma->vm_mm && !is_vm_hugetlb_page(vma))
- walk_page_range(vma, smaps_pte_range, &mss);
- return show_map_internal(m, v, &mss);
-}
-
-void clear_refs_smap(struct mm_struct *mm)
-{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF], *end;
+ struct mm_struct *mm;
struct vm_area_struct *vma;
- down_read(&mm->mmap_sem);
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- if (vma->vm_mm && !is_vm_hugetlb_page(vma))
- walk_page_range(vma, clear_refs_pte_range, NULL);
- flush_tlb_mm(mm);
- up_read(&mm->mmap_sem);
-}
-
-static void *m_start(struct seq_file *m, loff_t *pos)
-{
- struct proc_maps_private *priv = m->private;
- unsigned long last_addr = m->version;
- struct mm_struct *mm;
- struct vm_area_struct *vma, *tail_vma = NULL;
- loff_t l = *pos;
-
- /* Clear the per syscall fields in priv */
- priv->task = NULL;
- priv->tail_vma = NULL;
-
- /*
- * We remember last_addr rather than next_addr to hit with
- * mmap_cache most of the time. We have zero last_addr at
- * the beginning and also after lseek. We will have -1 last_addr
- * after the end of the vmas.
- */
-
- if (last_addr == -1UL)
- return NULL;
-
- priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
- if (!priv->task)
- return NULL;
-
- mm = mm_for_maps(priv->task);
- if (!mm)
- return NULL;
-
- priv->tail_vma = tail_vma = get_gate_vma(priv->task);
-
- /* Start with last addr hint */
- if (last_addr && (vma = find_vma(mm, last_addr))) {
- vma = vma->vm_next;
- goto out;
- }
-
- /*
- * Check the vma index is within the range and do
- * sequential scan until m_index.
- */
- vma = NULL;
- if ((unsigned long)l < mm->map_count) {
- vma = mm->mmap;
- while (l-- && vma)
- vma = vma->vm_next;
- goto out;
- }
-
- if (l != mm->map_count)
- tail_vma = NULL; /* After gate vma */
-
-out:
- if (vma)
- return vma;
-
- /* End of vmas has been reached */
- m->version = (tail_vma != NULL)? 0: -1UL;
- up_read(&mm->mmap_sem);
- mmput(mm);
- return tail_vma;
-}
-
-static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
-{
- if (vma && vma != priv->tail_vma) {
- struct mm_struct *mm = vma->vm_mm;
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ if (!simple_strtol(buffer, &end, 0))
+ return -EINVAL;
+ if (*end == '\n')
+ end++;
+ task = get_proc_task(file->f_path.dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ mm = get_task_mm(task);
+ if (mm) {
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ if (!is_vm_hugetlb_page(vma))
+ walk_page_range(mm, vma->vm_start, vma->vm_end,
+ &clear_refs_walk, vma);
+ flush_tlb_mm(mm);
up_read(&mm->mmap_sem);
mmput(mm);
}
+ put_task_struct(task);
+ if (end - buffer == 0)
+ return -EIO;
+ return end - buffer;
}
-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
-{
- struct proc_maps_private *priv = m->private;
- struct vm_area_struct *vma = v;
- struct vm_area_struct *tail_vma = priv->tail_vma;
-
- (*pos)++;
- if (vma && (vma != tail_vma) && vma->vm_next)
- return vma->vm_next;
- vma_stop(priv, vma);
- return (vma != tail_vma)? tail_vma: NULL;
-}
-
-static void m_stop(struct seq_file *m, void *v)
-{
- struct proc_maps_private *priv = m->private;
- struct vm_area_struct *vma = v;
-
- vma_stop(priv, vma);
- if (priv->task)
- put_task_struct(priv->task);
-}
-
-static struct seq_operations proc_pid_maps_op = {
- .start = m_start,
- .next = m_next,
- .stop = m_stop,
- .show = show_map
+const struct file_operations proc_clear_refs_operations = {
+ .write = clear_refs_write,
};
-static struct seq_operations proc_pid_smaps_op = {
- .start = m_start,
- .next = m_next,
- .stop = m_stop,
- .show = show_smap
+struct pagemapread {
+ char __user *out, *end;
};
-static int do_maps_open(struct inode *inode, struct file *file,
- struct seq_operations *ops)
+#define PM_ENTRY_BYTES sizeof(u64)
+#define PM_RESERVED_BITS 3
+#define PM_RESERVED_OFFSET (64 - PM_RESERVED_BITS)
+#define PM_RESERVED_MASK (((1LL<<PM_RESERVED_BITS)-1) << PM_RESERVED_OFFSET)
+#define PM_SPECIAL(nr) (((nr) << PM_RESERVED_OFFSET) | PM_RESERVED_MASK)
+#define PM_NOT_PRESENT PM_SPECIAL(1LL)
+#define PM_SWAP PM_SPECIAL(2LL)
+#define PM_END_OF_BUFFER 1
+
+static int add_to_pagemap(unsigned long addr, u64 pfn,
+ struct pagemapread *pm)
{
- struct proc_maps_private *priv;
- int ret = -ENOMEM;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (priv) {
- priv->pid = proc_pid(inode);
- ret = seq_open(file, ops);
- if (!ret) {
- struct seq_file *m = file->private_data;
- m->private = priv;
- } else {
- kfree(priv);
- }
+ /*
+ * Make sure there's room in the buffer for an
+ * entire entry. Otherwise, only copy part of
+ * the pfn.
+ */
+ if (pm->out + PM_ENTRY_BYTES >= pm->end) {
+ if (copy_to_user(pm->out, &pfn, pm->end - pm->out))
+ return -EFAULT;
+ pm->out = pm->end;
+ return PM_END_OF_BUFFER;
}
+
+ if (put_user(pfn, pm->out))
+ return -EFAULT;
+ pm->out += PM_ENTRY_BYTES;
+ return 0;
+}
+
+static int pagemap_pte_hole(unsigned long start, unsigned long end,
+ void *private)
+{
+ struct pagemapread *pm = private;
+ unsigned long addr;
+ int err = 0;
+ for (addr = start; addr < end; addr += PAGE_SIZE) {
+ err = add_to_pagemap(addr, PM_NOT_PRESENT, pm);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+u64 swap_pte_to_pagemap_entry(pte_t pte)
+{
+ swp_entry_t e = pte_to_swp_entry(pte);
+ return PM_SWAP | swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
+}
+
+static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+ void *private)
+{
+ struct pagemapread *pm = private;
+ pte_t *pte;
+ int err = 0;
+
+ for (; addr != end; addr += PAGE_SIZE) {
+ u64 pfn = PM_NOT_PRESENT;
+ pte = pte_offset_map(pmd, addr);
+ if (is_swap_pte(*pte))
+ pfn = swap_pte_to_pagemap_entry(*pte);
+ else if (pte_present(*pte))
+ pfn = pte_pfn(*pte);
+ /* unmap so we're not in atomic when we copy to userspace */
+ pte_unmap(pte);
+ err = add_to_pagemap(addr, pfn, pm);
+ if (err)
+ return err;
+ }
+
+ cond_resched();
+
+ return err;
+}
+
+static struct mm_walk pagemap_walk = {
+ .pmd_entry = pagemap_pte_range,
+ .pte_hole = pagemap_pte_hole
+};
+
+/*
+ * /proc/pid/pagemap - an array mapping virtual pages to pfns
+ *
+ * For each page in the address space, this file contains one 64-bit
+ * entry representing the corresponding physical page frame number
+ * (PFN) if the page is present. If there is a swap entry for the
+ * physical page, then an encoding of the swap file number and the
+ * page's offset into the swap file are returned. If no page is
+ * present at all, PM_NOT_PRESENT is returned. This allows determining
+ * precisely which pages are mapped (or in swap) and comparing mapped
+ * pages between processes.
+ *
+ * Efficient users of this interface will use /proc/pid/maps to
+ * determine which areas of memory are actually mapped and llseek to
+ * skip over unmapped regions.
+ */
+static ssize_t pagemap_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+ struct page **pages, *page;
+ unsigned long uaddr, uend;
+ struct mm_struct *mm;
+ struct pagemapread pm;
+ int pagecount;
+ int ret = -ESRCH;
+
+ if (!task)
+ goto out;
+
+ ret = -EACCES;
+ if (!ptrace_may_attach(task))
+ goto out;
+
+ ret = -EINVAL;
+ /* file position must be aligned */
+ if (*ppos % PM_ENTRY_BYTES)
+ goto out;
+
+ ret = 0;
+ mm = get_task_mm(task);
+ if (!mm)
+ goto out;
+
+ ret = -ENOMEM;
+ uaddr = (unsigned long)buf & PAGE_MASK;
+ uend = (unsigned long)(buf + count);
+ pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE;
+ pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ goto out_task;
+
+ down_read(¤t->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm, uaddr, pagecount,
+ 1, 0, pages, NULL);
+ up_read(¤t->mm->mmap_sem);
+
+ if (ret < 0)
+ goto out_free;
+
+ pm.out = buf;
+ pm.end = buf + count;
+
+ if (!ptrace_may_attach(task)) {
+ ret = -EIO;
+ } else {
+ unsigned long src = *ppos;
+ unsigned long svpfn = src / PM_ENTRY_BYTES;
+ unsigned long start_vaddr = svpfn << PAGE_SHIFT;
+ unsigned long end_vaddr = TASK_SIZE_OF(task);
+
+ /* watch out for wraparound */
+ if (svpfn > TASK_SIZE_OF(task) >> PAGE_SHIFT)
+ start_vaddr = end_vaddr;
+
+ /*
+ * The odds are that this will stop walking way
+ * before end_vaddr, because the length of the
+ * user buffer is tracked in "pm", and the walk
+ * will stop when we hit the end of the buffer.
+ */
+ ret = walk_page_range(mm, start_vaddr, end_vaddr,
+ &pagemap_walk, &pm);
+ if (ret == PM_END_OF_BUFFER)
+ ret = 0;
+ /* don't need mmap_sem for these, but this looks cleaner */
+ *ppos += pm.out - buf;
+ if (!ret)
+ ret = pm.out - buf;
+ }
+
+ for (; pagecount; pagecount--) {
+ page = pages[pagecount-1];
+ if (!PageReserved(page))
+ SetPageDirty(page);
+ page_cache_release(page);
+ }
+ mmput(mm);
+out_free:
+ kfree(pages);
+out_task:
+ put_task_struct(task);
+out:
return ret;
}
-static int maps_open(struct inode *inode, struct file *file)
-{
- return do_maps_open(inode, file, &proc_pid_maps_op);
-}
-
-const struct file_operations proc_maps_operations = {
- .open = maps_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
+const struct file_operations proc_pagemap_operations = {
+ .llseek = mem_lseek, /* borrow this */
+ .read = pagemap_read,
};
+#endif /* CONFIG_PROC_PAGE_MONITOR */
#ifdef CONFIG_NUMA
extern int show_numa_map(struct seq_file *m, void *v);
@@ -545,15 +753,3 @@
.release = seq_release_private,
};
#endif
-
-static int smaps_open(struct inode *inode, struct file *file)
-{
- return do_maps_open(inode, file, &proc_pid_smaps_op);
-}
-
-const struct file_operations proc_smaps_operations = {
- .open = smaps_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index 16b331d..f491ceb 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -272,7 +272,7 @@
/* If we don't have cached information on this bitmap block, we're
* going to have to load it later anyway. Loading it here allows us
- * to make a better decision. This favors long-term performace gain
+ * to make a better decision. This favors long-term performance gain
* with a better on-disk layout vs. a short term gain of skipping the
* read and potentially having a bad placement. */
if (info->free_count == UINT_MAX) {
@@ -663,7 +663,7 @@
/*
* Relocation based on dirid, hashing them into a given bitmap block
- * files. Formatted nodes are unaffected, a seperate policy covers them
+ * files. Formatted nodes are unaffected, a separate policy covers them
*/
static void dirid_groups(reiserfs_blocknr_hint_t * hint)
{
@@ -688,7 +688,7 @@
/*
* Relocation based on oid, hashing them into a given bitmap block
- * files. Formatted nodes are unaffected, a seperate policy covers them
+ * files. Formatted nodes are unaffected, a separate policy covers them
*/
static void oid_groups(reiserfs_blocknr_hint_t * hint)
{
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 231fd5c..1953098 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -2143,7 +2143,7 @@
/* if we are not on a block boundary */
if (length) {
length = blocksize - length;
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
if (buffer_mapped(bh) && bh->b_blocknr != 0) {
mark_buffer_dirty(bh);
}
@@ -2367,7 +2367,7 @@
unlock_page(page);
return 0;
}
- zero_user_page(page, last_offset, PAGE_CACHE_SIZE - last_offset, KM_USER0);
+ zero_user_segment(page, last_offset, PAGE_CACHE_SIZE);
}
bh = head;
block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 5e7388b..740bb8c 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -575,6 +575,8 @@
printk
("Block %llu contains unformatted data\n",
(unsigned long long)bh->b_blocknr);
+
+ va_end(args);
}
static char print_tb_buf[2048];
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 1597f6b..a5bd23c 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -1084,7 +1084,7 @@
}
/* This is the implementation for the xattr plugin infrastructure */
-static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers);
+static LIST_HEAD(xattr_handlers);
static DEFINE_RWLOCK(handler_lock);
static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
diff --git a/fs/select.c b/fs/select.c
index 47f4792..5633fe9 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -739,7 +739,7 @@
timeout_jiffies = -1;
else
#endif
- timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+ timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1;
} else {
/* Infinite (< 0) or no (0) timeout */
timeout_jiffies = timeout_msecs;
diff --git a/fs/signalfd.c b/fs/signalfd.c
index fb7f7e8..cb2b63a 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -27,6 +27,7 @@
#include <linux/list.h>
#include <linux/anon_inodes.h>
#include <linux/signalfd.h>
+#include <linux/syscalls.h>
struct signalfd_ctx {
sigset_t sigmask;
@@ -66,7 +67,7 @@
BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
/*
- * Unused memebers should be zero ...
+ * Unused members should be zero ...
*/
err = __clear_user(uinfo, sizeof(*uinfo));
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 9416ead..4e5c22c 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -500,6 +500,13 @@
struct smb_fattr root;
int ver;
void *mem;
+ static int warn_count;
+
+ if (warn_count < 5) {
+ warn_count++;
+ printk(KERN_EMERG "smbfs is deprecated and will be removed"
+ "from the 2.6.27 kernel. Please migrate to cifs\n");
+ }
if (!raw_data)
goto out_no_data;
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index e48bd82..e37fe4d 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -329,9 +329,8 @@
msg.msg_control = NULL;
/* Dont repeat bytes and count available bufferspace */
- rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd);
- if (req->rq_rlen < rlen)
- rlen = req->rq_rlen;
+ rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd),
+ (req->rq_rlen - req->rq_bytes_recvd));
result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 61983f3..10c80b5 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -25,13 +25,15 @@
struct hrtimer tmr;
ktime_t tintv;
wait_queue_head_t wqh;
+ u64 ticks;
int expired;
+ int clockid;
};
/*
* This gets called when the timer event triggers. We set the "expired"
* flag, but we do not re-arm the timer (in case it's necessary,
- * tintv.tv64 != 0) until the timer is read.
+ * tintv.tv64 != 0) until the timer is accessed.
*/
static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
{
@@ -40,13 +42,24 @@
spin_lock_irqsave(&ctx->wqh.lock, flags);
ctx->expired = 1;
+ ctx->ticks++;
wake_up_locked(&ctx->wqh);
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return HRTIMER_NORESTART;
}
-static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
+{
+ ktime_t now, remaining;
+
+ now = ctx->tmr.base->get_time();
+ remaining = ktime_sub(ctx->tmr.expires, now);
+
+ return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
+}
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int flags,
const struct itimerspec *ktmr)
{
enum hrtimer_mode htmode;
@@ -57,8 +70,9 @@
texp = timespec_to_ktime(ktmr->it_value);
ctx->expired = 0;
+ ctx->ticks = 0;
ctx->tintv = timespec_to_ktime(ktmr->it_interval);
- hrtimer_init(&ctx->tmr, clockid, htmode);
+ hrtimer_init(&ctx->tmr, ctx->clockid, htmode);
ctx->tmr.expires = texp;
ctx->tmr.function = timerfd_tmrproc;
if (texp.tv64 != 0)
@@ -83,7 +97,7 @@
poll_wait(file, &ctx->wqh, wait);
spin_lock_irqsave(&ctx->wqh.lock, flags);
- if (ctx->expired)
+ if (ctx->ticks)
events |= POLLIN;
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
@@ -102,11 +116,11 @@
return -EINVAL;
spin_lock_irq(&ctx->wqh.lock);
res = -EAGAIN;
- if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
+ if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) {
__add_wait_queue(&ctx->wqh, &wait);
for (res = 0;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (ctx->expired) {
+ if (ctx->ticks) {
res = 0;
break;
}
@@ -121,22 +135,21 @@
__remove_wait_queue(&ctx->wqh, &wait);
__set_current_state(TASK_RUNNING);
}
- if (ctx->expired) {
- ctx->expired = 0;
- if (ctx->tintv.tv64 != 0) {
+ if (ctx->ticks) {
+ ticks = ctx->ticks;
+ if (ctx->expired && ctx->tintv.tv64) {
/*
* If tintv.tv64 != 0, this is a periodic timer that
* needs to be re-armed. We avoid doing it in the timer
* callback to avoid DoS attacks specifying a very
* short timer period.
*/
- ticks = (u64)
- hrtimer_forward(&ctx->tmr,
- hrtimer_cb_get_time(&ctx->tmr),
- ctx->tintv);
+ ticks += hrtimer_forward_now(&ctx->tmr,
+ ctx->tintv) - 1;
hrtimer_restart(&ctx->tmr);
- } else
- ticks = 1;
+ }
+ ctx->expired = 0;
+ ctx->ticks = 0;
}
spin_unlock_irq(&ctx->wqh.lock);
if (ticks)
@@ -150,76 +163,132 @@
.read = timerfd_read,
};
-asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
- const struct itimerspec __user *utmr)
+static struct file *timerfd_fget(int fd)
{
- int error;
+ struct file *file;
+
+ file = fget(fd);
+ if (!file)
+ return ERR_PTR(-EBADF);
+ if (file->f_op != &timerfd_fops) {
+ fput(file);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return file;
+}
+
+asmlinkage long sys_timerfd_create(int clockid, int flags)
+{
+ int error, ufd;
struct timerfd_ctx *ctx;
struct file *file;
struct inode *inode;
- struct itimerspec ktmr;
+
+ if (flags)
+ return -EINVAL;
+ if (clockid != CLOCK_MONOTONIC &&
+ clockid != CLOCK_REALTIME)
+ return -EINVAL;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ init_waitqueue_head(&ctx->wqh);
+ ctx->clockid = clockid;
+ hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
+
+ error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
+ &timerfd_fops, ctx);
+ if (error) {
+ kfree(ctx);
+ return error;
+ }
+
+ return ufd;
+}
+
+asmlinkage long sys_timerfd_settime(int ufd, int flags,
+ const struct itimerspec __user *utmr,
+ struct itimerspec __user *otmr)
+{
+ struct file *file;
+ struct timerfd_ctx *ctx;
+ struct itimerspec ktmr, kotmr;
if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
return -EFAULT;
- if (clockid != CLOCK_MONOTONIC &&
- clockid != CLOCK_REALTIME)
- return -EINVAL;
if (!timespec_valid(&ktmr.it_value) ||
!timespec_valid(&ktmr.it_interval))
return -EINVAL;
- if (ufd == -1) {
- ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ file = timerfd_fget(ufd);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+ ctx = file->private_data;
- init_waitqueue_head(&ctx->wqh);
-
- timerfd_setup(ctx, clockid, flags, &ktmr);
-
- /*
- * When we call this, the initialization must be complete, since
- * anon_inode_getfd() will install the fd.
- */
- error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
- &timerfd_fops, ctx);
- if (error)
- goto err_tmrcancel;
- } else {
- file = fget(ufd);
- if (!file)
- return -EBADF;
- ctx = file->private_data;
- if (file->f_op != &timerfd_fops) {
- fput(file);
- return -EINVAL;
- }
- /*
- * We need to stop the existing timer before reprogramming
- * it to the new values.
- */
- for (;;) {
- spin_lock_irq(&ctx->wqh.lock);
- if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
- break;
- spin_unlock_irq(&ctx->wqh.lock);
- cpu_relax();
- }
- /*
- * Re-program the timer to the new value ...
- */
- timerfd_setup(ctx, clockid, flags, &ktmr);
-
+ /*
+ * We need to stop the existing timer before reprogramming
+ * it to the new values.
+ */
+ for (;;) {
+ spin_lock_irq(&ctx->wqh.lock);
+ if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
+ break;
spin_unlock_irq(&ctx->wqh.lock);
- fput(file);
+ cpu_relax();
}
- return ufd;
+ /*
+ * If the timer is expired and it's periodic, we need to advance it
+ * because the caller may want to know the previous expiration time.
+ * We do not update "ticks" and "expired" since the timer will be
+ * re-programmed again in the following timerfd_setup() call.
+ */
+ if (ctx->expired && ctx->tintv.tv64)
+ hrtimer_forward_now(&ctx->tmr, ctx->tintv);
-err_tmrcancel:
- hrtimer_cancel(&ctx->tmr);
- kfree(ctx);
- return error;
+ kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
+ kotmr.it_interval = ktime_to_timespec(ctx->tintv);
+
+ /*
+ * Re-program the timer to the new value ...
+ */
+ timerfd_setup(ctx, flags, &ktmr);
+
+ spin_unlock_irq(&ctx->wqh.lock);
+ fput(file);
+ if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
+ return -EFAULT;
+
+ return 0;
+}
+
+asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr)
+{
+ struct file *file;
+ struct timerfd_ctx *ctx;
+ struct itimerspec kotmr;
+
+ file = timerfd_fget(ufd);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+ ctx = file->private_data;
+
+ spin_lock_irq(&ctx->wqh.lock);
+ if (ctx->expired && ctx->tintv.tv64) {
+ ctx->expired = 0;
+ ctx->ticks +=
+ hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1;
+ hrtimer_restart(&ctx->tmr);
+ }
+ kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
+ kotmr.it_interval = ktime_to_timespec(ctx->tintv);
+ spin_unlock_irq(&ctx->wqh.lock);
+ fput(file);
+
+ return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0;
}
diff --git a/fs/utimes.c b/fs/utimes.c
index b9912ec..e5588cd 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/utime.h>
+#include <linux/syscalls.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
diff --git a/fs/xattr.c b/fs/xattr.c
index 6645b73..f7c8f87 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -105,6 +105,33 @@
EXPORT_SYMBOL_GPL(vfs_setxattr);
ssize_t
+xattr_getsecurity(struct inode *inode, const char *name, void *value,
+ size_t size)
+{
+ void *buffer = NULL;
+ ssize_t len;
+
+ if (!value || !size) {
+ len = security_inode_getsecurity(inode, name, &buffer, false);
+ goto out_noalloc;
+ }
+
+ len = security_inode_getsecurity(inode, name, &buffer, true);
+ if (len < 0)
+ return len;
+ if (size < len) {
+ len = -ERANGE;
+ goto out;
+ }
+ memcpy(value, buffer, len);
+out:
+ security_release_secctx(buffer, len);
+out_noalloc:
+ return len;
+}
+EXPORT_SYMBOL_GPL(xattr_getsecurity);
+
+ssize_t
vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
@@ -118,23 +145,23 @@
if (error)
return error;
- if (inode->i_op->getxattr)
- error = inode->i_op->getxattr(dentry, name, value, size);
- else
- error = -EOPNOTSUPP;
-
if (!strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN)) {
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
- int ret = security_inode_getsecurity(inode, suffix, value,
- size, error);
+ int ret = xattr_getsecurity(inode, suffix, value, size);
/*
* Only overwrite the return value if a security module
* is actually active.
*/
- if (ret != -EOPNOTSUPP)
- error = ret;
+ if (ret == -EOPNOTSUPP)
+ goto nolsm;
+ return ret;
}
+nolsm:
+ if (inode->i_op->getxattr)
+ error = inode->i_op->getxattr(dentry, name, value, size);
+ else
+ error = -EOPNOTSUPP;
return error;
}
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c
index ed2b16d..e040f1ce 100644
--- a/fs/xfs/linux-2.6/kmem.c
+++ b/fs/xfs/linux-2.6/kmem.c
@@ -92,8 +92,7 @@
void
kmem_free(void *ptr, size_t size)
{
- if (((unsigned long)ptr < VMALLOC_START) ||
- ((unsigned long)ptr >= VMALLOC_END)) {
+ if (!is_vmalloc_addr(ptr)) {
kfree(ptr);
} else {
vfree(ptr);
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index a49dd8d..0382c19 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -709,8 +709,7 @@
mem_to_page(
void *addr)
{
- if (((unsigned long)addr < VMALLOC_START) ||
- ((unsigned long)addr >= VMALLOC_END)) {
+ if ((!is_vmalloc_addr(addr))) {
return virt_to_page(addr);
} else {
return vmalloc_to_page(addr);
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index d6a8ddd..6f614f3 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -155,7 +155,7 @@
if (status)
break;
- zero_user_page(page, offset, bytes, KM_USER0);
+ zero_user(page, offset, bytes);
status = pagecache_write_end(NULL, mapping, pos, bytes, bytes,
page, fsdata);
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 347a911..47a1fd8 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -117,10 +117,6 @@
extern u32 acpi_gbl_nesting_level;
-/* Event counters */
-
-ACPI_EXTERN u32 acpi_gpe_count;
-
/* Support for dynamic control method tracing mechanism */
ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index f85f77a..581daa4 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -48,6 +48,7 @@
#define ACPI_BUTTON_HID_SLEEPF "LNXSLPBN"
#define ACPI_VIDEO_HID "LNXVIDEO"
#define ACPI_BAY_HID "LNXIOBAY"
+#define ACPI_DOCK_HID "LNXDOCK"
/* --------------------------------------------------------------------------
PCI
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index ca882b8..1a16cfb 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -181,6 +181,9 @@
acpi_status
acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine);
+void acpi_os_gpe_count(u32 gpe_number);
+void acpi_os_fixed_event_count(u32 fixed_event_number);
+
/*
* Threads and Scheduling
*/
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 9512f04..d970f7f 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -85,7 +85,7 @@
#endif
/*
- * ACPI Memory managment
+ * ACPI Memory management
*/
void *acpi_allocate(u32 size);
@@ -335,6 +335,8 @@
acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void);
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
+
acpi_status acpi_leave_sleep_state(u8 sleep_state);
#endif /* __ACXFACE_H__ */
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 0787635..0c75a0b 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -34,6 +34,7 @@
#define ACPI_CSTATE_SYSTEMIO (0)
#define ACPI_CSTATE_FFH (1)
+#define ACPI_CSTATE_HALT (2)
/* Power Management */
@@ -64,7 +65,7 @@
u8 valid;
u8 type;
u32 address;
- u8 space_id;
+ u8 entry_method;
u8 index;
u32 latency;
u32 latency_ticks;
@@ -182,7 +183,7 @@
/* Limit Interface */
struct acpi_processor_lx {
- int px; /* performace state */
+ int px; /* performance state */
int tx; /* throttle level */
};
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index f5cb7b8..ca88e54 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -100,7 +100,7 @@
/*
* Same as above, but return the result value
*/
-static __inline__ long atomic_add_return(int i, atomic_t * v)
+static inline int atomic_add_return(int i, atomic_t *v)
{
long temp, result;
smp_mb();
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 30ee766..d5b10ef 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -4,6 +4,7 @@
#ifdef __KERNEL__
#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
#include <asm/scatterlist.h>
#include <asm/machvec.h>
diff --git a/include/asm-alpha/pgalloc.h b/include/asm-alpha/pgalloc.h
index 471864e..fdbedac 100644
--- a/include/asm-alpha/pgalloc.h
+++ b/include/asm-alpha/pgalloc.h
@@ -31,7 +31,7 @@
extern pgd_t *pgd_alloc(struct mm_struct *mm);
static inline void
-pgd_free(pgd_t *pgd)
+pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
@@ -44,7 +44,7 @@
}
static inline void
-pmd_free(pmd_t *pmd)
+pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
free_page((unsigned long)pmd);
}
@@ -52,7 +52,7 @@
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
static inline void
-pte_free_kernel(pte_t *pte)
+pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
@@ -67,7 +67,7 @@
}
static inline void
-pte_free(struct page *page)
+pte_free(struct mm_struct *mm, struct page *page)
{
__free_page(page);
}
diff --git a/include/asm-alpha/tlb.h b/include/asm-alpha/tlb.h
index aa91335..c136365 100644
--- a/include/asm-alpha/tlb.h
+++ b/include/asm-alpha/tlb.h
@@ -9,7 +9,7 @@
#include <asm-generic/tlb.h>
-#define __pte_free_tlb(tlb,pte) pte_free(pte)
-#define __pmd_free_tlb(tlb,pmd) pmd_free(pmd)
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
#endif
diff --git a/include/asm-alpha/tlbflush.h b/include/asm-alpha/tlbflush.h
index b9e9147..9d87aaa 100644
--- a/include/asm-alpha/tlbflush.h
+++ b/include/asm-alpha/tlbflush.h
@@ -142,6 +142,10 @@
#endif /* CONFIG_SMP */
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ flush_tlb_all();
+}
#endif /* _ALPHA_TLBFLUSH_H */
diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
index 29bf2fd..5b5c174 100644
--- a/include/asm-alpha/unistd.h
+++ b/include/asm-alpha/unistd.h
@@ -442,7 +442,6 @@
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_SOCKETCALL
#define __ARCH_WANT_SYS_FADVISE64
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
diff --git a/include/asm-arm/arch-at91/at91_mci.h b/include/asm-arm/arch-at91/at91_mci.h
index c2e11cc..1551fc2 100644
--- a/include/asm-arm/arch-at91/at91_mci.h
+++ b/include/asm-arm/arch-at91/at91_mci.h
@@ -89,7 +89,7 @@
#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */
#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */
#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */
-#define At91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B [AT91RM9200 only] */
+#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */
#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */
#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */
#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */
diff --git a/include/asm-arm/arch-at91/at91rm9200.h b/include/asm-arm/arch-at91/at91rm9200.h
index 802891a..e8fc0b1 100644
--- a/include/asm-arm/arch-at91/at91rm9200.h
+++ b/include/asm-arm/arch-at91/at91rm9200.h
@@ -93,6 +93,11 @@
#define AT91_RTC (0xfffffe00 - AT91_BASE_SYS) /* Real-Time Clock */
#define AT91_MC (0xffffff00 - AT91_BASE_SYS) /* Memory Controllers */
+#define AT91_USART0 AT91RM9200_BASE_US0
+#define AT91_USART1 AT91RM9200_BASE_US1
+#define AT91_USART2 AT91RM9200_BASE_US2
+#define AT91_USART3 AT91RM9200_BASE_US3
+
#define AT91_MATRIX 0 /* not supported */
/*
diff --git a/include/asm-arm/arch-at91/at91sam9260.h b/include/asm-arm/arch-at91/at91sam9260.h
index 0427f86..c8934fe 100644
--- a/include/asm-arm/arch-at91/at91sam9260.h
+++ b/include/asm-arm/arch-at91/at91sam9260.h
@@ -99,6 +99,13 @@
#define AT91_WDT (0xfffffd40 - AT91_BASE_SYS)
#define AT91_GPBR (0xfffffd50 - AT91_BASE_SYS)
+#define AT91_USART0 AT91SAM9260_BASE_US0
+#define AT91_USART1 AT91SAM9260_BASE_US1
+#define AT91_USART2 AT91SAM9260_BASE_US2
+#define AT91_USART3 AT91SAM9260_BASE_US3
+#define AT91_USART4 AT91SAM9260_BASE_US4
+#define AT91_USART5 AT91SAM9260_BASE_US5
+
/*
* Internal Memory.
diff --git a/include/asm-arm/arch-at91/at91sam9261.h b/include/asm-arm/arch-at91/at91sam9261.h
index 9eb4595..c7c4778 100644
--- a/include/asm-arm/arch-at91/at91sam9261.h
+++ b/include/asm-arm/arch-at91/at91sam9261.h
@@ -84,6 +84,10 @@
#define AT91_WDT (0xfffffd40 - AT91_BASE_SYS)
#define AT91_GPBR (0xfffffd50 - AT91_BASE_SYS)
+#define AT91_USART0 AT91SAM9261_BASE_US0
+#define AT91_USART1 AT91SAM9261_BASE_US1
+#define AT91_USART2 AT91SAM9261_BASE_US2
+
/*
* Internal Memory.
diff --git a/include/asm-arm/arch-at91/at91sam9263.h b/include/asm-arm/arch-at91/at91sam9263.h
index 115c47a..018a647 100644
--- a/include/asm-arm/arch-at91/at91sam9263.h
+++ b/include/asm-arm/arch-at91/at91sam9263.h
@@ -101,6 +101,10 @@
#define AT91_RTT1 (0xfffffd50 - AT91_BASE_SYS)
#define AT91_GPBR (0xfffffd60 - AT91_BASE_SYS)
+#define AT91_USART0 AT91SAM9263_BASE_US0
+#define AT91_USART1 AT91SAM9263_BASE_US1
+#define AT91_USART2 AT91SAM9263_BASE_US2
+
#define AT91_SMC AT91_SMC0
/*
diff --git a/include/asm-arm/arch-at91/at91sam9rl.h b/include/asm-arm/arch-at91/at91sam9rl.h
index 8a9708a..16d2832 100644
--- a/include/asm-arm/arch-at91/at91sam9rl.h
+++ b/include/asm-arm/arch-at91/at91sam9rl.h
@@ -94,6 +94,11 @@
#define AT91_GPBR (0xfffffd60 - AT91_BASE_SYS)
#define AT91_RTC (0xfffffe00 - AT91_BASE_SYS)
+#define AT91_USART0 AT91SAM9RL_BASE_US0
+#define AT91_USART1 AT91SAM9RL_BASE_US1
+#define AT91_USART2 AT91SAM9RL_BASE_US2
+#define AT91_USART3 AT91SAM9RL_BASE_US3
+
/*
* Internal Memory.
diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
index 55b07bd..dc189f0 100644
--- a/include/asm-arm/arch-at91/board.h
+++ b/include/asm-arm/arch-at91/board.h
@@ -40,7 +40,8 @@
/* USB Device */
struct at91_udc_data {
u8 vbus_pin; /* high == host powering us */
- u8 pullup_pin; /* high == D+ pulled up */
+ u8 pullup_pin; /* active == D+ pulled up */
+ u8 pullup_active_low; /* true == pullup_pin is active low */
};
extern void __init at91_add_device_udc(struct at91_udc_data *data);
diff --git a/include/asm-arm/arch-at91/uncompress.h b/include/asm-arm/arch-at91/uncompress.h
index 272a7e0..f5636a8 100644
--- a/include/asm-arm/arch-at91/uncompress.h
+++ b/include/asm-arm/arch-at91/uncompress.h
@@ -22,7 +22,23 @@
#define __ASM_ARCH_UNCOMPRESS_H
#include <asm/io.h>
-#include <asm/arch/at91_dbgu.h>
+#include <linux/atmel_serial.h>
+
+#if defined(CONFIG_AT91_EARLY_DBGU)
+#define UART_OFFSET (AT91_DBGU + AT91_BASE_SYS)
+#elif defined(CONFIG_AT91_EARLY_USART0)
+#define UART_OFFSET AT91_USART0
+#elif defined(CONFIG_AT91_EARLY_USART1)
+#define UART_OFFSET AT91_USART1
+#elif defined(CONFIG_AT91_EARLY_USART2)
+#define UART_OFFSET AT91_USART2
+#elif defined(CONFIG_AT91_EARLY_USART3)
+#define UART_OFFSET AT91_USART3
+#elif defined(CONFIG_AT91_EARLY_USART4)
+#define UART_OFFSET AT91_USART4
+#elif defined(CONFIG_AT91_EARLY_USART5)
+#define UART_OFFSET AT91_USART5
+#endif
/*
* The following code assumes the serial port has already been
@@ -33,22 +49,22 @@
*/
static void putc(int c)
{
-#ifdef AT91_DBGU
- void __iomem *sys = (void __iomem *) AT91_BASE_SYS; /* physical address */
+#ifdef UART_OFFSET
+ void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */
- while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXRDY))
+ while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXRDY))
barrier();
- __raw_writel(c, sys + AT91_DBGU_THR);
+ __raw_writel(c, sys + ATMEL_US_THR);
#endif
}
static inline void flush(void)
{
-#ifdef AT91_DBGU
- void __iomem *sys = (void __iomem *) AT91_BASE_SYS; /* physical address */
+#ifdef UART_OFFSET
+ void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */
/* wait for transmission to complete */
- while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXEMPTY))
+ while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
barrier();
#endif
}
diff --git a/include/asm-arm/arch-iop13xx/adma.h b/include/asm-arm/arch-iop13xx/adma.h
index 04006c1..efd9a5e 100644
--- a/include/asm-arm/arch-iop13xx/adma.h
+++ b/include/asm-arm/arch-iop13xx/adma.h
@@ -247,7 +247,7 @@
}
static inline void
-iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags)
{
struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
union {
@@ -257,13 +257,13 @@
u_desc_ctrl.value = 0;
u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
hw_desc->crc_addr = 0;
}
static inline void
-iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags)
{
struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
union {
@@ -274,14 +274,15 @@
u_desc_ctrl.value = 0;
u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
u_desc_ctrl.field.block_fill_en = 1;
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
hw_desc->crc_addr = 0;
}
/* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
static inline void
-iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+ unsigned long flags)
{
struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
union {
@@ -292,7 +293,7 @@
u_desc_ctrl.value = 0;
u_desc_ctrl.field.src_select = src_cnt - 1;
u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
hw_desc->crc_addr = 0;
@@ -301,7 +302,8 @@
/* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
static inline int
-iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
+ unsigned long flags)
{
struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
union {
@@ -314,7 +316,7 @@
u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
u_desc_ctrl.field.zero_result = 1;
u_desc_ctrl.field.status_write_back_en = 1;
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
hw_desc->crc_addr = 0;
diff --git a/include/asm-arm/arch-ixp4xx/cpu.h b/include/asm-arm/arch-ixp4xx/cpu.h
index d2523b3..2fa3d6b 100644
--- a/include/asm-arm/arch-ixp4xx/cpu.h
+++ b/include/asm-arm/arch-ixp4xx/cpu.h
@@ -28,4 +28,19 @@
#define cpu_is_ixp46x() ((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
IXP465_PROCESSOR_ID_VALUE)
+static inline u32 ixp4xx_read_feature_bits(void)
+{
+ unsigned int val = ~*IXP4XX_EXP_CFG2;
+ val &= ~IXP4XX_FEATURE_RESERVED;
+ if (!cpu_is_ixp46x())
+ val &= ~IXP4XX_FEATURE_IXP46X_ONLY;
+
+ return val;
+}
+
+static inline void ixp4xx_write_feature_bits(u32 value)
+{
+ *IXP4XX_EXP_CFG2 = ~value;
+}
+
#endif /* _ASM_ARCH_CPU_H */
diff --git a/include/asm-arm/arch-ixp4xx/dsmg600.h b/include/asm-arm/arch-ixp4xx/dsmg600.h
index a19605ad..b7673e1 100644
--- a/include/asm-arm/arch-ixp4xx/dsmg600.h
+++ b/include/asm-arm/arch-ixp4xx/dsmg600.h
@@ -40,18 +40,13 @@
/* Buttons */
#define DSMG600_PB_GPIO 15 /* power button */
-#define DSMG600_PB_BM (1L << DSMG600_PB_GPIO)
-
#define DSMG600_RB_GPIO 3 /* reset button */
-#define DSMG600_RB_IRQ IRQ_IXP4XX_GPIO3
+/* Power control */
#define DSMG600_PO_GPIO 2 /* power off */
/* LEDs */
#define DSMG600_LED_PWR_GPIO 0
-#define DSMG600_LED_PWR_BM (1L << DSMG600_LED_PWR_GPIO)
-
#define DSMG600_LED_WLAN_GPIO 14
-#define DSMG600_LED_WLAN_BM (1L << DSMG600_LED_WLAN_GPIO)
diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h
index 297ceda..73e8dc3 100644
--- a/include/asm-arm/arch-ixp4xx/hardware.h
+++ b/include/asm-arm/arch-ixp4xx/hardware.h
@@ -27,13 +27,13 @@
#define pcibios_assign_all_busses() 1
+/* Register locations and bits */
+#include "ixp4xx-regs.h"
+
#ifndef __ASSEMBLER__
#include <asm/arch/cpu.h>
#endif
-/* Register locations and bits */
-#include "ixp4xx-regs.h"
-
/* Platform helper functions and definitions */
#include "platform.h"
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index 9c5d235..de181ce 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -13,6 +13,8 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
+#include <linux/bitops.h>
+
#include <asm/hardware.h>
#define IO_SPACE_LIMIT 0xffff0000
diff --git a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
index 5d949d7..68aca85 100644
--- a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
+++ b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
@@ -15,10 +15,6 @@
*
*/
-#ifndef __ASM_ARCH_HARDWARE_H__
-#error "Do not include this directly, instead #include <asm/hardware.h>"
-#endif
-
#ifndef _ASM_ARM_IXP4XX_H_
#define _ASM_ARM_IXP4XX_H_
@@ -587,24 +583,56 @@
#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */
#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
-#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */
-#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */
-#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */
-#define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */
-#define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */
-#define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */
-#define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */
-#define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */
+#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */
+#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */
+#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */
+#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */
+#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */
+#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */
+#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */
+#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */
-#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */
-#define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */
-#define USIR1_IR10 (1 << 2) /* Interrup request ep 10 */
-#define USIR1_IR11 (1 << 3) /* Interrup request ep 11 */
-#define USIR1_IR12 (1 << 4) /* Interrup request ep 12 */
-#define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */
-#define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */
-#define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */
+#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */
+#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */
+#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */
+#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */
+#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */
+#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */
+#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */
+#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
+/* "fuse" bits of IXP_EXP_CFG2 */
+#define IXP4XX_FEATURE_RCOMP (1 << 0)
+#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
+#define IXP4XX_FEATURE_HASH (1 << 2)
+#define IXP4XX_FEATURE_AES (1 << 3)
+#define IXP4XX_FEATURE_DES (1 << 4)
+#define IXP4XX_FEATURE_HDLC (1 << 5)
+#define IXP4XX_FEATURE_AAL (1 << 6)
+#define IXP4XX_FEATURE_HSS (1 << 7)
+#define IXP4XX_FEATURE_UTOPIA (1 << 8)
+#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
+#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
+#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
+#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
+#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
+#define IXP4XX_FEATURE_PCI (1 << 14)
+#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
+#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
+#define IXP4XX_FEATURE_USB_HOST (1 << 18)
+#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
+#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
+#define IXP4XX_FEATURE_RSA (1 << 21)
+#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
+#define IXP4XX_FEATURE_RESERVED (0xFF << 24)
+
+#define IXP4XX_FEATURE_IXP46X_ONLY (IXP4XX_FEATURE_ECC_TIMESYNC | \
+ IXP4XX_FEATURE_USB_HOST | \
+ IXP4XX_FEATURE_NPEA_ETH | \
+ IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
+ IXP4XX_FEATURE_RSA | \
+ IXP4XX_FEATURE_XSCALE_MAX_FREQ)
+
#endif
diff --git a/include/asm-arm/arch-ixp4xx/nas100d.h b/include/asm-arm/arch-ixp4xx/nas100d.h
index 131e0a1..98d9378 100644
--- a/include/asm-arm/arch-ixp4xx/nas100d.h
+++ b/include/asm-arm/arch-ixp4xx/nas100d.h
@@ -38,15 +38,15 @@
/* Buttons */
-#define NAS100D_PB_GPIO 14
-#define NAS100D_RB_GPIO 4
+#define NAS100D_PB_GPIO 14 /* power button */
+#define NAS100D_RB_GPIO 4 /* reset button */
+
+/* Power control */
+
#define NAS100D_PO_GPIO 12 /* power off */
-#define NAS100D_PB_IRQ IRQ_IXP4XX_GPIO14
-#define NAS100D_RB_IRQ IRQ_IXP4XX_GPIO4
+/* LEDs */
-/*
-#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO)
-#define NAS100D_PO_BM (1L << NAS100D_PO_GPIO)
-#define NAS100D_RB_BM (1L << NAS100D_RB_GPIO)
-*/
+#define NAS100D_LED_WLAN_GPIO 0
+#define NAS100D_LED_DISK_GPIO 3
+#define NAS100D_LED_PWR_GPIO 15
diff --git a/include/asm-arm/arch-ixp4xx/npe.h b/include/asm-arm/arch-ixp4xx/npe.h
new file mode 100644
index 0000000..37d0511
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/npe.h
@@ -0,0 +1,39 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <linux/kernel.h>
+
+extern const char *npe_names[];
+
+struct npe_regs {
+ u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+ u32 action_points[4];
+ u32 watchpoint_fifo, watch_count;
+ u32 profile_count;
+ u32 messaging_status, messaging_control;
+ u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+ struct resource *mem_res;
+ struct npe_regs __iomem *regs;
+ u32 regs_phys;
+ int id;
+ int valid;
+};
+
+
+static inline const char *npe_name(struct npe *npe)
+{
+ return npe_names[npe->id];
+}
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev);
+struct npe *npe_request(int id);
+void npe_release(struct npe *npe);
+
+#endif /* __IXP4XX_NPE_H */
diff --git a/include/asm-arm/arch-ixp4xx/nslu2.h b/include/asm-arm/arch-ixp4xx/nslu2.h
index 850fdc5..714bbc6 100644
--- a/include/asm-arm/arch-ixp4xx/nslu2.h
+++ b/include/asm-arm/arch-ixp4xx/nslu2.h
@@ -39,34 +39,17 @@
/* Buttons */
-#define NSLU2_PB_GPIO 5
+#define NSLU2_PB_GPIO 5 /* power button */
#define NSLU2_PO_GPIO 8 /* power off */
-#define NSLU2_RB_GPIO 12
-
-#define NSLU2_PB_IRQ IRQ_IXP4XX_GPIO5
-#define NSLU2_RB_IRQ IRQ_IXP4XX_GPIO12
-
-#define NSLU2_PB_BM (1L << NSLU2_PB_GPIO)
-#define NSLU2_PO_BM (1L << NSLU2_PO_GPIO)
-#define NSLU2_RB_BM (1L << NSLU2_RB_GPIO)
+#define NSLU2_RB_GPIO 12 /* reset button */
/* Buzzer */
#define NSLU2_GPIO_BUZZ 4
-#define NSLU2_BZ_BM (1L << NSLU2_GPIO_BUZZ)
/* LEDs */
#define NSLU2_LED_RED_GPIO 0
#define NSLU2_LED_GRN_GPIO 1
-
-#define NSLU2_LED_RED_BM (1L << NSLU2_LED_RED_GPIO)
-#define NSLU2_LED_GRN_BM (1L << NSLU2_LED_GRN_GPIO)
-
#define NSLU2_LED_DISK1_GPIO 3
#define NSLU2_LED_DISK2_GPIO 2
-
-#define NSLU2_LED_DISK1_BM (1L << NSLU2_LED_DISK1_GPIO)
-#define NSLU2_LED_DISK2_BM (1L << NSLU2_LED_DISK2_GPIO)
-
-
diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
index 2ce28e3..a1f2b54 100644
--- a/include/asm-arm/arch-ixp4xx/platform.h
+++ b/include/asm-arm/arch-ixp4xx/platform.h
@@ -91,6 +91,27 @@
struct sys_timer;
+#define IXP4XX_ETH_NPEA 0x00
+#define IXP4XX_ETH_NPEB 0x10
+#define IXP4XX_ETH_NPEC 0x20
+
+/* Information about built-in Ethernet MAC interfaces */
+struct eth_plat_info {
+ u8 phy; /* MII PHY ID, 0 - 31 */
+ u8 rxq; /* configurable, currently 0 - 31 only */
+ u8 txreadyq;
+ u8 hwaddr[6];
+};
+
+/* Information about built-in HSS (synchronous serial) interfaces */
+struct hss_plat_info {
+ int (*set_clock)(int port, unsigned int clock_type);
+ int (*open)(int port, void *pdev,
+ void (*set_carrier_cb)(void *pdev, int carrier));
+ void (*close)(int port, void *pdev);
+ u8 txreadyq;
+};
+
/*
* Frequency of clock used for primary clocksource
*/
diff --git a/include/asm-arm/arch-ixp4xx/qmgr.h b/include/asm-arm/arch-ixp4xx/qmgr.h
new file mode 100644
index 0000000..1e52b95
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/qmgr.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#define HALF_QUEUES 32
+#define QUEUES 64 /* only 32 lower queues currently supported */
+#define MAX_QUEUE_LENGTH 4 /* in dwords */
+
+#define QUEUE_STAT1_EMPTY 1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY 2
+#define QUEUE_STAT1_NEARLY_FULL 4
+#define QUEUE_STAT1_FULL 8
+#define QUEUE_STAT2_UNDERFLOW 1
+#define QUEUE_STAT2_OVERFLOW 2
+
+#define QUEUE_WATERMARK_0_ENTRIES 0
+#define QUEUE_WATERMARK_1_ENTRY 1
+#define QUEUE_WATERMARK_2_ENTRIES 2
+#define QUEUE_WATERMARK_4_ENTRIES 3
+#define QUEUE_WATERMARK_8_ENTRIES 4
+#define QUEUE_WATERMARK_16_ENTRIES 5
+#define QUEUE_WATERMARK_32_ENTRIES 6
+#define QUEUE_WATERMARK_64_ENTRIES 7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY 0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY 1
+#define QUEUE_IRQ_SRC_NEARLY_FULL 2
+#define QUEUE_IRQ_SRC_FULL 3
+#define QUEUE_IRQ_SRC_NOT_EMPTY 4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL 6
+#define QUEUE_IRQ_SRC_NOT_FULL 7
+
+struct qmgr_regs {
+ u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+ u32 stat1[4]; /* 0x400 - 0x40F */
+ u32 stat2[2]; /* 0x410 - 0x417 */
+ u32 statne_h; /* 0x418 - queue nearly empty */
+ u32 statf_h; /* 0x41C - queue full */
+ u32 irqsrc[4]; /* 0x420 - 0x42F IRC source */
+ u32 irqen[2]; /* 0x430 - 0x437 IRQ enabled */
+ u32 irqstat[2]; /* 0x438 - 0x43F - IRQ access only */
+ u32 reserved[1776];
+ u32 sram[2048]; /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+void qmgr_set_irq(unsigned int queue, int src,
+ void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark);
+void qmgr_release_queue(unsigned int queue);
+
+
+static inline void qmgr_put_entry(unsigned int queue, u32 val)
+{
+ extern struct qmgr_regs __iomem *qmgr_regs;
+ __raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+static inline u32 qmgr_get_entry(unsigned int queue)
+{
+ extern struct qmgr_regs __iomem *qmgr_regs;
+ return __raw_readl(&qmgr_regs->acc[queue][0]);
+}
+
+static inline int qmgr_get_stat1(unsigned int queue)
+{
+ extern struct qmgr_regs __iomem *qmgr_regs;
+ return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+ >> ((queue & 7) << 2)) & 0xF;
+}
+
+static inline int qmgr_get_stat2(unsigned int queue)
+{
+ extern struct qmgr_regs __iomem *qmgr_regs;
+ return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
+ >> ((queue & 0xF) << 1)) & 0x3;
+}
+
+static inline int qmgr_stat_empty(unsigned int queue)
+{
+ return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY);
+}
+
+static inline int qmgr_stat_nearly_empty(unsigned int queue)
+{
+ return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY);
+}
+
+static inline int qmgr_stat_nearly_full(unsigned int queue)
+{
+ return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL);
+}
+
+static inline int qmgr_stat_full(unsigned int queue)
+{
+ return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL);
+}
+
+static inline int qmgr_stat_underflow(unsigned int queue)
+{
+ return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW);
+}
+
+static inline int qmgr_stat_overflow(unsigned int queue)
+{
+ return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW);
+}
+
+#endif
diff --git a/include/asm-arm/arch-ixp4xx/uncompress.h b/include/asm-arm/arch-ixp4xx/uncompress.h
index f7a35b7..34ef48f 100644
--- a/include/asm-arm/arch-ixp4xx/uncompress.h
+++ b/include/asm-arm/arch-ixp4xx/uncompress.h
@@ -13,7 +13,7 @@
#ifndef _ARCH_UNCOMPRESS_H_
#define _ARCH_UNCOMPRESS_H_
-#include <asm/hardware.h>
+#include "ixp4xx-regs.h"
#include <asm/mach-types.h>
#include <linux/serial_reg.h>
diff --git a/include/asm-arm/arch-pxa/gpio.h b/include/asm-arm/arch-pxa/gpio.h
index 9dbc2dc..bdbf5f9 100644
--- a/include/asm-arm/arch-pxa/gpio.h
+++ b/include/asm-arm/arch-pxa/gpio.h
@@ -28,43 +28,35 @@
#include <asm/irq.h>
#include <asm/hardware.h>
-static inline int gpio_request(unsigned gpio, const char *label)
+#include <asm-generic/gpio.h>
+
+
+/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85).
+ * Those cases currently cause holes in the GPIO number space.
+ */
+#define NR_BUILTIN_GPIO 128
+
+static inline int gpio_get_value(unsigned gpio)
{
- return 0;
-}
-
-static inline void gpio_free(unsigned gpio)
-{
- return;
-}
-
-extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio, int value);
-
-static inline int __gpio_get_value(unsigned gpio)
-{
- return GPLR(gpio) & GPIO_bit(gpio);
-}
-
-#define gpio_get_value(gpio) \
- (__builtin_constant_p(gpio) ? \
- __gpio_get_value(gpio) : \
- pxa_gpio_get_value(gpio))
-
-static inline void __gpio_set_value(unsigned gpio, int value)
-{
- if (value)
- GPSR(gpio) = GPIO_bit(gpio);
+ if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO))
+ return GPLR(gpio) & GPIO_bit(gpio);
else
- GPCR(gpio) = GPIO_bit(gpio);
+ return __gpio_get_value(gpio);
}
-#define gpio_set_value(gpio,value) \
- (__builtin_constant_p(gpio) ? \
- __gpio_set_value(gpio, value) : \
- pxa_gpio_set_value(gpio, value))
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) {
+ if (value)
+ GPSR(gpio) = GPIO_bit(gpio);
+ else
+ GPCR(gpio) = GPIO_bit(gpio);
+ } else {
+ __gpio_set_value(gpio, value);
+ }
+}
-#include <asm-generic/gpio.h> /* cansleep wrappers */
+#define gpio_cansleep __gpio_cansleep
#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 442494d..ac175b4 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -737,25 +737,25 @@
#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */
-#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */
-#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */
-#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */
-#define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */
-#define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */
-#define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */
-#define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */
-#define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */
+#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */
+#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */
+#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */
+#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */
+#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */
+#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */
+#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */
+#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */
#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */
-#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */
-#define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */
-#define USIR1_IR10 (1 << 2) /* Interrup request ep 10 */
-#define USIR1_IR11 (1 << 3) /* Interrup request ep 11 */
-#define USIR1_IR12 (1 << 4) /* Interrup request ep 12 */
-#define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */
-#define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */
-#define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */
+#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */
+#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */
+#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */
+#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */
+#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */
+#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */
+#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */
+#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */
#elif defined(CONFIG_PXA27x)
@@ -1020,7 +1020,7 @@
#define ICSR0 __REG(0x40800014) /* ICP Status Register 0 */
#define ICSR1 __REG(0x40800018) /* ICP Status Register 1 */
-#define ICCR0_AME (1 << 7) /* Adress match enable */
+#define ICCR0_AME (1 << 7) /* Address match enable */
#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */
#define ICCR0_RIE (1 << 5) /* Recieve FIFO interrupt enable */
#define ICCR0_RXE (1 << 4) /* Receive enable */
@@ -1131,6 +1131,19 @@
* General Purpose I/O
*/
+#define GPIO0_BASE ((void __iomem *)io_p2v(0x40E00000))
+#define GPIO1_BASE ((void __iomem *)io_p2v(0x40E00004))
+#define GPIO2_BASE ((void __iomem *)io_p2v(0x40E00008))
+#define GPIO3_BASE ((void __iomem *)io_p2v(0x40E00100))
+
+#define GPLR_OFFSET 0x00
+#define GPDR_OFFSET 0x0C
+#define GPSR_OFFSET 0x18
+#define GPCR_OFFSET 0x24
+#define GRER_OFFSET 0x30
+#define GFER_OFFSET 0x3C
+#define GEDR_OFFSET 0x48
+
#define GPLR0 __REG(0x40E00000) /* GPIO Pin-Level Register GPIO<31:0> */
#define GPLR1 __REG(0x40E00004) /* GPIO Pin-Level Register GPIO<63:32> */
#define GPLR2 __REG(0x40E00008) /* GPIO Pin-Level Register GPIO<80:64> */
diff --git a/include/asm-arm/arch-pxa/pxa3xx-regs.h b/include/asm-arm/arch-pxa/pxa3xx-regs.h
index 66d5411..8e1b3ea 100644
--- a/include/asm-arm/arch-pxa/pxa3xx-regs.h
+++ b/include/asm-arm/arch-pxa/pxa3xx-regs.h
@@ -12,6 +12,19 @@
#ifndef __ASM_ARCH_PXA3XX_REGS_H
#define __ASM_ARCH_PXA3XX_REGS_H
+/*
+ * Service Power Management Unit (MPMU)
+ */
+#define PMCR __REG(0x40F50000) /* Power Manager Control Register */
+#define PSR __REG(0x40F50004) /* Power Manager S2 Status Register */
+#define PSPR __REG(0x40F50008) /* Power Manager Scratch Pad Register */
+#define PCFR __REG(0x40F5000C) /* Power Manager General Configuration Register */
+#define PWER __REG(0x40F50010) /* Power Manager Wake-up Enable Register */
+#define PWSR __REG(0x40F50014) /* Power Manager Wake-up Status Register */
+#define PECR __REG(0x40F50018) /* Power Manager EXT_WAKEUP[1:0] Control Register */
+#define DCDCSR __REG(0x40F50080) /* DC-DC Controller Status Register */
+#define PVCR __REG(0x40F50100) /* Power Manager Voltage Change Control Register */
+#define PCMD(x) __REG(0x40F50110 + ((x) << 2))
/*
* Slave Power Managment Unit
diff --git a/include/asm-arm/arch-realview/board-eb.h b/include/asm-arm/arch-realview/board-eb.h
new file mode 100644
index 0000000..3e437b7
--- /dev/null
+++ b/include/asm-arm/arch-realview/board-eb.h
@@ -0,0 +1,171 @@
+/*
+ * include/asm-arm/arch-realview/board-eb.h
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __ASM_ARCH_BOARD_EB_H
+#define __ASM_ARCH_BOARD_EB_H
+
+#include <asm/arch/platform.h>
+
+/*
+ * RealView EB + ARM11MPCore peripheral addresses
+ */
+#ifdef CONFIG_REALVIEW_EB_ARM11MP_REVB
+#define REALVIEW_EB11MP_SCU_BASE 0x10100000 /* SCU registers */
+#define REALVIEW_EB11MP_GIC_CPU_BASE 0x10100100 /* Generic interrupt controller CPU interface */
+#define REALVIEW_EB11MP_TWD_BASE 0x10100700
+#define REALVIEW_EB11MP_TWD_SIZE 0x00000100
+#define REALVIEW_EB11MP_GIC_DIST_BASE 0x10101000 /* Generic interrupt controller distributor */
+#define REALVIEW_EB11MP_L220_BASE 0x10102000 /* L220 registers */
+#define REALVIEW_EB11MP_SYS_PLD_CTRL1 0xD8 /* Register offset for MPCore sysctl */
+#else
+#define REALVIEW_EB11MP_SCU_BASE 0x1F000000 /* SCU registers */
+#define REALVIEW_EB11MP_GIC_CPU_BASE 0x1F000100 /* Generic interrupt controller CPU interface */
+#define REALVIEW_EB11MP_TWD_BASE 0x1F000700
+#define REALVIEW_EB11MP_TWD_SIZE 0x00000100
+#define REALVIEW_EB11MP_GIC_DIST_BASE 0x1F001000 /* Generic interrupt controller distributor */
+#define REALVIEW_EB11MP_L220_BASE 0x1F002000 /* L220 registers */
+#define REALVIEW_EB11MP_SYS_PLD_CTRL1 0x74 /* Register offset for MPCore sysctl */
+#endif
+
+#define IRQ_EB_GIC_START 32
+
+/*
+ * RealView EB interrupt sources
+ */
+#define IRQ_EB_WDOG (IRQ_EB_GIC_START + 0) /* Watchdog timer */
+#define IRQ_EB_SOFT (IRQ_EB_GIC_START + 1) /* Software interrupt */
+#define IRQ_EB_COMMRx (IRQ_EB_GIC_START + 2) /* Debug Comm Rx interrupt */
+#define IRQ_EB_COMMTx (IRQ_EB_GIC_START + 3) /* Debug Comm Tx interrupt */
+#define IRQ_EB_TIMER0_1 (IRQ_EB_GIC_START + 4) /* Timer 0 and 1 */
+#define IRQ_EB_TIMER2_3 (IRQ_EB_GIC_START + 5) /* Timer 2 and 3 */
+#define IRQ_EB_GPIO0 (IRQ_EB_GIC_START + 6) /* GPIO 0 */
+#define IRQ_EB_GPIO1 (IRQ_EB_GIC_START + 7) /* GPIO 1 */
+#define IRQ_EB_GPIO2 (IRQ_EB_GIC_START + 8) /* GPIO 2 */
+ /* 9 reserved */
+#define IRQ_EB_RTC (IRQ_EB_GIC_START + 10) /* Real Time Clock */
+#define IRQ_EB_SSP (IRQ_EB_GIC_START + 11) /* Synchronous Serial Port */
+#define IRQ_EB_UART0 (IRQ_EB_GIC_START + 12) /* UART 0 on development chip */
+#define IRQ_EB_UART1 (IRQ_EB_GIC_START + 13) /* UART 1 on development chip */
+#define IRQ_EB_UART2 (IRQ_EB_GIC_START + 14) /* UART 2 on development chip */
+#define IRQ_EB_UART3 (IRQ_EB_GIC_START + 15) /* UART 3 on development chip */
+#define IRQ_EB_SCI (IRQ_EB_GIC_START + 16) /* Smart Card Interface */
+#define IRQ_EB_MMCI0A (IRQ_EB_GIC_START + 17) /* Multimedia Card 0A */
+#define IRQ_EB_MMCI0B (IRQ_EB_GIC_START + 18) /* Multimedia Card 0B */
+#define IRQ_EB_AACI (IRQ_EB_GIC_START + 19) /* Audio Codec */
+#define IRQ_EB_KMI0 (IRQ_EB_GIC_START + 20) /* Keyboard/Mouse port 0 */
+#define IRQ_EB_KMI1 (IRQ_EB_GIC_START + 21) /* Keyboard/Mouse port 1 */
+#define IRQ_EB_CHARLCD (IRQ_EB_GIC_START + 22) /* Character LCD */
+#define IRQ_EB_CLCD (IRQ_EB_GIC_START + 23) /* CLCD controller */
+#define IRQ_EB_DMA (IRQ_EB_GIC_START + 24) /* DMA controller */
+#define IRQ_EB_PWRFAIL (IRQ_EB_GIC_START + 25) /* Power failure */
+#define IRQ_EB_PISMO (IRQ_EB_GIC_START + 26) /* PISMO interface */
+#define IRQ_EB_DoC (IRQ_EB_GIC_START + 27) /* Disk on Chip memory controller */
+#define IRQ_EB_ETH (IRQ_EB_GIC_START + 28) /* Ethernet controller */
+#define IRQ_EB_USB (IRQ_EB_GIC_START + 29) /* USB controller */
+#define IRQ_EB_TSPEN (IRQ_EB_GIC_START + 30) /* Touchscreen pen */
+#define IRQ_EB_TSKPAD (IRQ_EB_GIC_START + 31) /* Touchscreen keypad */
+
+/*
+ * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
+ */
+#define IRQ_EB11MP_AACI (IRQ_EB_GIC_START + 0)
+#define IRQ_EB11MP_TIMER0_1 (IRQ_EB_GIC_START + 1)
+#define IRQ_EB11MP_TIMER2_3 (IRQ_EB_GIC_START + 2)
+#define IRQ_EB11MP_USB (IRQ_EB_GIC_START + 3)
+#define IRQ_EB11MP_UART0 (IRQ_EB_GIC_START + 4)
+#define IRQ_EB11MP_UART1 (IRQ_EB_GIC_START + 5)
+#define IRQ_EB11MP_RTC (IRQ_EB_GIC_START + 6)
+#define IRQ_EB11MP_KMI0 (IRQ_EB_GIC_START + 7)
+#define IRQ_EB11MP_KMI1 (IRQ_EB_GIC_START + 8)
+#define IRQ_EB11MP_ETH (IRQ_EB_GIC_START + 9)
+#define IRQ_EB11MP_EB_IRQ1 (IRQ_EB_GIC_START + 10) /* main GIC */
+#define IRQ_EB11MP_EB_IRQ2 (IRQ_EB_GIC_START + 11) /* tile GIC */
+#define IRQ_EB11MP_EB_FIQ1 (IRQ_EB_GIC_START + 12) /* main GIC */
+#define IRQ_EB11MP_EB_FIQ2 (IRQ_EB_GIC_START + 13) /* tile GIC */
+#define IRQ_EB11MP_MMCI0A (IRQ_EB_GIC_START + 14)
+#define IRQ_EB11MP_MMCI0B (IRQ_EB_GIC_START + 15)
+
+#define IRQ_EB11MP_PMU_CPU0 (IRQ_EB_GIC_START + 17)
+#define IRQ_EB11MP_PMU_CPU1 (IRQ_EB_GIC_START + 18)
+#define IRQ_EB11MP_PMU_CPU2 (IRQ_EB_GIC_START + 19)
+#define IRQ_EB11MP_PMU_CPU3 (IRQ_EB_GIC_START + 20)
+#define IRQ_EB11MP_PMU_SCU0 (IRQ_EB_GIC_START + 21)
+#define IRQ_EB11MP_PMU_SCU1 (IRQ_EB_GIC_START + 22)
+#define IRQ_EB11MP_PMU_SCU2 (IRQ_EB_GIC_START + 23)
+#define IRQ_EB11MP_PMU_SCU3 (IRQ_EB_GIC_START + 24)
+#define IRQ_EB11MP_PMU_SCU4 (IRQ_EB_GIC_START + 25)
+#define IRQ_EB11MP_PMU_SCU5 (IRQ_EB_GIC_START + 26)
+#define IRQ_EB11MP_PMU_SCU6 (IRQ_EB_GIC_START + 27)
+#define IRQ_EB11MP_PMU_SCU7 (IRQ_EB_GIC_START + 28)
+
+#define IRQ_EB11MP_L220_EVENT (IRQ_EB_GIC_START + 29)
+#define IRQ_EB11MP_L220_SLAVE (IRQ_EB_GIC_START + 30)
+#define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
+
+#define IRQ_EB11MP_UART2 -1
+#define IRQ_EB11MP_UART3 -1
+#define IRQ_EB11MP_CLCD -1
+#define IRQ_EB11MP_DMA -1
+#define IRQ_EB11MP_WDOG -1
+#define IRQ_EB11MP_GPIO0 -1
+#define IRQ_EB11MP_GPIO1 -1
+#define IRQ_EB11MP_GPIO2 -1
+#define IRQ_EB11MP_SCI -1
+#define IRQ_EB11MP_SSP -1
+
+#define NR_GIC_EB11MP 2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_EB
+ */
+#define NR_IRQS_EB (IRQ_EB_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_EB) \
+ && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
+#undef NR_IRQS
+#define NR_IRQS NR_IRQS_EB
+#endif
+
+#if defined(CONFIG_REALVIEW_EB_ARM11MP) \
+ && (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
+#undef MAX_GIC_NR
+#define MAX_GIC_NR NR_GIC_EB11MP
+#endif
+
+/*
+ * Core tile identification (REALVIEW_SYS_PROCID)
+ */
+#define REALVIEW_EB_PROC_MASK 0xFF000000
+#define REALVIEW_EB_PROC_ARM7TDMI 0x00000000
+#define REALVIEW_EB_PROC_ARM9 0x02000000
+#define REALVIEW_EB_PROC_ARM11 0x04000000
+#define REALVIEW_EB_PROC_ARM11MP 0x06000000
+
+#define check_eb_proc(proc_type) \
+ ((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_EB_PROC_MASK) \
+ == proc_type)
+
+#ifdef CONFIG_REALVIEW_EB_ARM11MP
+#define core_tile_eb11mp() check_eb_proc(REALVIEW_EB_PROC_ARM11MP)
+#else
+#define core_tile_eb11mp() 0
+#endif
+
+#endif /* __ASM_ARCH_BOARD_EB_H */
diff --git a/include/asm-arm/arch-realview/entry-macro.S b/include/asm-arm/arch-realview/entry-macro.S
index 3b4e207..cd26306 100644
--- a/include/asm-arm/arch-realview/entry-macro.S
+++ b/include/asm-arm/arch-realview/entry-macro.S
@@ -14,7 +14,8 @@
.endm
.macro get_irqnr_preamble, base, tmp
- ldr \base, =IO_ADDRESS(REALVIEW_GIC_CPU_BASE)
+ ldr \base, =gic_cpu_base_addr
+ ldr \base, [\base]
.endm
.macro arch_ret_to_user, tmp1, tmp2
diff --git a/include/asm-arm/arch-realview/hardware.h b/include/asm-arm/arch-realview/hardware.h
index aa78fe0..bad8d7c 100644
--- a/include/asm-arm/arch-realview/hardware.h
+++ b/include/asm-arm/arch-realview/hardware.h
@@ -23,7 +23,6 @@
#define __ASM_ARCH_HARDWARE_H
#include <asm/sizes.h>
-#include <asm/arch/platform.h>
/* macro to get at IO space when running virtually */
#define IO_ADDRESS(x) ((((x) & 0x0effffff) | (((x) >> 4) & 0x0f000000)) + 0xf0000000)
diff --git a/include/asm-arm/arch-realview/irqs.h b/include/asm-arm/arch-realview/irqs.h
index 5a5db56..ad0c911 100644
--- a/include/asm-arm/arch-realview/irqs.h
+++ b/include/asm-arm/arch-realview/irqs.h
@@ -19,103 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/arch/platform.h>
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
-#define IRQ_LOCALTIMER 29
-#define IRQ_LOCALWDOG 30
+#include <asm/arch/board-eb.h>
-/*
- * IRQ interrupts definitions are the same the INT definitions
- * held within platform.h
- */
+#define IRQ_LOCALTIMER 29
+#define IRQ_LOCALWDOG 30
+
#define IRQ_GIC_START 32
-#define IRQ_WDOGINT (IRQ_GIC_START + INT_WDOGINT)
-#define IRQ_SOFTINT (IRQ_GIC_START + INT_SOFTINT)
-#define IRQ_COMMRx (IRQ_GIC_START + INT_COMMRx)
-#define IRQ_COMMTx (IRQ_GIC_START + INT_COMMTx)
-#define IRQ_TIMERINT0_1 (IRQ_GIC_START + INT_TIMERINT0_1)
-#define IRQ_TIMERINT2_3 (IRQ_GIC_START + INT_TIMERINT2_3)
-#define IRQ_GPIOINT0 (IRQ_GIC_START + INT_GPIOINT0)
-#define IRQ_GPIOINT1 (IRQ_GIC_START + INT_GPIOINT1)
-#define IRQ_GPIOINT2 (IRQ_GIC_START + INT_GPIOINT2)
-#define IRQ_GPIOINT3 (IRQ_GIC_START + INT_GPIOINT3)
-#define IRQ_RTCINT (IRQ_GIC_START + INT_RTCINT)
-#define IRQ_SSPINT (IRQ_GIC_START + INT_SSPINT)
-#define IRQ_UARTINT0 (IRQ_GIC_START + INT_UARTINT0)
-#define IRQ_UARTINT1 (IRQ_GIC_START + INT_UARTINT1)
-#define IRQ_UARTINT2 (IRQ_GIC_START + INT_UARTINT2)
-#define IRQ_UART3 (IRQ_GIC_START + INT_UARTINT3)
-#define IRQ_SCIINT (IRQ_GIC_START + INT_SCIINT)
-#define IRQ_CLCDINT (IRQ_GIC_START + INT_CLCDINT)
-#define IRQ_DMAINT (IRQ_GIC_START + INT_DMAINT)
-#define IRQ_PWRFAILINT (IRQ_GIC_START + INT_PWRFAILINT)
-#define IRQ_MBXINT (IRQ_GIC_START + INT_MBXINT)
-#define IRQ_GNDINT (IRQ_GIC_START + INT_GNDINT)
-#define IRQ_MMCI0B (IRQ_GIC_START + INT_MMCI0B)
-#define IRQ_MMCI1B (IRQ_GIC_START + INT_MMCI1B)
-#define IRQ_KMI0 (IRQ_GIC_START + INT_KMI0)
-#define IRQ_KMI1 (IRQ_GIC_START + INT_KMI1)
-#define IRQ_SCI3 (IRQ_GIC_START + INT_SCI3)
-#define IRQ_CLCD (IRQ_GIC_START + INT_CLCD)
-#define IRQ_TOUCH (IRQ_GIC_START + INT_TOUCH)
-#define IRQ_KEYPAD (IRQ_GIC_START + INT_KEYPAD)
-#define IRQ_DoC (IRQ_GIC_START + INT_DoC)
-#define IRQ_MMCI0A (IRQ_GIC_START + INT_MMCI0A)
-#define IRQ_MMCI1A (IRQ_GIC_START + INT_MMCI1A)
-#define IRQ_AACI (IRQ_GIC_START + INT_AACI)
-#define IRQ_ETH (IRQ_GIC_START + INT_ETH)
-#define IRQ_USB (IRQ_GIC_START + INT_USB)
-#define IRQ_PMU_CPU0 (IRQ_GIC_START + INT_PMU_CPU0)
-#define IRQ_PMU_CPU1 (IRQ_GIC_START + INT_PMU_CPU1)
-#define IRQ_PMU_CPU2 (IRQ_GIC_START + INT_PMU_CPU2)
-#define IRQ_PMU_CPU3 (IRQ_GIC_START + INT_PMU_CPU3)
-#define IRQ_PMU_SCU0 (IRQ_GIC_START + INT_PMU_SCU0)
-#define IRQ_PMU_SCU1 (IRQ_GIC_START + INT_PMU_SCU1)
-#define IRQ_PMU_SCU2 (IRQ_GIC_START + INT_PMU_SCU2)
-#define IRQ_PMU_SCU3 (IRQ_GIC_START + INT_PMU_SCU3)
-#define IRQ_PMU_SCU4 (IRQ_GIC_START + INT_PMU_SCU4)
-#define IRQ_PMU_SCU5 (IRQ_GIC_START + INT_PMU_SCU5)
-#define IRQ_PMU_SCU6 (IRQ_GIC_START + INT_PMU_SCU6)
-#define IRQ_PMU_SCU7 (IRQ_GIC_START + INT_PMU_SCU7)
-#define IRQ_EB_IRQ1 (IRQ_GIC_START + INT_EB_IRQ1)
-#define IRQ_EB_IRQ2 (IRQ_GIC_START + INT_EB_IRQ2)
+#ifndef NR_IRQS
+#error "NR_IRQS not defined by the board-specific files"
+#endif
-#define IRQMASK_WDOGINT INTMASK_WDOGINT
-#define IRQMASK_SOFTINT INTMASK_SOFTINT
-#define IRQMASK_COMMRx INTMASK_COMMRx
-#define IRQMASK_COMMTx INTMASK_COMMTx
-#define IRQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1
-#define IRQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3
-#define IRQMASK_GPIOINT0 INTMASK_GPIOINT0
-#define IRQMASK_GPIOINT1 INTMASK_GPIOINT1
-#define IRQMASK_GPIOINT2 INTMASK_GPIOINT2
-#define IRQMASK_GPIOINT3 INTMASK_GPIOINT3
-#define IRQMASK_RTCINT INTMASK_RTCINT
-#define IRQMASK_SSPINT INTMASK_SSPINT
-#define IRQMASK_UARTINT0 INTMASK_UARTINT0
-#define IRQMASK_UARTINT1 INTMASK_UARTINT1
-#define IRQMASK_UARTINT2 INTMASK_UARTINT2
-#define IRQMASK_SCIINT INTMASK_SCIINT
-#define IRQMASK_CLCDINT INTMASK_CLCDINT
-#define IRQMASK_DMAINT INTMASK_DMAINT
-#define IRQMASK_PWRFAILINT INTMASK_PWRFAILINT
-#define IRQMASK_MBXINT INTMASK_MBXINT
-#define IRQMASK_GNDINT INTMASK_GNDINT
-#define IRQMASK_MMCI0B INTMASK_MMCI0B
-#define IRQMASK_MMCI1B INTMASK_MMCI1B
-#define IRQMASK_KMI0 INTMASK_KMI0
-#define IRQMASK_KMI1 INTMASK_KMI1
-#define IRQMASK_SCI3 INTMASK_SCI3
-#define IRQMASK_UART3 INTMASK_UART3
-#define IRQMASK_CLCD INTMASK_CLCD
-#define IRQMASK_TOUCH INTMASK_TOUCH
-#define IRQMASK_KEYPAD INTMASK_KEYPAD
-#define IRQMASK_DoC INTMASK_DoC
-#define IRQMASK_MMCI0A INTMASK_MMCI0A
-#define IRQMASK_MMCI1A INTMASK_MMCI1A
-#define IRQMASK_AACI INTMASK_AACI
-#define IRQMASK_ETH INTMASK_ETH
-#define IRQMASK_USB INTMASK_USB
-
-#define NR_IRQS (IRQ_GIC_START + 96)
+#endif
diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h
index 6e0eab9..4fd351b 100644
--- a/include/asm-arm/arch-realview/platform.h
+++ b/include/asm-arm/arch-realview/platform.h
@@ -18,8 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __address_h
-#define __address_h 1
+#ifndef __ASM_ARCH_PLATFORM_H
+#define __ASM_ARCH_PLATFORM_H
/*
* Memory definitions
@@ -81,11 +81,12 @@
#define REALVIEW_SYS_24MHz_OFFSET 0x5C
#define REALVIEW_SYS_MISC_OFFSET 0x60
#define REALVIEW_SYS_IOSEL_OFFSET 0x70
-#define REALVIEW_SYS_TEST_OSC0_OFFSET 0x80
-#define REALVIEW_SYS_TEST_OSC1_OFFSET 0x84
-#define REALVIEW_SYS_TEST_OSC2_OFFSET 0x88
-#define REALVIEW_SYS_TEST_OSC3_OFFSET 0x8C
-#define REALVIEW_SYS_TEST_OSC4_OFFSET 0x90
+#define REALVIEW_SYS_PROCID_OFFSET 0x84
+#define REALVIEW_SYS_TEST_OSC0_OFFSET 0xC0
+#define REALVIEW_SYS_TEST_OSC1_OFFSET 0xC4
+#define REALVIEW_SYS_TEST_OSC2_OFFSET 0xC8
+#define REALVIEW_SYS_TEST_OSC3_OFFSET 0xCC
+#define REALVIEW_SYS_TEST_OSC4_OFFSET 0xD0
#define REALVIEW_SYS_BASE 0x10000000
#define REALVIEW_SYS_ID (REALVIEW_SYS_BASE + REALVIEW_SYS_ID_OFFSET)
@@ -114,6 +115,7 @@
#define REALVIEW_SYS_24MHz (REALVIEW_SYS_BASE + REALVIEW_SYS_24MHz_OFFSET)
#define REALVIEW_SYS_MISC (REALVIEW_SYS_BASE + REALVIEW_SYS_MISC_OFFSET)
#define REALVIEW_SYS_IOSEL (REALVIEW_SYS_BASE + REALVIEW_SYS_IOSEL_OFFSET)
+#define REALVIEW_SYS_PROCID (REALVIEW_SYS_BASE + REALVIEW_SYS_PROCID_OFFSET)
#define REALVIEW_SYS_TEST_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC0_OFFSET)
#define REALVIEW_SYS_TEST_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC1_OFFSET)
#define REALVIEW_SYS_TEST_OSC2 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC2_OFFSET)
@@ -203,30 +205,8 @@
/* Reserved 0x1001A000 - 0x1001FFFF */
#define REALVIEW_CLCD_BASE 0x10020000 /* CLCD */
#define REALVIEW_DMAC_BASE 0x10030000 /* DMA controller */
-#ifndef CONFIG_REALVIEW_MPCORE
#define REALVIEW_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */
#define REALVIEW_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */
-#else
-#ifdef CONFIG_REALVIEW_MPCORE_REVB
-#define REALVIEW_MPCORE_SCU_BASE 0x10100000 /* SCU registers */
-#define REALVIEW_GIC_CPU_BASE 0x10100100 /* Generic interrupt controller CPU interface */
-#define REALVIEW_TWD_BASE 0x10100700
-#define REALVIEW_TWD_SIZE 0x00000100
-#define REALVIEW_GIC_DIST_BASE 0x10101000 /* Generic interrupt controller distributor */
-#define REALVIEW_MPCORE_L220_BASE 0x10102000 /* L220 registers */
-#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0xD8 /* Register offset for MPCore sysctl */
-#else
-#define REALVIEW_MPCORE_SCU_BASE 0x1F000000 /* SCU registers */
-#define REALVIEW_GIC_CPU_BASE 0x1F000100 /* Generic interrupt controller CPU interface */
-#define REALVIEW_TWD_BASE 0x1F000700
-#define REALVIEW_TWD_SIZE 0x00000100
-#define REALVIEW_GIC_DIST_BASE 0x1F001000 /* Generic interrupt controller distributor */
-#define REALVIEW_MPCORE_L220_BASE 0x1F002000 /* L220 registers */
-#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0x74 /* Register offset for MPCore sysctl */
-#endif
-#define REALVIEW_GIC1_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */
-#define REALVIEW_GIC1_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */
-#endif
#define REALVIEW_SMC_BASE 0x10080000 /* SMC */
/* Reserved 0x10090000 - 0x100EFFFF */
@@ -283,134 +263,6 @@
#define REALVIEW_INTREG_OFFSET 0x8 /* Interrupt control */
#define REALVIEW_DECODE_OFFSET 0xC /* Fitted logic modules */
-/* ------------------------------------------------------------------------
- * Interrupts - bit assignment (primary)
- * ------------------------------------------------------------------------
- */
-#ifndef CONFIG_REALVIEW_MPCORE
-#define INT_WDOGINT 0 /* Watchdog timer */
-#define INT_SOFTINT 1 /* Software interrupt */
-#define INT_COMMRx 2 /* Debug Comm Rx interrupt */
-#define INT_COMMTx 3 /* Debug Comm Tx interrupt */
-#define INT_TIMERINT0_1 4 /* Timer 0 and 1 */
-#define INT_TIMERINT2_3 5 /* Timer 2 and 3 */
-#define INT_GPIOINT0 6 /* GPIO 0 */
-#define INT_GPIOINT1 7 /* GPIO 1 */
-#define INT_GPIOINT2 8 /* GPIO 2 */
-/* 9 reserved */
-#define INT_RTCINT 10 /* Real Time Clock */
-#define INT_SSPINT 11 /* Synchronous Serial Port */
-#define INT_UARTINT0 12 /* UART 0 on development chip */
-#define INT_UARTINT1 13 /* UART 1 on development chip */
-#define INT_UARTINT2 14 /* UART 2 on development chip */
-#define INT_UARTINT3 15 /* UART 3 on development chip */
-#define INT_SCIINT 16 /* Smart Card Interface */
-#define INT_MMCI0A 17 /* Multimedia Card 0A */
-#define INT_MMCI0B 18 /* Multimedia Card 0B */
-#define INT_AACI 19 /* Audio Codec */
-#define INT_KMI0 20 /* Keyboard/Mouse port 0 */
-#define INT_KMI1 21 /* Keyboard/Mouse port 1 */
-#define INT_CHARLCD 22 /* Character LCD */
-#define INT_CLCDINT 23 /* CLCD controller */
-#define INT_DMAINT 24 /* DMA controller */
-#define INT_PWRFAILINT 25 /* Power failure */
-#define INT_PISMO 26
-#define INT_DoC 27 /* Disk on Chip memory controller */
-#define INT_ETH 28 /* Ethernet controller */
-#define INT_USB 29 /* USB controller */
-#define INT_TSPENINT 30 /* Touchscreen pen */
-#define INT_TSKPADINT 31 /* Touchscreen keypad */
-
-#else
-
-#define MAX_GIC_NR 2
-
-#define INT_AACI 0
-#define INT_TIMERINT0_1 1
-#define INT_TIMERINT2_3 2
-#define INT_USB 3
-#define INT_UARTINT0 4
-#define INT_UARTINT1 5
-#define INT_RTCINT 6
-#define INT_KMI0 7
-#define INT_KMI1 8
-#define INT_ETH 9
-#define INT_EB_IRQ1 10 /* main GIC */
-#define INT_EB_IRQ2 11 /* tile GIC */
-#define INT_EB_FIQ1 12 /* main GIC */
-#define INT_EB_FIQ2 13 /* tile GIC */
-#define INT_MMCI0A 14
-#define INT_MMCI0B 15
-
-#define INT_PMU_CPU0 17
-#define INT_PMU_CPU1 18
-#define INT_PMU_CPU2 19
-#define INT_PMU_CPU3 20
-#define INT_PMU_SCU0 21
-#define INT_PMU_SCU1 22
-#define INT_PMU_SCU2 23
-#define INT_PMU_SCU3 24
-#define INT_PMU_SCU4 25
-#define INT_PMU_SCU5 26
-#define INT_PMU_SCU6 27
-#define INT_PMU_SCU7 28
-
-#define INT_L220_EVENT 29
-#define INT_L220_SLAVE 30
-#define INT_L220_DECODE 31
-
-#define INT_UARTINT2 -1
-#define INT_UARTINT3 -1
-#define INT_CLCDINT -1
-#define INT_DMAINT -1
-#define INT_WDOGINT -1
-#define INT_GPIOINT0 -1
-#define INT_GPIOINT1 -1
-#define INT_GPIOINT2 -1
-#define INT_SCIINT -1
-#define INT_SSPINT -1
-#endif
-
-/*
- * Interrupt bit positions
- *
- */
-#define INTMASK_WDOGINT (1 << INT_WDOGINT)
-#define INTMASK_SOFTINT (1 << INT_SOFTINT)
-#define INTMASK_COMMRx (1 << INT_COMMRx)
-#define INTMASK_COMMTx (1 << INT_COMMTx)
-#define INTMASK_TIMERINT0_1 (1 << INT_TIMERINT0_1)
-#define INTMASK_TIMERINT2_3 (1 << INT_TIMERINT2_3)
-#define INTMASK_GPIOINT0 (1 << INT_GPIOINT0)
-#define INTMASK_GPIOINT1 (1 << INT_GPIOINT1)
-#define INTMASK_GPIOINT2 (1 << INT_GPIOINT2)
-#define INTMASK_RTCINT (1 << INT_RTCINT)
-#define INTMASK_SSPINT (1 << INT_SSPINT)
-#define INTMASK_UARTINT0 (1 << INT_UARTINT0)
-#define INTMASK_UARTINT1 (1 << INT_UARTINT1)
-#define INTMASK_UARTINT2 (1 << INT_UARTINT2)
-#define INTMASK_UARTINT3 (1 << INT_UARTINT3)
-#define INTMASK_SCIINT (1 << INT_SCIINT)
-#define INTMASK_MMCI0A (1 << INT_MMCI0A)
-#define INTMASK_MMCI0B (1 << INT_MMCI0B)
-#define INTMASK_AACI (1 << INT_AACI)
-#define INTMASK_KMI0 (1 << INT_KMI0)
-#define INTMASK_KMI1 (1 << INT_KMI1)
-#define INTMASK_CHARLCD (1 << INT_CHARLCD)
-#define INTMASK_CLCDINT (1 << INT_CLCDINT)
-#define INTMASK_DMAINT (1 << INT_DMAINT)
-#define INTMASK_PWRFAILINT (1 << INT_PWRFAILINT)
-#define INTMASK_PISMO (1 << INT_PISMO)
-#define INTMASK_DoC (1 << INT_DoC)
-#define INTMASK_ETH (1 << INT_ETH)
-#define INTMASK_USB (1 << INT_USB)
-#define INTMASK_TSPENINT (1 << INT_TSPENINT)
-#define INTMASK_TSKPADINT (1 << INT_TSKPADINT)
-
-#define MAXIRQNUM 31
-#define MAXFIQNUM 31
-#define MAXSWINUM 31
-
/*
* Application Flash
*
@@ -463,6 +315,4 @@
#define REALVIEW_CSR_BASE 0x10000000
#define REALVIEW_CSR_SIZE 0x10000000
-#endif
-
-/* END */
+#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/include/asm-arm/arch-realview/scu.h b/include/asm-arm/arch-realview/scu.h
index cc29364..08b3db8 100644
--- a/include/asm-arm/arch-realview/scu.h
+++ b/include/asm-arm/arch-realview/scu.h
@@ -1,8 +1,8 @@
#ifndef __ASMARM_ARCH_SCU_H
#define __ASMARM_ARCH_SCU_H
-#include <asm/arch/platform.h>
+#include <asm/arch/board-eb.h>
-#define SCU_BASE REALVIEW_MPCORE_SCU_BASE
+#define SCU_BASE REALVIEW_EB11MP_SCU_BASE
#endif
diff --git a/include/asm-arm/arch-realview/uncompress.h b/include/asm-arm/arch-realview/uncompress.h
index f05631d..3d5c2db 100644
--- a/include/asm-arm/arch-realview/uncompress.h
+++ b/include/asm-arm/arch-realview/uncompress.h
@@ -19,6 +19,8 @@
*/
#include <asm/hardware.h>
+#include <asm/arch/platform.h>
+
#define AMBA_UART_DR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x00))
#define AMBA_UART_LCRH (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x2c))
#define AMBA_UART_CR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x30))
diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h
index 76fe5f6..bd85484 100644
--- a/include/asm-arm/arch-s3c2410/regs-lcd.h
+++ b/include/asm-arm/arch-s3c2410/regs-lcd.h
@@ -147,7 +147,16 @@
#define S3C2412_FRCPAT(x) S3C2410_LCDREG(0xB4 + ((x)*4))
+/* general registers */
+
+/* base of the LCD registers, where INTPND, INTSRC and then INTMSK
+ * are available. */
+
+#define S3C2410_LCDINTBASE S3C2410_LCDREG(0x54)
+#define S3C2412_LCDINTBASE S3C2410_LCDREG(0x24)
+
+#define S3C24XX_LCDINTPND (0x00)
+#define S3C24XX_LCDSRCPND (0x04)
+#define S3C24XX_LCDINTMSK (0x08)
+
#endif /* ___ASM_ARCH_REGS_LCD_H */
-
-
-
diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h
index ba1dca8..7380373 100644
--- a/include/asm-arm/arch-s3c2410/spi-gpio.h
+++ b/include/asm-arm/arch-s3c2410/spi-gpio.h
@@ -13,9 +13,6 @@
#ifndef __ASM_ARCH_SPIGPIO_H
#define __ASM_ARCH_SPIGPIO_H __FILE__
-struct s3c2410_spigpio_info;
-struct spi_board_info;
-
struct s3c2410_spigpio_info {
unsigned long pin_clk;
unsigned long pin_mosi;
@@ -23,9 +20,6 @@
int bus_num;
- unsigned long board_size;
- struct spi_board_info *board_info;
-
void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
};
diff --git a/include/asm-arm/arch-s3c2410/spi.h b/include/asm-arm/arch-s3c2410/spi.h
index 4029a1a..7ca0ed9 100644
--- a/include/asm-arm/arch-s3c2410/spi.h
+++ b/include/asm-arm/arch-s3c2410/spi.h
@@ -13,15 +13,9 @@
#ifndef __ASM_ARCH_SPI_H
#define __ASM_ARCH_SPI_H __FILE__
-struct s3c2410_spi_info;
-struct spi_board_info;
-
struct s3c2410_spi_info {
unsigned long pin_cs; /* simple gpio cs */
- unsigned long board_size;
- struct spi_board_info *board_info;
-
void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
};
diff --git a/include/asm-arm/arch-versatile/irqs.h b/include/asm-arm/arch-versatile/irqs.h
index 745aa84..f7263b9 100644
--- a/include/asm-arm/arch-versatile/irqs.h
+++ b/include/asm-arm/arch-versatile/irqs.h
@@ -22,7 +22,7 @@
#include <asm/arch/platform.h>
/*
- * IRQ interrupts definitions are the same the INT definitions
+ * IRQ interrupts definitions are the same as the INT definitions
* held within platform.h
*/
#define IRQ_VIC_START 0
@@ -94,7 +94,7 @@
#define IRQMASK_VICSOURCE31 INTMASK_VICSOURCE31
/*
- * FIQ interrupts definitions are the same the INT definitions.
+ * FIQ interrupts definitions are the same as the INT definitions.
*/
#define FIQ_WDOGINT INT_WDOGINT
#define FIQ_SOFTINT INT_SOFTINT
diff --git a/include/asm-arm/hardware/arm_twd.h b/include/asm-arm/hardware/arm_twd.h
index 131d5b4..e521b70 100644
--- a/include/asm-arm/hardware/arm_twd.h
+++ b/include/asm-arm/hardware/arm_twd.h
@@ -1,7 +1,7 @@
#ifndef __ASM_HARDWARE_TWD_H
#define __ASM_HARDWARE_TWD_H
-#define TWD_TIMER_LOAD 0x00
+#define TWD_TIMER_LOAD 0x00
#define TWD_TIMER_COUNTER 0x04
#define TWD_TIMER_CONTROL 0x08
#define TWD_TIMER_INTSTAT 0x0C
@@ -13,4 +13,9 @@
#define TWD_WDOG_RESETSTAT 0x30
#define TWD_WDOG_DISABLE 0x34
+#define TWD_TIMER_CONTROL_ENABLE (1 << 0)
+#define TWD_TIMER_CONTROL_ONESHOT (0 << 1)
+#define TWD_TIMER_CONTROL_PERIODIC (1 << 1)
+#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2)
+
#endif
diff --git a/include/asm-arm/hardware/iop3xx-adma.h b/include/asm-arm/hardware/iop3xx-adma.h
index 10834b5..5c529e6 100644
--- a/include/asm-arm/hardware/iop3xx-adma.h
+++ b/include/asm-arm/hardware/iop3xx-adma.h
@@ -414,7 +414,7 @@
}
static inline void
-iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags)
{
struct iop3xx_desc_dma *hw_desc = desc->hw_desc;
union {
@@ -425,14 +425,14 @@
u_desc_ctrl.value = 0;
u_desc_ctrl.field.mem_to_mem_en = 1;
u_desc_ctrl.field.pci_transaction = 0xe; /* memory read block */
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
hw_desc->upper_pci_src_addr = 0;
hw_desc->crc_addr = 0;
}
static inline void
-iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags)
{
struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
union {
@@ -443,12 +443,13 @@
u_desc_ctrl.value = 0;
u_desc_ctrl.field.blk1_cmd_ctrl = 0x2; /* memory block fill */
u_desc_ctrl.field.dest_write_en = 1;
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
}
static inline u32
-iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt, int int_en)
+iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt,
+ unsigned long flags)
{
int i, shift;
u32 edcr;
@@ -509,21 +510,23 @@
u_desc_ctrl.field.dest_write_en = 1;
u_desc_ctrl.field.blk1_cmd_ctrl = 0x7; /* direct fill */
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
return u_desc_ctrl.value;
}
static inline void
-iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+ unsigned long flags)
{
- iop3xx_desc_init_xor(desc->hw_desc, src_cnt, int_en);
+ iop3xx_desc_init_xor(desc->hw_desc, src_cnt, flags);
}
/* return the number of operations */
static inline int
-iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
+ unsigned long flags)
{
int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
struct iop3xx_desc_aau *hw_desc, *prev_hw_desc, *iter;
@@ -538,10 +541,10 @@
for (i = 0, j = 0; (slot_cnt -= slots_per_op) >= 0;
i += slots_per_op, j++) {
iter = iop_hw_desc_slot_idx(hw_desc, i);
- u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, int_en);
+ u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, flags);
u_desc_ctrl.field.dest_write_en = 0;
u_desc_ctrl.field.zero_result_en = 1;
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
iter->desc_ctrl = u_desc_ctrl.value;
/* for the subsequent descriptors preserve the store queue
@@ -559,7 +562,8 @@
}
static inline void
-iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+ unsigned long flags)
{
struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
union {
@@ -591,7 +595,7 @@
}
u_desc_ctrl.field.dest_write_en = 0;
- u_desc_ctrl.field.int_en = int_en;
+ u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
hw_desc->desc_ctrl = u_desc_ctrl.value;
}
diff --git a/include/asm-arm/hardware/it8152.h b/include/asm-arm/hardware/it8152.h
index aaebb61..74b5fff 100644
--- a/include/asm-arm/hardware/it8152.h
+++ b/include/asm-arm/hardware/it8152.h
@@ -42,7 +42,7 @@
#define IT8152_GPIO_GPDR __REG_IT8152(0x3f00500)
/*
- Interrup contoler per register summary:
+ Interrupt controller per register summary:
---------------------------------------
LCDNIRR:
IT8152_LD_IRQ(8) PCICLK stop
diff --git a/include/asm-arm/kexec.h b/include/asm-arm/kexec.h
index 46dcc4d..1ee17b6 100644
--- a/include/asm-arm/kexec.h
+++ b/include/asm-arm/kexec.h
@@ -16,6 +16,9 @@
#define KEXEC_BOOT_PARAMS_SIZE 1536
+#define KEXEC_ARM_ATAGS_OFFSET 0x1000
+#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
+
#ifndef __ASSEMBLY__
struct kimage;
diff --git a/include/asm-arm/mach/udc_pxa2xx.h b/include/asm-arm/mach/udc_pxa2xx.h
index ff0a957..f9f3606 100644
--- a/include/asm-arm/mach/udc_pxa2xx.h
+++ b/include/asm-arm/mach/udc_pxa2xx.h
@@ -16,10 +16,12 @@
#define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */
/* Boards following the design guidelines in the developer's manual,
- * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
+ * with on-chip GPIOs not Lubbock's weird hardware, can have a sane
* VBUS IRQ and omit the methods above. Store the GPIO number
* here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
+ * Note that sometimes the signals go through inverters...
*/
+ bool gpio_vbus_inverted;
u16 gpio_vbus; /* high == vbus present */
u16 gpio_pullup; /* high == pullup activated */
};
diff --git a/include/asm-arm/pgalloc.h b/include/asm-arm/pgalloc.h
index 4d43945..fb6c6e3 100644
--- a/include/asm-arm/pgalloc.h
+++ b/include/asm-arm/pgalloc.h
@@ -27,14 +27,14 @@
* Since we have only two-level page tables, these are trivial
*/
#define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(pmd) do { } while (0)
+#define pmd_free(mm, pmd) do { } while (0)
#define pgd_populate(mm,pmd,pte) BUG()
extern pgd_t *get_pgd_slow(struct mm_struct *mm);
-extern void free_pgd_slow(pgd_t *pgd);
+extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
#define pgd_alloc(mm) get_pgd_slow(mm)
-#define pgd_free(pgd) free_pgd_slow(pgd)
+#define pgd_free(mm, pgd) free_pgd_slow(mm, pgd)
/*
* Allocate one PTE table.
@@ -83,7 +83,7 @@
/*
* Free one PTE table.
*/
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
if (pte) {
pte -= PTRS_PER_PTE;
@@ -91,7 +91,7 @@
}
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h
index f67acce..af99636 100644
--- a/include/asm-arm/smp.h
+++ b/include/asm-arm/smp.h
@@ -61,6 +61,11 @@
extern void smp_send_timer(void);
/*
+ * Broadcast a clock event to other CPUs.
+ */
+extern void smp_timer_broadcast(cpumask_t mask);
+
+/*
* Boot a secondary CPU, and assign it the specified idle task.
* This also gives us the initial stack to use for this CPU.
*/
@@ -96,11 +101,12 @@
extern int platform_cpu_kill(unsigned int cpu);
extern void platform_cpu_enable(unsigned int cpu);
-#ifdef CONFIG_LOCAL_TIMERS
/*
- * Setup a local timer interrupt for a CPU.
+ * Local timer interrupt handling function (can be IPI'ed).
*/
-extern void local_timer_setup(unsigned int cpu);
+extern void local_timer_interrupt(void);
+
+#ifdef CONFIG_LOCAL_TIMERS
/*
* Stop a local timer interrupt.
@@ -114,10 +120,6 @@
#else
-static inline void local_timer_setup(unsigned int cpu)
-{
-}
-
static inline void local_timer_stop(unsigned int cpu)
{
}
@@ -125,6 +127,11 @@
#endif
/*
+ * Setup a local timer interrupt for a CPU.
+ */
+extern void local_timer_setup(unsigned int cpu);
+
+/*
* show local interrupt info
*/
extern void show_local_irqs(struct seq_file *);
diff --git a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h
index cb74002..36bd402 100644
--- a/include/asm-arm/tlb.h
+++ b/include/asm-arm/tlb.h
@@ -85,8 +85,8 @@
}
#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb,ptep) pte_free(ptep)
-#define pmd_free_tlb(tlb,pmdp) pmd_free(pmdp)
+#define pte_free_tlb(tlb, ptep) pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp) pmd_free((tlb)->mm, pmdp)
#define tlb_migrate_finish(mm) do { } while (0)
diff --git a/include/asm-avr32/arch-at32ap/at32ap700x.h b/include/asm-avr32/arch-at32ap/at32ap700x.h
index 99684d6..31e48b0 100644
--- a/include/asm-avr32/arch-at32ap/at32ap700x.h
+++ b/include/asm-avr32/arch-at32ap/at32ap700x.h
@@ -13,8 +13,6 @@
#define GPIO_PERIPH_A 0
#define GPIO_PERIPH_B 1
-#define NR_GPIO_CONTROLLERS 4
-
/*
* Pin numbers identifying specific GPIO pins on the chip. They can
* also be converted to IRQ numbers by passing them through
diff --git a/include/asm-avr32/arch-at32ap/gpio.h b/include/asm-avr32/arch-at32ap/gpio.h
index af7f953..0180f58 100644
--- a/include/asm-avr32/arch-at32ap/gpio.h
+++ b/include/asm-avr32/arch-at32ap/gpio.h
@@ -5,20 +5,36 @@
#include <asm/irq.h>
-/* Arch-neutral GPIO API */
-int __must_check gpio_request(unsigned int gpio, const char *label);
-void gpio_free(unsigned int gpio);
+/* Some GPIO chips can manage IRQs; some can't. The exact numbers can
+ * be changed if needed, but for the moment they're not configurable.
+ */
+#define ARCH_NR_GPIOS (NR_GPIO_IRQS + 2 * 32)
-int gpio_direction_input(unsigned int gpio);
-int gpio_direction_output(unsigned int gpio, int value);
-int gpio_get_value(unsigned int gpio);
-void gpio_set_value(unsigned int gpio, int value);
-#include <asm-generic/gpio.h> /* cansleep wrappers */
+/* Arch-neutral GPIO API, supporting both "native" and external GPIOs. */
+#include <asm-generic/gpio.h>
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
static inline int gpio_to_irq(unsigned int gpio)
{
- return gpio + GPIO_IRQ_BASE;
+ if (gpio < NR_GPIO_IRQS)
+ return gpio + GPIO_IRQ_BASE;
+ return -EINVAL;
}
static inline int irq_to_gpio(unsigned int irq)
diff --git a/include/asm-avr32/arch-at32ap/irq.h b/include/asm-avr32/arch-at32ap/irq.h
index 5adffab..608e350 100644
--- a/include/asm-avr32/arch-at32ap/irq.h
+++ b/include/asm-avr32/arch-at32ap/irq.h
@@ -3,11 +3,11 @@
#define EIM_IRQ_BASE NR_INTERNAL_IRQS
#define NR_EIM_IRQS 32
-
#define AT32_EXTINT(n) (EIM_IRQ_BASE + (n))
#define GPIO_IRQ_BASE (EIM_IRQ_BASE + NR_EIM_IRQS)
-#define NR_GPIO_IRQS (5 * 32)
+#define NR_GPIO_CTLR (5 /*internal*/ + 1 /*external*/)
+#define NR_GPIO_IRQS (NR_GPIO_CTLR * 32)
#define NR_IRQS (GPIO_IRQ_BASE + NR_GPIO_IRQS)
diff --git a/include/asm-avr32/delay.h b/include/asm-avr32/delay.h
index cc3b2e3..a0ed9a9 100644
--- a/include/asm-avr32/delay.h
+++ b/include/asm-avr32/delay.h
@@ -12,7 +12,7 @@
extern void __udelay(unsigned long usecs);
extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
extern void __delay(unsigned long loops);
#define udelay(n) (__builtin_constant_p(n) ? \
diff --git a/include/asm-avr32/pgalloc.h b/include/asm-avr32/pgalloc.h
index 0e680f4..b77e364 100644
--- a/include/asm-avr32/pgalloc.h
+++ b/include/asm-avr32/pgalloc.h
@@ -30,7 +30,7 @@
return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
kfree(pgd);
}
@@ -55,12 +55,12 @@
return pte;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
diff --git a/include/asm-avr32/timex.h b/include/asm-avr32/timex.h
index 5e44ecb..187dcf3 100644
--- a/include/asm-avr32/timex.h
+++ b/include/asm-avr32/timex.h
@@ -34,7 +34,6 @@
return 0;
}
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER 1
+#define ARCH_HAS_READ_CURRENT_TIMER
#endif /* __ASM_AVR32_TIMEX_H */
diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h
index de09009..89861a2 100644
--- a/include/asm-avr32/unistd.h
+++ b/include/asm-avr32/unistd.h
@@ -297,7 +297,7 @@
#define __NR_utimensat 278
#define __NR_signalfd 279
-#define __NR_timerfd 280
+/* 280 was __NR_timerfd */
#define __NR_eventfd 281
#ifdef __KERNEL__
diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h
index 1601d62f..574fe56 100644
--- a/include/asm-blackfin/io.h
+++ b/include/asm-blackfin/io.h
@@ -188,8 +188,6 @@
#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT)
-#define mm_ptov(vaddr) ((void *) (vaddr))
-#define mm_vtop(vaddr) ((unsigned long) (vaddr))
#define phys_to_virt(vaddr) ((void *) (vaddr))
#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h
index e2f49c2..75ea6e0 100644
--- a/include/asm-cris/bitops.h
+++ b/include/asm-cris/bitops.h
@@ -24,13 +24,6 @@
#include <linux/compiler.h>
/*
- * Some hacks to defeat gcc over-optimizations..
- */
-struct __dummy { unsigned long a[100]; };
-#define ADDR (*(struct __dummy *) addr)
-#define CONST_ADDR (*(const struct __dummy *) addr)
-
-/*
* set_bit - Atomically set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h
index deaddfe..8ddd66f 100644
--- a/include/asm-cris/pgalloc.h
+++ b/include/asm-cris/pgalloc.h
@@ -16,7 +16,7 @@
return (pgd_t *)get_zeroed_page(GFP_KERNEL);
}
-static inline void pgd_free (pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
@@ -34,12 +34,12 @@
return pte;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h
index d425d8d..6ec494a 100644
--- a/include/asm-frv/atomic.h
+++ b/include/asm-frv/atomic.h
@@ -1,7 +1,7 @@
/* atomic.h: atomic operation emulation for FR-V
*
* For an explanation of how atomic ops work in this arch, see:
- * Documentation/fujitsu/frv/atomic-ops.txt
+ * Documentation/frv/atomic-ops.txt
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h
index e29de71..5f86b87 100644
--- a/include/asm-frv/bitops.h
+++ b/include/asm-frv/bitops.h
@@ -1,7 +1,7 @@
/* bitops.h: bit operations for the Fujitsu FR-V CPUs
*
* For an explanation of how atomic ops work in this arch, see:
- * Documentation/fujitsu/frv/atomic-ops.txt
+ * Documentation/frv/atomic-ops.txt
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
diff --git a/include/asm-frv/cacheflush.h b/include/asm-frv/cacheflush.h
index 0250040..432a69e 100644
--- a/include/asm-frv/cacheflush.h
+++ b/include/asm-frv/cacheflush.h
@@ -29,7 +29,7 @@
#define flush_dcache_mmap_unlock(mapping) do {} while(0)
/*
- * physically-indexed cache managment
+ * physically-indexed cache management
* - see arch/frv/lib/cache.S
*/
extern void frv_dcache_writeback(unsigned long start, unsigned long size);
diff --git a/include/asm-frv/dma-mapping.h b/include/asm-frv/dma-mapping.h
index bcb2df6..2e8966c 100644
--- a/include/asm-frv/dma-mapping.h
+++ b/include/asm-frv/dma-mapping.h
@@ -17,16 +17,6 @@
void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle);
/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg) ((sg)->dma_address)
-#define sg_dma_len(sg) ((sg)->length)
-
-/*
* Map a single buffer of the indicated size for DMA in streaming mode.
* The 32-bit bus address to use is returned.
*
diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h
index ff4d6cd..26cefcd 100644
--- a/include/asm-frv/highmem.h
+++ b/include/asm-frv/highmem.h
@@ -4,7 +4,7 @@
* Written by David Howells (dhowells@redhat.com)
* - Derived from include/asm-i386/highmem.h
*
- * See Documentation/fujitsu/frv/mmu-layout.txt for more information.
+ * See Documentation/frv/mmu-layout.txt for more information.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/include/asm-frv/mem-layout.h b/include/asm-frv/mem-layout.h
index aaf2a77..8353225 100644
--- a/include/asm-frv/mem-layout.h
+++ b/include/asm-frv/mem-layout.h
@@ -39,7 +39,7 @@
#ifdef CONFIG_MMU
-/* see Documentation/fujitsu/frv/mmu-layout.txt */
+/* see Documentation/frv/mmu-layout.txt */
#define KERNEL_LOWMEM_START __UL(0xc0000000)
#define KERNEL_LOWMEM_END __UL(0xd0000000)
#define VMALLOC_START __UL(0xd0000000)
diff --git a/include/asm-frv/page.h b/include/asm-frv/page.h
index 213d92f..bd9bd2d 100644
--- a/include/asm-frv/page.h
+++ b/include/asm-frv/page.h
@@ -76,10 +76,6 @@
#endif /* __ASSEMBLY__ */
-#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
-#define WANT_PAGE_VIRTUAL 1
-#endif
-
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
diff --git a/include/asm-frv/pgalloc.h b/include/asm-frv/pgalloc.h
index ce982a6..e89620e 100644
--- a/include/asm-frv/pgalloc.h
+++ b/include/asm-frv/pgalloc.h
@@ -31,18 +31,18 @@
*/
extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *);
+extern void pgd_free(struct mm_struct *mm, pgd_t *);
extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
@@ -55,7 +55,7 @@
* (In the PAE case we free the pmds as part of the pgd.)
*/
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *) 2); })
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
#endif /* CONFIG_MMU */
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 147e995..6c0682e 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -93,7 +93,7 @@
/*
* we use 2-level page tables, folding the PMD (mid-level table) into the PGE (top-level entry)
- * [see Documentation/fujitsu/frv/mmu-layout.txt]
+ * [see Documentation/frv/mmu-layout.txt]
*
* Page Directory:
* - Size: 16KB
@@ -226,7 +226,7 @@
* inside the pgd, so has no extra memory associated with it.
*/
#define pud_alloc_one(mm, address) NULL
-#define pud_free(x) do { } while (0)
+#define pud_free(mm, x) do { } while (0)
#define __pud_free_tlb(tlb, x) do { } while (0)
/*
diff --git a/include/asm-frv/scatterlist.h b/include/asm-frv/scatterlist.h
index 2e7143b..4bca8a2 100644
--- a/include/asm-frv/scatterlist.h
+++ b/include/asm-frv/scatterlist.h
@@ -31,6 +31,16 @@
unsigned int length;
};
+/*
+ * These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->length)
+
#define ISA_DMA_THRESHOLD (0xffffffffUL)
#endif /* !_ASM_SCATTERLIST_H */
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index cd84f17..e8c9866 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -328,7 +328,7 @@
#define __NR_epoll_pwait 319
#define __NR_utimensat 320
#define __NR_signalfd 321
-#define __NR_timerfd 322
+/* #define __NR_timerfd 322 removed */
#define __NR_eventfd 323
#define __NR_fallocate 324
diff --git a/include/asm-generic/4level-fixup.h b/include/asm-generic/4level-fixup.h
index 7b88d39..9d40e87 100644
--- a/include/asm-generic/4level-fixup.h
+++ b/include/asm-generic/4level-fixup.h
@@ -28,7 +28,7 @@
#undef pud_free_tlb
#define pud_free_tlb(tlb, x) do { } while (0)
-#define pud_free(x) do { } while (0)
+#define pud_free(mm, x) do { } while (0)
#define __pud_free_tlb(tlb, x) do { } while (0)
#undef pud_addr_end
diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h
index 09204e4..1c1fa42 100644
--- a/include/asm-generic/cputime.h
+++ b/include/asm-generic/cputime.h
@@ -18,6 +18,7 @@
#define cputime_lt(__a, __b) ((__a) < (__b))
#define cputime_le(__a, __b) ((__a) <= (__b))
#define cputime_to_jiffies(__ct) (__ct)
+#define cputime_to_scaled(__ct) (__ct)
#define jiffies_to_cputime(__hz) (__hz)
typedef u64 cputime64_t;
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 2d0aab1..f29a502 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -1,6 +1,102 @@
#ifndef _ASM_GENERIC_GPIO_H
#define _ASM_GENERIC_GPIO_H
+#ifdef CONFIG_HAVE_GPIO_LIB
+
+/* Platforms may implement their GPIO interface with library code,
+ * at a small performance cost for non-inlined operations and some
+ * extra memory (for code and for per-GPIO table entries).
+ *
+ * While the GPIO programming interface defines valid GPIO numbers
+ * to be in the range 0..MAX_INT, this library restricts them to the
+ * smaller range 0..ARCH_NR_GPIOS.
+ */
+
+#ifndef ARCH_NR_GPIOS
+#define ARCH_NR_GPIOS 256
+#endif
+
+struct seq_file;
+
+/**
+ * struct gpio_chip - abstract a GPIO controller
+ * @label: for diagnostics
+ * @direction_input: configures signal "offset" as input, or returns error
+ * @get: returns value for signal "offset"; for output signals this
+ * returns either the value actually sensed, or zero
+ * @direction_output: configures signal "offset" as output, or returns error
+ * @set: assigns output value for signal "offset"
+ * @dbg_show: optional routine to show contents in debugfs; default code
+ * will be used when this is omitted, but custom code can show extra
+ * state (such as pullup/pulldown configuration).
+ * @base: identifies the first GPIO number handled by this chip; or, if
+ * negative during registration, requests dynamic ID allocation.
+ * @ngpio: the number of GPIOs handled by this controller; the last GPIO
+ * handled is (base + ngpio - 1).
+ * @can_sleep: flag must be set iff get()/set() methods sleep, as they
+ * must while accessing GPIO expander chips over I2C or SPI
+ *
+ * A gpio_chip can help platforms abstract various sources of GPIOs so
+ * they can all be accessed through a common programing interface.
+ * Example sources would be SOC controllers, FPGAs, multifunction
+ * chips, dedicated GPIO expanders, and so on.
+ *
+ * Each chip controls a number of signals, identified in method calls
+ * by "offset" values in the range 0..(@ngpio - 1). When those signals
+ * are referenced through calls like gpio_get_value(gpio), the offset
+ * is calculated by subtracting @base from the gpio number.
+ */
+struct gpio_chip {
+ char *label;
+
+ int (*direction_input)(struct gpio_chip *chip,
+ unsigned offset);
+ int (*get)(struct gpio_chip *chip,
+ unsigned offset);
+ int (*direction_output)(struct gpio_chip *chip,
+ unsigned offset, int value);
+ void (*set)(struct gpio_chip *chip,
+ unsigned offset, int value);
+ void (*dbg_show)(struct seq_file *s,
+ struct gpio_chip *chip);
+ int base;
+ u16 ngpio;
+ unsigned can_sleep:1;
+};
+
+extern const char *gpiochip_is_requested(struct gpio_chip *chip,
+ unsigned offset);
+
+/* add/remove chips */
+extern int gpiochip_add(struct gpio_chip *chip);
+extern int __must_check gpiochip_remove(struct gpio_chip *chip);
+
+
+/* Always use the library code for GPIO management calls,
+ * or when sleeping may be involved.
+ */
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
+
+extern int gpio_get_value_cansleep(unsigned gpio);
+extern void gpio_set_value_cansleep(unsigned gpio, int value);
+
+
+/* A platform's <asm/gpio.h> code may want to inline the I/O calls when
+ * the GPIO is constant and refers to some always-present controller,
+ * giving direct access to chip registers and tight bitbanging loops.
+ */
+extern int __gpio_get_value(unsigned gpio);
+extern void __gpio_set_value(unsigned gpio, int value);
+
+extern int __gpio_cansleep(unsigned gpio);
+
+
+#else
+
/* platforms that don't directly support access to GPIOs through I2C, SPI,
* or other blocking infrastructure can use these wrappers.
*/
@@ -22,4 +118,6 @@
gpio_set_value(gpio, value);
}
+#endif
+
#endif /* _ASM_GENERIC_GPIO_H */
diff --git a/include/asm-generic/pgtable-nopmd.h b/include/asm-generic/pgtable-nopmd.h
index 29ff5d8..087325e 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -54,7 +54,7 @@
* inside the pud, so has no extra memory associated with it.
*/
#define pmd_alloc_one(mm, address) NULL
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb, x) do { } while (0)
#undef pmd_addr_end
diff --git a/include/asm-generic/pgtable-nopud.h b/include/asm-generic/pgtable-nopud.h
index 5664645..87cf449 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -51,7 +51,7 @@
* inside the pgd, so has no extra memory associated with it.
*/
#define pud_alloc_one(mm, address) NULL
-#define pud_free(x) do { } while (0)
+#define pud_free(mm, x) do { } while (0)
#define __pud_free_tlb(tlb, x) do { } while (0)
#undef pud_addr_end
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index d3238f1f..dd1bed8 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -35,10 +35,11 @@
static inline unsigned char rtc_is_updating(void)
{
unsigned char uip;
+ unsigned long flags;
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return uip;
}
@@ -46,6 +47,8 @@
{
unsigned long uip_watchdog = jiffies;
unsigned char ctrl;
+ unsigned long flags;
+
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
#endif
@@ -72,7 +75,7 @@
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
* by the RTC when initially set to a non-zero value.
*/
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
time->tm_sec = CMOS_READ(RTC_SECONDS);
time->tm_min = CMOS_READ(RTC_MINUTES);
time->tm_hour = CMOS_READ(RTC_HOURS);
@@ -83,7 +86,7 @@
real_year = CMOS_READ(RTC_DEC_YEAR);
#endif
ctrl = CMOS_READ(RTC_CONTROL);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 962cad7..8feeae1 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -8,8 +8,6 @@
extern char __bss_start[], __bss_stop[];
extern char __init_begin[], __init_end[];
extern char _sinittext[], _einittext[];
-extern char _sextratext[] __attribute__((weak));
-extern char _eextratext[] __attribute__((weak));
extern char _end[];
extern char __per_cpu_start[], __per_cpu_end[];
extern char __kprobes_text_start[], __kprobes_text_end[];
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 75f2bfa..f490e43 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -14,7 +14,6 @@
#define _ASM_GENERIC__TLB_H
#include <linux/swap.h>
-#include <linux/quicklist.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
diff --git a/include/asm-h8300/io.h b/include/asm-h8300/io.h
index 7543a57..26dc6cc 100644
--- a/include/asm-h8300/io.h
+++ b/include/asm-h8300/io.h
@@ -302,8 +302,6 @@
/*
* Macros used for converting between virtual and physical mappings.
*/
-#define mm_ptov(vaddr) ((void *) (vaddr))
-#define mm_vtop(vaddr) ((unsigned long) (vaddr))
#define phys_to_virt(vaddr) ((void *) (vaddr))
#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
diff --git a/include/asm-h8300/virtconvert.h b/include/asm-h8300/virtconvert.h
index ee7d5ea..19cfd62 100644
--- a/include/asm-h8300/virtconvert.h
+++ b/include/asm-h8300/virtconvert.h
@@ -10,8 +10,6 @@
#include <asm/setup.h>
#include <asm/page.h>
-#define mm_ptov(vaddr) ((void *) (vaddr))
-#define mm_vtop(vaddr) ((unsigned long) (vaddr))
#define phys_to_virt(vaddr) ((void *) (vaddr))
#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
index a1b9719..953d3df 100644
--- a/include/asm-ia64/bitops.h
+++ b/include/asm-ia64/bitops.h
@@ -122,38 +122,40 @@
}
/**
- * __clear_bit_unlock - Non-atomically clear a bit with release
+ * __clear_bit_unlock - Non-atomically clears a bit in memory with release
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
*
- * This is like clear_bit_unlock, but the implementation uses a store
+ * Similarly to clear_bit_unlock, the implementation uses a store
* with release semantics. See also __raw_spin_unlock().
*/
static __inline__ void
-__clear_bit_unlock(int nr, volatile void *addr)
+__clear_bit_unlock(int nr, void *addr)
{
- __u32 mask, new;
- volatile __u32 *m;
+ __u32 * const m = (__u32 *) addr + (nr >> 5);
+ __u32 const new = *m & ~(1 << (nr & 31));
- m = (volatile __u32 *)addr + (nr >> 5);
- mask = ~(1 << (nr & 31));
- new = *m & mask;
- barrier();
ia64_st4_rel_nta(m, new);
}
/**
* __clear_bit - Clears a bit in memory (non-atomic version)
+ * @nr: the bit to clear
+ * @addr: the address to start counting from
+ *
+ * Unlike clear_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
*/
static __inline__ void
__clear_bit (int nr, volatile void *addr)
{
- volatile __u32 *p = (__u32 *) addr + (nr >> 5);
- __u32 m = 1 << (nr & 31);
- *p &= ~m;
+ *((__u32 *) addr + (nr >> 5)) &= ~(1 << (nr & 31));
}
/**
* change_bit - Toggle a bit in memory
- * @nr: Bit to clear
+ * @nr: Bit to toggle
* @addr: Address to start counting from
*
* change_bit() is atomic and may not be reordered.
@@ -178,7 +180,7 @@
/**
* __change_bit - Toggle a bit in memory
- * @nr: the bit to set
+ * @nr: the bit to toggle
* @addr: the address to start counting from
*
* Unlike change_bit(), this function is non-atomic and may be reordered.
@@ -197,7 +199,7 @@
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
+ * It also implies the acquisition side of the memory barrier.
*/
static __inline__ int
test_and_set_bit (int nr, volatile void *addr)
@@ -247,11 +249,11 @@
/**
* test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to clear
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
+ * It also implies the acquisition side of the memory barrier.
*/
static __inline__ int
test_and_clear_bit (int nr, volatile void *addr)
@@ -272,7 +274,7 @@
/**
* __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to clear
* @addr: Address to count from
*
* This operation is non-atomic and can be reordered.
@@ -292,11 +294,11 @@
/**
* test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to change
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
- * It also implies a memory barrier.
+ * It also implies the acquisition side of the memory barrier.
*/
static __inline__ int
test_and_change_bit (int nr, volatile void *addr)
@@ -315,8 +317,12 @@
return (old & bit) != 0;
}
-/*
- * WARNING: non atomic version.
+/**
+ * __test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
*/
static __inline__ int
__test_and_change_bit (int nr, void *addr)
diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h
index 0f6e526..dfcf75b 100644
--- a/include/asm-ia64/compat.h
+++ b/include/asm-ia64/compat.h
@@ -181,7 +181,7 @@
/*
* A pointer passed in from user mode. This should not be used for syscall parameters,
* just declare them as pointers because the syscall entry code will have appropriately
- * comverted them already.
+ * converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-ia64/gcc_intrin.h b/include/asm-ia64/gcc_intrin.h
index 5b6665c..de2ed2c 100644
--- a/include/asm-ia64/gcc_intrin.h
+++ b/include/asm-ia64/gcc_intrin.h
@@ -24,7 +24,9 @@
extern void ia64_bad_param_for_setreg (void);
extern void ia64_bad_param_for_getreg (void);
+#ifdef __KERNEL__
register unsigned long ia64_r13 asm ("r13") __used;
+#endif
#define ia64_setreg(regnum, val) \
({ \
diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
index 823553b..f1663aa 100644
--- a/include/asm-ia64/mca.h
+++ b/include/asm-ia64/mca.h
@@ -3,9 +3,9 @@
* Purpose: Machine check handling specific defines
*
* Copyright (C) 1999, 2004 Silicon Graphics, Inc.
- * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
- * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
- * Copyright (C) Russ Anderson (rja@sgi.com)
+ * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
+ * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
+ * Copyright (C) Russ Anderson <rja@sgi.com>
*/
#ifndef _ASM_IA64_MCA_H
diff --git a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h
index 76203f9..dd2a5b1 100644
--- a/include/asm-ia64/mca_asm.h
+++ b/include/asm-ia64/mca_asm.h
@@ -1,8 +1,9 @@
/*
* File: mca_asm.h
+ * Purpose: Machine check handling specific defines
*
* Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
+ * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
* Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
* Copyright (C) 2000 Hewlett-Packard Co.
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
index 67552ca..556d988 100644
--- a/include/asm-ia64/pgalloc.h
+++ b/include/asm-ia64/pgalloc.h
@@ -27,7 +27,7 @@
return quicklist_alloc(0, GFP_KERNEL, NULL);
}
-static inline void pgd_free(pgd_t * pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
quicklist_free(0, NULL, pgd);
}
@@ -44,11 +44,11 @@
return quicklist_alloc(0, GFP_KERNEL, NULL);
}
-static inline void pud_free(pud_t * pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
quicklist_free(0, NULL, pud);
}
-#define __pud_free_tlb(tlb, pud) pud_free(pud)
+#define __pud_free_tlb(tlb, pud) pud_free((tlb)->mm, pud)
#endif /* CONFIG_PGTABLE_4 */
static inline void
@@ -62,12 +62,12 @@
return quicklist_alloc(0, GFP_KERNEL, NULL);
}
-static inline void pmd_free(pmd_t * pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
quicklist_free(0, NULL, pmd);
}
-#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd)
+#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
static inline void
pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte)
@@ -94,12 +94,12 @@
return quicklist_alloc(0, GFP_KERNEL, NULL);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
quicklist_free_page(0, NULL, pte);
}
-static inline void pte_free_kernel(pte_t * pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
quicklist_free(0, NULL, pte);
}
@@ -109,6 +109,6 @@
quicklist_trim(0, NULL, 25, 16);
}
-#define __pte_free_tlb(tlb, pte) pte_free(pte)
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
#endif /* _ASM_IA64_PGALLOC_H */
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index be3b0ae..741f7ec 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -31,7 +31,8 @@
* each (assuming 8KB page size), for a total of 8TB of user virtual
* address space.
*/
-#define TASK_SIZE (current->thread.task_size)
+#define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size)
+#define TASK_SIZE TASK_SIZE_OF(current)
/*
* This decides where the kernel will search for a free chunk of vm
@@ -472,7 +473,7 @@
{
ia64_stop();
ia64_setreg(_IA64_REG_PSR_L, psr);
- ia64_srlz_d();
+ ia64_srlz_i();
}
/*
diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h
index 1f5412d..2251118 100644
--- a/include/asm-ia64/sal.h
+++ b/include/asm-ia64/sal.h
@@ -649,17 +649,6 @@
* Now define a couple of inline functions for improved type checking
* and convenience.
*/
-static inline long
-ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
- unsigned long *drift_info)
-{
- struct ia64_sal_retval isrv;
-
- SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0);
- *ticks_per_second = isrv.v0;
- *drift_info = isrv.v1;
- return isrv.status;
-}
extern s64 ia64_sal_cache_flush (u64 cache_type);
extern void __init check_sal_cache_flush (void);
@@ -841,6 +830,9 @@
u64, u64, u64, u64, u64);
extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64,
u64, u64, u64, u64, u64);
+extern long
+ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
+ unsigned long *drift_info);
#ifdef CONFIG_HOTPLUG_CPU
/*
* System Abstraction Layer Specification
diff --git a/include/asm-m32r/delay.h b/include/asm-m32r/delay.h
index 164448d..9dd9e99 100644
--- a/include/asm-m32r/delay.h
+++ b/include/asm-m32r/delay.h
@@ -12,7 +12,7 @@
extern void __udelay(unsigned long usecs);
extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
extern void __delay(unsigned long loops);
#define udelay(n) (__builtin_constant_p(n) ? \
diff --git a/include/asm-m32r/irq.h b/include/asm-m32r/irq.h
index 2f93f47..242028b 100644
--- a/include/asm-m32r/irq.h
+++ b/include/asm-m32r/irq.h
@@ -3,7 +3,7 @@
#define _ASM_M32R_IRQ_H
-#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_USRV)
+#if defined(CONFIG_PLAT_USRV)
/*
* IRQ definitions for M32700UT
* M32700 Chip: 64 interrupts
diff --git a/include/asm-m32r/m32700ut/m32700ut_pld.h b/include/asm-m32r/m32700ut/m32700ut_pld.h
index d391212..57623be 100644
--- a/include/asm-m32r/m32700ut/m32700ut_pld.h
+++ b/include/asm-m32r/m32700ut/m32700ut_pld.h
@@ -13,9 +13,7 @@
* this archive for more details.
*/
-#if defined(CONFIG_PLAT_M32700UT_Alpha)
-#define PLD_PLAT_BASE 0x08c00000
-#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV)
#define PLD_PLAT_BASE 0x04c00000
#else
#error "no platform configuration"
diff --git a/include/asm-m32r/pgalloc.h b/include/asm-m32r/pgalloc.h
index 943ba63..e5921ad 100644
--- a/include/asm-m32r/pgalloc.h
+++ b/include/asm-m32r/pgalloc.h
@@ -24,7 +24,7 @@
return pgd;
}
-static __inline__ void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
@@ -46,17 +46,17 @@
return pte;
}
-static __inline__ void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-static __inline__ void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
-#define __pte_free_tlb(tlb, pte) pte_free((pte))
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte))
/*
* allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -65,7 +65,7 @@
*/
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb, x) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h
index f467eac..cf701c9 100644
--- a/include/asm-m32r/unistd.h
+++ b/include/asm-m32r/unistd.h
@@ -327,7 +327,7 @@
#define __NR_epoll_pwait 319
#define __NR_utimensat 320
#define __NR_signalfd 321
-#define __NR_timerfd 322
+/* #define __NR_timerfd 322 removed */
#define __NR_eventfd 323
#define __NR_fallocate 324
diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h
index 27d11da..28b0f49 100644
--- a/include/asm-m68k/macintosh.h
+++ b/include/asm-m68k/macintosh.h
@@ -14,8 +14,6 @@
extern int mac_irq_pending(unsigned int);
extern void mac_identify(void);
extern void mac_report_hardware(void);
-extern void mac_debugging_penguin(int);
-extern void mac_boom(int);
/*
* Floppy driver magic hook - probably shouldnt be here
diff --git a/include/asm-m68k/motorola_pgalloc.h b/include/asm-m68k/motorola_pgalloc.h
index 5158412..500ec9b 100644
--- a/include/asm-m68k/motorola_pgalloc.h
+++ b/include/asm-m68k/motorola_pgalloc.h
@@ -22,7 +22,7 @@
return pte;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
cache_page(pte);
free_page((unsigned long) pte);
@@ -47,7 +47,7 @@
return page;
}
-static inline void pte_free(struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
{
cache_page(kmap(page));
kunmap(page);
@@ -67,7 +67,7 @@
return get_pointer_table();
}
-static inline int pmd_free(pmd_t *pmd)
+static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
return free_pointer_table(pmd);
}
@@ -78,9 +78,9 @@
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
- pmd_free((pmd_t *)pgd);
+ pmd_free(mm, (pmd_t *)pgd);
}
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index 778a4c5..0b604f0 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -107,8 +107,6 @@
/* 64-bit machines, beware! SRB. */
#define SIZEOF_PTR_LOG2 2
-#define mm_end_of_chunk(addr, len) 0
-
extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode);
/*
diff --git a/include/asm-m68k/sun3_pgalloc.h b/include/asm-m68k/sun3_pgalloc.h
index fd82411..a5a91e7 100644
--- a/include/asm-m68k/sun3_pgalloc.h
+++ b/include/asm-m68k/sun3_pgalloc.h
@@ -21,12 +21,12 @@
#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); })
-static inline void pte_free_kernel(pte_t * pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long) pte);
}
-static inline void pte_free(struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
{
__free_page(page);
}
@@ -72,10 +72,10 @@
* allocating and freeing a pmd is trivial: the 1-entry pmd is
* inside the pgd, so has no extra memory associated with it.
*/
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb, x) do { } while (0)
-static inline void pgd_free(pgd_t * pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long) pgd);
}
diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h
index f43afe1..c142fbf 100644
--- a/include/asm-m68knommu/bitops.h
+++ b/include/asm-m68knommu/bitops.h
@@ -262,7 +262,7 @@
* tmp = __swab32(*(p++));
* tmp |= ~0UL >> (32-offset);
*
- * but this would decrease preformance, so we change the
+ * but this would decrease performance, so we change the
* shift:
*/
tmp = *(p++);
diff --git a/include/asm-m68knommu/commproc.h b/include/asm-m68knommu/commproc.h
index 0161ebb..36e870b 100644
--- a/include/asm-m68knommu/commproc.h
+++ b/include/asm-m68knommu/commproc.h
@@ -715,7 +715,7 @@
#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */
#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */
#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */
-#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */
+#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrupt */
#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */
#define CICR_IEN ((uint)0x00000080) /* Int. enable */
#define CICR_SPS ((uint)0x00000001) /* SCC Spread */
diff --git a/include/asm-m68knommu/delay.h b/include/asm-m68knommu/delay.h
index 04a20fd..55cbd62 100644
--- a/include/asm-m68knommu/delay.h
+++ b/include/asm-m68knommu/delay.h
@@ -68,7 +68,7 @@
/*
* Moved the udelay() function into library code, no longer inlined.
* I had to change the algorithm because we are overflowing now on
- * the faster ColdFire parts. The code is a little biger, so it makes
+ * the faster ColdFire parts. The code is a little bigger, so it makes
* sense to library it.
*/
extern void udelay(unsigned long usecs);
diff --git a/include/asm-m68knommu/io.h b/include/asm-m68knommu/io.h
index 653d9b2..6adef1e 100644
--- a/include/asm-m68knommu/io.h
+++ b/include/asm-m68knommu/io.h
@@ -172,8 +172,6 @@
/*
* Macros used for converting between virtual and physical mappings.
*/
-#define mm_ptov(vaddr) ((void *) (vaddr))
-#define mm_vtop(vaddr) ((unsigned long) (vaddr))
#define phys_to_virt(vaddr) ((void *) (vaddr))
#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
diff --git a/include/asm-m68knommu/m5249sim.h b/include/asm-m68knommu/m5249sim.h
index 399814f..366eb86 100644
--- a/include/asm-m68knommu/m5249sim.h
+++ b/include/asm-m68knommu/m5249sim.h
@@ -43,10 +43,10 @@
#define MCFSIM_CSAR1 0x8c /* CS 1 Address reg (r/w) */
#define MCFSIM_CSMR1 0x90 /* CS 1 Mask reg (r/w) */
#define MCFSIM_CSCR1 0x96 /* CS 1 Control reg (r/w) */
-#define MCFSIM_CSAR2 0x98 /* CS 2 Adress reg (r/w) */
+#define MCFSIM_CSAR2 0x98 /* CS 2 Address reg (r/w) */
#define MCFSIM_CSMR2 0x9c /* CS 2 Mask reg (r/w) */
#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */
-#define MCFSIM_CSAR3 0xa4 /* CS 3 Adress reg (r/w) */
+#define MCFSIM_CSAR3 0xa4 /* CS 3 Address reg (r/w) */
#define MCFSIM_CSMR3 0xa8 /* CS 3 Mask reg (r/w) */
#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */
diff --git a/include/asm-m68knommu/m5307sim.h b/include/asm-m68knommu/m5307sim.h
index d3ce550..5886728 100644
--- a/include/asm-m68knommu/m5307sim.h
+++ b/include/asm-m68knommu/m5307sim.h
@@ -64,22 +64,22 @@
#define MCFSIM_CSMR7 0xda /* CS 7 Mask reg (r/w) */
#define MCFSIM_CSCR7 0xde /* CS 7 Control reg (r/w) */
#else
-#define MCFSIM_CSAR2 0x98 /* CS 2 Adress reg (r/w) */
+#define MCFSIM_CSAR2 0x98 /* CS 2 Address reg (r/w) */
#define MCFSIM_CSMR2 0x9c /* CS 2 Mask reg (r/w) */
#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */
-#define MCFSIM_CSAR3 0xa4 /* CS 3 Adress reg (r/w) */
+#define MCFSIM_CSAR3 0xa4 /* CS 3 Address reg (r/w) */
#define MCFSIM_CSMR3 0xa8 /* CS 3 Mask reg (r/w) */
#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */
-#define MCFSIM_CSAR4 0xb0 /* CS 4 Adress reg (r/w) */
+#define MCFSIM_CSAR4 0xb0 /* CS 4 Address reg (r/w) */
#define MCFSIM_CSMR4 0xb4 /* CS 4 Mask reg (r/w) */
#define MCFSIM_CSCR4 0xba /* CS 4 Control reg (r/w) */
-#define MCFSIM_CSAR5 0xbc /* CS 5 Adress reg (r/w) */
+#define MCFSIM_CSAR5 0xbc /* CS 5 Address reg (r/w) */
#define MCFSIM_CSMR5 0xc0 /* CS 5 Mask reg (r/w) */
#define MCFSIM_CSCR5 0xc6 /* CS 5 Control reg (r/w) */
-#define MCFSIM_CSAR6 0xc8 /* CS 6 Adress reg (r/w) */
+#define MCFSIM_CSAR6 0xc8 /* CS 6 Address reg (r/w) */
#define MCFSIM_CSMR6 0xcc /* CS 6 Mask reg (r/w) */
#define MCFSIM_CSCR6 0xd2 /* CS 6 Control reg (r/w) */
-#define MCFSIM_CSAR7 0xd4 /* CS 7 Adress reg (r/w) */
+#define MCFSIM_CSAR7 0xd4 /* CS 7 Address reg (r/w) */
#define MCFSIM_CSMR7 0xd8 /* CS 7 Mask reg (r/w) */
#define MCFSIM_CSCR7 0xde /* CS 7 Control reg (r/w) */
#endif /* CONFIG_OLDMASK */
diff --git a/include/asm-m68knommu/m5407sim.h b/include/asm-m68knommu/m5407sim.h
index 75dcdac..cc22c4a 100644
--- a/include/asm-m68knommu/m5407sim.h
+++ b/include/asm-m68knommu/m5407sim.h
@@ -48,22 +48,22 @@
#define MCFSIM_CSMR1 0x90 /* CS 1 Mask reg (r/w) */
#define MCFSIM_CSCR1 0x96 /* CS 1 Control reg (r/w) */
-#define MCFSIM_CSAR2 0x98 /* CS 2 Adress reg (r/w) */
+#define MCFSIM_CSAR2 0x98 /* CS 2 Address reg (r/w) */
#define MCFSIM_CSMR2 0x9c /* CS 2 Mask reg (r/w) */
#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */
-#define MCFSIM_CSAR3 0xa4 /* CS 3 Adress reg (r/w) */
+#define MCFSIM_CSAR3 0xa4 /* CS 3 Address reg (r/w) */
#define MCFSIM_CSMR3 0xa8 /* CS 3 Mask reg (r/w) */
#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */
-#define MCFSIM_CSAR4 0xb0 /* CS 4 Adress reg (r/w) */
+#define MCFSIM_CSAR4 0xb0 /* CS 4 Address reg (r/w) */
#define MCFSIM_CSMR4 0xb4 /* CS 4 Mask reg (r/w) */
#define MCFSIM_CSCR4 0xba /* CS 4 Control reg (r/w) */
-#define MCFSIM_CSAR5 0xbc /* CS 5 Adress reg (r/w) */
+#define MCFSIM_CSAR5 0xbc /* CS 5 Address reg (r/w) */
#define MCFSIM_CSMR5 0xc0 /* CS 5 Mask reg (r/w) */
#define MCFSIM_CSCR5 0xc6 /* CS 5 Control reg (r/w) */
-#define MCFSIM_CSAR6 0xc8 /* CS 6 Adress reg (r/w) */
+#define MCFSIM_CSAR6 0xc8 /* CS 6 Address reg (r/w) */
#define MCFSIM_CSMR6 0xcc /* CS 6 Mask reg (r/w) */
#define MCFSIM_CSCR6 0xd2 /* CS 6 Control reg (r/w) */
-#define MCFSIM_CSAR7 0xd4 /* CS 7 Adress reg (r/w) */
+#define MCFSIM_CSAR7 0xd4 /* CS 7 Address reg (r/w) */
#define MCFSIM_CSMR7 0xd8 /* CS 7 Mask reg (r/w) */
#define MCFSIM_CSCR7 0xde /* CS 7 Control reg (r/w) */
diff --git a/include/asm-m68knommu/m68360_regs.h b/include/asm-m68knommu/m68360_regs.h
index a3f8cc8..d57217c 100644
--- a/include/asm-m68knommu/m68360_regs.h
+++ b/include/asm-m68knommu/m68360_regs.h
@@ -138,7 +138,7 @@
#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */
#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */
-#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */
+#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrupt */
#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */
#define CICR_VBA_MASK ((uint)0x000000e0) /* Vector Base Address */
#define CICR_SPS ((uint)0x00000001) /* SCC Spread */
diff --git a/include/asm-m68knommu/mcfne.h b/include/asm-m68knommu/mcfne.h
index c920ccd..431f63a 100644
--- a/include/asm-m68knommu/mcfne.h
+++ b/include/asm-m68knommu/mcfne.h
@@ -60,17 +60,6 @@
#define NE2000_BYTE volatile unsigned char
#endif
-#if defined(CONFIG_CFV240)
-#define NE2000_ADDR 0x40010000
-#define NE2000_ADDR1 0x40010001
-#define NE2000_ODDOFFSET 0x00000000
-#define NE2000_IRQ 1
-#define NE2000_IRQ_VECTOR 0x19
-#define NE2000_IRQ_PRIORITY 2
-#define NE2000_IRQ_LEVEL 1
-#define NE2000_BYTE volatile unsigned char
-#endif
-
#if defined(CONFIG_M5307C3)
#define NE2000_ADDR 0x40000300
#define NE2000_ODDOFFSET 0x00010000
@@ -173,13 +162,8 @@
* On most NE2000 implementations on ColdFire boards the chip is
* mapped in kinda funny, due to its ISA heritage.
*/
-#ifdef CONFIG_CFV240
-#define NE2000_PTR(addr) (NE2000_ADDR + ((addr & 0x3f) << 1) + 1)
-#define NE2000_DATA_PTR(addr) (NE2000_ADDR + ((addr & 0x3f) << 1))
-#else
#define NE2000_PTR(addr) ((addr&0x1)?(NE2000_ODDOFFSET+addr-1):(addr))
#define NE2000_DATA_PTR(addr) (addr)
-#endif
void ne2000_outb(unsigned int val, unsigned int addr)
@@ -285,17 +269,6 @@
}
#endif
-#if defined(CONFIG_CFV240)
-void ne2000_irqsetup(int irq)
-{
- volatile unsigned char *icrp;
-
- icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_ICR1);
- *icrp = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI2 | MCFSIM_ICR_AUTOVEC;
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT1);
-}
-#endif
-
#if defined(CONFIG_M5206e) && defined(CONFIG_NETtel)
void ne2000_irqsetup(int irq)
{
diff --git a/include/asm-m68knommu/mcfsim.h b/include/asm-m68knommu/mcfsim.h
index 1074ae7..da3f2ce 100644
--- a/include/asm-m68knommu/mcfsim.h
+++ b/include/asm-m68knommu/mcfsim.h
@@ -17,9 +17,7 @@
* Include 5204, 5206/e, 5235, 5249, 5270/5271, 5272, 5280/5282,
* 5307 or 5407 specific addresses.
*/
-#if defined(CONFIG_M5204)
-#include <asm/m5204sim.h>
-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
#include <asm/m5206sim.h>
#elif defined(CONFIG_M520x)
#include <asm/m520xsim.h>
diff --git a/include/asm-m68knommu/mcftimer.h b/include/asm-m68knommu/mcftimer.h
index 6f4d796..0f90f6d 100644
--- a/include/asm-m68knommu/mcftimer.h
+++ b/include/asm-m68knommu/mcftimer.h
@@ -16,7 +16,7 @@
/*
* Get address specific defines for this ColdFire member.
*/
-#if defined(CONFIG_M5204) || defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
#define MCFTIMER_BASE1 0x100 /* Base address of TIMER1 */
#define MCFTIMER_BASE2 0x120 /* Base address of TIMER2 */
#elif defined(CONFIG_M5272)
diff --git a/include/asm-m68knommu/mcfuart.h b/include/asm-m68knommu/mcfuart.h
index 1319a81..ef22938 100644
--- a/include/asm-m68knommu/mcfuart.h
+++ b/include/asm-m68knommu/mcfuart.h
@@ -19,7 +19,7 @@
#if defined(CONFIG_M5272)
#define MCFUART_BASE1 0x100 /* Base address of UART1 */
#define MCFUART_BASE2 0x140 /* Base address of UART2 */
-#elif defined(CONFIG_M5204) || defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e)
#if defined(CONFIG_NETtel)
#define MCFUART_BASE1 0x180 /* Base address of UART1 */
#define MCFUART_BASE2 0x140 /* Base address of UART2 */
@@ -71,7 +71,7 @@
#define MCFUART_UTB 0x0c /* Transmit Buffer (w) */
#define MCFUART_UIPCR 0x10 /* Input Port Change (r) */
#define MCFUART_UACR 0x10 /* Auxiliary Control (w) */
-#define MCFUART_UISR 0x14 /* Interrup Status (r) */
+#define MCFUART_UISR 0x14 /* Interrupt Status (r) */
#define MCFUART_UIMR 0x14 /* Interrupt Mask (w) */
#define MCFUART_UBG1 0x18 /* Baud Rate MSB (r/w) */
#define MCFUART_UBG2 0x1c /* Baud Rate LSB (r/w) */
diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h
index 15b4c7d..ee2dc07 100644
--- a/include/asm-m68knommu/system.h
+++ b/include/asm-m68knommu/system.h
@@ -207,23 +207,6 @@
}
-#ifdef CONFIG_M68332
-#define HARD_RESET_NOW() ({ \
- local_irq_disable(); \
- asm(" \
- movew #0x0000, 0xfffa6a; \
- reset; \
- /*movew #0x1557, 0xfffa44;*/ \
- /*movew #0x0155, 0xfffa46;*/ \
- moveal #0, %a0; \
- movec %a0, %vbr; \
- moveal 0, %sp; \
- moveal 4, %a0; \
- jmp (%a0); \
- "); \
-})
-#endif
-
#if defined( CONFIG_M68328 ) || defined( CONFIG_M68EZ328 ) || \
defined (CONFIG_M68360) || defined( CONFIG_M68VZ328 )
#define HARD_RESET_NOW() ({ \
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 568c76c..ac5d541 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -128,7 +128,7 @@
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-mips/mach-excite/excite_fpga.h b/include/asm-mips/mach-excite/excite_fpga.h
index 38fcda7..0a1ef69 100644
--- a/include/asm-mips/mach-excite/excite_fpga.h
+++ b/include/asm-mips/mach-excite/excite_fpga.h
@@ -3,7 +3,7 @@
/**
- * Adress alignment of the individual FPGA bytes.
+ * Address alignment of the individual FPGA bytes.
* The address arrangement of the individual bytes of the FPGA is two
* byte aligned at the embedded MK2 platform.
*/
diff --git a/include/asm-mips/mach-wrppmc/mach-gt64120.h b/include/asm-mips/mach-wrppmc/mach-gt64120.h
index 00d8bf6..83746b8 100644
--- a/include/asm-mips/mach-wrppmc/mach-gt64120.h
+++ b/include/asm-mips/mach-wrppmc/mach-gt64120.h
@@ -45,7 +45,7 @@
#define GT_PCI_IO_SIZE 0x02000000UL
/*
- * PCI interrupts will come in on either the INTA or INTD interrups lines,
+ * PCI interrupts will come in on either the INTA or INTD interrupt lines,
* which are mapped to the #2 and #5 interrupt pins of the MIPS. On our
* boards, they all either come in on IntD or they all come in on IntA, they
* aren't mixed. There can be numerous PCI interrupts, so we keep a list of the
diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h
index 81b7212..c4efece 100644
--- a/include/asm-mips/pgalloc.h
+++ b/include/asm-mips/pgalloc.h
@@ -58,7 +58,7 @@
return ret;
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_pages((unsigned long)pgd, PGD_ORDER);
}
@@ -85,12 +85,12 @@
return pte;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_pages((unsigned long)pte, PTE_ORDER);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_pages(pte, PTE_ORDER);
}
@@ -103,7 +103,7 @@
* allocating and freeing a pmd is trivial: the 1-entry pmd is
* inside the pgd, so has no extra memory associated with it.
*/
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb, x) do { } while (0)
#endif
@@ -120,12 +120,12 @@
return pmd;
}
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
free_pages((unsigned long)pmd, PMD_ORDER);
}
-#define __pmd_free_tlb(tlb, x) pmd_free(x)
+#define __pmd_free_tlb(tlb, x) pmd_free((tlb)->mm, x)
#endif
diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h
index 83bc945..36f42de 100644
--- a/include/asm-mips/processor.h
+++ b/include/asm-mips/processor.h
@@ -65,6 +65,8 @@
#define TASK_UNMAPPED_BASE \
(test_thread_flag(TIF_32BIT_ADDR) ? \
PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
+#define TASK_SIZE_OF(tsk) \
+ (test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
#endif
#define NUM_FPU_REGS 32
diff --git a/include/asm-mips/sgi/ip22.h b/include/asm-mips/sgi/ip22.h
index f4981c4..c0501f9 100644
--- a/include/asm-mips/sgi/ip22.h
+++ b/include/asm-mips/sgi/ip22.h
@@ -15,7 +15,7 @@
/*
* These are the virtual IRQ numbers, we divide all IRQ's into
* 'spaces', the 'space' determines where and how to enable/disable
- * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrups
+ * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrupts
* are not supported this way. Driver is supposed to allocate HPC/MC
* interrupt as shareable and then look to proper status bit (see
* HAL2 driver). This will prevent many complications, trust me ;-)
diff --git a/include/asm-mips/sn/sn0/hubio.h b/include/asm-mips/sn/sn0/hubio.h
index ef91b33..0187895 100644
--- a/include/asm-mips/sn/sn0/hubio.h
+++ b/include/asm-mips/sn/sn0/hubio.h
@@ -338,7 +338,7 @@
#define IIO_IFDR 0x400398 /* IOQ FIFO Depth */
#define IIO_IIAP 0x4003a0 /* IIQ Arbitration Parameters */
#define IIO_IMMR IIO_IIAP
-#define IIO_ICMR 0x4003a8 /* CRB Managment Register */
+#define IIO_ICMR 0x4003a8 /* CRB Management Register */
#define IIO_ICCR 0x4003b0 /* CRB Control Register */
#define IIO_ICTO 0x4003b8 /* CRB Time Out Register */
#define IIO_ICTP 0x4003c0 /* CRB Time Out Prescalar */
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 5a85d1b..7f32611 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -132,7 +132,7 @@
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-parisc/elf.h b/include/asm-parisc/elf.h
index f628ac7..8e7946a 100644
--- a/include/asm-parisc/elf.h
+++ b/include/asm-parisc/elf.h
@@ -28,7 +28,7 @@
#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
-/* Additional section indeces. */
+/* Additional section indices. */
#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
symbols in ANSI C. */
diff --git a/include/asm-parisc/linkage.h b/include/asm-parisc/linkage.h
index ad8cd0d0..0b19a72 100644
--- a/include/asm-parisc/linkage.h
+++ b/include/asm-parisc/linkage.h
@@ -8,7 +8,7 @@
/*
* In parisc assembly a semicolon marks a comment while a
- * exclamation mark is used to seperate independent lines.
+ * exclamation mark is used to separate independent lines.
*/
#ifdef __ASSEMBLY__
diff --git a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
index 1af1a41..aab66f1 100644
--- a/include/asm-parisc/pgalloc.h
+++ b/include/asm-parisc/pgalloc.h
@@ -43,7 +43,7 @@
return actual_pgd;
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
#ifdef CONFIG_64BIT
pgd -= PTRS_PER_PGD;
@@ -70,7 +70,7 @@
return pmd;
}
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
#ifdef CONFIG_64BIT
if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
@@ -91,7 +91,7 @@
*/
#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
#endif
@@ -130,12 +130,12 @@
return pte;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-#define pte_free(page) pte_free_kernel(page_address(page))
+#define pte_free(mm, page) pte_free_kernel(page_address(page))
#define check_pgt_cache() do { } while (0)
diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
index 6b294fb..3bb06e8 100644
--- a/include/asm-parisc/processor.h
+++ b/include/asm-parisc/processor.h
@@ -32,7 +32,8 @@
#endif
#define current_text_addr() ({ void *pc; current_ia(pc); pc; })
-#define TASK_SIZE (current->thread.task_size)
+#define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size)
+#define TASK_SIZE TASK_SIZE_OF(current)
#define TASK_UNMAPPED_BASE (current->thread.map_base)
#define DEFAULT_TASK_SIZE32 (0xFFF00000UL)
diff --git a/include/asm-parisc/tlb.h b/include/asm-parisc/tlb.h
index 33107a2..383b1db 100644
--- a/include/asm-parisc/tlb.h
+++ b/include/asm-parisc/tlb.h
@@ -21,7 +21,7 @@
#include <asm-generic/tlb.h>
-#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd)
-#define __pte_free_tlb(tlb, pte) pte_free(pte)
+#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
#endif
diff --git a/include/asm-parisc/vga.h b/include/asm-parisc/vga.h
index 154a84c..171399a 100644
--- a/include/asm-parisc/vga.h
+++ b/include/asm-parisc/vga.h
@@ -3,4 +3,4 @@
/* nothing */
-#endif __ASM_PARISC_VGA_H__
+#endif /* __ASM_PARISC_VGA_H__ */
diff --git a/include/asm-powerpc/compat.h b/include/asm-powerpc/compat.h
index 64ab1dd..d811a8c 100644
--- a/include/asm-powerpc/compat.h
+++ b/include/asm-powerpc/compat.h
@@ -119,7 +119,7 @@
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-powerpc/cputime.h b/include/asm-powerpc/cputime.h
index 3108044..f42e623 100644
--- a/include/asm-powerpc/cputime.h
+++ b/include/asm-powerpc/cputime.h
@@ -52,12 +52,26 @@
* Convert cputime <-> jiffies
*/
extern u64 __cputime_jiffies_factor;
+DECLARE_PER_CPU(unsigned long, cputime_last_delta);
+DECLARE_PER_CPU(unsigned long, cputime_scaled_last_delta);
static inline unsigned long cputime_to_jiffies(const cputime_t ct)
{
return mulhdu(ct, __cputime_jiffies_factor);
}
+/* Estimate the scaled cputime by scaling the real cputime based on
+ * the last scaled to real ratio */
+static inline cputime_t cputime_to_scaled(const cputime_t ct)
+{
+ if (cpu_has_feature(CPU_FTR_SPURR) &&
+ per_cpu(cputime_last_delta, smp_processor_id()))
+ return ct *
+ per_cpu(cputime_scaled_last_delta, smp_processor_id())/
+ per_cpu(cputime_last_delta, smp_processor_id());
+ return ct;
+}
+
static inline cputime_t jiffies_to_cputime(const unsigned long jif)
{
cputime_t ct;
diff --git a/include/asm-powerpc/dma.h b/include/asm-powerpc/dma.h
index 7a4374b..a7e06e2 100644
--- a/include/asm-powerpc/dma.h
+++ b/include/asm-powerpc/dma.h
@@ -93,16 +93,6 @@
*
*/
-/* see prep_setup_arch() for detailed informations */
-#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_PPC_PREP)
-extern long ppc_cs4232_dma, ppc_cs4232_dma2;
-#define SND_DMA1 ppc_cs4232_dma
-#define SND_DMA2 ppc_cs4232_dma2
-#else
-#define SND_DMA1 -1
-#define SND_DMA2 -1
-#endif
-
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
@@ -269,24 +259,15 @@
dma_outb(pagenr >> 8, DMA_HI_PAGE_3);
break;
case 5:
- if (SND_DMA1 == 5 || SND_DMA2 == 5)
- dma_outb(pagenr, DMA_LO_PAGE_5);
- else
- dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+ dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
dma_outb(pagenr >> 8, DMA_HI_PAGE_5);
break;
case 6:
- if (SND_DMA1 == 6 || SND_DMA2 == 6)
- dma_outb(pagenr, DMA_LO_PAGE_6);
- else
- dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+ dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
dma_outb(pagenr >> 8, DMA_HI_PAGE_6);
break;
case 7:
- if (SND_DMA1 == 7 || SND_DMA2 == 7)
- dma_outb(pagenr, DMA_LO_PAGE_7);
- else
- dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+ dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
dma_outb(pagenr >> 8, DMA_HI_PAGE_7);
break;
}
@@ -302,12 +283,6 @@
((dmanr & 3) << 1) + IO_DMA1_BASE);
dma_outb((phys >> 8) & 0xff,
((dmanr & 3) << 1) + IO_DMA1_BASE);
- } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
- dma_outb(phys & 0xff,
- ((dmanr & 3) << 2) + IO_DMA2_BASE);
- dma_outb((phys >> 8) & 0xff,
- ((dmanr & 3) << 2) + IO_DMA2_BASE);
- dma_outb((dmanr & 3), DMA2_EXT_REG);
} else {
dma_outb((phys >> 1) & 0xff,
((dmanr & 3) << 2) + IO_DMA2_BASE);
@@ -334,11 +309,6 @@
((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
dma_outb((count >> 8) & 0xff,
((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
- } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
- dma_outb(count & 0xff,
- ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
- dma_outb((count >> 8) & 0xff,
- ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
} else {
dma_outb((count >> 1) & 0xff,
((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
@@ -368,8 +338,7 @@
count = 1 + dma_inb(io_port);
count += dma_inb(io_port) << 8;
- return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2)
- ? count : (count << 1);
+ return (dmanr <= 3) ? count : (count << 1);
}
/* These are in kernel/dma.c: */
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index 7a3cef7..852e15f 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -79,19 +79,19 @@
extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
int nid);
-extern int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+extern int iommu_map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, unsigned long mask,
enum dma_data_direction direction);
extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction);
-extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
- dma_addr_t *dma_handle, unsigned long mask,
- gfp_t flag, int node);
+extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
+ size_t size, dma_addr_t *dma_handle,
+ unsigned long mask, gfp_t flag, int node);
extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
void *vaddr, dma_addr_t dma_handle);
-extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
- size_t size, unsigned long mask,
+extern dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl,
+ void *vaddr, size_t size, unsigned long mask,
enum dma_data_direction direction);
extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
size_t size, enum dma_data_direction direction);
diff --git a/include/asm-powerpc/mediabay.h b/include/asm-powerpc/mediabay.h
index 9daa325..de83fe1 100644
--- a/include/asm-powerpc/mediabay.h
+++ b/include/asm-powerpc/mediabay.h
@@ -18,14 +18,14 @@
#define MB_NO 7 /* media bay contains nothing */
int check_media_bay(struct device_node *which_bay, int what);
-int check_media_bay_by_base(unsigned long base, int what);
/* Number of bays in the machine or 0 */
extern int media_bay_count;
-/* called by pmac-ide.c to register IDE controller for media bay */
-extern int media_bay_set_ide_infos(struct device_node* which_bay,
- unsigned long base, int irq, int index);
+int check_media_bay_by_base(unsigned long base, int what);
+/* called by IDE PMAC host driver to register IDE controller for media bay */
+int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base,
+ int irq, int index);
#endif /* __KERNEL__ */
#endif /* _PPC_MEDIABAY_H */
diff --git a/include/asm-powerpc/nvram.h b/include/asm-powerpc/nvram.h
index 4e7059c..efde5ac 100644
--- a/include/asm-powerpc/nvram.h
+++ b/include/asm-powerpc/nvram.h
@@ -58,6 +58,9 @@
};
#ifdef __KERNEL__
+
+#include <linux/list.h>
+
struct nvram_partition {
struct list_head partition;
struct nvram_header header;
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index f6dfce0..748b35a 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -115,8 +115,6 @@
u64 system_time; /* accumulated system TB ticks */
u64 startpurr; /* PURR/TB value snapshot */
u64 startspurr; /* SPURR value snapshot */
- u64 purrdelta; /* FIXME: document */
- u64 spurrdelta; /* FIXME: document */
};
extern struct paca_struct paca[];
diff --git a/include/asm-powerpc/pgalloc-32.h b/include/asm-powerpc/pgalloc-32.h
index e130743..c162a4c 100644
--- a/include/asm-powerpc/pgalloc-32.h
+++ b/include/asm-powerpc/pgalloc-32.h
@@ -6,14 +6,14 @@
extern void __bad_pte(pmd_t *pmd);
extern pgd_t *pgd_alloc(struct mm_struct *mm);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
/*
* We don't have any real pmd's, and this code never triggers because
* the pgd will always be present..
*/
/* #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) */
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
/* #define pgd_populate(mm, pmd, pte) BUG() */
@@ -31,10 +31,10 @@
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
-extern void pte_free_kernel(pte_t *pte);
-extern void pte_free(struct page *pte);
+extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte);
+extern void pte_free(struct mm_struct *mm, struct page *pte);
-#define __pte_free_tlb(tlb, pte) pte_free((pte))
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte))
#define check_pgt_cache() do { } while (0)
diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h
index 43214c8..5afae85 100644
--- a/include/asm-powerpc/pgalloc-64.h
+++ b/include/asm-powerpc/pgalloc-64.h
@@ -29,7 +29,7 @@
return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
subpage_prot_free(pgd);
kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
@@ -45,7 +45,7 @@
GFP_KERNEL|__GFP_REPEAT);
}
-static inline void pud_free(pud_t *pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
}
@@ -81,7 +81,7 @@
GFP_KERNEL|__GFP_REPEAT);
}
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
}
@@ -99,12 +99,12 @@
return pte ? virt_to_page(pte) : NULL;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-static inline void pte_free(struct page *ptepage)
+static inline void pte_free(struct mm_struct *mm, struct page *ptepage)
{
__free_page(ptepage);
}
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index dba7c94..1f4765d 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -99,8 +99,9 @@
*/
#define TASK_SIZE_USER32 (0x0000000100000000UL - (1*PAGE_SIZE))
-#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
+#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
TASK_SIZE_USER32 : TASK_SIZE_USER64)
+#define TASK_SIZE TASK_SIZE_OF(current)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h
index 967930b..fda9871 100644
--- a/include/asm-powerpc/ps3av.h
+++ b/include/asm-powerpc/ps3av.h
@@ -310,19 +310,25 @@
#define PS3AV_MONITOR_TYPE_HDMI 1 /* HDMI */
#define PS3AV_MONITOR_TYPE_DVI 2 /* DVI */
-#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60 2 /* 480p */
-#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60 1 /* 480i */
-#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50 7 /* 576p */
-#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50 6 /* 576i */
-
-#define PS3AV_REGION_60 0x01
-#define PS3AV_REGION_50 0x02
-#define PS3AV_REGION_RGB 0x10
-
-#define get_status(buf) (((__u32 *)buf)[2])
-#define PS3AV_HDR_SIZE 4 /* version + size */
/* for video mode */
+enum ps3av_mode_num {
+ PS3AV_MODE_AUTO = 0,
+ PS3AV_MODE_480I = 1,
+ PS3AV_MODE_480P = 2,
+ PS3AV_MODE_720P60 = 3,
+ PS3AV_MODE_1080I60 = 4,
+ PS3AV_MODE_1080P60 = 5,
+ PS3AV_MODE_576I = 6,
+ PS3AV_MODE_576P = 7,
+ PS3AV_MODE_720P50 = 8,
+ PS3AV_MODE_1080I50 = 9,
+ PS3AV_MODE_1080P50 = 10,
+ PS3AV_MODE_WXGA = 11,
+ PS3AV_MODE_SXGA = 12,
+ PS3AV_MODE_WUXGA = 13,
+};
+
#define PS3AV_MODE_MASK 0x000F
#define PS3AV_MODE_HDCP_OFF 0x1000 /* Retail PS3 product doesn't support this */
#define PS3AV_MODE_DITHER 0x0800
@@ -333,6 +339,19 @@
#define PS3AV_MODE_RGB 0x0020
+#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60 PS3AV_MODE_480P
+#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60 PS3AV_MODE_480I
+#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50 PS3AV_MODE_576P
+#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50 PS3AV_MODE_576I
+
+#define PS3AV_REGION_60 0x01
+#define PS3AV_REGION_50 0x02
+#define PS3AV_REGION_RGB 0x10
+
+#define get_status(buf) (((__u32 *)buf)[2])
+#define PS3AV_HDR_SIZE 4 /* version + size */
+
+
/** command packet structure **/
struct ps3av_send_hdr {
u16 version;
@@ -713,8 +732,6 @@
extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
extern int ps3av_get_auto_mode(void);
extern int ps3av_get_mode(void);
-extern int ps3av_get_scanmode(int);
-extern int ps3av_get_refresh_rate(int);
extern int ps3av_video_mode2res(u32, u32 *, u32 *);
extern int ps3av_video_mute(int);
extern int ps3av_audio_mute(int);
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 0c8b0d6..e996521 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -309,7 +309,7 @@
COMPAT_SYS(epoll_pwait)
COMPAT_SYS_SPU(utimensat)
COMPAT_SYS_SPU(signalfd)
-COMPAT_SYS_SPU(timerfd)
+SYSCALL(ni_syscall)
SYSCALL_SPU(eventfd)
COMPAT_SYS_SPU(sync_file_range2)
COMPAT_SYS(fallocate)
diff --git a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h
index 44d88a9..7c39a95 100644
--- a/include/asm-ppc/pgalloc.h
+++ b/include/asm-ppc/pgalloc.h
@@ -7,14 +7,14 @@
extern void __bad_pte(pmd_t *pmd);
extern pgd_t *pgd_alloc(struct mm_struct *mm);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
/*
* We don't have any real pmd's, and this code never triggers because
* the pgd will always be present..
*/
#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
#define pgd_populate(mm, pmd, pte) BUG()
@@ -32,10 +32,10 @@
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
-extern void pte_free_kernel(pte_t *pte);
-extern void pte_free(struct page *pte);
+extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte);
+extern void pte_free(struct mm_struct *mm, struct page *pte);
-#define __pte_free_tlb(tlb, pte) pte_free((pte))
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, (pte))
#define check_pgt_cache() do { } while (0)
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
index dba6fec..882db05 100644
--- a/include/asm-s390/bitops.h
+++ b/include/asm-s390/bitops.h
@@ -440,242 +440,256 @@
__test_bit((nr),(addr)) )
/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
+ * Optimized find bit helper functions.
*/
-static inline unsigned long ffz(unsigned long word)
-{
- unsigned long bit = 0;
+/**
+ * __ffz_word_loop - find byte offset of first long != -1UL
+ * @addr: pointer to array of unsigned long
+ * @size: size of the array in bits
+ */
+static inline unsigned long __ffz_word_loop(const unsigned long *addr,
+ unsigned long size)
+{
+ typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
+ unsigned long bytes = 0;
+
+ asm volatile(
+#ifndef __s390x__
+ " ahi %1,31\n"
+ " srl %1,5\n"
+ "0: c %2,0(%0,%3)\n"
+ " jne 1f\n"
+ " la %0,4(%0)\n"
+ " brct %1,0b\n"
+ "1:\n"
+#else
+ " aghi %1,63\n"
+ " srlg %1,%1,6\n"
+ "0: cg %2,0(%0,%3)\n"
+ " jne 1f\n"
+ " la %0,8(%0)\n"
+ " brct %1,0b\n"
+ "1:\n"
+#endif
+ : "+a" (bytes), "+d" (size)
+ : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr)
+ : "cc" );
+ return bytes;
+}
+
+/**
+ * __ffs_word_loop - find byte offset of first long != 0UL
+ * @addr: pointer to array of unsigned long
+ * @size: size of the array in bits
+ */
+static inline unsigned long __ffs_word_loop(const unsigned long *addr,
+ unsigned long size)
+{
+ typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
+ unsigned long bytes = 0;
+
+ asm volatile(
+#ifndef __s390x__
+ " ahi %1,31\n"
+ " srl %1,5\n"
+ "0: c %2,0(%0,%3)\n"
+ " jne 1f\n"
+ " la %0,4(%0)\n"
+ " brct %1,0b\n"
+ "1:\n"
+#else
+ " aghi %1,63\n"
+ " srlg %1,%1,6\n"
+ "0: cg %2,0(%0,%3)\n"
+ " jne 1f\n"
+ " la %0,8(%0)\n"
+ " brct %1,0b\n"
+ "1:\n"
+#endif
+ : "+a" (bytes), "+a" (size)
+ : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr)
+ : "cc" );
+ return bytes;
+}
+
+/**
+ * __ffz_word - add number of the first unset bit
+ * @nr: base value the bit number is added to
+ * @word: the word that is searched for unset bits
+ */
+static inline unsigned long __ffz_word(unsigned long nr, unsigned long word)
+{
#ifdef __s390x__
if (likely((word & 0xffffffff) == 0xffffffff)) {
word >>= 32;
- bit += 32;
+ nr += 32;
}
#endif
if (likely((word & 0xffff) == 0xffff)) {
word >>= 16;
- bit += 16;
+ nr += 16;
}
if (likely((word & 0xff) == 0xff)) {
word >>= 8;
- bit += 8;
+ nr += 8;
}
- return bit + _zb_findmap[word & 0xff];
+ return nr + _zb_findmap[(unsigned char) word];
}
-/*
- * __ffs = find first bit in word. Undefined if no bit exists,
- * so code should check against 0UL first..
+/**
+ * __ffs_word - add number of the first set bit
+ * @nr: base value the bit number is added to
+ * @word: the word that is searched for set bits
*/
-static inline unsigned long __ffs (unsigned long word)
+static inline unsigned long __ffs_word(unsigned long nr, unsigned long word)
{
- unsigned long bit = 0;
-
#ifdef __s390x__
if (likely((word & 0xffffffff) == 0)) {
word >>= 32;
- bit += 32;
+ nr += 32;
}
#endif
if (likely((word & 0xffff) == 0)) {
word >>= 16;
- bit += 16;
+ nr += 16;
}
if (likely((word & 0xff) == 0)) {
word >>= 8;
- bit += 8;
+ nr += 8;
}
- return bit + _sb_findmap[word & 0xff];
+ return nr + _sb_findmap[(unsigned char) word];
+}
+
+
+/**
+ * __load_ulong_be - load big endian unsigned long
+ * @p: pointer to array of unsigned long
+ * @offset: byte offset of source value in the array
+ */
+static inline unsigned long __load_ulong_be(const unsigned long *p,
+ unsigned long offset)
+{
+ p = (unsigned long *)((unsigned long) p + offset);
+ return *p;
+}
+
+/**
+ * __load_ulong_le - load little endian unsigned long
+ * @p: pointer to array of unsigned long
+ * @offset: byte offset of source value in the array
+ */
+static inline unsigned long __load_ulong_le(const unsigned long *p,
+ unsigned long offset)
+{
+ unsigned long word;
+
+ p = (unsigned long *)((unsigned long) p + offset);
+#ifndef __s390x__
+ asm volatile(
+ " ic %0,0(%1)\n"
+ " icm %0,2,1(%1)\n"
+ " icm %0,4,2(%1)\n"
+ " icm %0,8,3(%1)"
+ : "=&d" (word) : "a" (p), "m" (*p) : "cc");
+#else
+ asm volatile(
+ " lrvg %0,%1"
+ : "=d" (word) : "m" (*p) );
+#endif
+ return word;
}
/*
- * Find-bit routines..
+ * The various find bit functions.
*/
-#ifndef __s390x__
-
-static inline int
-find_first_zero_bit(const unsigned long * addr, unsigned long size)
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
{
- typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
- unsigned long cmp, count;
- unsigned int res;
+ return __ffz_word(0, word);
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs (unsigned long word)
+{
+ return __ffs_word(0, word);
+}
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static inline int ffs(int x)
+{
+ if (!x)
+ return 0;
+ return __ffs_word(1, x);
+}
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+static inline unsigned long find_first_zero_bit(const unsigned long *addr,
+ unsigned long size)
+{
+ unsigned long bytes, bits;
if (!size)
return 0;
- asm volatile(
- " lhi %1,-1\n"
- " lr %2,%3\n"
- " slr %0,%0\n"
- " ahi %2,31\n"
- " srl %2,5\n"
- "0: c %1,0(%0,%4)\n"
- " jne 1f\n"
- " la %0,4(%0)\n"
- " brct %2,0b\n"
- " lr %0,%3\n"
- " j 4f\n"
- "1: l %2,0(%0,%4)\n"
- " sll %0,3\n"
- " lhi %1,0xff\n"
- " tml %2,0xffff\n"
- " jno 2f\n"
- " ahi %0,16\n"
- " srl %2,16\n"
- "2: tml %2,0x00ff\n"
- " jno 3f\n"
- " ahi %0,8\n"
- " srl %2,8\n"
- "3: nr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " alr %0,%2\n"
- "4:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (addr), "a" (&_zb_findmap),
- "m" (*(addrtype *) addr) : "cc");
- return (res < size) ? res : size;
+ bytes = __ffz_word_loop(addr, size);
+ bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
+ return (bits < size) ? bits : size;
}
-static inline int
-find_first_bit(const unsigned long * addr, unsigned long size)
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+static inline unsigned long find_first_bit(const unsigned long * addr,
+ unsigned long size)
{
- typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
- unsigned long cmp, count;
- unsigned int res;
+ unsigned long bytes, bits;
if (!size)
return 0;
- asm volatile(
- " slr %1,%1\n"
- " lr %2,%3\n"
- " slr %0,%0\n"
- " ahi %2,31\n"
- " srl %2,5\n"
- "0: c %1,0(%0,%4)\n"
- " jne 1f\n"
- " la %0,4(%0)\n"
- " brct %2,0b\n"
- " lr %0,%3\n"
- " j 4f\n"
- "1: l %2,0(%0,%4)\n"
- " sll %0,3\n"
- " lhi %1,0xff\n"
- " tml %2,0xffff\n"
- " jnz 2f\n"
- " ahi %0,16\n"
- " srl %2,16\n"
- "2: tml %2,0x00ff\n"
- " jnz 3f\n"
- " ahi %0,8\n"
- " srl %2,8\n"
- "3: nr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " alr %0,%2\n"
- "4:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (addr), "a" (&_sb_findmap),
- "m" (*(addrtype *) addr) : "cc");
- return (res < size) ? res : size;
+ bytes = __ffs_word_loop(addr, size);
+ bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
+ return (bits < size) ? bits : size;
}
-#else /* __s390x__ */
-
-static inline unsigned long
-find_first_zero_bit(const unsigned long * addr, unsigned long size)
-{
- typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
- unsigned long res, cmp, count;
-
- if (!size)
- return 0;
- asm volatile(
- " lghi %1,-1\n"
- " lgr %2,%3\n"
- " slgr %0,%0\n"
- " aghi %2,63\n"
- " srlg %2,%2,6\n"
- "0: cg %1,0(%0,%4)\n"
- " jne 1f\n"
- " la %0,8(%0)\n"
- " brct %2,0b\n"
- " lgr %0,%3\n"
- " j 5f\n"
- "1: lg %2,0(%0,%4)\n"
- " sllg %0,%0,3\n"
- " clr %2,%1\n"
- " jne 2f\n"
- " aghi %0,32\n"
- " srlg %2,%2,32\n"
- "2: lghi %1,0xff\n"
- " tmll %2,0xffff\n"
- " jno 3f\n"
- " aghi %0,16\n"
- " srl %2,16\n"
- "3: tmll %2,0x00ff\n"
- " jno 4f\n"
- " aghi %0,8\n"
- " srl %2,8\n"
- "4: ngr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " algr %0,%2\n"
- "5:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (addr), "a" (&_zb_findmap),
- "m" (*(addrtype *) addr) : "cc");
- return (res < size) ? res : size;
-}
-
-static inline unsigned long
-find_first_bit(const unsigned long * addr, unsigned long size)
-{
- typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
- unsigned long res, cmp, count;
-
- if (!size)
- return 0;
- asm volatile(
- " slgr %1,%1\n"
- " lgr %2,%3\n"
- " slgr %0,%0\n"
- " aghi %2,63\n"
- " srlg %2,%2,6\n"
- "0: cg %1,0(%0,%4)\n"
- " jne 1f\n"
- " aghi %0,8\n"
- " brct %2,0b\n"
- " lgr %0,%3\n"
- " j 5f\n"
- "1: lg %2,0(%0,%4)\n"
- " sllg %0,%0,3\n"
- " clr %2,%1\n"
- " jne 2f\n"
- " aghi %0,32\n"
- " srlg %2,%2,32\n"
- "2: lghi %1,0xff\n"
- " tmll %2,0xffff\n"
- " jnz 3f\n"
- " aghi %0,16\n"
- " srl %2,16\n"
- "3: tmll %2,0x00ff\n"
- " jnz 4f\n"
- " aghi %0,8\n"
- " srl %2,8\n"
- "4: ngr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " algr %0,%2\n"
- "5:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (addr), "a" (&_sb_findmap),
- "m" (*(addrtype *) addr) : "cc");
- return (res < size) ? res : size;
-}
-
-#endif /* __s390x__ */
-
-static inline int
-find_next_zero_bit (const unsigned long * addr, unsigned long size,
- unsigned long offset)
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static inline int find_next_zero_bit (const unsigned long * addr,
+ unsigned long size,
+ unsigned long offset)
{
const unsigned long *p;
unsigned long bit, set;
@@ -688,10 +702,10 @@
p = addr + offset / __BITOPS_WORDSIZE;
if (bit) {
/*
- * s390 version of ffz returns __BITOPS_WORDSIZE
+ * __ffz_word returns __BITOPS_WORDSIZE
* if no zero bit is present in the word.
*/
- set = ffz(*p >> bit) + bit;
+ set = __ffz_word(0, *p >> bit) + bit;
if (set >= size)
return size + offset;
if (set < __BITOPS_WORDSIZE)
@@ -703,9 +717,15 @@
return offset + find_first_zero_bit(p, size);
}
-static inline int
-find_next_bit (const unsigned long * addr, unsigned long size,
- unsigned long offset)
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static inline int find_next_bit (const unsigned long * addr,
+ unsigned long size,
+ unsigned long offset)
{
const unsigned long *p;
unsigned long bit, set;
@@ -718,10 +738,10 @@
p = addr + offset / __BITOPS_WORDSIZE;
if (bit) {
/*
- * s390 version of __ffs returns __BITOPS_WORDSIZE
+ * __ffs_word returns __BITOPS_WORDSIZE
* if no one bit is present in the word.
*/
- set = __ffs(*p & (~0UL << bit));
+ set = __ffs_word(0, *p & (~0UL << bit));
if (set >= size)
return size + offset;
if (set < __BITOPS_WORDSIZE)
@@ -744,8 +764,6 @@
return find_first_bit(b, 140);
}
-#include <asm-generic/bitops/ffs.h>
-
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/fls64.h>
@@ -772,108 +790,23 @@
test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
#define ext2_test_bit(nr, addr) \
test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-#define ext2_find_next_bit(addr, size, off) \
- generic_find_next_le_bit((unsigned long *)(addr), (size), (off))
-#ifndef __s390x__
-
-static inline int
-ext2_find_first_zero_bit(void *vaddr, unsigned int size)
+static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size)
{
- typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
- unsigned long cmp, count;
- unsigned int res;
+ unsigned long bytes, bits;
if (!size)
return 0;
- asm volatile(
- " lhi %1,-1\n"
- " lr %2,%3\n"
- " ahi %2,31\n"
- " srl %2,5\n"
- " slr %0,%0\n"
- "0: cl %1,0(%0,%4)\n"
- " jne 1f\n"
- " ahi %0,4\n"
- " brct %2,0b\n"
- " lr %0,%3\n"
- " j 4f\n"
- "1: l %2,0(%0,%4)\n"
- " sll %0,3\n"
- " ahi %0,24\n"
- " lhi %1,0xff\n"
- " tmh %2,0xffff\n"
- " jo 2f\n"
- " ahi %0,-16\n"
- " srl %2,16\n"
- "2: tml %2,0xff00\n"
- " jo 3f\n"
- " ahi %0,-8\n"
- " srl %2,8\n"
- "3: nr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " alr %0,%2\n"
- "4:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
- "m" (*(addrtype *) vaddr) : "cc");
- return (res < size) ? res : size;
+ bytes = __ffz_word_loop(vaddr, size);
+ bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes));
+ return (bits < size) ? bits : size;
}
-#else /* __s390x__ */
-
-static inline unsigned long
-ext2_find_first_zero_bit(void *vaddr, unsigned long size)
-{
- typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
- unsigned long res, cmp, count;
-
- if (!size)
- return 0;
- asm volatile(
- " lghi %1,-1\n"
- " lgr %2,%3\n"
- " aghi %2,63\n"
- " srlg %2,%2,6\n"
- " slgr %0,%0\n"
- "0: clg %1,0(%0,%4)\n"
- " jne 1f\n"
- " aghi %0,8\n"
- " brct %2,0b\n"
- " lgr %0,%3\n"
- " j 5f\n"
- "1: cl %1,0(%0,%4)\n"
- " jne 2f\n"
- " aghi %0,4\n"
- "2: l %2,0(%0,%4)\n"
- " sllg %0,%0,3\n"
- " aghi %0,24\n"
- " lghi %1,0xff\n"
- " tmlh %2,0xffff\n"
- " jo 3f\n"
- " aghi %0,-16\n"
- " srl %2,16\n"
- "3: tmll %2,0xff00\n"
- " jo 4f\n"
- " aghi %0,-8\n"
- " srl %2,8\n"
- "4: ngr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " algr %0,%2\n"
- "5:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
- "m" (*(addrtype *) vaddr) : "cc");
- return (res < size) ? res : size;
-}
-
-#endif /* __s390x__ */
-
-static inline int
-ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
+static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size,
+ unsigned long offset)
{
unsigned long *addr = vaddr, *p;
- unsigned long word, bit, set;
+ unsigned long bit, set;
if (offset >= size)
return size;
@@ -882,23 +815,11 @@
size -= offset;
p = addr + offset / __BITOPS_WORDSIZE;
if (bit) {
-#ifndef __s390x__
- asm volatile(
- " ic %0,0(%1)\n"
- " icm %0,2,1(%1)\n"
- " icm %0,4,2(%1)\n"
- " icm %0,8,3(%1)"
- : "=&a" (word) : "a" (p), "m" (*p) : "cc");
-#else
- asm volatile(
- " lrvg %0,%1"
- : "=a" (word) : "m" (*p) );
-#endif
/*
* s390 version of ffz returns __BITOPS_WORDSIZE
* if no zero bit is present in the word.
*/
- set = ffz(word >> bit) + bit;
+ set = ffz(__load_ulong_le(p, 0) >> bit) + bit;
if (set >= size)
return size + offset;
if (set < __BITOPS_WORDSIZE)
@@ -910,6 +831,47 @@
return offset + ext2_find_first_zero_bit(p, size);
}
+static inline unsigned long ext2_find_first_bit(void *vaddr,
+ unsigned long size)
+{
+ unsigned long bytes, bits;
+
+ if (!size)
+ return 0;
+ bytes = __ffs_word_loop(vaddr, size);
+ bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes));
+ return (bits < size) ? bits : size;
+}
+
+static inline int ext2_find_next_bit(void *vaddr, unsigned long size,
+ unsigned long offset)
+{
+ unsigned long *addr = vaddr, *p;
+ unsigned long bit, set;
+
+ if (offset >= size)
+ return size;
+ bit = offset & (__BITOPS_WORDSIZE - 1);
+ offset -= bit;
+ size -= offset;
+ p = addr + offset / __BITOPS_WORDSIZE;
+ if (bit) {
+ /*
+ * s390 version of ffz returns __BITOPS_WORDSIZE
+ * if no zero bit is present in the word.
+ */
+ set = ffs(__load_ulong_le(p, 0) >> bit) + bit;
+ if (set >= size)
+ return size + offset;
+ if (set < __BITOPS_WORDSIZE)
+ return set + offset;
+ offset += __BITOPS_WORDSIZE;
+ size -= __BITOPS_WORDSIZE;
+ p++;
+ }
+ return offset + ext2_find_first_bit(p, size);
+}
+
#include <asm-generic/bitops/minix.h>
#endif /* __KERNEL__ */
diff --git a/include/asm-s390/cacheflush.h b/include/asm-s390/cacheflush.h
index f7cade8..49d5af9 100644
--- a/include/asm-s390/cacheflush.h
+++ b/include/asm-s390/cacheflush.h
@@ -24,4 +24,8 @@
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
memcpy(dst, src, len)
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void kernel_map_pages(struct page *page, int numpages, int enable);
+#endif
+
#endif /* _S390_CACHEFLUSH_H */
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h
index 7109c7c..289053e 100644
--- a/include/asm-s390/ccwgroup.h
+++ b/include/asm-s390/ccwgroup.h
@@ -37,6 +37,7 @@
* @remove: function called on remove
* @set_online: function called when device is set online
* @set_offline: function called when device is set offline
+ * @shutdown: function called when device is shut down
* @driver: embedded driver structure
*/
struct ccwgroup_driver {
@@ -49,6 +50,7 @@
void (*remove) (struct ccwgroup_device *);
int (*set_online) (struct ccwgroup_device *);
int (*set_offline) (struct ccwgroup_device *);
+ void (*shutdown)(struct ccwgroup_device *);
struct device_driver driver;
};
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h
index 7f4ad62..de065b3 100644
--- a/include/asm-s390/compat.h
+++ b/include/asm-s390/compat.h
@@ -149,7 +149,7 @@
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h
index 4b3ef7c..133ce05 100644
--- a/include/asm-s390/cputime.h
+++ b/include/asm-s390/cputime.h
@@ -54,6 +54,7 @@
#define cputime_lt(__a, __b) ((__a) < (__b))
#define cputime_le(__a, __b) ((__a) <= (__b))
#define cputime_to_jiffies(__ct) (__div((__ct), 1000000 / HZ))
+#define cputime_to_scaled(__ct) (__ct)
#define jiffies_to_cputime(__hz) ((cputime_t)(__hz) * (1000000 / HZ))
#define cputime64_zero (0ULL)
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
index 709dd17..6f6619b 100644
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -57,10 +57,10 @@
}
#define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); })
-#define pud_free(x) do { } while (0)
+#define pud_free(mm, x) do { } while (0)
#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define pgd_populate(mm, pgd, pud) BUG()
#define pgd_populate_kernel(mm, pgd, pud) BUG()
@@ -76,7 +76,7 @@
}
#define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); })
-#define pud_free(x) do { } while (0)
+#define pud_free(mm, x) do { } while (0)
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
{
@@ -85,7 +85,7 @@
crst_table_init(crst, _SEGMENT_ENTRY_EMPTY);
return (pmd_t *) crst;
}
-#define pmd_free(pmd) crst_table_free((unsigned long *) pmd)
+#define pmd_free(mm, pmd) crst_table_free((unsigned long *)pmd)
#define pgd_populate(mm, pgd, pud) BUG()
#define pgd_populate_kernel(mm, pgd, pud) BUG()
@@ -115,7 +115,7 @@
crst_table_init(crst, pgd_entry_type(mm));
return (pgd_t *) crst;
}
-#define pgd_free(pgd) crst_table_free((unsigned long *) pgd)
+#define pgd_free(mm, pgd) crst_table_free((unsigned long *) pgd)
static inline void
pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
@@ -151,9 +151,9 @@
#define pte_alloc_one(mm, vmaddr) \
virt_to_page(page_table_alloc(s390_noexec))
-#define pte_free_kernel(pte) \
+#define pte_free_kernel(mm, pte) \
page_table_free((unsigned long *) pte)
-#define pte_free(pte) \
+#define pte_free(mm, pte) \
page_table_free((unsigned long *) page_to_phys((struct page *) pte))
#endif /* _S390_PGALLOC_H */
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 79b9eab..3f52075 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -115,15 +115,21 @@
#ifndef __s390x__
#define VMALLOC_START 0x78000000UL
#define VMALLOC_END 0x7e000000UL
-#define VMEM_MAP_MAX 0x80000000UL
+#define VMEM_MAP_END 0x80000000UL
#else /* __s390x__ */
#define VMALLOC_START 0x3e000000000UL
#define VMALLOC_END 0x3e040000000UL
-#define VMEM_MAP_MAX 0x40000000000UL
+#define VMEM_MAP_END 0x40000000000UL
#endif /* __s390x__ */
+/*
+ * VMEM_MAX_PHYS is the highest physical address that can be added to the 1:1
+ * mapping. This needs to be calculated at compile time since the size of the
+ * VMEM_MAP is static but the size of struct page can change.
+ */
+#define VMEM_MAX_PHYS min(VMALLOC_START, ((VMEM_MAP_END - VMALLOC_END) / \
+ sizeof(struct page) * PAGE_SIZE) & ~((16 << 20) - 1))
#define VMEM_MAP ((struct page *) VMALLOC_END)
-#define VMEM_MAP_SIZE ((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
/*
* A 31 bit pagetable entry of S390 has following format:
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index c86b982..4f74460 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -70,8 +70,9 @@
#else /* __s390x__ */
-# define TASK_SIZE (test_thread_flag(TIF_31BIT) ? \
+# define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_31BIT) ? \
(0x80000000UL) : (0x40000000000UL))
+# define TASK_SIZE TASK_SIZE_OF(current)
# define TASK_UNMAPPED_BASE (TASK_SIZE / 2)
# define DEFAULT_TASK_SIZE (0x40000000000UL)
diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h
index 618693cf..985de2b 100644
--- a/include/asm-s390/tlb.h
+++ b/include/asm-s390/tlb.h
@@ -65,9 +65,9 @@
if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS))
__tlb_flush_mm(tlb->mm);
while (tlb->nr_ptes > 0)
- pte_free(tlb->array[--tlb->nr_ptes]);
+ pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
while (tlb->nr_pmds < TLB_NR_PTRS)
- pmd_free((pmd_t *) tlb->array[tlb->nr_pmds++]);
+ pmd_free(tlb->mm, (pmd_t *) tlb->array[tlb->nr_pmds++]);
}
static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -102,7 +102,7 @@
if (tlb->nr_ptes >= tlb->nr_pmds)
tlb_flush_mmu(tlb, 0, 0);
} else
- pte_free(page);
+ pte_free(tlb->mm, page);
}
/*
@@ -117,7 +117,7 @@
if (tlb->nr_ptes >= tlb->nr_pmds)
tlb_flush_mmu(tlb, 0, 0);
} else
- pmd_free(pmd);
+ pmd_free(tlb->mm, pmd);
#endif
}
diff --git a/include/asm-sh/delay.h b/include/asm-sh/delay.h
index 031db84..d5d4640 100644
--- a/include/asm-sh/delay.h
+++ b/include/asm-sh/delay.h
@@ -12,7 +12,7 @@
extern void __udelay(unsigned long usecs);
extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
extern void __delay(unsigned long loops);
#ifdef CONFIG_SUPERH32
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
index 18b613c..59ca16d 100644
--- a/include/asm-sh/pgalloc.h
+++ b/include/asm-sh/pgalloc.h
@@ -36,7 +36,7 @@
return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
quicklist_free(QUICK_PGD, NULL, pgd);
}
@@ -54,12 +54,12 @@
return pg ? virt_to_page(pg) : NULL;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
quicklist_free(QUICK_PT, NULL, pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
quicklist_free_page(QUICK_PT, NULL, pte);
}
@@ -71,7 +71,7 @@
* inside the pgd, so has no extra memory associated with it.
*/
-#define pmd_free(x) do { } while (0)
+#define pmd_free(mm, x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
static inline void check_pgt_cache(void)
diff --git a/include/asm-sh/unistd_32.h b/include/asm-sh/unistd_32.h
index b182b1c..433fd1b 100644
--- a/include/asm-sh/unistd_32.h
+++ b/include/asm-sh/unistd_32.h
@@ -330,7 +330,7 @@
#define __NR_epoll_pwait 319
#define __NR_utimensat 320
#define __NR_signalfd 321
-#define __NR_timerfd 322
+/* #define __NR_timerfd 322 removed */
#define __NR_eventfd 323
#define __NR_fallocate 324
diff --git a/include/asm-sh/unistd_64.h b/include/asm-sh/unistd_64.h
index 94451188..108d2ba 100644
--- a/include/asm-sh/unistd_64.h
+++ b/include/asm-sh/unistd_64.h
@@ -370,7 +370,7 @@
#define __NR_epoll_pwait 347
#define __NR_utimensat 348
#define __NR_signalfd 349
-#define __NR_timerfd 350
+/* #define __NR_timerfd 350 removed */
#define __NR_eventfd 351
#define __NR_fallocate 352
diff --git a/include/asm-sparc/pgalloc.h b/include/asm-sparc/pgalloc.h
index a449cd4..b5fbdd3 100644
--- a/include/asm-sparc/pgalloc.h
+++ b/include/asm-sparc/pgalloc.h
@@ -32,7 +32,7 @@
BTFIXUPDEF_CALL(void, free_pgd_fast, pgd_t *)
#define free_pgd_fast(pgd) BTFIXUP_CALL(free_pgd_fast)(pgd)
-#define pgd_free(pgd) free_pgd_fast(pgd)
+#define pgd_free(mm, pgd) free_pgd_fast(pgd)
#define pgd_alloc(mm) get_pgd_fast()
BTFIXUPDEF_CALL(void, pgd_set, pgd_t *, pmd_t *)
@@ -45,8 +45,8 @@
BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *)
#define free_pmd_fast(pmd) BTFIXUP_CALL(free_pmd_fast)(pmd)
-#define pmd_free(pmd) free_pmd_fast(pmd)
-#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd)
+#define pmd_free(mm, pmd) free_pmd_fast(pmd)
+#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
BTFIXUPDEF_CALL(void, pmd_populate, pmd_t *, struct page *)
#define pmd_populate(MM, PMD, PTE) BTFIXUP_CALL(pmd_populate)(PMD, PTE)
@@ -59,10 +59,10 @@
#define pte_alloc_one_kernel(mm, addr) BTFIXUP_CALL(pte_alloc_one_kernel)(mm, addr)
BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *)
-#define pte_free_kernel(pte) BTFIXUP_CALL(free_pte_fast)(pte)
+#define pte_free_kernel(mm, pte) BTFIXUP_CALL(free_pte_fast)(pte)
BTFIXUPDEF_CALL(void, pte_free, struct page *)
-#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte)
-#define __pte_free_tlb(tlb, pte) pte_free(pte)
+#define pte_free(mm, pte) BTFIXUP_CALL(pte_free)(pte)
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
#endif /* _SPARC_PGALLOC_H */
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index 0decdf7..2338a02 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -327,11 +327,13 @@
#define __NR_epoll_pwait 309
#define __NR_utimensat 310
#define __NR_signalfd 311
-#define __NR_timerfd 312
+#define __NR_timerfd_create 312
#define __NR_eventfd 313
#define __NR_fallocate 314
+#define __NR_timerfd_settime 315
+#define __NR_timerfd_gettime 316
-#define NR_SYSCALLS 315
+#define NR_SYSCALLS 317
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
* it never had the plain ones and there is no value to adding those
diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h
index 01fe668..f260b58 100644
--- a/include/asm-sparc64/compat.h
+++ b/include/asm-sparc64/compat.h
@@ -152,7 +152,7 @@
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index c299b85..b6ece22 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -16,7 +16,7 @@
/* BIO layer definitions. */
extern unsigned long kern_base, kern_size;
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
-#define BIO_VMERGE_BOUNDARY 8192
+#define BIO_VMERGE_BOUNDARY 0
static inline u8 _inb(unsigned long addr)
{
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index 5d66b85..b48f73c 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -20,7 +20,7 @@
return quicklist_alloc(0, GFP_KERNEL, NULL);
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
quicklist_free(0, NULL, pgd);
}
@@ -32,7 +32,7 @@
return quicklist_alloc(0, GFP_KERNEL, NULL);
}
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
quicklist_free(0, NULL, pmd);
}
@@ -50,12 +50,12 @@
return pg ? virt_to_page(pg) : NULL;
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
quicklist_free(0, NULL, pte);
}
-static inline void pte_free(struct page *ptepage)
+static inline void pte_free(struct mm_struct *mm, struct page *ptepage)
{
quicklist_free_page(0, NULL, ptepage);
}
diff --git a/include/asm-sparc64/timex.h b/include/asm-sparc64/timex.h
index 2a5e4eb..c622535 100644
--- a/include/asm-sparc64/timex.h
+++ b/include/asm-sparc64/timex.h
@@ -14,10 +14,6 @@
typedef unsigned long cycles_t;
#define get_cycles() tick_ops->get_tick()
-#define ARCH_HAS_READ_CURRENT_TIMER 1
-#define read_current_timer(timer_val_p) \
-({ *timer_val_p = tick_ops->get_tick(); \
- 0; \
-})
+#define ARCH_HAS_READ_CURRENT_TIMER
#endif
diff --git a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h
index 349d1d3..ec81cde 100644
--- a/include/asm-sparc64/tlb.h
+++ b/include/asm-sparc64/tlb.h
@@ -100,8 +100,8 @@
}
#define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#define pte_free_tlb(mp,ptepage) pte_free(ptepage)
-#define pmd_free_tlb(mp,pmdp) pmd_free(pmdp)
+#define pte_free_tlb(mp, ptepage) pte_free((mp)->mm, ptepage)
+#define pmd_free_tlb(mp, pmdp) pmd_free((mp)->mm, pmdp)
#define pud_free_tlb(tlb,pudp) __pud_free_tlb(tlb,pudp)
#define tlb_migrate_finish(mm) do { } while (0)
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index cb751b4..77559da 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -329,11 +329,13 @@
#define __NR_epoll_pwait 309
#define __NR_utimensat 310
#define __NR_signalfd 311
-#define __NR_timerfd 312
+#define __NR_timerfd_create 312
#define __NR_eventfd 313
#define __NR_fallocate 314
+#define __NR_timerfd_settime 315
+#define __NR_timerfd_gettime 316
-#define NR_SYSCALLS 315
+#define NR_SYSCALLS 317
#ifdef __KERNEL__
/* sysconf options, for SunOS compatibility */
diff --git a/include/asm-um/a.out.h b/include/asm-um/a.out.h
index 9281dd8..f42ff145 100644
--- a/include/asm-um/a.out.h
+++ b/include/asm-um/a.out.h
@@ -13,11 +13,9 @@
extern unsigned long stacksizelim;
-extern unsigned long host_task_size;
-
#define STACK_ROOM (stacksizelim)
-#define STACK_TOP task_size
+#define STACK_TOP (TASK_SIZE - 2 * PAGE_SIZE)
#define STACK_TOP_MAX STACK_TOP
diff --git a/include/asm-um/current.h b/include/asm-um/current.h
index 8fd72f6..c2191d9 100644
--- a/include/asm-um/current.h
+++ b/include/asm-um/current.h
@@ -1,32 +1,13 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#ifndef __UM_CURRENT_H
#define __UM_CURRENT_H
-#ifndef __ASSEMBLY__
-
-#include "asm/page.h"
#include "linux/thread_info.h"
#define current (current_thread_info()->task)
-/*Backward compatibility - it's used inside arch/um.*/
-#define current_thread current_thread_info()
-
-#endif /* __ASSEMBLY__ */
-
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/include/asm-um/elf-i386.h b/include/asm-um/elf-i386.h
index ca94a13..23d6893 100644
--- a/include/asm-um/elf-i386.h
+++ b/include/asm-um/elf-i386.h
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#ifndef __UM_ELF_I386_H
#define __UM_ELF_I386_H
-#include <linux/sched.h>
+#include <asm/user.h>
#include "skas.h"
#define R_386_NONE 0
@@ -46,7 +46,7 @@
PT_REGS_EDI(regs) = 0; \
PT_REGS_EBP(regs) = 0; \
PT_REGS_EAX(regs) = 0; \
-} while(0)
+} while (0)
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
@@ -74,14 +74,9 @@
pr_reg[14] = PT_REGS_EFLAGS(regs); \
pr_reg[15] = PT_REGS_SP(regs); \
pr_reg[16] = PT_REGS_SS(regs); \
-} while(0);
+} while (0);
-static inline int elf_core_copy_fpregs(struct task_struct *t,
- elf_fpregset_t *fpu)
-{
- int cpu = ((struct thread_info *) t->stack)->cpu;
- return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
-}
+extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
#define ELF_CORE_COPY_FPREGS(t, fpu) elf_core_copy_fpregs(t, fpu)
@@ -91,7 +86,7 @@
extern char * elf_aux_platform;
#define ELF_PLATFORM (elf_aux_platform)
-#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+#define SET_PERSONALITY(ex, ibcs2) do { } while (0)
extern unsigned long vsyscall_ehdr;
extern unsigned long vsyscall_end;
@@ -166,14 +161,3 @@
}
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/include/asm-um/elf-x86_64.h b/include/asm-um/elf-x86_64.h
index 3c9d543e..3b2d522 100644
--- a/include/asm-um/elf-x86_64.h
+++ b/include/asm-um/elf-x86_64.h
@@ -7,7 +7,6 @@
#ifndef __UM_ELF_X86_64_H
#define __UM_ELF_X86_64_H
-#include <linux/sched.h>
#include <asm/user.h>
#include "skas.h"
@@ -96,12 +95,7 @@
(pr_reg)[25] = 0; \
(pr_reg)[26] = 0;
-static inline int elf_core_copy_fpregs(struct task_struct *t,
- elf_fpregset_t *fpu)
-{
- int cpu = current_thread->cpu;
- return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
-}
+extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
#define ELF_CORE_COPY_FPREGS(t, fpu) elf_core_copy_fpregs(t, fpu)
diff --git a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h
index d352a35..89a87c1 100644
--- a/include/asm-um/fixmap.h
+++ b/include/asm-um/fixmap.h
@@ -1,9 +1,10 @@
#ifndef __UM_FIXMAP_H
#define __UM_FIXMAP_H
+#include <asm/system.h>
#include <asm/kmap_types.h>
#include <asm/archparam.h>
-#include <asm/elf.h>
+#include <asm/page.h>
/*
* Here we define all the compile-time 'special' virtual
@@ -55,9 +56,8 @@
* the start of the fixmap, and leave one page empty
* at the top of mem..
*/
-extern unsigned long get_kmem_end(void);
-#define FIXADDR_TOP (get_kmem_end() - 0x2000)
+#define FIXADDR_TOP (CONFIG_TOP_ADDR - 2 * PAGE_SIZE)
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
diff --git a/include/asm-um/ldt.h b/include/asm-um/ldt.h
index b2553f3..52af512 100644
--- a/include/asm-um/ldt.h
+++ b/include/asm-um/ldt.h
@@ -8,7 +8,7 @@
#ifndef __ASM_LDT_H
#define __ASM_LDT_H
-#include "asm/semaphore.h"
+#include <linux/mutex.h>
#include "asm/host_ldt.h"
extern void ldt_host_info(void);
@@ -27,7 +27,7 @@
typedef struct uml_ldt {
int entry_count;
- struct semaphore semaphore;
+ struct mutex lock;
union {
struct ldt_entry * pages[LDT_PAGES_MAX];
struct ldt_entry entries[LDT_DIRECT_ENTRIES];
diff --git a/include/asm-um/linkage.h b/include/asm-um/linkage.h
index cdb3024..7dfce37 100644
--- a/include/asm-um/linkage.h
+++ b/include/asm-um/linkage.h
@@ -3,10 +3,4 @@
#include "asm/arch/linkage.h"
-
-/* <linux/linkage.h> will pick sane defaults */
-#ifdef CONFIG_GPROF
-#undef fastcall
-#endif
-
#endif
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 5f3b863..6686fc52 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -6,11 +6,12 @@
#ifndef __UM_MMU_CONTEXT_H
#define __UM_MMU_CONTEXT_H
-#include <asm-generic/mm_hooks.h>
-
#include "linux/sched.h"
#include "um_mmu.h"
+extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+extern void arch_exit_mmap(struct mm_struct *mm);
+
#define get_mmu_context(task) do ; while(0)
#define activate_context(tsk) do ; while(0)
@@ -30,6 +31,8 @@
*/
if (old != new && (current->flags & PF_BORROWED_MM))
__switch_mm(&new->context.id);
+
+ arch_dup_mmap(old, new);
}
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index 4b424c7..fe2374d 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -30,7 +30,7 @@
#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT)
typedef struct { unsigned long pte_low, pte_high; } pte_t;
-typedef struct { unsigned long long pmd; } pmd_t;
+typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
#define pte_val(x) ((x).pte_low | ((unsigned long long) (x).pte_high << 32))
@@ -106,8 +106,8 @@
#define __pa(virt) to_phys((void *) (unsigned long) (virt))
#define __va(phys) to_virt((unsigned long) (phys))
-#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
-#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT)
+#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT))
+#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT))
#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
diff --git a/include/asm-um/param.h b/include/asm-um/param.h
index f914e7d..4cd4a22 100644
--- a/include/asm-um/param.h
+++ b/include/asm-um/param.h
@@ -10,7 +10,7 @@
#define MAXHOSTNAMELEN 64 /* max length of hostname */
#ifdef __KERNEL__
-#define HZ 100
+#define HZ CONFIG_HZ
#define USER_HZ 100 /* .. some user interfaces are in "ticks" */
#define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */
#endif
diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h
index 1490487..4f3e62b 100644
--- a/include/asm-um/pgalloc.h
+++ b/include/asm-um/pgalloc.h
@@ -23,17 +23,17 @@
* Allocate and free page tables.
*/
extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long) pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
@@ -42,7 +42,7 @@
#ifdef CONFIG_3_LEVEL_PGTABLES
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
free_page((unsigned long)pmd);
}
diff --git a/include/asm-um/pgtable-2level.h b/include/asm-um/pgtable-2level.h
index 172a75f..f534b73 100644
--- a/include/asm-um/pgtable-2level.h
+++ b/include/asm-um/pgtable-2level.h
@@ -41,9 +41,6 @@
#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
-#define pmd_page_vaddr(pmd) \
- ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
/*
* Bits 0 through 4 are taken
*/
diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h
index 3ebafba..0446f45 100644
--- a/include/asm-um/pgtable-3level.h
+++ b/include/asm-um/pgtable-3level.h
@@ -11,7 +11,11 @@
/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#ifdef CONFIG_64BIT
#define PGDIR_SHIFT 30
+#else
+#define PGDIR_SHIFT 31
+#endif
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
@@ -28,9 +32,15 @@
*/
#define PTRS_PER_PTE 512
+#ifdef CONFIG_64BIT
#define PTRS_PER_PMD 512
-#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE)
#define PTRS_PER_PGD 512
+#else
+#define PTRS_PER_PMD 1024
+#define PTRS_PER_PGD 1024
+#endif
+
+#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0
#define pte_ERROR(e) \
@@ -49,7 +59,12 @@
#define pud_populate(mm, pud, pmd) \
set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd)))
+#ifdef CONFIG_64BIT
#define set_pud(pudptr, pudval) set_64bit((phys_t *) (pudptr), pud_val(pudval))
+#else
+#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
+#endif
+
static inline int pgd_newpage(pgd_t pgd)
{
return(pgd_val(pgd) & _PAGE_NEWPAGE);
@@ -57,17 +72,14 @@
static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
+#ifdef CONFIG_64BIT
#define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
+#else
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#endif
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-
- if(pmd)
- memset(pmd, 0, PAGE_SIZE);
-
- return pmd;
-}
+struct mm_struct;
+extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address);
static inline void pud_clear (pud_t *pud)
{
@@ -75,8 +87,7 @@
}
#define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK)
-#define pud_page_vaddr(pud) \
- ((struct page *) __va(pud_val(pud) & PAGE_MASK))
+#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PAGE_MASK))
/* Find an entry in the second-level page table.. */
#define pmd_offset(pud, address) ((pmd_t *) pud_page_vaddr(*(pud)) + \
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 830fc6e..4102b44 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Copyright 2003 PathScale, Inc.
* Derived from include/asm-i386/pgtable.h
* Licensed under the GPL
@@ -8,11 +8,7 @@
#ifndef __UM_PGTABLE_H
#define __UM_PGTABLE_H
-#include "linux/sched.h"
-#include "linux/linkage.h"
-#include "asm/processor.h"
-#include "asm/page.h"
-#include "asm/fixmap.h"
+#include <asm/fixmap.h>
#define _PAGE_PRESENT 0x001
#define _PAGE_NEWPAGE 0x002
@@ -34,22 +30,11 @@
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
- pte_t *pte_out);
-
/* zero page used for uninitialized stuff */
extern unsigned long *empty_zero_page;
#define pgtable_cache_init() do ; while (0)
-/*
- * pgd entries used up by user/kernel:
- */
-
-#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#ifndef __ASSEMBLY__
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. That means that
@@ -62,16 +47,12 @@
#define VMALLOC_OFFSET (__va_space)
#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
#else
# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
#endif
-#define REGION_SHIFT (sizeof(pte_t) * 8 - 4)
-#define REGION_MASK (((unsigned long) 0xf) << REGION_SHIFT)
-
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -81,11 +62,12 @@
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
/*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The i386 can't do page protection for execute, and considers that the same
+ * are read.
+ * Also, write permissions imply read permissions. This is the closest we can
+ * get..
*/
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
@@ -106,40 +88,16 @@
#define __S111 PAGE_SHARED
/*
- * Define this if things work differently on an i386 and an i486:
- * it will (on an i486) warn about kernel memory accesses that are
- * done without a 'access_ok(VERIFY_WRITE,..)'
- */
-#undef TEST_VERIFY_AREA
-
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-
-/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
-
#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR (8*sizeof(unsigned long))
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK (~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-/* 64-bit machines, beware! SRB. */
-#define SIZEOF_PTR_LOG2 3
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
#define pte_clear(mm,addr,xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE))
#define pmd_none(x) (!((unsigned long)pmd_val(x) & ~_PAGE_NEWPAGE))
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
@@ -149,14 +107,9 @@
#define pud_newpage(x) (pud_val(x) & _PAGE_NEWPAGE)
#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE)
-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-
#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
#define pte_page(x) pfn_to_page(pte_pfn(x))
-#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
-#define mk_phys(a, r) ((a) + (((unsigned long) r) << REGION_SHIFT))
-#define phys_addr(p) ((p) & ~REGION_MASK)
#define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE))
@@ -309,7 +262,8 @@
#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys))
#define __virt_to_page(virt) phys_to_page(__pa(virt))
-#define page_to_phys(page) pfn_to_phys(page_to_pfn(page))
+#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page))
+#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
#define mk_pte(page, pgprot) \
({ pte_t pte; \
@@ -325,8 +279,6 @@
return pte;
}
-#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
/*
* the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
*
@@ -335,8 +287,6 @@
*/
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_index_k(addr) pgd_index(addr)
-
/*
* pgd_offset() returns a (pgd_t *)
* pgd_index() is used get the offset into the pgd page's array of pgd_t's;
@@ -355,8 +305,12 @@
* this macro returns the index of the entry in the pmd page which would
* control the given virtual address
*/
+#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
/*
* the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
*
@@ -372,6 +326,9 @@
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
+struct mm_struct;
+extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
+
#define update_mmu_cache(vma,address,pte) do ; while (0)
/* Encode and de-code a swap entry */
@@ -388,29 +345,4 @@
#include <asm-generic/pgtable.h>
-#include <asm-generic/pgtable-nopud.h>
-
-#ifdef CONFIG_HIGHMEM
-/* Clear a kernel PTE and flush it from the TLB */
-#define kpte_clear_flush(ptep, vaddr) \
-do { \
- pte_clear(&init_mm, vaddr, ptep); \
- __flush_tlb_one(vaddr); \
-} while (0)
#endif
-
-#endif
-#endif
-
-#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
index 78c0599..b7d9a16 100644
--- a/include/asm-um/processor-generic.h
+++ b/include/asm-um/processor-generic.h
@@ -11,6 +11,7 @@
struct task_struct;
#include "asm/ptrace.h"
+#include "asm/pgtable.h"
#include "registers.h"
#include "sysdep/archsetjmp.h"
@@ -26,7 +27,6 @@
* as of 2.6.11).
*/
int forking;
- int nsyscalls;
struct pt_regs regs;
int singlestep_syscall;
void *fault_addr;
@@ -58,7 +58,6 @@
#define INIT_THREAD \
{ \
.forking = 0, \
- .nsyscalls = 0, \
.regs = EMPTY_REGS, \
.fault_addr = NULL, \
.prev_sched = NULL, \
@@ -68,10 +67,6 @@
.request = { 0 } \
}
-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
extern struct task_struct *alloc_task_struct(void);
static inline void release_thread(struct task_struct *task)
@@ -97,9 +92,7 @@
/*
* User space process size: 3GB (default).
*/
-extern unsigned long task_size;
-
-#define TASK_SIZE (task_size)
+#define TASK_SIZE (CONFIG_TOP_ADDR & PGDIR_MASK)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
@@ -128,6 +121,6 @@
#define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf)
-#define get_wchan(p) (0)
+extern unsigned long get_wchan(struct task_struct *p);
#endif
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
index 595f1c3..a2b7fe1 100644
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -10,7 +10,6 @@
#include "asm/host_ldt.h"
#include "asm/segment.h"
-extern int host_has_xmm;
extern int host_has_cmov;
/* include faultinfo structure */
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 6e5fd5c..356b83e 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -8,8 +8,9 @@
#ifndef __ASSEMBLY__
-#include <asm/processor.h>
#include <asm/types.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
struct thread_info {
struct task_struct *task; /* main task structure */
@@ -75,8 +76,8 @@
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
- * TIF_NEED_RESCHED
+#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
+ * TIF_NEED_RESCHED
*/
#define TIF_RESTART_BLOCK 4
#define TIF_MEMDIE 5
diff --git a/include/asm-um/tlb.h b/include/asm-um/tlb.h
index c640033..39fc475 100644
--- a/include/asm-um/tlb.h
+++ b/include/asm-um/tlb.h
@@ -1,6 +1,126 @@
#ifndef __UM_TLB_H
#define __UM_TLB_H
-#include <asm/arch/tlb.h>
+#include <linux/swap.h>
+#include <asm/percpu.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+/* struct mmu_gather is an opaque type used by the mm code for passing around
+ * any data needed by arch specific code for tlb_remove_page.
+ */
+struct mmu_gather {
+ struct mm_struct *mm;
+ unsigned int need_flush; /* Really unmapped some ptes? */
+ unsigned long start;
+ unsigned long end;
+ unsigned int fullmm; /* non-zero means full mm flush */
+};
+
+/* Users of the generic TLB shootdown code must declare this storage space. */
+DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
+ unsigned long address)
+{
+ if (tlb->start > address)
+ tlb->start = address;
+ if (tlb->end < address + PAGE_SIZE)
+ tlb->end = address + PAGE_SIZE;
+}
+
+static inline void init_tlb_gather(struct mmu_gather *tlb)
+{
+ tlb->need_flush = 0;
+
+ tlb->start = TASK_SIZE;
+ tlb->end = 0;
+
+ if (tlb->fullmm) {
+ tlb->start = 0;
+ tlb->end = TASK_SIZE;
+ }
+}
+
+/* tlb_gather_mmu
+ * Return a pointer to an initialized struct mmu_gather.
+ */
+static inline struct mmu_gather *
+tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+{
+ struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+
+ tlb->mm = mm;
+ tlb->fullmm = full_mm_flush;
+
+ init_tlb_gather(tlb);
+
+ return tlb;
+}
+
+extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+
+static inline void
+tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+ if (!tlb->need_flush)
+ return;
+
+ flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end);
+ init_tlb_gather(tlb);
+}
+
+/* tlb_finish_mmu
+ * Called at the end of the shootdown operation to free up any resources
+ * that were required.
+ */
+static inline void
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+ tlb_flush_mmu(tlb, start, end);
+
+ /* keep the page table cache within bounds */
+ check_pgt_cache();
+
+ put_cpu_var(mmu_gathers);
+}
+
+/* tlb_remove_page
+ * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)),
+ * while handling the additional races in SMP caused by other CPUs
+ * caching valid mappings in their TLBs.
+ */
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ tlb->need_flush = 1;
+ free_page_and_swap_cache(page);
+ return;
+}
+
+/**
+ * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation.
+ *
+ * Record the fact that pte's were really umapped in ->need_flush, so we can
+ * later optimise away the tlb invalidate. This helps when userspace is
+ * unmapping already-unmapped pages, which happens quite a lot.
+ */
+#define tlb_remove_tlb_entry(tlb, ptep, address) \
+ do { \
+ tlb->need_flush = 1; \
+ __tlb_remove_tlb_entry(tlb, ptep, address); \
+ } while (0)
+
+#define pte_free_tlb(tlb, ptep) __pte_free_tlb(tlb, ptep)
+
+#define pud_free_tlb(tlb, pudp) __pud_free_tlb(tlb, pudp)
+
+#define pmd_free_tlb(tlb, pmdp) __pmd_free_tlb(tlb, pmdp)
+
+#define tlb_migrate_finish(mm) do {} while (0)
#endif
diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h
index 077032d..b9a895d 100644
--- a/include/asm-um/uaccess.h
+++ b/include/asm-um/uaccess.h
@@ -6,7 +6,15 @@
#ifndef __UM_UACCESS_H
#define __UM_UACCESS_H
-#include "linux/sched.h"
+#include <asm/errno.h>
+#include <asm/processor.h>
+
+/* thread_info has a mm_segment_t in it, so put the definition up here */
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
+#include "linux/thread_info.h"
#define VERIFY_READ 0
#define VERIFY_WRITE 1
diff --git a/include/asm-v850/io.h b/include/asm-v850/io.h
index cc364fcb..cdad251 100644
--- a/include/asm-v850/io.h
+++ b/include/asm-v850/io.h
@@ -122,8 +122,6 @@
#endif
/* Conversion between virtual and physical mappings. */
-#define mm_ptov(addr) ((void *)__phys_to_virt (addr))
-#define mm_vtop(addr) ((unsigned long)__virt_to_phys (addr))
#define phys_to_virt(addr) ((void *)__phys_to_virt (addr))
#define virt_to_phys(addr) ((unsigned long)__virt_to_phys (addr))
diff --git a/include/asm-x86/asm.h b/include/asm-x86/asm.h
index 1a6980a..90dec0c 100644
--- a/include/asm-x86/asm.h
+++ b/include/asm-x86/asm.h
@@ -29,4 +29,11 @@
#endif /* CONFIG_X86_32 */
+/* Exception table entry */
+# define _ASM_EXTABLE(from,to) \
+ " .section __ex_table,\"a\"\n" \
+ _ASM_ALIGN "\n" \
+ _ASM_PTR #from "," #to "\n" \
+ " .previous\n"
+
#endif /* _ASM_X86_ASM_H */
diff --git a/include/asm-x86/bitops_64.h b/include/asm-x86/bitops_64.h
index 48adbf5..aaf1519 100644
--- a/include/asm-x86/bitops_64.h
+++ b/include/asm-x86/bitops_64.h
@@ -37,12 +37,6 @@
((off)+(__scanbit(~(((*(unsigned long *)addr)) >> (off)),(size)-(off)))) : \
find_next_zero_bit(addr,size,off)))
-/*
- * Find string of zero bits in a bitmap. -1 when not found.
- */
-extern unsigned long
-find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len);
-
static inline void set_bit_string(unsigned long *bitmap, unsigned long i,
int len)
{
@@ -53,16 +47,6 @@
}
}
-static inline void __clear_bit_string(unsigned long *bitmap, unsigned long i,
- int len)
-{
- unsigned long end = i + len;
- while (i < end) {
- __clear_bit(i, bitmap);
- i++;
- }
-}
-
/**
* ffz - find first zero in word.
* @word: The word to search
diff --git a/include/asm-x86/bugs.h b/include/asm-x86/bugs.h
index 3fcc30d..021cbdd 100644
--- a/include/asm-x86/bugs.h
+++ b/include/asm-x86/bugs.h
@@ -2,6 +2,6 @@
#define _ASM_X86_BUGS_H
extern void check_bugs(void);
-extern int ppro_with_ram_bug(void);
+int ppro_with_ram_bug(void);
#endif /* _ASM_X86_BUGS_H */
diff --git a/include/asm-x86/compat.h b/include/asm-x86/compat.h
index b270ee0..d3e8f3e 100644
--- a/include/asm-x86/compat.h
+++ b/include/asm-x86/compat.h
@@ -190,7 +190,7 @@
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
* as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
*/
typedef u32 compat_uptr_t;
diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h
index 3fb7dfa..065e929 100644
--- a/include/asm-x86/cpufeature.h
+++ b/include/asm-x86/cpufeature.h
@@ -4,9 +4,6 @@
#ifndef _ASM_X86_CPUFEATURE_H
#define _ASM_X86_CPUFEATURE_H
-#ifndef __ASSEMBLY__
-#include <linux/bitops.h>
-#endif
#include <asm/required-features.h>
#define NCAPINTS 8 /* N 32-bit words worth of info */
@@ -49,6 +46,7 @@
#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
#define X86_FEATURE_NX (1*32+20) /* Execute Disable */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_GBPAGES (1*32+26) /* GB pages */
#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
@@ -115,6 +113,13 @@
*/
#define X86_FEATURE_IDA (7*32+ 0) /* Intel Dynamic Acceleration */
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+
+#include <linux/bitops.h>
+
+extern const char * const x86_cap_flags[NCAPINTS*32];
+extern const char * const x86_power_flags[32];
+
#define cpu_has(c, bit) \
(__builtin_constant_p(bit) && \
( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \
@@ -175,6 +180,7 @@
#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH)
#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
+#define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES)
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
# define cpu_has_invlpg 1
@@ -204,4 +210,6 @@
#endif /* CONFIG_X86_64 */
+#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
+
#endif /* _ASM_X86_CPUFEATURE_H */
diff --git a/include/asm-x86/delay.h b/include/asm-x86/delay.h
index d11d47f..409a649 100644
--- a/include/asm-x86/delay.h
+++ b/include/asm-x86/delay.h
@@ -13,7 +13,7 @@
extern void __udelay(unsigned long usecs);
extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
extern void __delay(unsigned long loops);
/* 0x10c7 is 2**32 / 1000000 (rounded up) */
diff --git a/include/asm-x86/efi.h b/include/asm-x86/efi.h
index 9c68a1f..ea9734b 100644
--- a/include/asm-x86/efi.h
+++ b/include/asm-x86/efi.h
@@ -33,7 +33,7 @@
#define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
efi_call_virt(f, a1, a2, a3, a4, a5, a6)
-#define efi_ioremap(addr, size) ioremap(addr, size)
+#define efi_ioremap(addr, size) ioremap_cache(addr, size)
#else /* !CONFIG_X86_32 */
@@ -86,7 +86,7 @@
efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
(u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
-extern void *efi_ioremap(unsigned long offset, unsigned long size);
+extern void *efi_ioremap(unsigned long addr, unsigned long size);
#endif /* CONFIG_X86_32 */
diff --git a/include/asm-x86/futex.h b/include/asm-x86/futex.h
index 9d91926..cd9f894 100644
--- a/include/asm-x86/futex.h
+++ b/include/asm-x86/futex.h
@@ -17,11 +17,8 @@
"2: .section .fixup,\"ax\"\n \
3: mov %3, %1\n \
jmp 2b\n \
- .previous\n \
- .section __ex_table,\"a\"\n \
- .align 8\n" \
- _ASM_PTR "1b,3b\n \
- .previous" \
+ .previous\n" \
+ _ASM_EXTABLE(1b,3b) \
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
: "i" (-EFAULT), "0" (oparg), "1" (0))
@@ -35,11 +32,9 @@
3: .section .fixup,\"ax\"\n \
4: mov %5, %1\n \
jmp 3b\n \
- .previous\n \
- .section __ex_table,\"a\"\n \
- .align 8\n" \
- _ASM_PTR "1b,4b,2b,4b\n \
- .previous" \
+ .previous\n" \
+ _ASM_EXTABLE(1b,4b) \
+ _ASM_EXTABLE(2b,4b) \
: "=&a" (oldval), "=&r" (ret), "+m" (*uaddr), \
"=&r" (tem) \
: "r" (oparg), "i" (-EFAULT), "1" (0))
@@ -111,18 +106,12 @@
return -EFAULT;
__asm__ __volatile__(
-
"1: lock; cmpxchgl %3, %1 \n"
"2: .section .fixup, \"ax\" \n"
"3: mov %2, %0 \n"
" jmp 2b \n"
" .previous \n"
-
- " .section __ex_table, \"a\" \n"
- " .align 8 \n"
- _ASM_PTR " 1b,3b \n"
- " .previous \n"
-
+ _ASM_EXTABLE(1b,3b)
: "=a" (oldval), "+m" (*uaddr)
: "i" (-EFAULT), "r" (newval), "0" (oldval)
: "memory"
diff --git a/include/asm-x86/highmem.h b/include/asm-x86/highmem.h
index 13cdcd6..479767c 100644
--- a/include/asm-x86/highmem.h
+++ b/include/asm-x86/highmem.h
@@ -38,11 +38,6 @@
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
*/
-#ifdef CONFIG_X86_PAE
-#define LAST_PKMAP 512
-#else
-#define LAST_PKMAP 1024
-#endif
/*
* Ordering is:
*
@@ -58,13 +53,12 @@
* VMALLOC_START
* high_memory
*/
-#define PKMAP_BASE ( (FIXADDR_BOOT_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK )
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-extern void * FASTCALL(kmap_high(struct page *page));
-extern void FASTCALL(kunmap_high(struct page *page));
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
void *kmap(struct page *page);
void kunmap(struct page *page);
diff --git a/include/asm-x86/hw_irq_32.h b/include/asm-x86/hw_irq_32.h
index 6d65fbb..ea88054 100644
--- a/include/asm-x86/hw_irq_32.h
+++ b/include/asm-x86/hw_irq_32.h
@@ -47,7 +47,7 @@
int i8259A_irq_pending(unsigned int irq);
void make_8259A_irq(unsigned int irq);
void init_8259A(int aeoi);
-void FASTCALL(send_IPI_self(int vector));
+void send_IPI_self(int vector);
void init_VISWS_APIC_irqs(void);
void setup_IO_APIC(void);
void disable_IO_APIC(void);
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h
index ba8105c..6b1895c 100644
--- a/include/asm-x86/i387.h
+++ b/include/asm-x86/i387.h
@@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/regset.h>
+#include <asm/asm.h>
#include <asm/processor.h>
#include <asm/sigcontext.h>
#include <asm/user.h>
@@ -41,10 +42,7 @@
{
asm volatile("1: fwait\n"
"2:\n"
- " .section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,2b\n"
- " .previous\n");
+ _ASM_EXTABLE(1b,2b));
}
static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
@@ -57,10 +55,7 @@
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: [err] "=r" (err)
#if 0 /* See comment in __save_init_fpu() below. */
: [fx] "r" (fx), "m" (*fx), "0" (0));
@@ -99,10 +94,7 @@
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: [err] "=r" (err), "=m" (*fx)
#if 0 /* See comment in __fxsave_clear() below. */
: [fx] "r" (fx), "0" (0));
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index 586d7aa..58d2c45 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -275,29 +275,6 @@
#endif
-#ifdef CONFIG_X86_NUMAQ
-extern void *xquad_portio; /* Where the IO area was mapped */
-#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
-#define __BUILDIO(bwl,bw,type) \
-static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \
- if (xquad_portio) \
- write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \
- else \
- out##bwl##_local(value, port); \
-} \
-static inline void out##bwl(unsigned type value, int port) { \
- out##bwl##_quad(value, port, 0); \
-} \
-static inline unsigned type in##bwl##_quad(int port, int quad) { \
- if (xquad_portio) \
- return read##bwl(XQUAD_PORT_ADDR(port, quad)); \
- else \
- return in##bwl##_local(port); \
-} \
-static inline unsigned type in##bwl(int port) { \
- return in##bwl##_quad(port, 0); \
-}
-#else
#define __BUILDIO(bwl,bw,type) \
static inline void out##bwl(unsigned type value, int port) { \
out##bwl##_local(value, port); \
@@ -305,8 +282,6 @@
static inline unsigned type in##bwl(int port) { \
return in##bwl##_local(port); \
}
-#endif
-
#define BUILDIO(bwl,bw,type) \
static inline void out##bwl##_local(unsigned type value, int port) { \
diff --git a/include/asm-x86/mach-numaq/mach_apic.h b/include/asm-x86/mach-numaq/mach_apic.h
index 17e183b..3b637fa 100644
--- a/include/asm-x86/mach-numaq/mach_apic.h
+++ b/include/asm-x86/mach-numaq/mach_apic.h
@@ -109,6 +109,8 @@
return logical_apicid;
}
+extern void *xquad_portio;
+
static inline void setup_portio_remap(void)
{
int num_quads = num_online_nodes();
diff --git a/include/asm-x86/mach-voyager/do_timer.h b/include/asm-x86/mach-voyager/do_timer.h
index bc2b589..9e5a459f 100644
--- a/include/asm-x86/mach-voyager/do_timer.h
+++ b/include/asm-x86/mach-voyager/do_timer.h
@@ -6,7 +6,6 @@
/**
* do_timer_interrupt_hook - hook into timer tick
- * @regs: standard registers from interrupt
*
* Call the pit clock event handler. see asm/i8253.h
**/
diff --git a/include/asm-x86/msr.h b/include/asm-x86/msr.h
index 204a8a3..3ca29eb 100644
--- a/include/asm-x86/msr.h
+++ b/include/asm-x86/msr.h
@@ -57,10 +57,7 @@
".section .fixup,\"ax\"\n\t"
"3: mov %3,%0 ; jmp 1b\n\t"
".previous\n\t"
- ".section __ex_table,\"a\"\n"
- _ASM_ALIGN "\n\t"
- _ASM_PTR " 2b,3b\n\t"
- ".previous"
+ _ASM_EXTABLE(2b,3b)
: "=r" (*err), EAX_EDX_RET(val, low, high)
: "c" (msr), "i" (-EFAULT));
return EAX_EDX_VAL(val, low, high);
@@ -81,10 +78,7 @@
".section .fixup,\"ax\"\n\t"
"3: mov %4,%0 ; jmp 1b\n\t"
".previous\n\t"
- ".section __ex_table,\"a\"\n"
- _ASM_ALIGN "\n\t"
- _ASM_PTR " 2b,3b\n\t"
- ".previous"
+ _ASM_EXTABLE(2b,3b)
: "=a" (err)
: "c" (msr), "0" (low), "d" (high),
"i" (-EFAULT));
diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h
index c8b30ef..1cb7c51 100644
--- a/include/asm-x86/page.h
+++ b/include/asm-x86/page.h
@@ -13,8 +13,8 @@
#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK)
#define PTE_MASK (_AT(long, PHYSICAL_PAGE_MASK))
-#define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT)
-#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+#define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT)
+#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1))
#define HPAGE_SHIFT PMD_SHIFT
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
diff --git a/include/asm-x86/page_64.h b/include/asm-x86/page_64.h
index c1ac42d..dcf0c07 100644
--- a/include/asm-x86/page_64.h
+++ b/include/asm-x86/page_64.h
@@ -23,6 +23,9 @@
#define MCE_STACK 5
#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
+#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
+#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
+
#define __PAGE_OFFSET _AC(0xffff810000000000, UL)
#define __PHYSICAL_START CONFIG_PHYSICAL_START
diff --git a/include/asm-x86/pgalloc_32.h b/include/asm-x86/pgalloc_32.h
index 7641e7b..bab1271 100644
--- a/include/asm-x86/pgalloc_32.h
+++ b/include/asm-x86/pgalloc_32.h
@@ -36,17 +36,17 @@
* Allocate and free page tables.
*/
extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
free_page((unsigned long)pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
@@ -63,7 +63,7 @@
return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
}
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
free_page((unsigned long)pmd);
@@ -80,8 +80,10 @@
set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
/*
- * Pentium-II erratum A13: in PAE mode we explicitly have to flush
- * the TLB via cr3 if the top-level pgd is changed...
+ * According to Intel App note "TLBs, Paging-Structure Caches,
+ * and Their Invalidation", April 2007, document 317080-001,
+ * section 8.1: in PAE mode we explicitly have to flush the
+ * TLB via cr3 if the top-level pgd is changed...
*/
if (mm == current->active_mm)
write_cr3(read_cr3());
diff --git a/include/asm-x86/pgalloc_64.h b/include/asm-x86/pgalloc_64.h
index 8bb5646..4f6220d 100644
--- a/include/asm-x86/pgalloc_64.h
+++ b/include/asm-x86/pgalloc_64.h
@@ -17,7 +17,7 @@
set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
}
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
free_page((unsigned long)pmd);
@@ -33,7 +33,7 @@
return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
}
-static inline void pud_free (pud_t *pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
free_page((unsigned long)pud);
@@ -42,19 +42,21 @@
static inline void pgd_list_add(pgd_t *pgd)
{
struct page *page = virt_to_page(pgd);
+ unsigned long flags;
- spin_lock(&pgd_lock);
+ spin_lock_irqsave(&pgd_lock, flags);
list_add(&page->lru, &pgd_list);
- spin_unlock(&pgd_lock);
+ spin_unlock_irqrestore(&pgd_lock, flags);
}
static inline void pgd_list_del(pgd_t *pgd)
{
struct page *page = virt_to_page(pgd);
+ unsigned long flags;
- spin_lock(&pgd_lock);
+ spin_lock_irqsave(&pgd_lock, flags);
list_del(&page->lru);
- spin_unlock(&pgd_lock);
+ spin_unlock_irqrestore(&pgd_lock, flags);
}
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
@@ -77,7 +79,7 @@
return pgd;
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
pgd_list_del(pgd);
@@ -100,13 +102,13 @@
/* Should really implement gc for free page table pages. This could be
done with a reference count in struct page. */
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
free_page((unsigned long)pte);
}
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
{
__free_page(pte);
}
diff --git a/include/asm-x86/pgtable-3level.h b/include/asm-x86/pgtable-3level.h
index a195c3e..1d763ee 100644
--- a/include/asm-x86/pgtable-3level.h
+++ b/include/asm-x86/pgtable-3level.h
@@ -93,26 +93,22 @@
static inline void pud_clear(pud_t *pudp)
{
+ unsigned long pgd;
+
set_pud(pudp, __pud(0));
/*
- * In principle we need to do a cr3 reload here to make sure
- * the processor recognizes the changed pgd. In practice, all
- * the places where pud_clear() gets called are followed by
- * full tlb flushes anyway, so we can defer the cost here.
+ * According to Intel App note "TLBs, Paging-Structure Caches,
+ * and Their Invalidation", April 2007, document 317080-001,
+ * section 8.1: in PAE mode we explicitly have to flush the
+ * TLB via cr3 if the top-level pgd is changed...
*
- * Specifically:
- *
- * mm/memory.c:free_pmd_range() - immediately after the
- * pud_clear() it does a pmd_free_tlb(). We change the
- * mmu_gather structure to do a full tlb flush (which has the
- * effect of reloading cr3) when the pagetable free is
- * complete.
- *
- * arch/x86/mm/hugetlbpage.c:huge_pmd_unshare() - the call to
- * this is followed by a flush_tlb_range, which on x86 does a
- * full tlb flush.
+ * Make sure the pud entry we're updating is within the
+ * current pgd to avoid unnecessary TLB flushes.
*/
+ pgd = read_cr3();
+ if (__pa(pudp) >= pgd && __pa(pudp) < (pgd + sizeof(pgd_t)*PTRS_PER_PGD))
+ write_cr3(pgd);
}
#define pud_page(pud) \
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h
index cd2524f..44c0a4f 100644
--- a/include/asm-x86/pgtable.h
+++ b/include/asm-x86/pgtable.h
@@ -13,10 +13,12 @@
#define _PAGE_BIT_DIRTY 6
#define _PAGE_BIT_FILE 6
#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */
+#define _PAGE_BIT_PAT 7 /* on 4KB pages */
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
#define _PAGE_BIT_UNUSED2 10
#define _PAGE_BIT_UNUSED3 11
+#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
/*
@@ -36,6 +38,8 @@
#define _PAGE_UNUSED1 (_AC(1, L)<<_PAGE_BIT_UNUSED1)
#define _PAGE_UNUSED2 (_AC(1, L)<<_PAGE_BIT_UNUSED2)
#define _PAGE_UNUSED3 (_AC(1, L)<<_PAGE_BIT_UNUSED3)
+#define _PAGE_PAT (_AC(1, L)<<_PAGE_BIT_PAT)
+#define _PAGE_PAT_LARGE (_AC(1, L)<<_PAGE_BIT_PAT_LARGE)
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
#define _PAGE_NX (_AC(1, ULL) << _PAGE_BIT_NX)
diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h
index 21e70fb..80dd438 100644
--- a/include/asm-x86/pgtable_32.h
+++ b/include/asm-x86/pgtable_32.h
@@ -66,6 +66,14 @@
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long) high_memory + \
2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))
+#ifdef CONFIG_X86_PAE
+#define LAST_PKMAP 512
+#else
+#define LAST_PKMAP 1024
+#endif
+
+#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
+
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
#else
@@ -148,6 +156,8 @@
*/
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+static inline int pud_large(pud_t pud) { return 0; }
+
/*
* the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
*
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index 6e615a1..bd4740a 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -21,7 +21,6 @@
#define swapper_pg_dir init_level4_pgt
extern void paging_init(void);
-extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
#endif /* !__ASSEMBLY__ */
@@ -199,6 +198,12 @@
#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address))
#define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
+static inline int pud_large(pud_t pte)
+{
+ return (pud_val(pte) & (_PAGE_PSE|_PAGE_PRESENT)) ==
+ (_PAGE_PSE|_PAGE_PRESENT);
+}
+
/* PMD - Level 2 access */
#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
diff --git a/include/asm-x86/string_32.h b/include/asm-x86/string_32.h
index 55bfa30..c5d13a8 100644
--- a/include/asm-x86/string_32.h
+++ b/include/asm-x86/string_32.h
@@ -213,14 +213,14 @@
case 0:
return s;
case 1:
- *(unsigned char *)s = pattern;
+ *(unsigned char *)s = pattern & 0xff;
return s;
case 2:
- *(unsigned short *)s = pattern;
+ *(unsigned short *)s = pattern & 0xffff;
return s;
case 3:
- *(unsigned short *)s = pattern;
- *(2+(unsigned char *)s) = pattern;
+ *(unsigned short *)s = pattern & 0xffff;
+ *(2+(unsigned char *)s) = pattern & 0xff;
return s;
case 4:
*(unsigned long *)s = pattern;
diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h
index ee32ef9..9cff02f 100644
--- a/include/asm-x86/system.h
+++ b/include/asm-x86/system.h
@@ -20,8 +20,8 @@
#ifdef CONFIG_X86_32
struct task_struct; /* one of the stranger aspects of C forward declarations */
-extern struct task_struct *FASTCALL(__switch_to(struct task_struct *prev,
- struct task_struct *next));
+struct task_struct *__switch_to(struct task_struct *prev,
+ struct task_struct *next);
/*
* Saving eflags is important. It switches not only IOPL between tasks,
@@ -130,10 +130,7 @@
"movl %k1, %%" #seg "\n\t" \
"jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n\t" \
- _ASM_ALIGN "\n\t" \
- _ASM_PTR " 1b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(1b,3b) \
: :"r" (value), "r" (0))
@@ -214,12 +211,10 @@
/* This could fault if %cr4 does not exist. In x86_64, a cr4 always
* exists, so it will never fail. */
#ifdef CONFIG_X86_32
- asm volatile("1: mov %%cr4, %0 \n"
- "2: \n"
- ".section __ex_table,\"a\" \n"
- ".long 1b,2b \n"
- ".previous \n"
- : "=r" (val), "=m" (__force_order) : "0" (0));
+ asm volatile("1: mov %%cr4, %0\n"
+ "2:\n"
+ _ASM_EXTABLE(1b,2b)
+ : "=r" (val), "=m" (__force_order) : "0" (0));
#else
val = native_read_cr4();
#endif
@@ -276,9 +271,9 @@
#endif /* __KERNEL__ */
-static inline void clflush(void *__p)
+static inline void clflush(volatile void *__p)
{
- asm volatile("clflush %0" : "+m" (*(char __force *)__p));
+ asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
}
#define nop() __asm__ __volatile__ ("nop")
diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h
index 27cfd6c..43e5a78 100644
--- a/include/asm-x86/timex.h
+++ b/include/asm-x86/timex.h
@@ -14,7 +14,6 @@
#endif
#define CLOCK_TICK_RATE PIT_TICK_RATE
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER 1
+#define ARCH_HAS_READ_CURRENT_TIMER
#endif
diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h
index d2a4f7b..fcc570e 100644
--- a/include/asm-x86/uaccess_32.h
+++ b/include/asm-x86/uaccess_32.h
@@ -8,6 +8,7 @@
#include <linux/thread_info.h>
#include <linux/prefetch.h>
#include <linux/string.h>
+#include <asm/asm.h>
#include <asm/page.h>
#define VERIFY_READ 0
@@ -287,11 +288,8 @@
"4: movl %3,%0\n" \
" jmp 3b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,4b\n" \
- " .long 2b,4b\n" \
- ".previous" \
+ _ASM_EXTABLE(1b,4b) \
+ _ASM_EXTABLE(2b,4b) \
: "=r"(err) \
: "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
@@ -338,10 +336,7 @@
"3: movl %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(1b,3b) \
: "=r"(err) \
: ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
@@ -378,10 +373,7 @@
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(1b,3b) \
: "=r"(err), ltype (x) \
: "m"(__m(addr)), "i"(errret), "0"(err))
diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h
index 31d7947..b87eb4b 100644
--- a/include/asm-x86/uaccess_64.h
+++ b/include/asm-x86/uaccess_64.h
@@ -181,10 +181,7 @@
"3: mov %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 1b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(1b,3b) \
: "=r"(err) \
: ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
@@ -226,10 +223,7 @@
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 1b,3b\n" \
- ".previous" \
+ _ASM_EXTABLE(1b,3b) \
: "=r"(err), ltype (x) \
: "m"(__m(addr)), "i"(errno), "0"(err))
diff --git a/include/asm-x86/unistd_32.h b/include/asm-x86/unistd_32.h
index 8d8f9b5..984123a 100644
--- a/include/asm-x86/unistd_32.h
+++ b/include/asm-x86/unistd_32.h
@@ -327,9 +327,11 @@
#define __NR_epoll_pwait 319
#define __NR_utimensat 320
#define __NR_signalfd 321
-#define __NR_timerfd 322
+#define __NR_timerfd_create 322
#define __NR_eventfd 323
#define __NR_fallocate 324
+#define __NR_timerfd_settime 325
+#define __NR_timerfd_gettime 326
#ifdef __KERNEL__
diff --git a/include/asm-x86/unistd_64.h b/include/asm-x86/unistd_64.h
index 5ff4d3e..3883ceb 100644
--- a/include/asm-x86/unistd_64.h
+++ b/include/asm-x86/unistd_64.h
@@ -629,12 +629,17 @@
__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
#define __NR_signalfd 282
__SYSCALL(__NR_signalfd, sys_signalfd)
-#define __NR_timerfd 283
-__SYSCALL(__NR_timerfd, sys_timerfd)
+#define __NR_timerfd_create 283
+__SYSCALL(__NR_timerfd_create, sys_timerfd_create)
#define __NR_eventfd 284
__SYSCALL(__NR_eventfd, sys_eventfd)
#define __NR_fallocate 285
__SYSCALL(__NR_fallocate, sys_fallocate)
+#define __NR_timerfd_settime 286
+__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+#define __NR_timerfd_gettime 287
+__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-x86/vm86.h b/include/asm-x86/vm86.h
index a5edf51..c92fe4a 100644
--- a/include/asm-x86/vm86.h
+++ b/include/asm-x86/vm86.h
@@ -195,6 +195,7 @@
void handle_vm86_fault(struct kernel_vm86_regs *, long);
int handle_vm86_trap(struct kernel_vm86_regs *, long, int);
+struct pt_regs *save_v86_state(struct kernel_vm86_regs *);
struct task_struct;
void release_vm86_irqs(struct task_struct *);
diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h
index 3e5b565..1d51ba5 100644
--- a/include/asm-xtensa/pgalloc.h
+++ b/include/asm-xtensa/pgalloc.h
@@ -31,7 +31,7 @@
return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER);
}
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
@@ -52,12 +52,12 @@
return virt_to_page(pte_alloc_one_kernel(mm, addr));
}
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
{
kmem_cache_free(pgtable_cache, pte);
}
-static inline void pte_free(struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
{
kmem_cache_free(pgtable_cache, page_address(page));
}
diff --git a/include/asm-xtensa/tlb.h b/include/asm-xtensa/tlb.h
index 4830232..31c220f 100644
--- a/include/asm-xtensa/tlb.h
+++ b/include/asm-xtensa/tlb.h
@@ -42,6 +42,6 @@
#include <asm-generic/tlb.h>
-#define __pte_free_tlb(tlb,pte) pte_free(pte)
+#define __pte_free_tlb(tlb, pte) pte_free((tlb)->mm, pte)
#endif /* _XTENSA_TLB_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 85b2482..9363122 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -143,6 +143,7 @@
header-y += sockios.h
header-y += som.h
header-y += sound.h
+header-y += suspend_ioctls.h
header-y += taskstats.h
header-y += telephony.h
header-y += termios.h
@@ -218,6 +219,7 @@
unifdef-y += icmp.h
unifdef-y += icmpv6.h
unifdef-y += if_addr.h
+unifdef-y += if_addrlabel.h
unifdef-y += if_arp.h
unifdef-y += if_bridge.h
unifdef-y += if_ec.h
diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
index 22eb936..0260c3e 100644
--- a/include/linux/ac97_codec.h
+++ b/include/linux/ac97_codec.h
@@ -326,11 +326,7 @@
#define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */
};
-extern int ac97_read_proc (char *page_out, char **start, off_t off,
- int count, int *eof, void *data);
extern int ac97_probe_codec(struct ac97_codec *);
-extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
-extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
extern struct ac97_codec *ac97_alloc_codec(void);
extern void ac97_release_codec(struct ac97_codec *codec);
@@ -363,7 +359,4 @@
int type; /* quirk type above */
};
-struct pci_dev;
-extern int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override);
-
#endif /* _AC97_CODEC_H_ */
diff --git a/include/linux/acct.h b/include/linux/acct.h
index 302eb72..e8cae54 100644
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -173,7 +173,11 @@
static inline u32 jiffies_to_AHZ(unsigned long x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / AHZ)) == 0
+# if HZ < AHZ
+ return x * (AHZ / HZ);
+# else
return x / (HZ / AHZ);
+# endif
#else
u64 tmp = (u64)x * TICK_NSEC;
do_div(tmp, (NSEC_PER_SEC / AHZ));
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 63f2e6e..cf13bec 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -80,7 +80,6 @@
typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
-unsigned long acpi_find_rsdp (void);
int acpi_boot_init (void);
int acpi_boot_table_init (void);
int acpi_numa_init (void);
@@ -115,7 +114,9 @@
int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
+void acpi_irq_stats_init(void);
+extern u32 acpi_irq_handled;
extern int acpi_mp_config;
extern struct acpi_mcfg_allocation *pci_mmcfg_config;
diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h
index abc521c..03e3454 100644
--- a/include/linux/agp_backend.h
+++ b/include/linux/agp_backend.h
@@ -109,6 +109,7 @@
extern void agp_enable(struct agp_bridge_data *, u32);
extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *);
extern void agp_backend_release(struct agp_bridge_data *);
+extern void agp_flush_chipset(struct agp_bridge_data *);
#endif /* __KERNEL__ */
#endif /* _AGP_BACKEND_H */
diff --git a/include/linux/agpgart.h b/include/linux/agpgart.h
index 09fbf7e..62aef58 100644
--- a/include/linux/agpgart.h
+++ b/include/linux/agpgart.h
@@ -38,6 +38,7 @@
#define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int)
#define AGPIOC_BIND _IOW (AGPIOC_BASE, 8, struct agp_bind*)
#define AGPIOC_UNBIND _IOW (AGPIOC_BASE, 9, struct agp_unbind*)
+#define AGPIOC_CHIPSET_FLUSH _IO (AGPIOC_BASE, 10)
#define AGP_DEVICE "/dev/agpgart"
diff --git a/include/linux/async_tx.h b/include/linux/async_tx.h
index bdca3f1..eb640f0 100644
--- a/include/linux/async_tx.h
+++ b/include/linux/async_tx.h
@@ -47,7 +47,6 @@
* address is an implied source, whereas the asynchronous case it must be listed
* as a source. The destination address must be the first address in the source
* array.
- * @ASYNC_TX_ASSUME_COHERENT: skip cache maintenance operations
* @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
* dependency chain
* @ASYNC_TX_DEP_ACK: ack the dependency descriptor. Useful for chaining.
@@ -55,7 +54,6 @@
enum async_tx_flags {
ASYNC_TX_XOR_ZERO_DST = (1 << 0),
ASYNC_TX_XOR_DROP_DST = (1 << 1),
- ASYNC_TX_ASSUME_COHERENT = (1 << 2),
ASYNC_TX_ACK = (1 << 3),
ASYNC_TX_DEP_ACK = (1 << 4),
};
@@ -64,9 +62,15 @@
void async_tx_issue_pending_all(void);
enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx);
+#ifdef CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+#include <asm/async_tx.h>
+#else
+#define async_tx_find_channel(dep, type, dst, dst_count, src, src_count, len) \
+ __async_tx_find_channel(dep, type)
struct dma_chan *
-async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
enum dma_transaction_type tx_type);
+#endif /* CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL */
#else
static inline void async_tx_issue_pending_all(void)
{
@@ -88,7 +92,8 @@
static inline struct dma_chan *
async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
- enum dma_transaction_type tx_type)
+ enum dma_transaction_type tx_type, struct page **dst, int dst_count,
+ struct page **src, int src_count, size_t len)
{
return NULL;
}
diff --git a/include/linux/pata_platform.h b/include/linux/ata_platform.h
similarity index 75%
rename from include/linux/pata_platform.h
rename to include/linux/ata_platform.h
index 6a7a92d..b856a2a 100644
--- a/include/linux/pata_platform.h
+++ b/include/linux/ata_platform.h
@@ -1,5 +1,5 @@
-#ifndef __LINUX_PATA_PLATFORM_H
-#define __LINUX_PATA_PLATFORM_H
+#ifndef __LINUX_ATA_PLATFORM_H
+#define __LINUX_ATA_PLATFORM_H
struct pata_platform_info {
/*
@@ -24,4 +24,11 @@
extern int __devexit __pata_platform_remove(struct device *dev);
-#endif /* __LINUX_PATA_PLATFORM_H */
+/*
+ * Marvell SATA private data
+ */
+struct mv_sata_platform_data {
+ int n_ports; /* number of sata ports */
+};
+
+#endif /* __LINUX_ATA_PLATFORM_H */
diff --git a/drivers/serial/atmel_serial.h b/include/linux/atmel_serial.h
similarity index 98%
rename from drivers/serial/atmel_serial.h
rename to include/linux/atmel_serial.h
index e014177..fd68337 100644
--- a/drivers/serial/atmel_serial.h
+++ b/include/linux/atmel_serial.h
@@ -1,5 +1,5 @@
/*
- * drivers/serial/atmel_serial.h
+ * include/linux/atmel_serial.h
*
* Copyright (C) 2005 Ivan Kokshaysky
* Copyright (C) SAN People
diff --git a/include/linux/capability.h b/include/linux/capability.h
index bb017ed..7d50ff6 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -14,7 +14,6 @@
#define _LINUX_CAPABILITY_H
#include <linux/types.h>
-#include <linux/compiler.h>
struct task_struct;
@@ -23,13 +22,20 @@
kernel might be somewhat backwards compatible, but don't bet on
it. */
-/* XXX - Note, cap_t, is defined by POSIX to be an "opaque" pointer to
+/* Note, cap_t, is defined by POSIX (draft) to be an "opaque" pointer to
a set of three capability sets. The transposition of 3*the
following structure to such a composite is better handled in a user
library since the draft standard requires the use of malloc/free
etc.. */
-#define _LINUX_CAPABILITY_VERSION 0x19980330
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define _LINUX_CAPABILITY_U32S_1 1
+
+#define _LINUX_CAPABILITY_VERSION_2 0x20071026
+#define _LINUX_CAPABILITY_U32S_2 2
+
+#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2
+#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2
typedef struct __user_cap_header_struct {
__u32 version;
@@ -42,41 +48,42 @@
__u32 inheritable;
} __user *cap_user_data_t;
+
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
-#define XATTR_CAPS_SZ (3*sizeof(__le32))
#define VFS_CAP_REVISION_MASK 0xFF000000
-#define VFS_CAP_REVISION_1 0x01000000
-
-#define VFS_CAP_REVISION VFS_CAP_REVISION_1
-
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
+#define VFS_CAP_REVISION_1 0x01000000
+#define VFS_CAP_U32_1 1
+#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
+
+#define VFS_CAP_REVISION_2 0x02000000
+#define VFS_CAP_U32_2 2
+#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
+
+#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
+#define VFS_CAP_U32 VFS_CAP_U32_2
+#define VFS_CAP_REVISION VFS_CAP_REVISION_2
+
+
struct vfs_cap_data {
- __u32 magic_etc; /* Little endian */
- __u32 permitted; /* Little endian */
- __u32 inheritable; /* Little endian */
+ __le32 magic_etc; /* Little endian */
+ struct {
+ __le32 permitted; /* Little endian */
+ __le32 inheritable; /* Little endian */
+ } data[VFS_CAP_U32];
};
#ifdef __KERNEL__
-/* #define STRICT_CAP_T_TYPECHECKS */
-
-#ifdef STRICT_CAP_T_TYPECHECKS
-
typedef struct kernel_cap_struct {
- __u32 cap;
+ __u32 cap[_LINUX_CAPABILITY_U32S];
} kernel_cap_t;
-#else
-
-typedef __u32 kernel_cap_t;
-
-#endif
-
-#define _USER_CAP_HEADER_SIZE (2*sizeof(__u32))
+#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
#endif
@@ -119,10 +126,6 @@
#define CAP_FSETID 4
-/* Used to decide between falling back on the old suser() or fsuser(). */
-
-#define CAP_FS_MASK 0x1f
-
/* Overrides the restriction that the real or effective user ID of a
process sending a signal must match the real or effective user ID
of the process receiving the signal. */
@@ -145,8 +148,14 @@
** Linux-specific capabilities
**/
-/* Transfer any capability in your permitted set to any pid,
- remove any capability in your permitted set from any pid */
+/* Without VFS support for capabilities:
+ * Transfer any capability in your permitted set to any pid,
+ * remove any capability in your permitted set from any pid
+ * With VFS support for capabilities (neither of above, but)
+ * Add any capability from current's capability bounding set
+ * to the current process' inheritable set
+ * Allow taking bits out of capability bounding set
+ */
#define CAP_SETPCAP 8
@@ -195,7 +204,6 @@
#define CAP_IPC_OWNER 15
/* Insert and remove kernel modules - modify kernel without limit */
-/* Modify cap_bset */
#define CAP_SYS_MODULE 16
/* Allow ioperm/iopl access */
@@ -307,74 +315,183 @@
#define CAP_SETFCAP 31
+/* Override MAC access.
+ The base kernel enforces no MAC policy.
+ An LSM may enforce a MAC policy, and if it does and it chooses
+ to implement capability based overrides of that policy, this is
+ the capability it should use to do so. */
+
+#define CAP_MAC_OVERRIDE 32
+
+/* Allow MAC configuration or state changes.
+ The base kernel requires no MAC configuration.
+ An LSM may enforce a MAC policy, and if it does and it chooses
+ to implement capability based checks on modifications to that
+ policy or the data required to maintain it, this is the
+ capability it should use to do so. */
+
+#define CAP_MAC_ADMIN 33
+
+#define CAP_LAST_CAP CAP_MAC_ADMIN
+
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+
+/*
+ * Bit location of each capability (used by user-space library and kernel)
+ */
+
+#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */
+#define CAP_TO_MASK(x) (1 << ((x) & 31)) /* mask for indexed __u32 */
+
#ifdef __KERNEL__
/*
* Internal kernel functions only
*/
-#ifdef STRICT_CAP_T_TYPECHECKS
+#define CAP_FOR_EACH_U32(__capi) \
+ for (__capi = 0; __capi < _LINUX_CAPABILITY_U32S; ++__capi)
-#define to_cap_t(x) { x }
-#define cap_t(x) (x).cap
+# define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
+ | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
+ | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
+ | CAP_TO_MASK(CAP_FOWNER) \
+ | CAP_TO_MASK(CAP_FSETID))
-#else
+# define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
-#define to_cap_t(x) (x)
-#define cap_t(x) (x)
+#if _LINUX_CAPABILITY_U32S != 2
+# error Fix up hand-coded capability macro initializers
+#else /* HAND-CODED capability initializers */
-#endif
+# define CAP_EMPTY_SET {{ 0, 0 }}
+# define CAP_FULL_SET {{ ~0, ~0 }}
+# define CAP_INIT_EFF_SET {{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }}
+# define CAP_FS_SET {{ CAP_FS_MASK_B0, CAP_FS_MASK_B1 } }
+# define CAP_NFSD_SET {{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), \
+ CAP_FS_MASK_B1 } }
-#define CAP_EMPTY_SET to_cap_t(0)
-#define CAP_FULL_SET to_cap_t(~0)
-#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
-#define CAP_INIT_INH_SET to_cap_t(0)
+#endif /* _LINUX_CAPABILITY_U32S != 2 */
-#define CAP_TO_MASK(x) (1 << (x))
-#define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag))
-#define cap_lower(c, flag) (cap_t(c) &= ~CAP_TO_MASK(flag))
-#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag))
+#define CAP_INIT_INH_SET CAP_EMPTY_SET
-static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
+# define cap_clear(c) do { (c) = __cap_empty_set; } while (0)
+# define cap_set_full(c) do { (c) = __cap_full_set; } while (0)
+# define cap_set_init_eff(c) do { (c) = __cap_init_eff_set; } while (0)
+
+#define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
+#define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
+#define cap_raised(c, flag) ((c).cap[CAP_TO_INDEX(flag)] & CAP_TO_MASK(flag))
+
+#define CAP_BOP_ALL(c, a, b, OP) \
+do { \
+ unsigned __capi; \
+ CAP_FOR_EACH_U32(__capi) { \
+ c.cap[__capi] = a.cap[__capi] OP b.cap[__capi]; \
+ } \
+} while (0)
+
+#define CAP_UOP_ALL(c, a, OP) \
+do { \
+ unsigned __capi; \
+ CAP_FOR_EACH_U32(__capi) { \
+ c.cap[__capi] = OP a.cap[__capi]; \
+ } \
+} while (0)
+
+static inline kernel_cap_t cap_combine(const kernel_cap_t a,
+ const kernel_cap_t b)
{
- kernel_cap_t dest;
- cap_t(dest) = cap_t(a) | cap_t(b);
- return dest;
+ kernel_cap_t dest;
+ CAP_BOP_ALL(dest, a, b, |);
+ return dest;
}
-static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b)
+static inline kernel_cap_t cap_intersect(const kernel_cap_t a,
+ const kernel_cap_t b)
{
- kernel_cap_t dest;
- cap_t(dest) = cap_t(a) & cap_t(b);
- return dest;
+ kernel_cap_t dest;
+ CAP_BOP_ALL(dest, a, b, &);
+ return dest;
}
-static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop)
+static inline kernel_cap_t cap_drop(const kernel_cap_t a,
+ const kernel_cap_t drop)
{
- kernel_cap_t dest;
- cap_t(dest) = cap_t(a) & ~cap_t(drop);
- return dest;
+ kernel_cap_t dest;
+ CAP_BOP_ALL(dest, a, drop, &~);
+ return dest;
}
-static inline kernel_cap_t cap_invert(kernel_cap_t c)
+static inline kernel_cap_t cap_invert(const kernel_cap_t c)
{
- kernel_cap_t dest;
- cap_t(dest) = ~cap_t(c);
- return dest;
+ kernel_cap_t dest;
+ CAP_UOP_ALL(dest, c, ~);
+ return dest;
}
-#define cap_isclear(c) (!cap_t(c))
-#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set)))
+static inline int cap_isclear(const kernel_cap_t a)
+{
+ unsigned __capi;
+ CAP_FOR_EACH_U32(__capi) {
+ if (a.cap[__capi] != 0)
+ return 0;
+ }
+ return 1;
+}
-#define cap_clear(c) do { cap_t(c) = 0; } while(0)
-#define cap_set_full(c) do { cap_t(c) = ~0; } while(0)
-#define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0)
+static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
+{
+ kernel_cap_t dest;
+ dest = cap_drop(a, set);
+ return cap_isclear(dest);
+}
-#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK)
+/* Used to decide between falling back on the old suser() or fsuser(). */
+
+static inline int cap_is_fs_cap(int cap)
+{
+ const kernel_cap_t __cap_fs_set = CAP_FS_SET;
+ return !!(CAP_TO_MASK(cap) & __cap_fs_set.cap[CAP_TO_INDEX(cap)]);
+}
+
+static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a)
+{
+ const kernel_cap_t __cap_fs_set = CAP_FS_SET;
+ return cap_drop(a, __cap_fs_set);
+}
+
+static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a,
+ const kernel_cap_t permitted)
+{
+ const kernel_cap_t __cap_fs_set = CAP_FS_SET;
+ return cap_combine(a,
+ cap_intersect(permitted, __cap_fs_set));
+}
+
+static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a)
+{
+ const kernel_cap_t __cap_fs_set = CAP_NFSD_SET;
+ return cap_drop(a, __cap_fs_set);
+}
+
+static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a,
+ const kernel_cap_t permitted)
+{
+ const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET;
+ return cap_combine(a,
+ cap_intersect(permitted, __cap_nfsd_set));
+}
+
+extern const kernel_cap_t __cap_empty_set;
+extern const kernel_cap_t __cap_full_set;
+extern const kernel_cap_t __cap_init_eff_set;
int capable(int cap);
int __capable(struct task_struct *t, int cap);
+extern long cap_prctl_drop(unsigned long cap);
+
#endif /* __KERNEL__ */
#endif /* !_LINUX_CAPABILITY_H */
diff --git a/include/linux/chio.h b/include/linux/chio.h
index a404c11..519248d 100644
--- a/include/linux/chio.h
+++ b/include/linux/chio.h
@@ -108,7 +108,7 @@
/*
* CHIOGELEM
- * get more detailed status informtion for a single element
+ * get more detailed status information for a single element
*/
struct changer_get_element {
int cge_type; /* type/unit */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index d38655f..a671dbf 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -257,16 +257,8 @@
/*
* epoll (fs/eventpoll.c) compat bits follow ...
*/
-#ifndef CONFIG_HAS_COMPAT_EPOLL_EVENT
struct epoll_event;
#define compat_epoll_event epoll_event
-#else
-asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
- struct compat_epoll_event __user *event);
-asmlinkage long compat_sys_epoll_wait(int epfd,
- struct compat_epoll_event __user *events,
- int maxevents, int timeout);
-#endif
asmlinkage long compat_sys_epoll_pwait(int epfd,
struct compat_epoll_event __user *events,
int maxevents, int timeout,
@@ -279,8 +271,11 @@
asmlinkage long compat_sys_signalfd(int ufd,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
-asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
- const struct compat_itimerspec __user *utmr);
+asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
+ const struct compat_itimerspec __user *utmr,
+ struct compat_itimerspec __user *otmr);
+asmlinkage long compat_sys_timerfd_gettime(int ufd,
+ struct compat_itimerspec __user *otmr);
#endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index c4e0016..c8eb8c7 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -46,9 +46,10 @@
/* Idle State Flags */
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */
-#define CPUIDLE_FLAG_SHALLOW (0x10) /* low latency, minimal savings */
-#define CPUIDLE_FLAG_BALANCED (0x20) /* medium latency, moderate savings */
-#define CPUIDLE_FLAG_DEEP (0x40) /* high latency, large savings */
+#define CPUIDLE_FLAG_POLL (0x10) /* no latency, no savings */
+#define CPUIDLE_FLAG_SHALLOW (0x20) /* low latency, minimal savings */
+#define CPUIDLE_FLAG_BALANCED (0x40) /* medium latency, moderate savings */
+#define CPUIDLE_FLAG_DEEP (0x80) /* high latency, large savings */
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
@@ -72,6 +73,19 @@
state->driver_data = data;
}
+#ifdef CONFIG_SMP
+#ifdef CONFIG_ARCH_HAS_CPU_IDLE_WAIT
+static inline void cpuidle_kick_cpus(void)
+{
+ cpu_idle_wait();
+}
+#else /* !CONFIG_ARCH_HAS_CPU_IDLE_WAIT */
+#error "Arch needs cpu_idle_wait() equivalent here"
+#endif /* !CONFIG_ARCH_HAS_CPU_IDLE_WAIT */
+#else /* !CONFIG_SMP */
+static inline void cpuidle_kick_cpus(void) {}
+#endif /* !CONFIG_SMP */
+
struct cpuidle_state_kobj {
struct cpuidle_state *state;
struct completion kobj_unregister;
@@ -79,7 +93,7 @@
};
struct cpuidle_device {
- int enabled:1;
+ unsigned int enabled:1;
unsigned int cpu;
int last_residency;
@@ -178,4 +192,10 @@
#endif
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+#define CPUIDLE_DRIVER_STATE_START 1
+#else
+#define CPUIDLE_DRIVER_STATE_START 0
+#endif
+
#endif /* _LINUX_CPUIDLE_H */
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h
index 8f3dcd3..504cb2c 100644
--- a/include/linux/cyclades.h
+++ b/include/linux/cyclades.h
@@ -177,7 +177,7 @@
__u32 fpga_version; /* FPGA Version Number Register */
__u32 cpu_start; /* CPU start Register (write) */
__u32 cpu_stop; /* CPU stop Register (write) */
- __u32 misc_reg; /* Miscelaneous Register */
+ __u32 misc_reg; /* Miscellaneous Register */
__u32 idt_mode; /* IDT mode Register */
__u32 uart_irq_status; /* UART IRQ status Register */
__u32 clear_timer0_irq; /* Clear timer interrupt Register */
diff --git a/include/linux/cycx_x25.h b/include/linux/cycx_x25.h
index f7a9065..362bf19 100644
--- a/include/linux/cycx_x25.h
+++ b/include/linux/cycx_x25.h
@@ -81,7 +81,7 @@
* @n2win - level 2 window (values: 1 thru 7)
* @n3win - level 3 window (values: 1 thru 7)
* @nvc - # of logical channels (values: 1 thru 64)
- * @pktlen - level 3 packet lenght - log base 2 of size
+ * @pktlen - level 3 packet length - log base 2 of size
* @locaddr - my address
* @remaddr - remote address
* @t1 - time, in seconds
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 484e45c..aa07370 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -525,6 +525,7 @@
__u64 dccps_gsr;
__u64 dccps_gar;
__be32 dccps_service;
+ __u32 dccps_mss_cache;
struct dccp_service_list *dccps_service_list;
__u32 dccps_timestamp_echo;
__u32 dccps_timestamp_time;
@@ -533,7 +534,6 @@
__u16 dccps_pcslen;
__u16 dccps_pcrlen;
unsigned long dccps_ndp_count;
- __u32 dccps_mss_cache;
unsigned long dccps_rate_last;
struct dccp_minisock dccps_minisock;
struct dccp_ackvec *dccps_hc_rx_ackvec;
diff --git a/include/linux/device.h b/include/linux/device.h
index db375be..2258d89 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -410,6 +410,15 @@
extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
extern void devm_kfree(struct device *dev, void *p);
+struct device_dma_parameters {
+ /*
+ * a low level driver may set these to teach IOMMU code about
+ * sg limitations.
+ */
+ unsigned int max_segment_size;
+ unsigned long segment_boundary_mask;
+};
+
struct device {
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
@@ -445,6 +454,8 @@
64 bit addresses for consistent
allocations such descriptors. */
+ struct device_dma_parameters *dma_parms;
+
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
@@ -534,11 +545,17 @@
extern void device_destroy(struct class *cls, dev_t devt);
#ifdef CONFIG_PM_SLEEP
extern void destroy_suspended_device(struct class *cls, dev_t devt);
+extern void device_pm_schedule_removal(struct device *);
#else /* !CONFIG_PM_SLEEP */
static inline void destroy_suspended_device(struct class *cls, dev_t devt)
{
device_destroy(cls, devt);
}
+
+static inline void device_pm_schedule_removal(struct device *dev)
+{
+ device_unregister(dev);
+}
#endif /* !CONFIG_PM_SLEEP */
/*
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 101a2d4..3320307 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_LINUX_DMA_MAPPING_H
-#define _ASM_LINUX_DMA_MAPPING_H
+#ifndef _LINUX_DMA_MAPPING_H
+#define _LINUX_DMA_MAPPING_H
#include <linux/device.h>
#include <linux/err.h>
@@ -60,6 +60,36 @@
extern u64 dma_get_required_mask(struct device *dev);
+static inline unsigned int dma_get_max_seg_size(struct device *dev)
+{
+ return dev->dma_parms ? dev->dma_parms->max_segment_size : 65536;
+}
+
+static inline unsigned int dma_set_max_seg_size(struct device *dev,
+ unsigned int size)
+{
+ if (dev->dma_parms) {
+ dev->dma_parms->max_segment_size = size;
+ return 0;
+ } else
+ return -EIO;
+}
+
+static inline unsigned long dma_get_seg_boundary(struct device *dev)
+{
+ return dev->dma_parms ?
+ dev->dma_parms->segment_boundary_mask : 0xffffffff;
+}
+
+static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
+{
+ if (dev->dma_parms) {
+ dev->dma_parms->segment_boundary_mask = mask;
+ return 0;
+ } else
+ return -EIO;
+}
+
/* flags for the coherent memory api */
#define DMA_MEMORY_MAP 0x01
#define DMA_MEMORY_IO 0x02
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 55c9a69..acbb364 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -29,7 +29,7 @@
#include <linux/dma-mapping.h>
/**
- * enum dma_state - resource PNP/power managment state
+ * enum dma_state - resource PNP/power management state
* @DMA_RESOURCE_SUSPEND: DMA device going into low power state
* @DMA_RESOURCE_RESUME: DMA device returning to full power
* @DMA_RESOURCE_AVAILABLE: DMA device available to the system
@@ -95,6 +95,15 @@
#define DMA_TX_TYPE_END (DMA_INTERRUPT + 1)
/**
+ * enum dma_prep_flags - DMA flags to augment operation preparation
+ * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of
+ * this transaction
+ */
+enum dma_prep_flags {
+ DMA_PREP_INTERRUPT = (1 << 0),
+};
+
+/**
* dma_cap_mask_t - capabilities bitmap modeled after cpumask_t.
* See linux/cpumask.h
*/
@@ -209,8 +218,6 @@
* descriptors
* @chan: target channel for this operation
* @tx_submit: set the prepared descriptor(s) to be executed by the engine
- * @tx_set_dest: set a destination address in a hardware descriptor
- * @tx_set_src: set a source address in a hardware descriptor
* @callback: routine to call after this operation is complete
* @callback_param: general parameter to pass to the callback routine
* ---async_tx api specific fields---
@@ -227,10 +234,6 @@
struct list_head tx_list;
struct dma_chan *chan;
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
- void (*tx_set_dest)(dma_addr_t addr,
- struct dma_async_tx_descriptor *tx, int index);
- void (*tx_set_src)(dma_addr_t addr,
- struct dma_async_tx_descriptor *tx, int index);
dma_async_tx_callback callback;
void *callback_param;
struct list_head depend_list;
@@ -279,15 +282,17 @@
void (*device_free_chan_resources)(struct dma_chan *chan);
struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
- struct dma_chan *chan, size_t len, int int_en);
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
- struct dma_chan *chan, unsigned int src_cnt, size_t len,
- int int_en);
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+ unsigned int src_cnt, size_t len, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_zero_sum)(
- struct dma_chan *chan, unsigned int src_cnt, size_t len,
- u32 *result, int int_en);
+ struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt,
+ size_t len, u32 *result, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
- struct dma_chan *chan, int value, size_t len, int int_en);
+ struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
+ unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
struct dma_chan *chan);
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 5b42a65..b1251b2 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -79,7 +79,6 @@
extern int dmi_get_year(int field);
extern int dmi_name_in_vendors(const char *str);
extern int dmi_available;
-extern char *dmi_get_slot(int slot);
#else
@@ -90,7 +89,6 @@
static inline int dmi_get_year(int year) { return 0; }
static inline int dmi_name_in_vendors(const char *s) { return 0; }
#define dmi_available 0
-static inline char *dmi_get_slot(int slot) { return NULL; }
#endif
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 71d4ada..fcbe8b6 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -309,7 +309,7 @@
* get_ringparam: Report ring sizes
* set_ringparam: Set ring sizes
* get_pauseparam: Report pause parameters
- * set_pauseparam: Set pause paramters
+ * set_pauseparam: Set pause parameters
* get_rx_csum: Report whether receive checksums are turned on or off
* set_rx_csum: Turn receive checksum on or off
* get_tx_csum: Report whether transmit checksums are turned on or off
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a516b67..109734b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -21,7 +21,7 @@
/* Fixed constants first: */
#undef NR_OPEN
-#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */
+extern int sysctl_nr_open;
#define INR_OPEN 1024 /* Initial setting for nfile rlimits */
#define BLOCK_SIZE_BITS 10
@@ -872,6 +872,7 @@
struct list_head fl_block; /* circular list of blocked processes */
fl_owner_t fl_owner;
unsigned int fl_pid;
+ struct pid *fl_nspid;
wait_queue_head_t fl_wait;
struct file *fl_file;
unsigned char fl_flags;
@@ -976,7 +977,6 @@
extern struct list_head super_blocks;
extern spinlock_t sb_lock;
-#define sb_entry(list) list_entry((list), struct super_block, s_list)
#define S_BIAS (1<<30)
struct super_block {
struct list_head s_list; /* Keep this first */
@@ -1278,8 +1278,10 @@
*
* Two bits are used for locking and completion notification, I_LOCK and I_SYNC.
*
- * I_DIRTY_SYNC Inode itself is dirty.
- * I_DIRTY_DATASYNC Data-related inode changes pending
+ * I_DIRTY_SYNC Inode is dirty, but doesn't have to be written on
+ * fdatasync(). i_atime is the usual cause.
+ * I_DIRTY_DATASYNC Inode is dirty and must be written on fdatasync(), f.e.
+ * because i_size changed.
* I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean.
* I_NEW get_new_inode() sets i_state to I_LOCK|I_NEW. Both
* are cleared by unlock_new_inode(), called from iget().
@@ -1307,12 +1309,10 @@
* being set. find_inode() uses this to prevent returning
* nearly-dead inodes.
* I_SYNC Similar to I_LOCK, but limited in scope to writeback
- * of inode dirty data. Having a seperate lock for this
+ * of inode dirty data. Having a separate lock for this
* purpose reduces latency and prevents some filesystem-
* specific deadlocks.
*
- * Q: Why does I_DIRTY_DATASYNC exist? It appears as if it could be replaced
- * by (I_DIRTY_SYNC|I_DIRTY_PAGES).
* Q: What is the difference between I_WILL_FREE and I_FREEING?
* Q: igrab() only checks on (I_FREEING|I_WILL_FREE). Should it also check on
* I_CLEAR? If not, why?
@@ -2112,6 +2112,7 @@
int proc_nr_files(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+int get_filesystem_list(char * buf);
#endif /* __KERNEL__ */
#endif /* _LINUX_FS_H */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 2bd31fa..d4b7c4a 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -92,6 +92,14 @@
}
/*
+ * fsnotify_link_count - inode's link count changed
+ */
+static inline void fsnotify_link_count(struct inode *inode)
+{
+ inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
+}
+
+/*
* fsnotify_create - 'name' was linked in
*/
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
@@ -103,6 +111,20 @@
}
/*
+ * fsnotify_link - new hardlink in 'inode' directory
+ * Note: We have to pass also the linked inode ptr as some filesystems leave
+ * new_dentry->d_inode NULL and instantiate inode pointer later
+ */
+static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
+{
+ inode_dir_notify(dir, DN_CREATE);
+ inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
+ inode);
+ fsnotify_link_count(inode);
+ audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
+}
+
+/*
* fsnotify_mkdir - directory 'name' was created
*/
static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 7e93a9a..0c6ce51 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -228,5 +228,7 @@
void page_alloc_init(void);
void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
+void drain_all_pages(void);
+void drain_local_pages(void *dummy);
#endif /* __LINUX_GFP_H */
diff --git a/include/linux/hash.h b/include/linux/hash.h
index acf17bb..06d25c1 100644
--- a/include/linux/hash.h
+++ b/include/linux/hash.h
@@ -1,6 +1,6 @@
#ifndef _LINUX_HASH_H
#define _LINUX_HASH_H
-/* Fast hashing routine for a long.
+/* Fast hashing routine for ints, longs and pointers.
(C) 2002 William Lee Irwin III, IBM */
/*
@@ -13,23 +13,30 @@
* them can use shifts and additions instead of multiplications for
* machines where multiplications are slow.
*/
-#if BITS_PER_LONG == 32
+
+#include <asm/types.h>
+
/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e370001UL
-#elif BITS_PER_LONG == 64
+#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
+#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
+
+#if BITS_PER_LONG == 32
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32
+#define hash_long(val, bits) hash_32(val, bits)
+#elif BITS_PER_LONG == 64
+#define hash_long(val, bits) hash_64(val, bits)
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64
#else
-#error Define GOLDEN_RATIO_PRIME for your wordsize.
+#error Wordsize not 32 or 64
#endif
-static inline unsigned long hash_long(unsigned long val, unsigned int bits)
+static inline u64 hash_64(u64 val, unsigned int bits)
{
- unsigned long hash = val;
+ u64 hash = val;
-#if BITS_PER_LONG == 64
/* Sigh, gcc can't optimise this alone like it does for 32 bits. */
- unsigned long n = hash;
+ u64 n = hash;
n <<= 18;
hash -= n;
n <<= 33;
@@ -42,15 +49,20 @@
hash += n;
n <<= 2;
hash += n;
-#else
- /* On some cpus multiply is faster, on others gcc will do shifts */
- hash *= GOLDEN_RATIO_PRIME;
-#endif
/* High bits are more random, so use them. */
- return hash >> (BITS_PER_LONG - bits);
+ return hash >> (64 - bits);
}
-
+
+static inline u32 hash_32(u32 val, unsigned int bits)
+{
+ /* On some cpus multiply is faster, on others gcc will do shifts */
+ u32 hash = val * GOLDEN_RATIO_PRIME_32;
+
+ /* High bits are more random, so use them. */
+ return hash >> (32 - bits);
+}
+
static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
{
return hash_long((unsigned long)ptr, bits);
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index db390c5..6115545 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -26,13 +26,6 @@
#include <linux/netdevice.h>
#include <linux/hdlc/ioctl.h>
-
-/* Used by all network devices here, pointed to by netdev_priv(dev) */
-struct hdlc_device_desc {
- int (*netif_rx)(struct sk_buff *skb);
- struct net_device_stats stats;
-};
-
/* This structure is a private property of HDLC protocols.
Hardware drivers have no interest here */
@@ -44,12 +37,15 @@
void (*detach)(struct net_device *dev);
int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
__be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
+ int (*netif_rx)(struct sk_buff *skb);
struct module *module;
struct hdlc_proto *next; /* next protocol in the list */
};
+/* Pointed to by dev->priv */
typedef struct hdlc_device {
+ struct net_device_stats stats;
/* used by HDLC layer to take control over HDLC device from hw driver*/
int (*attach)(struct net_device *dev,
unsigned short encoding, unsigned short parity);
@@ -83,18 +79,11 @@
struct net_device *alloc_hdlcdev(void *priv);
-
-static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
+static inline struct hdlc_device* dev_to_hdlc(struct net_device *dev)
{
- return netdev_priv(dev);
+ return dev->priv;
}
-static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
-{
- return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
-}
-
-
static __inline__ void debug_frame(const struct sk_buff *skb)
{
int i;
@@ -116,13 +105,13 @@
void hdlc_close(struct net_device *dev);
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
- int (*rx)(struct sk_buff *skb), size_t size);
+ size_t size);
/* May be used by hardware driver to gain control over HDLC device */
void detach_hdlc_protocol(struct net_device *dev);
static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
{
- return &dev_to_desc(dev)->stats;
+ return &dev_to_hdlc(dev)->stats;
}
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index ff43f8d..e38e759 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -364,7 +364,7 @@
#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */
#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */
#define SETFEATURES_EN_REST 0xAC /* ATA-1 */
-#define SETFEATURES_4B_RW_LONG 0xBB /* Set Lenght of 4 bytes */
+#define SETFEATURES_4B_RW_LONG 0xBB /* Set Length of 4 bytes */
#define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */
#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */
#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt ATAPI */
@@ -706,8 +706,10 @@
*/
#define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */
#define IDE_NICE_ATAPI_OVERLAP (1) /* not supported yet */
-#define IDE_NICE_0 (2) /* when sure that it won't affect us */
#define IDE_NICE_1 (3) /* when probably won't affect us much */
+#ifndef __KERNEL__
+#define IDE_NICE_0 (2) /* when sure that it won't affect us */
#define IDE_NICE_2 (4) /* when we know it's on our expense */
+#endif
#endif /* _LINUX_HDREG_H */
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 1fcb003..7dcbc82 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -68,8 +68,6 @@
void *addr = kmap_atomic(page, KM_USER0);
clear_user_page(addr, vaddr, page);
kunmap_atomic(addr, KM_USER0);
- /* Make sure this page is cleared on other CPU's too before using it */
- smp_wmb();
}
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
@@ -124,28 +122,40 @@
kunmap_atomic(kaddr, KM_USER0);
}
-/*
- * Same but also flushes aliased cache contents to RAM.
- *
- * This must be a macro because KM_USER0 and friends aren't defined if
- * !CONFIG_HIGHMEM
- */
-#define zero_user_page(page, offset, size, km_type) \
- do { \
- void *kaddr; \
- \
- BUG_ON((offset) + (size) > PAGE_SIZE); \
- \
- kaddr = kmap_atomic(page, km_type); \
- memset((char *)kaddr + (offset), 0, (size)); \
- flush_dcache_page(page); \
- kunmap_atomic(kaddr, (km_type)); \
- } while (0)
+static inline void zero_user_segments(struct page *page,
+ unsigned start1, unsigned end1,
+ unsigned start2, unsigned end2)
+{
+ void *kaddr = kmap_atomic(page, KM_USER0);
+
+ BUG_ON(end1 > PAGE_SIZE || end2 > PAGE_SIZE);
+
+ if (end1 > start1)
+ memset(kaddr + start1, 0, end1 - start1);
+
+ if (end2 > start2)
+ memset(kaddr + start2, 0, end2 - start2);
+
+ kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(page);
+}
+
+static inline void zero_user_segment(struct page *page,
+ unsigned start, unsigned end)
+{
+ zero_user_segments(page, start, end, 0, 0);
+}
+
+static inline void zero_user(struct page *page,
+ unsigned start, unsigned size)
+{
+ zero_user_segments(page, start, start + size, 0, 0);
+}
static inline void __deprecated memclear_highpage_flush(struct page *page,
unsigned int offset, unsigned int size)
{
- zero_user_page(page, offset, size, KM_USER0);
+ zero_user(page, offset, size);
}
#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
@@ -160,8 +170,6 @@
copy_user_page(vto, vfrom, vaddr, to);
kunmap_atomic(vfrom, KM_USER0);
kunmap_atomic(vto, KM_USER1);
- /* Make sure this page is cleared on other CPU's too before using it */
- smp_wmb();
}
#endif
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 49067f1..8371b66 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -147,7 +147,6 @@
* @get_time: function to retrieve the current time of the clock
* @get_softirq_time: function to retrieve the current time from the softirq
* @softirq_time: the time when running the hrtimer queue in the softirq
- * @cb_pending: list of timers where the callback is pending
* @offset: offset of this clock to the monotonic base
* @reprogram: function to reprogram the timer event
*/
@@ -302,9 +301,16 @@
}
/* Forward a hrtimer so it expires after now: */
-extern unsigned long
+extern u64
hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
+/* Forward a hrtimer so it expires after the hrtimer's current now */
+static inline u64 hrtimer_forward_now(struct hrtimer *timer,
+ ktime_t interval)
+{
+ return hrtimer_forward(timer, timer->base->get_time(), interval);
+}
+
/* Precise sleep: */
extern long hrtimer_nanosleep(struct timespec *rqtp,
struct timespec *rmtp,
@@ -323,9 +329,9 @@
extern void __init hrtimers_init(void);
#if BITS_PER_LONG < 64
-extern unsigned long ktime_divns(const ktime_t kt, s64 div);
+extern u64 ktime_divns(const ktime_t kt, s64 div);
#else /* BITS_PER_LONG < 64 */
-# define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div))
+# define ktime_divns(kt, div) (u64)((kt).tv64 / (div))
#endif
/* Show pending timers: */
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 85d1191..4213182 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -44,7 +44,15 @@
/** Register a new Hardware Random Number Generator driver. */
extern int hwrng_register(struct hwrng *rng);
/** Unregister a Hardware Random Number Generator driver. */
-extern void hwrng_unregister(struct hwrng *rng);
+extern void __hwrng_unregister(struct hwrng *rng, bool suspended);
+static inline void hwrng_unregister(struct hwrng *rng)
+{
+ __hwrng_unregister(rng, false);
+}
+static inline void hwrng_unregister_suspended(struct hwrng *rng)
+{
+ __hwrng_unregister(rng, true);
+}
#endif /* __KERNEL__ */
#endif /* LINUX_HWRANDOM_H_ */
diff --git a/include/linux/i2c/pca953x.h b/include/linux/i2c/pca953x.h
new file mode 100644
index 0000000..3c73612
--- /dev/null
+++ b/include/linux/i2c/pca953x.h
@@ -0,0 +1,18 @@
+/* platform data for the PCA9539 16-bit I/O expander driver */
+
+struct pca953x_platform_data {
+ /* number of the first GPIO */
+ unsigned gpio_base;
+
+ /* initial polarity inversion setting */
+ uint16_t invert;
+
+ void *context; /* param to setup/teardown */
+
+ int (*setup)(struct i2c_client *client,
+ unsigned gpio, unsigned ngpio,
+ void *context);
+ int (*teardown)(struct i2c_client *client,
+ unsigned gpio, unsigned ngpio,
+ void *context);
+};
diff --git a/include/linux/i2c/pcf857x.h b/include/linux/i2c/pcf857x.h
new file mode 100644
index 0000000..ba8ea6e
--- /dev/null
+++ b/include/linux/i2c/pcf857x.h
@@ -0,0 +1,45 @@
+#ifndef __LINUX_PCF857X_H
+#define __LINUX_PCF857X_H
+
+/**
+ * struct pcf857x_platform_data - data to set up pcf857x driver
+ * @gpio_base: number of the chip's first GPIO
+ * @n_latch: optional bit-inverse of initial register value; if
+ * you leave this initialized to zero the driver will act
+ * like the chip was just reset
+ * @setup: optional callback issued once the GPIOs are valid
+ * @teardown: optional callback issued before the GPIOs are invalidated
+ * @context: optional parameter passed to setup() and teardown()
+ *
+ * In addition to the I2C_BOARD_INFO() state appropriate to each chip,
+ * the i2c_board_info used with the pcf875x driver must provide the
+ * chip "type" ("pcf8574", "pcf8574a", "pcf8575", "pcf8575c") and its
+ * platform_data (pointer to one of these structures) with at least
+ * the gpio_base value initialized.
+ *
+ * The @setup callback may be used with the kind of board-specific glue
+ * which hands the (now-valid) GPIOs to other drivers, or which puts
+ * devices in their initial states using these GPIOs.
+ *
+ * These GPIO chips are only "quasi-bidirectional"; read the chip specs
+ * to understand the behavior. They don't have separate registers to
+ * record which pins are used for input or output, record which output
+ * values are driven, or provide access to input values. That must be
+ * inferred by reading the chip's value and knowing the last value written
+ * to it. If you leave n_latch initialized to zero, that last written
+ * value is presumed to be all ones (as if the chip were just reset).
+ */
+struct pcf857x_platform_data {
+ unsigned gpio_base;
+ unsigned n_latch;
+
+ int (*setup)(struct i2c_client *client,
+ int gpio, unsigned ngpio,
+ void *context);
+ int (*teardown)(struct i2c_client *client,
+ int gpio, unsigned ngpio,
+ void *context);
+ void *context;
+};
+
+#endif /* __LINUX_PCF857X_H */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index ec10b2a..acec99d 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -112,18 +112,8 @@
#define SATA_NR_PORTS (3) /* 16 possible ?? */
#define SATA_STATUS_OFFSET (0)
-#define SATA_STATUS_REG (HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
#define SATA_ERROR_OFFSET (1)
-#define SATA_ERROR_REG (HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
#define SATA_CONTROL_OFFSET (2)
-#define SATA_CONTROL_REG (HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
-
-#define SATA_MISC_OFFSET (0)
-#define SATA_MISC_REG (HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
-#define SATA_PHY_OFFSET (1)
-#define SATA_PHY_REG (HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
-#define SATA_IEN_OFFSET (2)
-#define SATA_IEN_REG (HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
/*
* Our Physical Region Descriptor (PRD) table should be large enough
@@ -179,7 +169,7 @@
ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives,
ide_pmac, ide_etrax100, ide_acorn,
- ide_au1xxx, ide_forced
+ ide_au1xxx, ide_palm3710, ide_forced
};
typedef u8 hwif_chipset_t;
@@ -196,6 +186,7 @@
} hw_regs_t;
struct hwif_s * ide_find_port(unsigned long);
+struct hwif_s *ide_deprecated_find_port(unsigned long);
void ide_init_port_data(struct hwif_s *, unsigned int);
void ide_init_port_hw(struct hwif_s *, hw_regs_t *);
@@ -203,17 +194,6 @@
int ide_register_hw(hw_regs_t *, void (*)(struct ide_drive_s *),
struct hwif_s **);
-void ide_setup_ports( hw_regs_t *hw,
- unsigned long base,
- int *offsets,
- unsigned long ctrl,
- unsigned long intr,
- ide_ack_intr_t *ack_intr,
-#if 0
- ide_io_ops_t *iops,
-#endif
- int irq);
-
static inline void ide_std_init_ports(hw_regs_t *hw,
unsigned long io_addr,
unsigned long ctl_addr)
@@ -406,8 +386,6 @@
unsigned no_unmask : 1; /* disallow setting unmask bit */
unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
unsigned atapi_overlap : 1; /* ATAPI overlap (not supported) */
- unsigned nice0 : 1; /* give obvious excess bandwidth */
- unsigned nice2 : 1; /* give a share in our own bandwidth */
unsigned doorlocking : 1; /* for removable only: door lock/unlock works */
unsigned nodma : 1; /* disallow DMA */
unsigned autotune : 2; /* 0=default, 1=autotune, 2=noautotune */
@@ -480,14 +458,12 @@
/* task file registers for pata and sata */
unsigned long io_ports[IDE_NR_PORTS];
unsigned long sata_scr[SATA_NR_PORTS];
- unsigned long sata_misc[SATA_NR_PORTS];
ide_drive_t drives[MAX_DRIVES]; /* drive info */
u8 major; /* our major number */
u8 index; /* 0 for ide0; 1 for ide1; ... */
u8 channel; /* for dual-port chips: 0=primary, 1=secondary */
- u8 straight8; /* Alan's straight 8 check */
u8 bus_state; /* power state of the IDE bus */
u32 host_flags;
@@ -513,6 +489,8 @@
#if 0
ide_hwif_ops_t *hwifops;
#else
+ /* host specific initialization of devices on a port */
+ void (*port_init_devs)(struct hwif_s *);
/* routine to program host for PIO mode */
void (*set_pio_mode)(ide_drive_t *, const u8);
/* routine to program host for DMA mode */
@@ -535,6 +513,8 @@
u8 (*mdma_filter)(ide_drive_t *);
u8 (*udma_filter)(ide_drive_t *);
+ u8 (*cable_detect)(struct hwif_s *);
+
void (*ata_input_data)(ide_drive_t *, void *, u32);
void (*ata_output_data)(ide_drive_t *, void *, u32);
@@ -602,10 +582,9 @@
unsigned serialized : 1; /* serialized all channel operation */
unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */
unsigned reset : 1; /* reset after probe */
- unsigned auto_poll : 1; /* supports nop auto-poll */
unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */
- unsigned no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */
unsigned mmio : 1; /* host uses MMIO */
+ unsigned straight8 : 1; /* Alan's straight 8 check */
struct device gendev;
struct completion gendev_rel_comp; /* To deal with device release() */
@@ -625,6 +604,9 @@
typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
typedef int (ide_expiry_t)(ide_drive_t *);
+/* used by ide-cd, ide-floppy, etc. */
+typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
+
typedef struct hwgroup_s {
/* irq handler, if active */
ide_startstop_t (*handler)(ide_drive_t *);
@@ -708,6 +690,7 @@
void proc_ide_create(void);
void proc_ide_destroy(void);
void ide_proc_register_port(ide_hwif_t *);
+void ide_proc_port_register_devices(ide_hwif_t *);
void ide_proc_unregister_port(ide_hwif_t *);
void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
@@ -740,6 +723,7 @@
static inline void proc_ide_create(void) { ; }
static inline void proc_ide_destroy(void) { ; }
static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; }
static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
@@ -988,10 +972,8 @@
extern int system_bus_clock(void);
extern int ide_driveid_update(ide_drive_t *);
-extern int ide_ata66_check(ide_drive_t *, ide_task_t *);
extern int ide_config_drive_speed(ide_drive_t *, u8);
extern u8 eighty_ninty_three (ide_drive_t *);
-extern int set_transfer(ide_drive_t *, ide_task_t *);
extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
extern int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout);
@@ -1016,6 +998,14 @@
void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int, u8 *);
void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
+/* FIXME: palm_bk3710 uses BLK_DEV_IDEDMA_PCI without BLK_DEV_IDEPCI! */
+#if defined(CONFIG_BLK_DEV_IDEPCI) && defined(CONFIG_BLK_DEV_IDEDMA_PCI)
+void ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *);
+#else
+static inline void ide_hwif_setup_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d) { }
+#endif
+
extern void default_hwif_iops(ide_hwif_t *);
extern void default_hwif_mmiops(ide_hwif_t *);
extern void default_hwif_transport(ide_hwif_t *);
@@ -1052,7 +1042,7 @@
IDE_HFLAG_NO_SET_MODE = (1 << 9),
/* trust BIOS for programming chipset/device for DMA */
IDE_HFLAG_TRUST_BIOS_FOR_DMA = (1 << 10),
- /* host uses VDMA */
+ /* host uses VDMA (tied with IDE_HFLAG_CS5520 for now) */
IDE_HFLAG_VDMA = (1 << 11),
/* ATAPI DMA is unsupported */
IDE_HFLAG_NO_ATAPI_DMA = (1 << 12),
@@ -1062,8 +1052,10 @@
IDE_HFLAG_NO_DMA = (1 << 14),
/* check if host is PCI IDE device before allowing DMA */
IDE_HFLAG_NO_AUTODMA = (1 << 15),
+ /* don't autotune PIO */
+ IDE_HFLAG_NO_AUTOTUNE = (1 << 16),
/* host is CS5510/CS5520 */
- IDE_HFLAG_CS5520 = (1 << 16),
+ IDE_HFLAG_CS5520 = IDE_HFLAG_VDMA,
/* no LBA48 */
IDE_HFLAG_NO_LBA48 = (1 << 17),
/* no LBA48 DMA */
@@ -1089,6 +1081,10 @@
IDE_HFLAG_CLEAR_SIMPLEX = (1 << 28),
/* DSC overlap is unsupported */
IDE_HFLAG_NO_DSC = (1 << 29),
+ /* never use 32-bit I/O ops */
+ IDE_HFLAG_NO_IO_32BIT = (1 << 30),
+ /* never unmask IRQs */
+ IDE_HFLAG_NO_UNMASK_IRQS = (1 << 31),
};
#ifdef CONFIG_BLK_DEV_OFFBOARD
@@ -1144,6 +1140,7 @@
void ide_dma_off(ide_drive_t *);
void ide_dma_on(ide_drive_t *);
int ide_set_dma(ide_drive_t *);
+void ide_check_dma_crc(ide_drive_t *);
ide_startstop_t ide_dma_intr(ide_drive_t *);
int ide_build_sglist(ide_drive_t *, struct request *);
@@ -1171,6 +1168,7 @@
static inline void ide_dma_on(ide_drive_t *drive) { ; }
static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
+static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
#endif /* CONFIG_BLK_DEV_IDEDMA */
#ifndef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -1182,27 +1180,29 @@
extern void ide_acpi_get_timing(ide_hwif_t *hwif);
extern void ide_acpi_push_timing(ide_hwif_t *hwif);
extern void ide_acpi_init(ide_hwif_t *hwif);
+void ide_acpi_port_init_devices(ide_hwif_t *);
extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
#else
static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_port_init_devices(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
#endif
void ide_remove_port_from_hwgroup(ide_hwif_t *);
extern int ide_hwif_request_regions(ide_hwif_t *hwif);
extern void ide_hwif_release_regions(ide_hwif_t* hwif);
-extern void ide_unregister (unsigned int index);
+void ide_unregister(unsigned int, int, int);
void ide_register_region(struct gendisk *);
void ide_unregister_region(struct gendisk *);
void ide_undecoded_slave(ide_drive_t *);
-int ide_device_add_all(u8 *idx);
-int ide_device_add(u8 idx[4]);
+int ide_device_add_all(u8 *idx, const struct ide_port_info *);
+int ide_device_add(u8 idx[4], const struct ide_port_info *);
static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
{
@@ -1309,4 +1309,25 @@
drive->hwif->OUTB(drive->ctl | (on ? 0 : 2), IDE_CONTROL_REG);
}
+static inline u8 ide_read_status(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ return hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+}
+
+static inline u8 ide_read_altstatus(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ return hwif->INB(hwif->io_ports[IDE_CONTROL_OFFSET]);
+}
+
+static inline u8 ide_read_error(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ return hwif->INB(hwif->io_ports[IDE_ERROR_OFFSET]);
+}
+
#endif /* _IDE_H */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 5de6d91..f577c8f 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -287,6 +287,12 @@
#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004
#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010
+/* MIMO Power Save Modes */
+#define WLAN_HT_CAP_MIMO_PS_STATIC 0
+#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1
+#define WLAN_HT_CAP_MIMO_PS_INVALID 2
+#define WLAN_HT_CAP_MIMO_PS_DISABLED 3
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 34f40ef..79504b2 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -327,7 +327,7 @@
*
* Returns error if the skb is not of VLAN type
*/
-static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
{
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
@@ -347,7 +347,8 @@
*
* Returns error if @skb->cb[] is not set correctly
*/
-static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
+ unsigned short *tag)
{
struct vlan_skb_tx_cookie *cookie;
@@ -370,7 +371,7 @@
*
* Returns error if the skb is not VLAN tagged
*/
-static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
{
if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
return __vlan_hwaccel_get_tag(skb, tag);
diff --git a/include/linux/init.h b/include/linux/init.h
index 2efbda0..a404a00 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -110,6 +110,7 @@
#define __FINIT .previous
#define __INITDATA .section ".init.data","aw"
+#define __FINITDATA .previous
#define __DEVINIT .section ".devinit.text", "ax"
#define __DEVINITDATA .section ".devinit.data", "aw"
@@ -124,9 +125,6 @@
#define __REF .section ".ref.text", "ax"
#define __REFDATA .section ".ref.data", "aw"
#define __REFCONST .section ".ref.rodata", "aw"
-/* backward compatibility */
-#define __INIT_REFOK .section __REF
-#define __INITDATA_REFOK .section __REFDATA
#ifndef __ASSEMBLY__
/*
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index f42663e..1f74e1d 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -121,6 +121,18 @@
#else
#define INIT_IDS
#endif
+
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+/*
+ * Because of the reduced scope of CAP_SETPCAP when filesystem
+ * capabilities are in effect, it is safe to allow CAP_SETPCAP to
+ * be available in the default configuration.
+ */
+# define CAP_INIT_BSET CAP_FULL_SET
+#else
+# define CAP_INIT_BSET CAP_INIT_EFF_SET
+#endif
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -156,6 +168,7 @@
.cap_effective = CAP_INIT_EFF_SET, \
.cap_inheritable = CAP_INIT_INH_SET, \
.cap_permitted = CAP_FULL_SET, \
+ .cap_bset = CAP_INIT_BSET, \
.keep_capabilities = 0, \
.user = INIT_USER, \
.comm = "swapper", \
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index c3db4a0..dea7598 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -444,4 +444,6 @@
}
#endif
+int show_interrupts(struct seq_file *p, void *v);
+
#endif
diff --git a/include/linux/iommu-helper.h b/include/linux/iommu-helper.h
new file mode 100644
index 0000000..4dd4c04
--- /dev/null
+++ b/include/linux/iommu-helper.h
@@ -0,0 +1,7 @@
+extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
+ unsigned long start, unsigned int nr,
+ unsigned long shift,
+ unsigned long boundary_size,
+ unsigned long align_mask);
+extern void iommu_area_free(unsigned long *map, unsigned long start,
+ unsigned int nr);
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index d0ecc8e..9cb2855 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -507,7 +507,6 @@
struct ktermios normal_termios; /* For saving termios structs */
struct ktermios callout_termios;
wait_queue_head_t open_wait, close_wait;
- struct semaphore write_sem;
spinlock_t readlock;
} modem_info;
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index d9ecd13..b18fd3b 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -33,7 +33,6 @@
#include <linux/lockdep.h>
#include <asm/semaphore.h>
-#endif
#define journal_oom_retry 1
@@ -84,7 +83,6 @@
#define JFS_MIN_JOURNAL_BLOCKS 1024
-#ifdef __KERNEL__
/**
* typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
@@ -924,7 +922,6 @@
extern int journal_wipe (journal_t *, int);
extern int journal_skip_recovery (journal_t *);
extern void journal_update_superblock (journal_t *, int);
-extern void __journal_abort_hard (journal_t *);
extern void journal_abort (journal_t *, int);
extern int journal_errno (journal_t *);
extern void journal_ack_err (journal_t *);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index ff356b2..18222f2 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -35,7 +35,7 @@
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
-#define IS_ALIGNED(x,a) (((x) % ((typeof(x))(a))) == 0)
+#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 6168c0a..4a6ce82 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -152,8 +152,10 @@
struct kretprobe {
struct kprobe kp;
kretprobe_handler_t handler;
+ kretprobe_handler_t entry_handler;
int maxactive;
int nmissed;
+ size_t data_size;
struct hlist_head free_instances;
struct hlist_head used_instances;
};
@@ -164,6 +166,7 @@
struct kretprobe *rp;
kprobe_opcode_t *ret_addr;
struct task_struct *task;
+ char data[0];
};
struct kretprobe_blackpoint {
diff --git a/include/linux/latency.h b/include/linux/latency.h
deleted file mode 100644
index c08b52b..0000000
--- a/include/linux/latency.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * latency.h: Explicit system-wide latency-expectation infrastructure
- *
- * (C) Copyright 2006 Intel Corporation
- * Author: Arjan van de Ven <arjan@linux.intel.com>
- *
- */
-
-#ifndef _INCLUDE_GUARD_LATENCY_H_
-#define _INCLUDE_GUARD_LATENCY_H_
-
-#include <linux/notifier.h>
-
-void set_acceptable_latency(char *identifier, int usecs);
-void modify_acceptable_latency(char *identifier, int usecs);
-void remove_acceptable_latency(char *identifier);
-void synchronize_acceptable_latency(void);
-int system_latency_constraint(void);
-
-int register_latency_notifier(struct notifier_block * nb);
-int unregister_latency_notifier(struct notifier_block * nb);
-
-#define INFINITE_LATENCY 1000000
-
-#endif
diff --git a/include/linux/leds.h b/include/linux/leds.h
index b4130ff..00f89fd 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -54,7 +54,15 @@
extern int led_classdev_register(struct device *parent,
struct led_classdev *led_cdev);
-extern void led_classdev_unregister(struct led_classdev *led_cdev);
+extern void __led_classdev_unregister(struct led_classdev *led_cdev, bool sus);
+static inline void led_classdev_unregister(struct led_classdev *lcd)
+{
+ __led_classdev_unregister(lcd, false);
+}
+static inline void led_classdev_unregister_suspended(struct led_classdev *lcd)
+{
+ __led_classdev_unregister(lcd, true);
+}
extern void led_classdev_suspend(struct led_classdev *led_cdev);
extern void led_classdev_resume(struct led_classdev *led_cdev);
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
index 697104d..589be3e 100644
--- a/include/linux/lguest_launcher.h
+++ b/include/linux/lguest_launcher.h
@@ -23,7 +23,12 @@
struct lguest_device_desc {
/* The device type: console, network, disk etc. Type 0 terminates. */
__u8 type;
- /* The number of bytes of the config array. */
+ /* The number of virtqueues (first in config array) */
+ __u8 num_vq;
+ /* The number of bytes of feature bits. Multiply by 2: one for host
+ * features and one for guest acknowledgements. */
+ __u8 feature_len;
+ /* The number of bytes of the config array after virtqueues. */
__u8 config_len;
/* A status byte, written by the Guest. */
__u8 status;
@@ -31,7 +36,7 @@
};
/*D:135 This is how we expect the device configuration field for a virtqueue
- * (type VIRTIO_CONFIG_F_VIRTQUEUE) to be laid out: */
+ * to be laid out in config space. */
struct lguest_vqconfig {
/* The number of entries in the virtio_ring */
__u16 num;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 4374c42..bc5a8d0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -457,7 +457,6 @@
unsigned long flags; /* ATA_QCFLAG_xxx */
unsigned int tag;
unsigned int n_elem;
- unsigned int n_iter;
unsigned int mapped_n_elem;
int dma_dir;
@@ -1367,7 +1366,6 @@
qc->nbytes = qc->raw_nbytes = qc->curbytes = 0;
qc->n_elem = 0;
qc->mapped_n_elem = 0;
- qc->n_iter = 0;
qc->err_mask = 0;
qc->pad_len = 0;
qc->last_sg = NULL;
diff --git a/include/linux/llc.h b/include/linux/llc.h
index 09f2e6d..77335856 100644
--- a/include/linux/llc.h
+++ b/include/linux/llc.h
@@ -49,9 +49,9 @@
/* LLC SAP types. */
#define LLC_SAP_NULL 0x00 /* NULL SAP. */
-#define LLC_SAP_LLC 0x02 /* LLC Sublayer Managment. */
+#define LLC_SAP_LLC 0x02 /* LLC Sublayer Management. */
#define LLC_SAP_SNA 0x04 /* SNA Path Control. */
-#define LLC_SAP_PNM 0x0E /* Proway Network Managment. */
+#define LLC_SAP_PNM 0x0E /* Proway Network Management. */
#define LLC_SAP_IP 0x06 /* TCP/IP. */
#define LLC_SAP_BSPAN 0x42 /* Bridge Spanning Tree Proto */
#define LLC_SAP_MMS 0x4E /* Manufacturing Message Srv. */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index e2d1ce3..4babb2a 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -173,14 +173,17 @@
/*
* Host cache
*/
-struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
+struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *, int, int,
+ const char *, unsigned int);
+struct nlm_host *nlmsvc_lookup_host(struct svc_rqst *, const char *,
+ unsigned int);
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_release_host(struct nlm_host *);
void nlm_shutdown_hosts(void);
-extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
+extern void nlm_host_rebooted(const struct sockaddr_in *, const char *,
+ unsigned int, u32);
void nsm_release(struct nsm_handle *);
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index 83a1f9f..df18fa0 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -29,7 +29,7 @@
/* Lock info passed via NLM */
struct nlm_lock {
char * caller;
- int len; /* length of "caller" */
+ unsigned int len; /* length of "caller" */
struct nfs_fh fh;
struct xdr_netobj oh;
u32 svid;
@@ -78,7 +78,7 @@
*/
struct nlm_reboot {
char * mon;
- int len;
+ unsigned int len;
u32 state;
__be32 addr;
__be32 vers;
diff --git a/include/linux/log2.h b/include/linux/log2.h
index c8cf5e8..25b8086 100644
--- a/include/linux/log2.h
+++ b/include/linux/log2.h
@@ -190,4 +190,20 @@
__rounddown_pow_of_two(n) \
)
+/**
+ * order_base_2 - calculate the (rounded up) base 2 order of the argument
+ * @n: parameter
+ *
+ * The first few values calculated by this routine:
+ * ob2(0) = 0
+ * ob2(1) = 0
+ * ob2(2) = 1
+ * ob2(3) = 2
+ * ob2(4) = 2
+ * ob2(5) = 3
+ * ... and so on.
+ */
+
+#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+
#endif /* _LINUX_LOG2_H */
diff --git a/include/linux/loop.h b/include/linux/loop.h
index 26a0a103..46169a7 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -76,6 +76,7 @@
enum {
LO_FLAGS_READ_ONLY = 1,
LO_FLAGS_USE_AOPS = 2,
+ LO_FLAGS_AUTOCLEAR = 4,
};
#include <asm/posix_types.h> /* for __kernel_old_dev_t */
diff --git a/include/linux/lp.h b/include/linux/lp.h
index 7059b6b..0df024b 100644
--- a/include/linux/lp.h
+++ b/include/linux/lp.h
@@ -99,7 +99,7 @@
#ifdef __KERNEL__
#include <linux/wait.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
/* Magic numbers for defining port-device mappings */
#define LP_PARPORT_UNSPEC -4
@@ -145,7 +145,7 @@
#endif
wait_queue_head_t waitq;
unsigned int last_error;
- struct semaphore port_mutex;
+ struct mutex port_mutex;
wait_queue_head_t dataq;
long timeout;
unsigned int best_mode;
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index dff9ea3..24b30b9 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -43,7 +43,15 @@
};
extern int misc_register(struct miscdevice * misc);
-extern int misc_deregister(struct miscdevice * misc);
+extern int __misc_deregister(struct miscdevice *misc, bool suspended);
+static inline int misc_deregister(struct miscdevice *misc)
+{
+ return __misc_deregister(misc, false);
+}
+static inline int misc_deregister_suspended(struct miscdevice *misc)
+{
+ return __misc_deregister(misc, true);
+}
#define MODULE_ALIAS_MISCDEV(minor) \
MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 1bba678..89d7c69 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -227,10 +227,22 @@
*/
static inline int get_page_unless_zero(struct page *page)
{
- VM_BUG_ON(PageCompound(page));
+ VM_BUG_ON(PageTail(page));
return atomic_inc_not_zero(&page->_count);
}
+/* Support for virtually mapped pages */
+struct page *vmalloc_to_page(const void *addr);
+unsigned long vmalloc_to_pfn(const void *addr);
+
+/* Determine if an address is within the vmalloc range */
+static inline int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+
static inline struct page *compound_head(struct page *page)
{
if (unlikely(PageTail(page)))
@@ -706,6 +718,28 @@
struct vm_area_struct *start_vma, unsigned long start_addr,
unsigned long end_addr, unsigned long *nr_accounted,
struct zap_details *);
+
+/**
+ * mm_walk - callbacks for walk_page_range
+ * @pgd_entry: if set, called for each non-empty PGD (top-level) entry
+ * @pud_entry: if set, called for each non-empty PUD (2nd-level) entry
+ * @pmd_entry: if set, called for each non-empty PMD (3rd-level) entry
+ * @pte_entry: if set, called for each non-empty PTE (4th-level) entry
+ * @pte_hole: if set, called for each hole at all levels
+ *
+ * (see walk_page_range for more details)
+ */
+struct mm_walk {
+ int (*pgd_entry)(pgd_t *, unsigned long, unsigned long, void *);
+ int (*pud_entry)(pud_t *, unsigned long, unsigned long, void *);
+ int (*pmd_entry)(pmd_t *, unsigned long, unsigned long, void *);
+ int (*pte_entry)(pte_t *, unsigned long, unsigned long, void *);
+ int (*pte_hole)(unsigned long, unsigned long, void *);
+};
+
+int walk_page_range(const struct mm_struct *, unsigned long addr,
+ unsigned long end, const struct mm_walk *walk,
+ void *private);
void free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
unsigned long end, unsigned long floor, unsigned long ceiling);
void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *start_vma,
@@ -1089,8 +1123,6 @@
pgprot_t vm_get_page_prot(unsigned long vm_flags);
struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr);
-struct page *vmalloc_to_page(void *addr);
-unsigned long vmalloc_to_pfn(void *addr);
int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t);
int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 4c4522a..8d8d197 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -113,7 +113,7 @@
};
struct per_cpu_pageset {
- struct per_cpu_pages pcp[2]; /* 0: hot. 1: cold */
+ struct per_cpu_pages pcp;
#ifdef CONFIG_NUMA
s8 expire;
#endif
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index e9fddb42..139d49d 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -343,7 +343,8 @@
__u8 class; /* Standard interface or SDIO_ANY_ID */
__u16 vendor; /* Vendor or SDIO_ANY_ID */
__u16 device; /* Device ID or SDIO_ANY_ID */
- kernel_ulong_t driver_data; /* Data private to the driver */
+ kernel_ulong_t driver_data /* Data private to the driver */
+ __attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* SSB core, see drivers/ssb/ */
diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild
index d9c5455..e726fc3 100644
--- a/include/linux/nfsd/Kbuild
+++ b/include/linux/nfsd/Kbuild
@@ -4,4 +4,3 @@
unifdef-y += syscall.h
unifdef-y += nfsfh.h
unifdef-y += debug.h
-unifdef-y += auth.h
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
index 007480c..7b5d784 100644
--- a/include/linux/nfsd/cache.h
+++ b/include/linux/nfsd/cache.h
@@ -72,8 +72,8 @@
*/
#define RC_DELAY (HZ/5)
-void nfsd_cache_init(void);
-void nfsd_cache_shutdown(void);
+int nfsd_reply_cache_init(void);
+void nfsd_reply_cache_shutdown(void);
int nfsd_cache_lookup(struct svc_rqst *, int);
void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index bcb7aba..3a16872 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -122,7 +122,7 @@
/*
* Function declarations
*/
-void nfsd_export_init(void);
+int nfsd_export_init(void);
void nfsd_export_shutdown(void);
void nfsd_export_flush(void);
void exp_readlock(void);
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 604a0d7..8caf4c4 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -20,7 +20,6 @@
#include <linux/nfsd/debug.h>
#include <linux/nfsd/nfsfh.h>
#include <linux/nfsd/export.h>
-#include <linux/nfsd/auth.h>
#include <linux/nfsd/stats.h>
/*
* nfsd version
@@ -70,9 +69,9 @@
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp);
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
- const char *, int, struct svc_fh *);
+ const char *, unsigned int, struct svc_fh *);
__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
- const char *, int,
+ const char *, unsigned int,
struct svc_export **, struct dentry **);
__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *, int, time_t);
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
index 8bcddcc..4e43976 100644
--- a/include/linux/nfsd/syscall.h
+++ b/include/linux/nfsd/syscall.h
@@ -18,7 +18,6 @@
#include <linux/nfsd/const.h>
#include <linux/nfsd/export.h>
#include <linux/nfsd/nfsfh.h>
-#include <linux/nfsd/auth.h>
/*
* Version of the syscall interface
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
index 67885d5..a0132ef 100644
--- a/include/linux/nfsd/xdr.h
+++ b/include/linux/nfsd/xdr.h
@@ -23,7 +23,7 @@
struct nfsd_diropargs {
struct svc_fh fh;
char * name;
- int len;
+ unsigned int len;
};
struct nfsd_readargs {
@@ -43,17 +43,17 @@
struct nfsd_createargs {
struct svc_fh fh;
char * name;
- int len;
+ unsigned int len;
struct iattr attrs;
};
struct nfsd_renameargs {
struct svc_fh ffh;
char * fname;
- int flen;
+ unsigned int flen;
struct svc_fh tfh;
char * tname;
- int tlen;
+ unsigned int tlen;
};
struct nfsd_readlinkargs {
@@ -65,15 +65,15 @@
struct svc_fh ffh;
struct svc_fh tfh;
char * tname;
- int tlen;
+ unsigned int tlen;
};
struct nfsd_symlinkargs {
struct svc_fh ffh;
char * fname;
- int flen;
+ unsigned int flen;
char * tname;
- int tlen;
+ unsigned int tlen;
struct iattr attrs;
};
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index 89d9d60..421eddd 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -21,7 +21,7 @@
struct nfsd3_diropargs {
struct svc_fh fh;
char * name;
- int len;
+ unsigned int len;
};
struct nfsd3_accessargs {
@@ -48,7 +48,7 @@
struct nfsd3_createargs {
struct svc_fh fh;
char * name;
- int len;
+ unsigned int len;
int createmode;
struct iattr attrs;
__be32 * verf;
@@ -57,7 +57,7 @@
struct nfsd3_mknodargs {
struct svc_fh fh;
char * name;
- int len;
+ unsigned int len;
__u32 ftype;
__u32 major, minor;
struct iattr attrs;
@@ -66,10 +66,10 @@
struct nfsd3_renameargs {
struct svc_fh ffh;
char * fname;
- int flen;
+ unsigned int flen;
struct svc_fh tfh;
char * tname;
- int tlen;
+ unsigned int tlen;
};
struct nfsd3_readlinkargs {
@@ -81,15 +81,15 @@
struct svc_fh ffh;
struct svc_fh tfh;
char * tname;
- int tlen;
+ unsigned int tlen;
};
struct nfsd3_symlinkargs {
struct svc_fh ffh;
char * fname;
- int flen;
+ unsigned int flen;
char * tname;
- int tlen;
+ unsigned int tlen;
struct iattr attrs;
};
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index b0ddfb4..27bd3e3 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -441,7 +441,7 @@
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
struct dentry *dentry, __be32 *buffer, int *countp,
- u32 *bmval, struct svc_rqst *);
+ u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
struct nfsd4_compound_state *,
struct nfsd4_setclientid *setclid);
diff --git a/include/linux/nfsd_idmap.h b/include/linux/nfsd_idmap.h
index e82746f..d4a2ac1 100644
--- a/include/linux/nfsd_idmap.h
+++ b/include/linux/nfsd_idmap.h
@@ -44,11 +44,16 @@
#define IDMAP_NAMESZ 128
#ifdef CONFIG_NFSD_V4
-void nfsd_idmap_init(void);
+int nfsd_idmap_init(void);
void nfsd_idmap_shutdown(void);
#else
-static inline void nfsd_idmap_init(void) {};
-static inline void nfsd_idmap_shutdown(void) {};
+static inline int nfsd_idmap_init(void)
+{
+ return 0;
+}
+static inline void nfsd_idmap_shutdown(void)
+{
+}
#endif
int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 5dfbc68..f4df400 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -228,6 +228,8 @@
#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */
#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */
#define PM_POST_SUSPEND 0x0004 /* Suspend finished */
+#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */
+#define PM_POST_RESTORE 0x0006 /* Restore failed */
/* Console keyboard events.
* Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
diff --git a/include/linux/nubus.h b/include/linux/nubus.h
index cdb3e9b..c435507 100644
--- a/include/linux/nubus.h
+++ b/include/linux/nubus.h
@@ -132,10 +132,12 @@
NUBUS_DRHW_RDIUS_DCGX = 0x027C, /* Radius DirectColor/GX */
NUBUS_DRHW_RDIUS_PC8 = 0x0291, /* Radius PrecisionColor 8 */
NUBUS_DRHW_LAPIS_PCS8 = 0x0292, /* Lapis ProColorServer 8 */
- NUBUS_DRHW_RASTER_24LXI = 0x02A0, /* RasterOps 8/24 XLi */
+ NUBUS_DRHW_RASTER_24XLI = 0x02A0, /* RasterOps 8/24 XLi */
NUBUS_DRHW_RASTER_PBPGT = 0x02A5, /* RasterOps PaintBoard Prism GT */
NUBUS_DRHW_EMACH_FSX = 0x02AE, /* E-Machines Futura SX */
+ NUBUS_DRHW_RASTER_24XLTV = 0x02B7, /* RasterOps 24XLTV */
NUBUS_DRHW_SMAC_THUND24 = 0x02CB, /* SuperMac Thunder/24 */
+ NUBUS_DRHW_SMAC_THUNDLGHT = 0x03D9, /* SuperMac ThunderLight */
NUBUS_DRHW_RDIUS_PC24XP = 0x0406, /* Radius PrecisionColor 24Xp */
NUBUS_DRHW_RDIUS_PC24X = 0x040A, /* Radius PrecisionColor 24X */
NUBUS_DRHW_RDIUS_PC8XJ = 0x040B, /* Radius PrecisionColor 8XJ */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 209d3a4..bbad43fb 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -131,16 +131,52 @@
#define ClearPageReferenced(page) clear_bit(PG_referenced, &(page)->flags)
#define TestClearPageReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags)
-#define PageUptodate(page) test_bit(PG_uptodate, &(page)->flags)
+static inline int PageUptodate(struct page *page)
+{
+ int ret = test_bit(PG_uptodate, &(page)->flags);
+
+ /*
+ * Must ensure that the data we read out of the page is loaded
+ * _after_ we've loaded page->flags to check for PageUptodate.
+ * We can skip the barrier if the page is not uptodate, because
+ * we wouldn't be reading anything from it.
+ *
+ * See SetPageUptodate() for the other side of the story.
+ */
+ if (ret)
+ smp_rmb();
+
+ return ret;
+}
+
+static inline void __SetPageUptodate(struct page *page)
+{
+ smp_wmb();
+ __set_bit(PG_uptodate, &(page)->flags);
#ifdef CONFIG_S390
+ page_clear_dirty(page);
+#endif
+}
+
static inline void SetPageUptodate(struct page *page)
{
+#ifdef CONFIG_S390
if (!test_and_set_bit(PG_uptodate, &page->flags))
page_clear_dirty(page);
-}
#else
-#define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags)
+ /*
+ * Memory barrier must be issued before setting the PG_uptodate bit,
+ * so that all previous stores issued in order to bring the page
+ * uptodate are actually visible before PageUptodate becomes true.
+ *
+ * s390 doesn't need an explicit smp_wmb here because the test and
+ * set bit already provides full barriers.
+ */
+ smp_wmb();
+ set_bit(PG_uptodate, &(page)->flags);
#endif
+}
+
#define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags)
#define PageDirty(page) test_bit(PG_dirty, &(page)->flags)
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 936ef82..3ba2506 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -48,7 +48,15 @@
#ifdef CONFIG_ACPI
extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
-extern acpi_status pci_osc_support_set(u32 flags);
+extern acpi_status __pci_osc_support_set(u32 flags, const char *hid);
+static inline acpi_status pci_osc_support_set(u32 flags)
+{
+ return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING);
+}
+static inline acpi_status pcie_osc_support_set(u32 flags)
+{
+ return __pci_osc_support_set(flags, PCI_EXPRESS_ROOT_HID_STRING);
+}
#else
#if !defined(AE_ERROR)
typedef u32 acpi_status;
@@ -57,6 +65,7 @@
static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
{return AE_ERROR;}
static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;}
+static inline acpi_status pcie_osc_support_set(u32 flags) {return AE_ERROR;}
#endif
#endif /* _PCI_ACPI_H_ */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index ae10063..7215d3b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -28,7 +28,7 @@
* 7:3 = slot
* 2:0 = function
*/
-#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
@@ -66,7 +66,6 @@
#define PCI_DMA_FROMDEVICE 2
#define PCI_DMA_NONE 3
-#define DEVICE_COUNT_COMPATIBLE 4
#define DEVICE_COUNT_RESOURCE 12
typedef int __bitwise pci_power_t;
@@ -160,6 +159,8 @@
this if your device has broken DMA
or supports 64-bit transfers. */
+ struct device_dma_parameters dma_parms;
+
pci_power_t current_state; /* Current operating state. In ACPI-speak,
this is D0-D3, D0 being fully functional,
and D3 being off. */
@@ -167,10 +168,6 @@
pci_channel_state_t error_state; /* current connectivity state */
struct device dev; /* Generic device interface */
- /* device is compatible with these IDs */
- unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
- unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
-
int cfg_size; /* Size of configuration space */
/*
@@ -219,7 +216,7 @@
}
static inline struct pci_cap_saved_state *pci_find_saved_cap(
- struct pci_dev *pci_dev,char cap)
+ struct pci_dev *pci_dev, char cap)
{
struct pci_cap_saved_state *tmp;
struct hlist_node *pos;
@@ -278,13 +275,13 @@
unsigned short bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */
pci_bus_flags_t bus_flags; /* Inherited by child busses */
struct device *bridge;
- struct class_device class_dev;
+ struct device dev;
struct bin_attribute *legacy_io; /* legacy I/O for this bus */
struct bin_attribute *legacy_mem; /* legacy mem */
};
#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
-#define to_pci_bus(n) container_of(n, struct pci_bus, class_dev)
+#define to_pci_bus(n) container_of(n, struct pci_bus, dev)
/*
* Error values that may be returned by PCI functions.
@@ -314,8 +311,8 @@
extern struct pci_raw_ops *raw_pci_ops;
struct pci_bus_region {
- unsigned long start;
- unsigned long end;
+ resource_size_t start;
+ resource_size_t end;
};
struct pci_dynids {
@@ -351,11 +348,10 @@
};
/* PCI bus error event callbacks */
-struct pci_error_handlers
-{
+struct pci_error_handlers {
/* PCI bus error detected on this device */
pci_ers_result_t (*error_detected)(struct pci_dev *dev,
- enum pci_channel_state error);
+ enum pci_channel_state error);
/* MMIO has been re-enabled, but not DMA */
pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
@@ -390,7 +386,7 @@
struct pci_dynids dynids;
};
-#define to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
+#define to_pci_driver(drv) container_of(drv, struct pci_driver, driver)
/**
* PCI_DEVICE - macro used to describe a specific pci device
@@ -448,7 +444,7 @@
void pcibios_fixup_bus(struct pci_bus *);
int __must_check pcibios_enable_device(struct pci_dev *, int mask);
-char *pcibios_setup (char *str);
+char *pcibios_setup(char *str);
/* Used only when drivers/pci/setup.c is used */
void pcibios_align_resource(void *, struct resource *, resource_size_t,
@@ -459,8 +455,10 @@
extern struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(struct pci_bus *bus);
-struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
-static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
+struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata);
+static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
+ void *sysdata)
{
struct pci_bus *root_bus;
root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
@@ -468,15 +466,18 @@
pci_bus_add_devices(root_bus);
return root_bus;
}
-struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
-struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
+struct pci_bus *pci_create_bus(struct device *parent, int bus,
+ struct pci_ops *ops, void *sysdata);
+struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
+ int busnr);
int pci_scan_slot(struct pci_bus *bus, int devfn);
-struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
+struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
unsigned int pci_scan_child_bus(struct pci_bus *bus);
int __must_check pci_bus_add_device(struct pci_dev *dev);
void pci_read_bridge_bases(struct pci_bus *child);
-struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res);
+struct resource *pci_find_parent_resource(const struct pci_dev *dev,
+ struct resource *res);
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
extern void pci_dev_put(struct pci_dev *dev);
@@ -489,15 +490,19 @@
/* Generic PCI functions exported to card drivers */
#ifdef CONFIG_PCI_LEGACY
-struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
-struct pci_dev __deprecated *pci_find_slot (unsigned int bus, unsigned int devfn);
+struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
+ unsigned int device,
+ const struct pci_dev *from);
+struct pci_dev __deprecated *pci_find_slot(unsigned int bus,
+ unsigned int devfn);
#endif /* CONFIG_PCI_LEGACY */
-int pci_find_capability (struct pci_dev *dev, int cap);
-int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
-int pci_find_ext_capability (struct pci_dev *dev, int cap);
-int pci_find_ht_capability (struct pci_dev *dev, int ht_cap);
-int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap);
+int pci_find_capability(struct pci_dev *dev, int cap);
+int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
+int pci_find_ext_capability(struct pci_dev *dev, int cap);
+int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
+int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
+void pcie_wait_pending_transaction(struct pci_dev *dev);
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
@@ -505,49 +510,58 @@
struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device,
struct pci_dev *from);
-struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
+struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
struct pci_dev *from);
-struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn);
-struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn);
-struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from);
+struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
+struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn);
+struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
int pci_dev_present(const struct pci_device_id *ids);
const struct pci_device_id *pci_find_present(const struct pci_device_id *ids);
-int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
-int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
-int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
-int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val);
-int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 val);
-int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 val);
+int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn,
+ int where, u8 *val);
+int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn,
+ int where, u16 *val);
+int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn,
+ int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
+ int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, u32 val);
static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
{
- return pci_bus_read_config_byte (dev->bus, dev->devfn, where, val);
+ return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
}
static inline int pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
{
- return pci_bus_read_config_word (dev->bus, dev->devfn, where, val);
+ return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
}
-static inline int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val)
+static inline int pci_read_config_dword(struct pci_dev *dev, int where,
+ u32 *val)
{
- return pci_bus_read_config_dword (dev->bus, dev->devfn, where, val);
+ return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
}
static inline int pci_write_config_byte(struct pci_dev *dev, int where, u8 val)
{
- return pci_bus_write_config_byte (dev->bus, dev->devfn, where, val);
+ return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
}
static inline int pci_write_config_word(struct pci_dev *dev, int where, u16 val)
{
- return pci_bus_write_config_word (dev->bus, dev->devfn, where, val);
+ return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
}
-static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val)
+static inline int pci_write_config_dword(struct pci_dev *dev, int where,
+ u32 val)
{
- return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val);
+ return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
}
int __must_check pci_enable_device(struct pci_dev *dev);
-int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask);
+int __must_check pci_enable_device_io(struct pci_dev *dev);
+int __must_check pci_enable_device_mem(struct pci_dev *dev);
int __must_check pci_reenable_device(struct pci_dev *);
int __must_check pcim_enable_device(struct pci_dev *pdev);
void pcim_pin_device(struct pci_dev *pdev);
@@ -568,6 +582,8 @@
void pci_msi_off(struct pci_dev *dev);
int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
int pcix_get_max_mmrbc(struct pci_dev *dev);
int pcix_get_mmrbc(struct pci_dev *dev);
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
@@ -576,14 +592,11 @@
void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
-void pci_restore_bars(struct pci_dev *dev);
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
/* ROM control related routines */
void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
-void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size);
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
-void pci_remove_rom(struct pci_dev *pdev);
size_t pci_get_rom_size(void __iomem *rom, size_t size);
/* Power management related routines */
@@ -594,7 +607,7 @@
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
/* Functions for PCI Hotplug drivers to use */
-int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
+int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
void pci_bus_assign_resources(struct pci_bus *bus);
@@ -631,16 +644,18 @@
return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
-void pci_unregister_driver(struct pci_driver *);
-void pci_remove_behind_bridge(struct pci_dev *);
-struct pci_driver *pci_dev_driver(const struct pci_dev *);
-const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
-int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);
+void pci_unregister_driver(struct pci_driver *dev);
+void pci_remove_behind_bridge(struct pci_dev *dev);
+struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
+const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
+ struct pci_dev *dev);
+int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
+ int pass);
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
void *userdata);
int pci_cfg_space_size(struct pci_dev *dev);
-unsigned char pci_bus_max_busnr(struct pci_bus* bus);
+unsigned char pci_bus_max_busnr(struct pci_bus *bus);
/* kmem_cache style wrapper around pci_alloc_consistent() */
@@ -669,19 +684,36 @@
#ifndef CONFIG_PCI_MSI
-static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
-static inline void pci_disable_msi(struct pci_dev *dev) {}
-static inline int pci_enable_msix(struct pci_dev* dev,
- struct msix_entry *entries, int nvec) {return -1;}
-static inline void pci_disable_msix(struct pci_dev *dev) {}
-static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int pci_enable_msi(struct pci_dev *dev)
+{
+ return -1;
+}
+
+static inline void pci_disable_msi(struct pci_dev *dev)
+{ }
+
+static inline int pci_enable_msix(struct pci_dev *dev,
+ struct msix_entry *entries, int nvec)
+{
+ return -1;
+}
+
+static inline void pci_disable_msix(struct pci_dev *dev)
+{ }
+
+static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev)
+{ }
+
+static inline void pci_restore_msi_state(struct pci_dev *dev)
+{ }
#else
extern int pci_enable_msi(struct pci_dev *dev);
extern void pci_disable_msi(struct pci_dev *dev);
-extern int pci_enable_msix(struct pci_dev* dev,
+extern int pci_enable_msix(struct pci_dev *dev,
struct msix_entry *entries, int nvec);
extern void pci_disable_msix(struct pci_dev *dev);
extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern void pci_restore_msi_state(struct pci_dev *dev);
#endif
#ifdef CONFIG_HT_IRQ
@@ -702,7 +734,11 @@
extern int pci_domains_supported;
#else
enum { pci_domains_supported = 0 };
-static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+ return 0;
+}
+
static inline int pci_proc_domain(struct pci_bus *bus)
{
return 0;
@@ -716,67 +752,173 @@
* these as simple inline functions to avoid hair in drivers.
*/
-#define _PCI_NOP(o,s,t) \
- static inline int pci_##o##_config_##s (struct pci_dev *dev, int where, t val) \
+#define _PCI_NOP(o, s, t) \
+ static inline int pci_##o##_config_##s(struct pci_dev *dev, \
+ int where, t val) \
{ return PCIBIOS_FUNC_NOT_SUPPORTED; }
-#define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \
- _PCI_NOP(o,word,u16 x) \
- _PCI_NOP(o,dword,u32 x)
+
+#define _PCI_NOP_ALL(o, x) _PCI_NOP(o, byte, u8 x) \
+ _PCI_NOP(o, word, u16 x) \
+ _PCI_NOP(o, dword, u32 x)
_PCI_NOP_ALL(read, *)
_PCI_NOP_ALL(write,)
-static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{ return NULL; }
+static inline struct pci_dev *pci_find_device(unsigned int vendor,
+ unsigned int device,
+ const struct pci_dev *from)
+{
+ return NULL;
+}
-static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
-{ return NULL; }
+static inline struct pci_dev *pci_find_slot(unsigned int bus,
+ unsigned int devfn)
+{
+ return NULL;
+}
static inline struct pci_dev *pci_get_device(unsigned int vendor,
- unsigned int device, struct pci_dev *from)
-{ return NULL; }
+ unsigned int device,
+ struct pci_dev *from)
+{
+ return NULL;
+}
static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor,
- unsigned int device, struct pci_dev *from)
-{ return NULL; }
+ unsigned int device,
+ struct pci_dev *from)
+{
+ return NULL;
+}
-static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
-unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from)
-{ return NULL; }
+static inline struct pci_dev *pci_get_subsys(unsigned int vendor,
+ unsigned int device,
+ unsigned int ss_vendor,
+ unsigned int ss_device,
+ struct pci_dev *from)
+{
+ return NULL;
+}
-static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
-{ return NULL; }
+static inline struct pci_dev *pci_get_class(unsigned int class,
+ struct pci_dev *from)
+{
+ return NULL;
+}
#define pci_dev_present(ids) (0)
#define no_pci_devices() (1)
#define pci_find_present(ids) (NULL)
#define pci_dev_put(dev) do { } while (0)
-static inline void pci_set_master(struct pci_dev *dev) { }
-static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
-static inline void pci_disable_device(struct pci_dev *dev) { }
-static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
-static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
-static inline int __pci_register_driver(struct pci_driver *drv, struct module *owner) { return 0;}
-static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
-static inline void pci_unregister_driver(struct pci_driver *drv) { }
-static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
-static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; }
-static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
+static inline void pci_set_master(struct pci_dev *dev)
+{ }
+
+static inline int pci_enable_device(struct pci_dev *dev)
+{
+ return -EIO;
+}
+
+static inline void pci_disable_device(struct pci_dev *dev)
+{ }
+
+static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+ return -EIO;
+}
+
+static inline int pci_set_dma_max_seg_size(struct pci_dev *dev,
+ unsigned int size)
+{
+ return -EIO;
+}
+
+static inline int pci_set_dma_seg_boundary(struct pci_dev *dev,
+ unsigned long mask)
+{
+ return -EIO;
+}
+
+static inline int pci_assign_resource(struct pci_dev *dev, int i)
+{
+ return -EBUSY;
+}
+
+static inline int __pci_register_driver(struct pci_driver *drv,
+ struct module *owner)
+{
+ return 0;
+}
+
+static inline int pci_register_driver(struct pci_driver *drv)
+{
+ return 0;
+}
+
+static inline void pci_unregister_driver(struct pci_driver *drv)
+{ }
+
+static inline int pci_find_capability(struct pci_dev *dev, int cap)
+{
+ return 0;
+}
+
+static inline int pci_find_next_capability(struct pci_dev *dev, u8 post,
+ int cap)
+{
+ return 0;
+}
+
+static inline int pci_find_ext_capability(struct pci_dev *dev, int cap)
+{
+ return 0;
+}
+
+static inline void pcie_wait_pending_transaction(struct pci_dev *dev)
+{ }
/* Power management related routines */
-static inline int pci_save_state(struct pci_dev *dev) { return 0; }
-static inline int pci_restore_state(struct pci_dev *dev) { return 0; }
-static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { return 0; }
-static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
-static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
+static inline int pci_save_state(struct pci_dev *dev)
+{
+ return 0;
+}
-static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) { return -EIO; }
-static inline void pci_release_regions(struct pci_dev *dev) { }
+static inline int pci_restore_state(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+ return 0;
+}
+
+static inline pci_power_t pci_choose_state(struct pci_dev *dev,
+ pm_message_t state)
+{
+ return PCI_D0;
+}
+
+static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
+ int enable)
+{
+ return 0;
+}
+
+static inline int pci_request_regions(struct pci_dev *dev, const char *res_name)
+{
+ return -EIO;
+}
+
+static inline void pci_release_regions(struct pci_dev *dev)
+{ }
#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
-static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
-static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) { }
+static inline void pci_block_user_cfg_access(struct pci_dev *dev)
+{ }
+
+static inline void pci_unblock_user_cfg_access(struct pci_dev *dev)
+{ }
static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
{ return NULL; }
@@ -797,27 +939,27 @@
/* these helpers provide future and backwards compatibility
* for accessing popular PCI BAR info */
-#define pci_resource_start(dev,bar) ((dev)->resource[(bar)].start)
-#define pci_resource_end(dev,bar) ((dev)->resource[(bar)].end)
-#define pci_resource_flags(dev,bar) ((dev)->resource[(bar)].flags)
+#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
+#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end)
+#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags)
#define pci_resource_len(dev,bar) \
- ((pci_resource_start((dev),(bar)) == 0 && \
- pci_resource_end((dev),(bar)) == \
- pci_resource_start((dev),(bar))) ? 0 : \
- \
- (pci_resource_end((dev),(bar)) - \
- pci_resource_start((dev),(bar)) + 1))
+ ((pci_resource_start((dev), (bar)) == 0 && \
+ pci_resource_end((dev), (bar)) == \
+ pci_resource_start((dev), (bar))) ? 0 : \
+ \
+ (pci_resource_end((dev), (bar)) - \
+ pci_resource_start((dev), (bar)) + 1))
/* Similar to the helpers above, these manipulate per-pci_dev
* driver-specific data. They are really just a wrapper around
* the generic device structure functions of these calls.
*/
-static inline void *pci_get_drvdata (struct pci_dev *pdev)
+static inline void *pci_get_drvdata(struct pci_dev *pdev)
{
return dev_get_drvdata(&pdev->dev);
}
-static inline void pci_set_drvdata (struct pci_dev *pdev, void *data)
+static inline void pci_set_drvdata(struct pci_dev *pdev, void *data)
{
dev_set_drvdata(&pdev->dev, data);
}
@@ -836,7 +978,7 @@
*/
#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
- const struct resource *rsrc, resource_size_t *start,
+ const struct resource *rsrc, resource_size_t *start,
resource_size_t *end)
{
*start = rsrc->start;
@@ -888,9 +1030,9 @@
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
-void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
+void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
-void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
+void __iomem * const *pcim_iomap_table(struct pci_dev *pdev);
int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 41f6f28..df6dd79a 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1765,6 +1765,7 @@
#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020
#define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050
#define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060
+#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278
#define PCI_VENDOR_ID_SEALEVEL 0x135e
#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101
@@ -2043,6 +2044,23 @@
#define PCI_VENDOR_ID_QUICKNET 0x15e2
#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+#define PCI_VENDOR_ID_ADDIDATA_OLD 0x10E8
+#define PCI_VENDOR_ID_ADDIDATA 0x15B8
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500 0x7000
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420 0x7001
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300 0x7002
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800 0x818E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2 0x7009
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2 0x700A
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2 0x700B
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3 0x700C
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F
+
#define PCI_VENDOR_ID_PDC 0x15e9
#define PCI_VENDOR_ID_FARSITE 0x1619
diff --git a/include/linux/pda_power.h b/include/linux/pda_power.h
index 1375f15..225beb1 100644
--- a/include/linux/pda_power.h
+++ b/include/linux/pda_power.h
@@ -26,6 +26,7 @@
unsigned int wait_for_status; /* msecs, default is 500 */
unsigned int wait_for_charger; /* msecs, default is 500 */
+ unsigned int polling_interval; /* msecs, default is 2000 */
};
#endif /* __PDA_POWER_H__ */
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 50faa0e..1ac9697 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -54,7 +54,7 @@
#ifdef CONFIG_SMP
struct percpu_data {
- void *ptrs[NR_CPUS];
+ void *ptrs[1];
};
#define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 554836e..5e43ae7 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -88,7 +88,7 @@
/* A lock to ensure that only one thing can read/write
* the MDIO bus at a time */
- spinlock_t mdio_lock;
+ struct mutex mdio_lock;
struct device *dev;
@@ -284,10 +284,11 @@
/* Interrupt and Polling infrastructure */
struct work_struct phy_queue;
+ struct work_struct state_queue;
struct timer_list phy_timer;
atomic_t irq_disable;
- spinlock_t lock;
+ struct mutex lock;
struct net_device *attached_dev;
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 1c1dba9..28dfc61c 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -348,6 +348,7 @@
FLOW_KEY_RTCLASSID,
FLOW_KEY_SKUID,
FLOW_KEY_SKGID,
+ FLOW_KEY_VLAN_TAG,
__FLOW_KEY_MAX,
};
@@ -459,7 +460,8 @@
#define TCF_EM_U32 3
#define TCF_EM_META 4
#define TCF_EM_TEXT 5
-#define TCF_EM_MAX 5
+#define TCF_EM_VLAN 6
+#define TCF_EM_MAX 6
enum
{
diff --git a/include/linux/pm.h b/include/linux/pm.h
index b78e029..eccf59e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -95,7 +95,7 @@
};
/* Functions above this comment are list-based old-style power
- * managment. Please avoid using them. */
+ * management. Please avoid using them. */
/*
* Callbacks for platform drivers to implement.
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
new file mode 100644
index 0000000..2e4e97b
--- /dev/null
+++ b/include/linux/pm_qos_params.h
@@ -0,0 +1,25 @@
+/* interface for the pm_qos_power infrastructure of the linux kernel.
+ *
+ * Mark Gross
+ */
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/miscdevice.h>
+
+#define PM_QOS_RESERVED 0
+#define PM_QOS_CPU_DMA_LATENCY 1
+#define PM_QOS_NETWORK_LATENCY 2
+#define PM_QOS_NETWORK_THROUGHPUT 3
+
+#define PM_QOS_NUM_CLASSES 4
+#define PM_QOS_DEFAULT_VALUE -1
+
+int pm_qos_add_requirement(int qos, char *name, s32 value);
+int pm_qos_update_requirement(int qos, char *name, s32 new_value);
+void pm_qos_remove_requirement(int qos, char *name);
+
+int pm_qos_requirement(int qos);
+
+int pm_qos_add_notifier(int qos, struct notifier_block *notifier);
+int pm_qos_remove_notifier(int qos, struct notifier_block *notifier);
+
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 2a6d62c..cd6332b 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -126,7 +126,7 @@
};
/*
- * Device Managemnt
+ * Device Management
*/
struct pnp_card {
@@ -258,6 +258,7 @@
#else
#define pnp_device_is_isapnp(dev) 0
#endif
+extern struct mutex pnp_res_mutex;
#ifdef CONFIG_PNPBIOS
extern struct pnp_protocol pnpbios_protocol;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 606c095..68ed19c 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -54,15 +54,7 @@
POWER_SUPPLY_TECHNOLOGY_LIPO,
POWER_SUPPLY_TECHNOLOGY_LiFe,
POWER_SUPPLY_TECHNOLOGY_NiCd,
-};
-
-enum {
- POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
- POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
- POWER_SUPPLY_CAPACITY_LEVEL_LOW,
- POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
- POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
- POWER_SUPPLY_CAPACITY_LEVEL_FULL,
+ POWER_SUPPLY_TECHNOLOGY_LiMn,
};
enum power_supply_property {
@@ -72,6 +64,8 @@
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -91,7 +85,6 @@
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_ENERGY_AVG,
POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
- POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
@@ -101,6 +94,7 @@
/* Properties of type `const char *' */
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
enum power_supply_type {
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index e2eff90..3800639 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -63,4 +63,8 @@
#define PR_GET_SECCOMP 21
#define PR_SET_SECCOMP 22
+/* Get/set the capability bounding set */
+#define PR_CAPBSET_READ 23
+#define PR_CAPBSET_DROP 24
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 8f92546..e435515 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -19,6 +19,8 @@
*/
#define FIRST_PROCESS_ENTRY 256
+/* Worst case buffer size needed for holding an integer. */
+#define PROC_NUMBUF 13
/*
* We always define these enumerators
@@ -117,7 +119,6 @@
unsigned long task_vsize(struct mm_struct *);
int task_statm(struct mm_struct *, int *, int *, int *, int *);
char *task_mem(struct mm_struct *, char *);
-void clear_refs_smap(struct mm_struct *mm);
struct proc_dir_entry *de_get(struct proc_dir_entry *de);
void de_put(struct proc_dir_entry *de);
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 515bff0..6ab8071 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -204,6 +204,41 @@
}
#endif /* arch_has_block_step */
+#ifndef arch_ptrace_stop_needed
+/**
+ * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called
+ * @code: current->exit_code value ptrace will stop with
+ * @info: siginfo_t pointer (or %NULL) for signal ptrace will stop with
+ *
+ * This is called with the siglock held, to decide whether or not it's
+ * necessary to release the siglock and call arch_ptrace_stop() with the
+ * same @code and @info arguments. It can be defined to a constant if
+ * arch_ptrace_stop() is never required, or always is. On machines where
+ * this makes sense, it should be defined to a quick test to optimize out
+ * calling arch_ptrace_stop() when it would be superfluous. For example,
+ * if the thread has not been back to user mode since the last stop, the
+ * thread state might indicate that nothing needs to be done.
+ */
+#define arch_ptrace_stop_needed(code, info) (0)
+#endif
+
+#ifndef arch_ptrace_stop
+/**
+ * arch_ptrace_stop - Do machine-specific work before stopping for ptrace
+ * @code: current->exit_code value ptrace will stop with
+ * @info: siginfo_t pointer (or %NULL) for signal ptrace will stop with
+ *
+ * This is called with no locks held when arch_ptrace_stop_needed() has
+ * just returned nonzero. It is allowed to block, e.g. for user memory
+ * access. The arch can have machine-specific work to be done before
+ * ptrace stops. On ia64, register backing store gets written back to user
+ * memory here. Since this can be costly (requires dropping the siglock),
+ * we only do it when the arch requires it for this particular stop, as
+ * indicated by arch_ptrace_stop_needed().
+ */
+#define arch_ptrace_stop(code, info) do { } while (0)
+#endif
+
#endif
#endif
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index b6116b4..b8ce2b4 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -91,7 +91,7 @@
*
* For API usage, in general,
* - any function _modifying_ the tree or tags (inserting or deleting
- * items, setting or clearing tags must exclude other modifications, and
+ * items, setting or clearing tags) must exclude other modifications, and
* exclude any functions reading the tree.
* - any function _reading_ the tree or tags (looking up items or tags,
* gang lookups) must exclude modifications to the tree, but may occur
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index 306a1d1a..e51b531 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -244,6 +244,8 @@
*/
unsigned long daemon_lastrun; /* jiffies of last run */
unsigned long daemon_sleep; /* how many seconds between updates? */
+ unsigned long last_end_sync; /* when we lasted called end_sync to
+ * update bitmap with resync progress */
atomic_t pending_writes; /* pending writes to the bitmap file */
wait_queue_head_t write_wait;
@@ -275,6 +277,7 @@
int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded);
void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted);
void bitmap_close_sync(struct bitmap *bitmap);
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
void bitmap_unplug(struct bitmap *bitmap);
void bitmap_daemon_work(struct bitmap *bitmap);
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index dcb7292..85a068b 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -81,6 +81,8 @@
#define In_sync 2 /* device is in_sync with rest of array */
#define WriteMostly 4 /* Avoid reading if at all possible */
#define BarriersNotsupp 5 /* BIO_RW_BARRIER is not supported */
+#define AllReserved 6 /* If whole device is reserved for
+ * one array */
int desc_nr; /* descriptor index in the superblock */
int raid_disk; /* role of device in array */
@@ -130,6 +132,9 @@
minor_version,
patch_version;
int persistent;
+ int external; /* metadata is
+ * managed externally */
+ char metadata_type[17]; /* externally set*/
int chunk_size;
time_t ctime, utime;
int level, layout;
@@ -216,6 +221,8 @@
atomic_t recovery_active; /* blocks scheduled, but not written */
wait_queue_head_t recovery_wait;
sector_t recovery_cp;
+ sector_t resync_max; /* resync should pause
+ * when it gets here */
spinlock_t write_lock;
wait_queue_head_t sb_wait; /* for waiting on superblock updates */
@@ -306,23 +313,17 @@
* iterates through some rdev ringlist. It's safe to remove the
* current 'rdev'. Dont touch 'tmp' though.
*/
-#define ITERATE_RDEV_GENERIC(head,rdev,tmp) \
+#define rdev_for_each_list(rdev, tmp, list) \
\
- for ((tmp) = (head).next; \
+ for ((tmp) = (list).next; \
(rdev) = (list_entry((tmp), mdk_rdev_t, same_set)), \
- (tmp) = (tmp)->next, (tmp)->prev != &(head) \
+ (tmp) = (tmp)->next, (tmp)->prev != &(list) \
; )
/*
* iterates through the 'same array disks' ringlist
*/
-#define ITERATE_RDEV(mddev,rdev,tmp) \
- ITERATE_RDEV_GENERIC((mddev)->disks,rdev,tmp)
-
-/*
- * Iterates through 'pending RAID disks'
- */
-#define ITERATE_RDEV_PENDING(rdev,tmp) \
- ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp)
+#define rdev_for_each(rdev, tmp, mddev) \
+ rdev_for_each_list(rdev, tmp, (mddev)->disks)
typedef struct mdk_thread_s {
void (*run) (mddev_t *mddev);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index d32c14d..37a642c 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -174,10 +174,13 @@
* code.
*/
-#define rcu_assign_pointer(p, v) ({ \
- smp_wmb(); \
- (p) = (v); \
- })
+#define rcu_assign_pointer(p, v) \
+ ({ \
+ if (!__builtin_constant_p(v) || \
+ ((v) != NULL)) \
+ smp_wmb(); \
+ (p) = (v); \
+ })
/**
* synchronize_sched - block until all CPUs have exited any non-preemptive
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 85ea63f..b93b541 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -59,8 +59,6 @@
* Architecture independent implemenations of sys_reboot commands.
*/
-extern void kernel_shutdown_prepare(enum system_states state);
-
extern void kernel_restart(char *cmd);
extern void kernel_halt(void);
extern void kernel_power_off(void);
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 10fa0c8..db5ef9b 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -185,7 +185,7 @@
unsigned long j_trans_id;
unsigned long j_mount_id;
unsigned long j_start; /* start of current waiting commit (index into j_ap_blocks) */
- unsigned long j_len; /* lenght of current waiting commit */
+ unsigned long j_len; /* length of current waiting commit */
unsigned long j_len_alloc; /* number of buffers requested by journal_begin() */
atomic_t j_wcount; /* count of writers for current commit */
unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index b014f6b..b9e1740 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -602,24 +602,12 @@
#include <linux/mutex.h>
-extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size);
static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
{
int len = strlen(str) + 1;
return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
}
-extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
-extern int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
- struct rtattr *rta, int len);
-
-#define rtattr_parse_nested(tb, max, rta) \
- rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta)))
-
-#define rtattr_parse_nested_compat(tb, max, rta, data, len) \
-({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
- __rtattr_parse_nested_compat(tb, max, rta, len); })
-
extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index af6947e..7c8ca05 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -555,6 +555,13 @@
#define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */
#define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */
+/* If true, all threads except ->group_exit_task have pending SIGKILL */
+static inline int signal_group_exit(const struct signal_struct *sig)
+{
+ return (sig->flags & SIGNAL_GROUP_EXIT) ||
+ (sig->group_exit_task != NULL);
+}
+
/*
* Some day this will be a full-fledged user tracking system..
*/
@@ -803,7 +810,7 @@
struct io_context; /* See blkdev.h */
#define NGROUPS_SMALL 32
-#define NGROUPS_PER_BLOCK ((int)(PAGE_SIZE / sizeof(gid_t)))
+#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
struct group_info {
int ngroups;
atomic_t usage;
@@ -1091,7 +1098,7 @@
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
struct group_info *group_info;
- kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
+ kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset;
unsigned keep_capabilities:1;
struct user_struct *user;
#ifdef CONFIG_KEYS
@@ -1770,7 +1777,7 @@
struct task_struct *fork_idle(int);
extern void set_task_comm(struct task_struct *tsk, char *from);
-extern void get_task_comm(char *to, struct task_struct *tsk);
+extern char *get_task_comm(char *to, struct task_struct *tsk);
#ifdef CONFIG_SMP
extern void wait_task_inactive(struct task_struct * p);
@@ -2080,6 +2087,10 @@
}
#endif
+#ifndef TASK_SIZE_OF
+#define TASK_SIZE_OF(tsk) TASK_SIZE
+#endif
+
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/security.h b/include/linux/security.h
index d249742..fe52cde 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -40,11 +40,6 @@
#define ROOTCONTEXT_MNT 0x04
#define DEFCONTEXT_MNT 0x08
-/*
- * Bounding set
- */
-extern kernel_cap_t cap_bset;
-
extern unsigned securebits;
struct ctl_table;
@@ -423,15 +418,12 @@
* identified by @name for @dentry.
* Return 0 if permission is granted.
* @inode_getsecurity:
- * Copy the extended attribute representation of the security label
- * associated with @name for @inode into @buffer. @buffer may be
- * NULL to request the size of the buffer required. @size indicates
- * the size of @buffer in bytes. Note that @name is the remainder
- * of the attribute name after the security. prefix has been removed.
- * @err is the return value from the preceding fs getxattr call,
- * and can be used by the security module to determine whether it
- * should try and canonicalize the attribute value.
- * Return number of bytes used/required on success.
+ * Retrieve a copy of the extended attribute representation of the
+ * security label associated with @name for @inode via @buffer. Note that
+ * @name is the remainder of the attribute name after the security prefix
+ * has been removed. @alloc is used to specify of the call should return a
+ * value via the buffer or just the value length Return size of buffer on
+ * success.
* @inode_setsecurity:
* Set the security label associated with @name for @inode from the
* extended attribute value @value. @size indicates the size of the
@@ -1304,7 +1296,7 @@
int (*inode_removexattr) (struct dentry *dentry, char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
- int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
+ int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1565,7 +1557,7 @@
int security_inode_removexattr(struct dentry *dentry, char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
-int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
+int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
int security_file_permission(struct file *file, int mask);
@@ -1967,7 +1959,7 @@
return cap_inode_killpriv(dentry);
}
-static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index afe0f6d..00b65c0a 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -23,6 +23,7 @@
resource_size_t mapbase; /* resource base */
unsigned int irq; /* interrupt number */
unsigned int uartclk; /* UART clock rate */
+ void *private_data;
unsigned char regshift; /* register shift */
unsigned char iotype; /* UPIO_* */
unsigned char hub6;
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 0ae3388..7e09514 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -371,6 +371,8 @@
(!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
(t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
+void signals_init(void);
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SIGNAL_H */
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
index 86f9b1ef..ea037f2 100644
--- a/include/linux/signalfd.h
+++ b/include/linux/signalfd.h
@@ -29,7 +29,7 @@
/*
* Pad strcture to 128 bytes. Remember to update the
- * pad size when you add new memebers. We use a fixed
+ * pad size when you add new members. We use a fixed
* size structure to avoid compatibility problems with
* future versions, and we leave extra space for additional
* members. We use fixed size members because this strcture
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index dfe975a..412672a7 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1810,5 +1810,6 @@
skb->ip_summed = CHECKSUM_NONE;
}
+bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
#endif /* __KERNEL__ */
#endif /* _LINUX_SKBUFF_H */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 40801e7..ddb1a70 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -12,11 +12,11 @@
#include <linux/kobject.h>
struct kmem_cache_cpu {
- void **freelist;
- struct page *page;
- int node;
- unsigned int offset;
- unsigned int objsize;
+ void **freelist; /* Pointer to first free per cpu object */
+ struct page *page; /* The slab from which we are allocating */
+ int node; /* The node of the page (or -1 for debug) */
+ unsigned int offset; /* Freepointer offset (in word units) */
+ unsigned int objsize; /* Size of an object (from kmem_cache) */
};
struct kmem_cache_node {
@@ -59,7 +59,10 @@
#endif
#ifdef CONFIG_NUMA
- int defrag_ratio;
+ /*
+ * Defragmentation by allocating from a remote node.
+ */
+ int remote_node_defrag_ratio;
struct kmem_cache_node *node[MAX_NUMNODES];
#endif
#ifdef CONFIG_SMP
diff --git a/include/linux/sm501-regs.h b/include/linux/sm501-regs.h
index df7620d..64236b7 100644
--- a/include/linux/sm501-regs.h
+++ b/include/linux/sm501-regs.h
@@ -171,7 +171,7 @@
/* USB slave/gadget data port base */
#define SM501_USB_GADGET_DATA (0x070000)
-/* Display contoller/video engine base */
+/* Display controller/video engine base */
#define SM501_DC (0x080000)
/* common defines for the SM501 address registers */
diff --git a/include/linux/sm501.h b/include/linux/sm501.h
index 9e3aaad..932a9ef 100644
--- a/include/linux/sm501.h
+++ b/include/linux/sm501.h
@@ -70,6 +70,8 @@
#define SM501FB_FLAG_DISABLE_AT_EXIT (1<<1)
#define SM501FB_FLAG_USE_HWCURSOR (1<<2)
#define SM501FB_FLAG_USE_HWACCEL (1<<3)
+#define SM501FB_FLAG_PANEL_USE_FPEN (1<<4)
+#define SM501FB_FLAG_PANEL_USE_VBIASEN (1<<5)
struct sm501_platdata_fbsub {
struct fb_videomode *def_mode;
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index 40c7b5d..f41ffd7 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -101,6 +101,8 @@
#define SONYPI_EVENT_FNKEY_RELEASED 59
#define SONYPI_EVENT_WIRELESS_ON 60
#define SONYPI_EVENT_WIRELESS_OFF 61
+#define SONYPI_EVENT_ZOOM_IN_PRESSED 62
+#define SONYPI_EVENT_ZOOM_OUT_PRESSED 63
/* get/set brightness */
#define SONYPI_IOCGBRT _IOR('v', 0, __u8)
diff --git a/include/linux/spi/mcp23s08.h b/include/linux/spi/mcp23s08.h
new file mode 100644
index 0000000..835ddf4
--- /dev/null
+++ b/include/linux/spi/mcp23s08.h
@@ -0,0 +1,24 @@
+
+/* FIXME driver should be able to handle all four slaves that
+ * can be hooked up to each chipselect, as well as IRQs...
+ */
+
+struct mcp23s08_platform_data {
+ /* four slaves can share one SPI chipselect */
+ u8 slave;
+
+ /* number assigned to the first GPIO */
+ unsigned base;
+
+ /* pins with pullups */
+ u8 pullups;
+
+ void *context; /* param to setup/teardown */
+
+ int (*setup)(struct spi_device *spi,
+ int gpio, unsigned ngpio,
+ void *context);
+ int (*teardown)(struct spi_device *spi,
+ int gpio, unsigned ngpio,
+ void *context);
+};
diff --git a/include/linux/spinlock_api_up.h b/include/linux/spinlock_api_up.h
index 67faa04..04e1d31 100644
--- a/include/linux/spinlock_api_up.h
+++ b/include/linux/spinlock_api_up.h
@@ -21,7 +21,7 @@
/*
* In the UP-nondebug case there's no real locking going on, so the
* only thing we have to do is to keep the preempt counts and irq
- * flags straight, to supress compiler warnings of unused lock
+ * flags straight, to suppress compiler warnings of unused lock
* variables, and to add the proper checker annotations:
*/
#define __LOCK(lock) \
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index e18f5c2..9d5da8b 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -373,6 +373,15 @@
if (sdev->bus->bustype == SSB_BUSTYPE_PCI)
pci_set_power_state(sdev->bus->host_pci, state);
}
+#else
+static inline void ssb_pcihost_unregister(struct pci_driver *driver)
+{
+}
+
+static inline
+void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
+{
+}
#endif /* CONFIG_SSB_PCIHOST */
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index bd7a6b0..03547d6 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -169,8 +169,8 @@
extern void cache_flush(void);
extern void cache_purge(struct cache_detail *detail);
#define NEVER (0x7FFFFFFF)
-extern void cache_register(struct cache_detail *cd);
-extern int cache_unregister(struct cache_detail *cd);
+extern int cache_register(struct cache_detail *cd);
+extern void cache_unregister(struct cache_detail *cd);
extern void qword_add(char **bpp, int *lp, char *str);
extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index 3912cf1..10709cbe 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -20,7 +20,7 @@
#define RPCDBG_BIND 0x0020
#define RPCDBG_SCHED 0x0040
#define RPCDBG_TRANS 0x0080
-#define RPCDBG_SVCSOCK 0x0100
+#define RPCDBG_SVCXPRT 0x0100
#define RPCDBG_SVCDSP 0x0200
#define RPCDBG_MISC 0x0400
#define RPCDBG_CACHE 0x0800
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 8531a70..64c7710 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -204,7 +204,7 @@
struct svc_rqst {
struct list_head rq_list; /* idle list */
struct list_head rq_all; /* all threads list */
- struct svc_sock * rq_sock; /* socket */
+ struct svc_xprt * rq_xprt; /* transport ptr */
struct sockaddr_storage rq_addr; /* peer address */
size_t rq_addrlen;
@@ -214,9 +214,10 @@
struct auth_ops * rq_authop; /* authentication flavour */
u32 rq_flavor; /* pseudoflavor */
struct svc_cred rq_cred; /* auth info */
- struct sk_buff * rq_skbuff; /* fast recv inet buffer */
+ void * rq_xprt_ctxt; /* transport specific context ptr */
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
+ size_t rq_xprt_hlen; /* xprt header len */
struct xdr_buf rq_arg;
struct xdr_buf rq_res;
struct page * rq_pages[RPCSVC_MAXPAGES];
@@ -317,11 +318,12 @@
struct svc_deferred_req {
u32 prot; /* protocol (UDP or TCP) */
- struct svc_sock *svsk;
+ struct svc_xprt *xprt;
struct sockaddr_storage addr; /* where reply must go */
size_t addrlen;
union svc_addr_u daddr; /* where reply must come from */
struct cache_deferred_req handle;
+ size_t xprt_hlen;
int argslen;
__be32 args[0];
};
@@ -382,6 +384,8 @@
*/
struct svc_serv * svc_create(struct svc_program *, unsigned int,
void (*shutdown)(struct svc_serv*));
+struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
+ struct svc_pool *pool);
int svc_create_thread(svc_thread_fn, struct svc_serv *);
void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
new file mode 100644
index 0000000..c11bbcc
--- /dev/null
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#ifndef SVC_RDMA_H
+#define SVC_RDMA_H
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#define SVCRDMA_DEBUG
+
+/* RPC/RDMA parameters and stats */
+extern unsigned int svcrdma_ord;
+extern unsigned int svcrdma_max_requests;
+extern unsigned int svcrdma_max_req_size;
+
+extern atomic_t rdma_stat_recv;
+extern atomic_t rdma_stat_read;
+extern atomic_t rdma_stat_write;
+extern atomic_t rdma_stat_sq_starve;
+extern atomic_t rdma_stat_rq_starve;
+extern atomic_t rdma_stat_rq_poll;
+extern atomic_t rdma_stat_rq_prod;
+extern atomic_t rdma_stat_sq_poll;
+extern atomic_t rdma_stat_sq_prod;
+
+#define RPCRDMA_VERSION 1
+
+/*
+ * Contexts are built when an RDMA request is created and are a
+ * record of the resources that can be recovered when the request
+ * completes.
+ */
+struct svc_rdma_op_ctxt {
+ struct svc_rdma_op_ctxt *next;
+ struct xdr_buf arg;
+ struct list_head dto_q;
+ enum ib_wr_opcode wr_op;
+ enum ib_wc_status wc_status;
+ u32 byte_len;
+ struct svcxprt_rdma *xprt;
+ unsigned long flags;
+ enum dma_data_direction direction;
+ int count;
+ struct ib_sge sge[RPCSVC_MAXPAGES];
+ struct page *pages[RPCSVC_MAXPAGES];
+};
+
+#define RDMACTXT_F_READ_DONE 1
+#define RDMACTXT_F_LAST_CTXT 2
+
+struct svcxprt_rdma {
+ struct svc_xprt sc_xprt; /* SVC transport structure */
+ struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
+ struct list_head sc_accept_q; /* Conn. waiting accept */
+ int sc_ord; /* RDMA read limit */
+ wait_queue_head_t sc_read_wait;
+ int sc_max_sge;
+
+ int sc_sq_depth; /* Depth of SQ */
+ atomic_t sc_sq_count; /* Number of SQ WR on queue */
+
+ int sc_max_requests; /* Depth of RQ */
+ int sc_max_req_size; /* Size of each RQ WR buf */
+
+ struct ib_pd *sc_pd;
+
+ struct svc_rdma_op_ctxt *sc_ctxt_head;
+ int sc_ctxt_cnt;
+ int sc_ctxt_bump;
+ int sc_ctxt_max;
+ spinlock_t sc_ctxt_lock;
+ struct list_head sc_rq_dto_q;
+ spinlock_t sc_rq_dto_lock;
+ struct ib_qp *sc_qp;
+ struct ib_cq *sc_rq_cq;
+ struct ib_cq *sc_sq_cq;
+ struct ib_mr *sc_phys_mr; /* MR for server memory */
+
+ spinlock_t sc_lock; /* transport lock */
+
+ wait_queue_head_t sc_send_wait; /* SQ exhaustion waitlist */
+ unsigned long sc_flags;
+ struct list_head sc_dto_q; /* DTO tasklet I/O pending Q */
+ struct list_head sc_read_complete_q;
+ spinlock_t sc_read_complete_lock;
+};
+/* sc_flags */
+#define RDMAXPRT_RQ_PENDING 1
+#define RDMAXPRT_SQ_PENDING 2
+#define RDMAXPRT_CONN_PENDING 3
+
+#define RPCRDMA_LISTEN_BACKLOG 10
+/* The default ORD value is based on two outstanding full-size writes with a
+ * page size of 4k, or 32k * 2 ops / 4k = 16 outstanding RDMA_READ. */
+#define RPCRDMA_ORD (64/4)
+#define RPCRDMA_SQ_DEPTH_MULT 8
+#define RPCRDMA_MAX_THREADS 16
+#define RPCRDMA_MAX_REQUESTS 16
+#define RPCRDMA_MAX_REQ_SIZE 4096
+
+/* svc_rdma_marshal.c */
+extern void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *,
+ int *, int *);
+extern int svc_rdma_xdr_decode_req(struct rpcrdma_msg **, struct svc_rqst *);
+extern int svc_rdma_xdr_decode_deferred_req(struct svc_rqst *);
+extern int svc_rdma_xdr_encode_error(struct svcxprt_rdma *,
+ struct rpcrdma_msg *,
+ enum rpcrdma_errcode, u32 *);
+extern void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *, int);
+extern void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *, int);
+extern void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *, int,
+ u32, u64, u32);
+extern void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *,
+ struct rpcrdma_msg *,
+ struct rpcrdma_msg *,
+ enum rpcrdma_proc);
+extern int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *);
+
+/* svc_rdma_recvfrom.c */
+extern int svc_rdma_recvfrom(struct svc_rqst *);
+
+/* svc_rdma_sendto.c */
+extern int svc_rdma_sendto(struct svc_rqst *);
+
+/* svc_rdma_transport.c */
+extern int svc_rdma_send(struct svcxprt_rdma *, struct ib_send_wr *);
+extern int svc_rdma_send_error(struct svcxprt_rdma *, struct rpcrdma_msg *,
+ enum rpcrdma_errcode);
+struct page *svc_rdma_get_page(void);
+extern int svc_rdma_post_recv(struct svcxprt_rdma *);
+extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
+extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
+extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
+extern void svc_sq_reap(struct svcxprt_rdma *);
+extern void svc_rq_reap(struct svcxprt_rdma *);
+extern struct svc_xprt_class svc_rdma_class;
+extern void svc_rdma_prep_reply_hdr(struct svc_rqst *);
+
+/* svc_rdma.c */
+extern int svc_rdma_init(void);
+extern void svc_rdma_cleanup(void);
+
+/*
+ * Returns the address of the first read chunk or <nul> if no read chunk is
+ * present
+ */
+static inline struct rpcrdma_read_chunk *
+svc_rdma_get_read_chunk(struct rpcrdma_msg *rmsgp)
+{
+ struct rpcrdma_read_chunk *ch =
+ (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+
+ if (ch->rc_discrim == 0)
+ return NULL;
+
+ return ch;
+}
+
+/*
+ * Returns the address of the first read write array element or <nul> if no
+ * write array list is present
+ */
+static inline struct rpcrdma_write_array *
+svc_rdma_get_write_array(struct rpcrdma_msg *rmsgp)
+{
+ if (rmsgp->rm_body.rm_chunks[0] != 0
+ || rmsgp->rm_body.rm_chunks[1] == 0)
+ return NULL;
+
+ return (struct rpcrdma_write_array *)&rmsgp->rm_body.rm_chunks[1];
+}
+
+/*
+ * Returns the address of the first reply array element or <nul> if no
+ * reply array is present
+ */
+static inline struct rpcrdma_write_array *
+svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp)
+{
+ struct rpcrdma_read_chunk *rch;
+ struct rpcrdma_write_array *wr_ary;
+ struct rpcrdma_write_array *rp_ary;
+
+ /* XXX: Need to fix when reply list may occur with read-list and/or
+ * write list */
+ if (rmsgp->rm_body.rm_chunks[0] != 0 ||
+ rmsgp->rm_body.rm_chunks[1] != 0)
+ return NULL;
+
+ rch = svc_rdma_get_read_chunk(rmsgp);
+ if (rch) {
+ while (rch->rc_discrim)
+ rch++;
+
+ /* The reply list follows an empty write array located
+ * at 'rc_position' here. The reply array is at rc_target.
+ */
+ rp_ary = (struct rpcrdma_write_array *)&rch->rc_target;
+
+ goto found_it;
+ }
+
+ wr_ary = svc_rdma_get_write_array(rmsgp);
+ if (wr_ary) {
+ rp_ary = (struct rpcrdma_write_array *)
+ &wr_ary->
+ wc_array[wr_ary->wc_nchunks].wc_target.rs_length;
+
+ goto found_it;
+ }
+
+ /* No read list, no write list */
+ rp_ary = (struct rpcrdma_write_array *)
+ &rmsgp->rm_body.rm_chunks[2];
+
+ found_it:
+ if (rp_ary->wc_discrim == 0)
+ return NULL;
+
+ return rp_ary;
+}
+#endif
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
new file mode 100644
index 0000000..6fd7b01
--- /dev/null
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -0,0 +1,159 @@
+/*
+ * linux/include/linux/sunrpc/svc_xprt.h
+ *
+ * RPC server transport I/O
+ */
+
+#ifndef SUNRPC_SVC_XPRT_H
+#define SUNRPC_SVC_XPRT_H
+
+#include <linux/sunrpc/svc.h>
+#include <linux/module.h>
+
+struct svc_xprt_ops {
+ struct svc_xprt *(*xpo_create)(struct svc_serv *,
+ struct sockaddr *, int,
+ int);
+ struct svc_xprt *(*xpo_accept)(struct svc_xprt *);
+ int (*xpo_has_wspace)(struct svc_xprt *);
+ int (*xpo_recvfrom)(struct svc_rqst *);
+ void (*xpo_prep_reply_hdr)(struct svc_rqst *);
+ int (*xpo_sendto)(struct svc_rqst *);
+ void (*xpo_release_rqst)(struct svc_rqst *);
+ void (*xpo_detach)(struct svc_xprt *);
+ void (*xpo_free)(struct svc_xprt *);
+};
+
+struct svc_xprt_class {
+ const char *xcl_name;
+ struct module *xcl_owner;
+ struct svc_xprt_ops *xcl_ops;
+ struct list_head xcl_list;
+ u32 xcl_max_payload;
+};
+
+struct svc_xprt {
+ struct svc_xprt_class *xpt_class;
+ struct svc_xprt_ops *xpt_ops;
+ struct kref xpt_ref;
+ struct list_head xpt_list;
+ struct list_head xpt_ready;
+ unsigned long xpt_flags;
+#define XPT_BUSY 0 /* enqueued/receiving */
+#define XPT_CONN 1 /* conn pending */
+#define XPT_CLOSE 2 /* dead or dying */
+#define XPT_DATA 3 /* data pending */
+#define XPT_TEMP 4 /* connected transport */
+#define XPT_DEAD 6 /* transport closed */
+#define XPT_CHNGBUF 7 /* need to change snd/rcv buf sizes */
+#define XPT_DEFERRED 8 /* deferred request pending */
+#define XPT_OLD 9 /* used for xprt aging mark+sweep */
+#define XPT_DETACHED 10 /* detached from tempsocks list */
+#define XPT_LISTENER 11 /* listening endpoint */
+#define XPT_CACHE_AUTH 12 /* cache auth info */
+
+ struct svc_pool *xpt_pool; /* current pool iff queued */
+ struct svc_serv *xpt_server; /* service for transport */
+ atomic_t xpt_reserved; /* space on outq that is rsvd */
+ struct mutex xpt_mutex; /* to serialize sending data */
+ spinlock_t xpt_lock; /* protects sk_deferred
+ * and xpt_auth_cache */
+ void *xpt_auth_cache;/* auth cache */
+ struct list_head xpt_deferred; /* deferred requests that need
+ * to be revisted */
+ struct sockaddr_storage xpt_local; /* local address */
+ size_t xpt_locallen; /* length of address */
+ struct sockaddr_storage xpt_remote; /* remote peer's address */
+ size_t xpt_remotelen; /* length of address */
+};
+
+int svc_reg_xprt_class(struct svc_xprt_class *);
+void svc_unreg_xprt_class(struct svc_xprt_class *);
+void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
+ struct svc_serv *);
+int svc_create_xprt(struct svc_serv *, char *, unsigned short, int);
+void svc_xprt_enqueue(struct svc_xprt *xprt);
+void svc_xprt_received(struct svc_xprt *);
+void svc_xprt_put(struct svc_xprt *xprt);
+void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
+void svc_close_xprt(struct svc_xprt *xprt);
+void svc_delete_xprt(struct svc_xprt *xprt);
+int svc_port_is_privileged(struct sockaddr *sin);
+int svc_print_xprts(char *buf, int maxlen);
+struct svc_xprt *svc_find_xprt(struct svc_serv *, char *, int, int);
+int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
+
+static inline void svc_xprt_get(struct svc_xprt *xprt)
+{
+ kref_get(&xprt->xpt_ref);
+}
+static inline void svc_xprt_set_local(struct svc_xprt *xprt,
+ struct sockaddr *sa, int salen)
+{
+ memcpy(&xprt->xpt_local, sa, salen);
+ xprt->xpt_locallen = salen;
+}
+static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
+ struct sockaddr *sa, int salen)
+{
+ memcpy(&xprt->xpt_remote, sa, salen);
+ xprt->xpt_remotelen = salen;
+}
+static inline unsigned short svc_addr_port(struct sockaddr *sa)
+{
+ unsigned short ret = 0;
+ switch (sa->sa_family) {
+ case AF_INET:
+ ret = ntohs(((struct sockaddr_in *)sa)->sin_port);
+ break;
+ case AF_INET6:
+ ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ break;
+ }
+ return ret;
+}
+
+static inline size_t svc_addr_len(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ }
+ return -EAFNOSUPPORT;
+}
+
+static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt)
+{
+ return svc_addr_port((struct sockaddr *)&xprt->xpt_local);
+}
+
+static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt)
+{
+ return svc_addr_port((struct sockaddr *)&xprt->xpt_remote);
+}
+
+static inline char *__svc_print_addr(struct sockaddr *addr,
+ char *buf, size_t len)
+{
+ switch (addr->sa_family) {
+ case AF_INET:
+ snprintf(buf, len, "%u.%u.%u.%u, port=%u",
+ NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
+ ntohs(((struct sockaddr_in *) addr)->sin_port));
+ break;
+
+ case AF_INET6:
+ snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
+ NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
+ ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
+ break;
+
+ default:
+ snprintf(buf, len, "unknown address type: %d", addr->sa_family);
+ break;
+ }
+ return buf;
+}
+#endif /* SUNRPC_SVC_XPRT_H */
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index a53e0fa..206f092 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -10,42 +10,16 @@
#define SUNRPC_SVCSOCK_H
#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svc_xprt.h>
/*
* RPC server socket.
*/
struct svc_sock {
- struct list_head sk_ready; /* list of ready sockets */
- struct list_head sk_list; /* list of all sockets */
+ struct svc_xprt sk_xprt;
struct socket * sk_sock; /* berkeley socket layer */
struct sock * sk_sk; /* INET layer */
- struct svc_pool * sk_pool; /* current pool iff queued */
- struct svc_serv * sk_server; /* service for this socket */
- atomic_t sk_inuse; /* use count */
- unsigned long sk_flags;
-#define SK_BUSY 0 /* enqueued/receiving */
-#define SK_CONN 1 /* conn pending */
-#define SK_CLOSE 2 /* dead or dying */
-#define SK_DATA 3 /* data pending */
-#define SK_TEMP 4 /* temp (TCP) socket */
-#define SK_DEAD 6 /* socket closed */
-#define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */
-#define SK_DEFERRED 8 /* request on sk_deferred */
-#define SK_OLD 9 /* used for temp socket aging mark+sweep */
-#define SK_DETACHED 10 /* detached from tempsocks list */
-
- atomic_t sk_reserved; /* space on outq that is reserved */
-
- spinlock_t sk_lock; /* protects sk_deferred and
- * sk_info_authunix */
- struct list_head sk_deferred; /* deferred requests that need to
- * be revisted */
- struct mutex sk_mutex; /* to serialize sending data */
-
- int (*sk_recvfrom)(struct svc_rqst *rqstp);
- int (*sk_sendto)(struct svc_rqst *rqstp);
-
/* We keep the old state_change and data_ready CB's here */
void (*sk_ostate)(struct sock *);
void (*sk_odata)(struct sock *, int bytes);
@@ -54,21 +28,12 @@
/* private TCP part */
int sk_reclen; /* length of record */
int sk_tcplen; /* current read length */
- time_t sk_lastrecv; /* time of last received request */
-
- /* cache of various info for TCP sockets */
- void *sk_info_authunix;
-
- struct sockaddr_storage sk_local; /* local address */
- struct sockaddr_storage sk_remote; /* remote peer's address */
- int sk_remotelen; /* length of address */
};
/*
* Function prototypes.
*/
-int svc_makesock(struct svc_serv *, int, unsigned short, int flags);
-void svc_force_close_socket(struct svc_sock *);
+void svc_close_all(struct list_head *);
int svc_recv(struct svc_rqst *, long);
int svc_send(struct svc_rqst *);
void svc_drop(struct svc_rqst *);
@@ -78,6 +43,8 @@
int fd,
char *name_return,
int *proto);
+void svc_init_xprt_sock(void);
+void svc_cleanup_xprt_sock(void);
/*
* svc_makesock socket characteristics
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 0751c94..e4057d7 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -112,7 +112,8 @@
__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
__be32 *xdr_encode_string(__be32 *p, const char *s);
-__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen);
+__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp,
+ unsigned int maxlen);
__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 40280df..1d7d4c5 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -38,18 +38,16 @@
* There is the %suspend_valid_only_mem function available that can be
* assigned to this if the platform only supports mem sleep.
*
- * @set_target: Tell the platform which system sleep state is going to be
- * entered.
- * @set_target() is executed right prior to suspending devices. The
- * information conveyed to the platform code by @set_target() should be
- * disregarded by the platform as soon as @finish() is executed and if
- * @prepare() fails. If @set_target() fails (ie. returns nonzero),
+ * @begin: Initialise a transition to given system sleep state.
+ * @begin() is executed right prior to suspending devices. The information
+ * conveyed to the platform code by @begin() should be disregarded by it as
+ * soon as @end() is executed. If @begin() fails (ie. returns nonzero),
* @prepare(), @enter() and @finish() will not be called by the PM core.
* This callback is optional. However, if it is implemented, the argument
- * passed to @enter() is meaningless and should be ignored.
+ * passed to @enter() is redundant and should be ignored.
*
* @prepare: Prepare the platform for entering the system sleep state indicated
- * by @set_target().
+ * by @begin().
* @prepare() is called right after devices have been suspended (ie. the
* appropriate .suspend() method has been executed for each device) and
* before the nonboot CPUs are disabled (it is executed with IRQs enabled).
@@ -57,8 +55,8 @@
* error code otherwise, in which case the system cannot enter the desired
* sleep state (@enter() and @finish() will not be called in that case).
*
- * @enter: Enter the system sleep state indicated by @set_target() or
- * represented by the argument if @set_target() is not implemented.
+ * @enter: Enter the system sleep state indicated by @begin() or represented by
+ * the argument if @begin() is not implemented.
* This callback is mandatory. It returns 0 on success or a negative
* error code otherwise, in which case the system cannot enter the desired
* sleep state.
@@ -69,13 +67,22 @@
* This callback is optional, but should be implemented by the platforms
* that implement @prepare(). If implemented, it is always called after
* @enter() (even if @enter() fails).
+ *
+ * @end: Called by the PM core right after resuming devices, to indicate to
+ * the platform that the system has returned to the working state or
+ * the transition to the sleep state has been aborted.
+ * This callback is optional, but should be implemented by the platforms
+ * that implement @begin(), but platforms implementing @begin() should
+ * also provide a @end() which cleans up transitions aborted before
+ * @enter().
*/
struct platform_suspend_ops {
int (*valid)(suspend_state_t state);
- int (*set_target)(suspend_state_t state);
+ int (*begin)(suspend_state_t state);
int (*prepare)(void);
int (*enter)(suspend_state_t state);
void (*finish)(void);
+ void (*end)(void);
};
#ifdef CONFIG_SUSPEND
@@ -123,20 +130,22 @@
};
/* mm/page_alloc.c */
-extern void drain_local_pages(void);
extern void mark_free_pages(struct zone *zone);
/**
* struct platform_hibernation_ops - hibernation platform support
*
- * The methods in this structure allow a platform to override the default
- * mechanism of shutting down the machine during a hibernation transition.
+ * The methods in this structure allow a platform to carry out special
+ * operations required by it during a hibernation transition.
*
- * All three methods must be assigned.
+ * All the methods below must be implemented.
*
- * @start: Tell the platform driver that we're starting hibernation.
+ * @begin: Tell the platform driver that we're starting hibernation.
* Called right after shrinking memory and before freezing devices.
*
+ * @end: Called by the PM core right after resuming devices, to indicate to
+ * the platform that the system has returned to the working state.
+ *
* @pre_snapshot: Prepare the platform for creating the hibernation image.
* Called right after devices have been frozen and before the nonboot
* CPUs are disabled (runs with IRQs on).
@@ -171,7 +180,8 @@
* thawing devices (runs with IRQs on).
*/
struct platform_hibernation_ops {
- int (*start)(void);
+ int (*begin)(void);
+ void (*end)(void);
int (*pre_snapshot)(void);
void (*finish)(void);
int (*prepare)(void);
@@ -213,17 +223,8 @@
void restore_processor_state(void);
/* kernel/power/main.c */
-extern struct blocking_notifier_head pm_chain_head;
-
-static inline int register_pm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&pm_chain_head, nb);
-}
-
-static inline int unregister_pm_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&pm_chain_head, nb);
-}
+extern int register_pm_notifier(struct notifier_block *nb);
+extern int unregister_pm_notifier(struct notifier_block *nb);
#define pm_notifier(fn, pri) { \
static struct notifier_block fn##_nb = \
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
new file mode 100644
index 0000000..2c6faec
--- /dev/null
+++ b/include/linux/suspend_ioctls.h
@@ -0,0 +1,32 @@
+#ifndef _LINUX_SUSPEND_IOCTLS_H
+#define _LINUX_SUSPEND_IOCTLS_H
+
+/*
+ * This structure is used to pass the values needed for the identification
+ * of the resume swap area from a user space to the kernel via the
+ * SNAPSHOT_SET_SWAP_AREA ioctl
+ */
+struct resume_swap_area {
+ loff_t offset;
+ u_int32_t dev;
+} __attribute__((packed));
+
+#define SNAPSHOT_IOC_MAGIC '3'
+#define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
+#define SNAPSHOT_UNFREEZE _IO(SNAPSHOT_IOC_MAGIC, 2)
+#define SNAPSHOT_ATOMIC_RESTORE _IO(SNAPSHOT_IOC_MAGIC, 4)
+#define SNAPSHOT_FREE _IO(SNAPSHOT_IOC_MAGIC, 5)
+#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
+#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
+#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
+ struct resume_swap_area)
+#define SNAPSHOT_GET_IMAGE_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
+#define SNAPSHOT_PLATFORM_SUPPORT _IO(SNAPSHOT_IOC_MAGIC, 15)
+#define SNAPSHOT_POWER_OFF _IO(SNAPSHOT_IOC_MAGIC, 16)
+#define SNAPSHOT_CREATE_IMAGE _IOW(SNAPSHOT_IOC_MAGIC, 17, int)
+#define SNAPSHOT_PREF_IMAGE_SIZE _IO(SNAPSHOT_IOC_MAGIC, 18)
+#define SNAPSHOT_AVAIL_SWAP_SIZE _IOR(SNAPSHOT_IOC_MAGIC, 19, loff_t)
+#define SNAPSHOT_ALLOC_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 20, loff_t)
+#define SNAPSHOT_IOC_MAXNR 20
+
+#endif /* _LINUX_SUSPEND_IOCTLS_H */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 4f3838a..353153e 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -158,9 +158,6 @@
/* Swap 50% full? Release swapcache more aggressively.. */
#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
-/* linux/mm/memory.c */
-extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
-
/* linux/mm/page_alloc.c */
extern unsigned long totalram_pages;
extern unsigned long totalreserve_pages;
@@ -223,16 +220,17 @@
#define total_swapcache_pages swapper_space.nrpages
extern void show_swap_cache_info(void);
extern int add_to_swap(struct page *, gfp_t);
+extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t);
extern void __delete_from_swap_cache(struct page *);
extern void delete_from_swap_cache(struct page *);
-extern int move_to_swap_cache(struct page *, swp_entry_t);
-extern int move_from_swap_cache(struct page *, unsigned long,
- struct address_space *);
extern void free_page_and_swap_cache(struct page *);
extern void free_pages_and_swap_cache(struct page **, int);
-extern struct page * lookup_swap_cache(swp_entry_t);
-extern struct page * read_swap_cache_async(swp_entry_t, struct vm_area_struct *vma,
- unsigned long addr);
+extern struct page *lookup_swap_cache(swp_entry_t);
+extern struct page *read_swap_cache_async(swp_entry_t, gfp_t,
+ struct vm_area_struct *vma, unsigned long addr);
+extern struct page *swapin_readahead(swp_entry_t, gfp_t,
+ struct vm_area_struct *vma, unsigned long addr);
+
/* linux/mm/swapfile.c */
extern long total_swap_pages;
extern unsigned int nr_swapfiles;
@@ -306,7 +304,7 @@
{
}
-static inline struct page *read_swap_cache_async(swp_entry_t swp,
+static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
struct vm_area_struct *vma, unsigned long addr)
{
return NULL;
@@ -317,22 +315,12 @@
return NULL;
}
-static inline int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
-{
- return 0;
-}
-
#define can_share_swap_page(p) (page_mapcount(p) == 1)
-static inline int move_to_swap_cache(struct page *page, swp_entry_t entry)
+static inline int add_to_swap_cache(struct page *page, swp_entry_t entry,
+ gfp_t gfp_mask)
{
- return 1;
-}
-
-static inline int move_from_swap_cache(struct page *page, unsigned long index,
- struct address_space *mapping)
-{
- return 1;
+ return -1;
}
static inline void __delete_from_swap_cache(struct page *page)
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index ceb6cc5..7bf2d14 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -42,6 +42,12 @@
return entry.val & SWP_OFFSET_MASK(entry);
}
+/* check whether a pte points to a swap entry */
+static inline int is_swap_pte(pte_t pte)
+{
+ return !pte_none(pte) && !pte_present(pte) && !pte_file(pte);
+}
+
/*
* Convert the arch-dependent pte representation of a swp_entry_t into an
* arch-independent swp_entry_t.
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 61def7c8..4c2577b 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -607,8 +607,11 @@
size_t len);
asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
-asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
- const struct itimerspec __user *utmr);
+asmlinkage long sys_timerfd_create(int clockid, int flags);
+asmlinkage long sys_timerfd_settime(int ufd, int flags,
+ const struct itimerspec __user *utmr,
+ struct itimerspec __user *otmr);
+asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr);
asmlinkage long sys_eventfd(unsigned int count);
asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index bf4ae4e..571f01d 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -102,7 +102,6 @@
KERN_NODENAME=7,
KERN_DOMAINNAME=8,
- KERN_CAP_BSET=14, /* int: capability bounding set */
KERN_PANIC=15, /* int: panic timeout */
KERN_REALROOTDEV=16, /* real root device to mount after initrd */
@@ -965,8 +964,6 @@
void __user *, size_t *, loff_t *);
extern int proc_dointvec(struct ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *);
-extern int proc_dointvec_bset(struct ctl_table *, int, struct file *,
- void __user *, size_t *, loff_t *);
extern int proc_dointvec_minmax(struct ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *);
extern int proc_dointvec_jiffies(struct ctl_table *, int, struct file *,
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h
index e21937c..c50d2ba 100644
--- a/include/linux/tc_ematch/tc_em_meta.h
+++ b/include/linux/tc_ematch/tc_em_meta.h
@@ -81,6 +81,7 @@
TCF_META_ID_SK_SNDTIMEO,
TCF_META_ID_SK_SENDMSG_OFF,
TCF_META_ID_SK_WRITE_PENDING,
+ TCF_META_ID_VLAN_TAG,
__TCF_META_ID_MAX
};
#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 24c6a2b..8ea3e71 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -244,6 +244,8 @@
/* Don't use! Compatibility define for existing users. */
#define tickadj (500/HZ ? : 1)
+int read_current_timer(unsigned long *timer_val);
+
#endif /* KERNEL */
#endif /* LINUX_TIMEX_H */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 402de89..5824a97 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -74,7 +74,6 @@
struct tty_bufhead {
struct delayed_work work;
- struct semaphore pty_sem;
spinlock_t lock;
struct tty_buffer *head; /* Queue head */
struct tty_buffer *tail; /* Active buffer */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 5fc8ff7..2372e2e 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -162,19 +162,19 @@
unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
struct device dev; /* interface specific device info */
- struct device *usb_dev; /* pointer to the usb class's device, if any */
+ struct device *usb_dev;
int pm_usage_cnt; /* usage counter for autosuspend */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
#define interface_to_usbdev(intf) \
container_of(intf->dev.parent, struct usb_device, dev)
-static inline void *usb_get_intfdata (struct usb_interface *intf)
+static inline void *usb_get_intfdata(struct usb_interface *intf)
{
- return dev_get_drvdata (&intf->dev);
+ return dev_get_drvdata(&intf->dev);
}
-static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
+static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{
dev_set_drvdata(&intf->dev, data);
}
@@ -275,9 +275,10 @@
int __usb_get_extra_descriptor(char *buffer, unsigned size,
unsigned char type, void **ptr);
-#define usb_get_extra_descriptor(ifpoint,type,ptr)\
- __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\
- type,(void**)ptr)
+#define usb_get_extra_descriptor(ifpoint, type, ptr) \
+ __usb_get_extra_descriptor((ifpoint)->extra, \
+ (ifpoint)->extralen, \
+ type, (void **)ptr)
/* ----------------------------------------------------------------------- */
@@ -318,7 +319,7 @@
#ifdef CONFIG_USB_DEVICEFS
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
#endif
- struct class_device *class_dev; /* class device for this bus */
+ struct device *dev; /* device for this bus */
#if defined(CONFIG_USB_MON)
struct mon_bus *mon_bus; /* non-null when associated */
@@ -388,7 +389,7 @@
unsigned can_submit:1; /* URBs may be submitted */
unsigned discon_suspended:1; /* Disconnected while suspended */
unsigned have_langid:1; /* whether string_langid is valid */
- unsigned authorized:1; /* Policy has determined we can use it */
+ unsigned authorized:1; /* Policy has said we can use it */
unsigned wusb:1; /* Device is Wireless USB */
int string_langid; /* language ID for strings */
@@ -417,7 +418,10 @@
int pm_usage_cnt; /* usage counter for autosuspend */
u32 quirks; /* quirks of the whole device */
- atomic_t urbnum; /* number of URBs submitted for the whole device */
+ atomic_t urbnum; /* number of URBs submitted for
+ the whole device */
+
+ unsigned long active_duration; /* total time device is not suspended */
#ifdef CONFIG_PM
struct delayed_work autosuspend; /* for delayed autosuspends */
@@ -425,6 +429,7 @@
unsigned long last_busy; /* time of last use */
int autosuspend_delay; /* in jiffies */
+ unsigned long connect_time; /* time device was first connected */
unsigned auto_pm:1; /* autosuspend/resume in progress */
unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */
@@ -498,11 +503,11 @@
/*-------------------------------------------------------------------------*/
/* for drivers using iso endpoints */
-extern int usb_get_current_frame_number (struct usb_device *usb_dev);
+extern int usb_get_current_frame_number(struct usb_device *usb_dev);
/* used these for multi-interface device registration */
extern int usb_driver_claim_interface(struct usb_driver *driver,
- struct usb_interface *iface, void* priv);
+ struct usb_interface *iface, void *priv);
/**
* usb_interface_claimed - returns true iff an interface is claimed
@@ -514,7 +519,8 @@
* may need to explicitly claim that lock.
*
*/
-static inline int usb_interface_claimed(struct usb_interface *iface) {
+static inline int usb_interface_claimed(struct usb_interface *iface)
+{
return (iface->dev.driver != NULL);
}
@@ -557,12 +563,11 @@
* USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
* high speed, and a different one if they are full or low speed.
*/
-static inline int usb_make_path (struct usb_device *dev, char *buf,
- size_t size)
+static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
{
int actual;
- actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name,
- dev->devpath);
+ actual = snprintf(buf, size, "usb-%s-%s", dev->bus->bus_name,
+ dev->devpath);
return (actual >= (int)size) ? -1 : actual;
}
@@ -608,7 +613,8 @@
*
* Returns true if the endpoint is of type OUT, otherwise it returns false.
*/
-static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_dir_out(
+ const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
}
@@ -619,7 +625,8 @@
*
* Returns true if the endpoint is of type bulk, otherwise it returns false.
*/
-static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_bulk(
+ const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK);
@@ -631,7 +638,8 @@
*
* Returns true if the endpoint is of type control, otherwise it returns false.
*/
-static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_control(
+ const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL);
@@ -644,7 +652,8 @@
* Returns true if the endpoint is of type interrupt, otherwise it returns
* false.
*/
-static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_int(
+ const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT);
@@ -657,7 +666,8 @@
* Returns true if the endpoint is of type isochronous, otherwise it returns
* false.
*/
-static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_isoc(
+ const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_ISOC);
@@ -670,7 +680,8 @@
* Returns true if the endpoint has bulk transfer type and IN direction,
* otherwise it returns false.
*/
-static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_bulk_in(
+ const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
}
@@ -682,7 +693,8 @@
* Returns true if the endpoint has bulk transfer type and OUT direction,
* otherwise it returns false.
*/
-static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_bulk_out(
+ const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
}
@@ -694,7 +706,8 @@
* Returns true if the endpoint has interrupt transfer type and IN direction,
* otherwise it returns false.
*/
-static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_int_in(
+ const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
}
@@ -706,7 +719,8 @@
* Returns true if the endpoint has interrupt transfer type and OUT direction,
* otherwise it returns false.
*/
-static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_int_out(
+ const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
}
@@ -718,7 +732,8 @@
* Returns true if the endpoint has isochronous transfer type and IN direction,
* otherwise it returns false.
*/
-static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_isoc_in(
+ const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
}
@@ -730,7 +745,8 @@
* Returns true if the endpoint has isochronous transfer type and OUT direction,
* otherwise it returns false.
*/
-static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_isoc_out(
+ const struct usb_endpoint_descriptor *epd)
{
return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
}
@@ -761,8 +777,9 @@
* specific device.
*/
#define USB_DEVICE(vend,prod) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
- .idProduct = (prod)
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+ .idVendor = (vend), \
+ .idProduct = (prod)
/**
* USB_DEVICE_VER - macro used to describe a specific usb device with a
* version range
@@ -774,10 +791,12 @@
* This macro is used to create a struct usb_device_id that matches a
* specific device, with a version range.
*/
-#define USB_DEVICE_VER(vend,prod,lo,hi) \
+#define USB_DEVICE_VER(vend, prod, lo, hi) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
- .idVendor = (vend), .idProduct = (prod), \
- .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .bcdDevice_lo = (lo), \
+ .bcdDevice_hi = (hi)
/**
* USB_DEVICE_INTERFACE_PROTOCOL - macro used to describe a usb
@@ -789,8 +808,9 @@
* This macro is used to create a struct usb_device_id that matches a
* specific interface protocol of devices.
*/
-#define USB_DEVICE_INTERFACE_PROTOCOL(vend,prod,pr) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
+#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
.idVendor = (vend), \
.idProduct = (prod), \
.bInterfaceProtocol = (pr)
@@ -804,12 +824,14 @@
* This macro is used to create a struct usb_device_id that matches a
* specific class of devices.
*/
-#define USB_DEVICE_INFO(cl,sc,pr) \
- .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \
- .bDeviceSubClass = (sc), .bDeviceProtocol = (pr)
+#define USB_DEVICE_INFO(cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
+ .bDeviceClass = (cl), \
+ .bDeviceSubClass = (sc), \
+ .bDeviceProtocol = (pr)
/**
- * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
+ * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
* @cl: bInterfaceClass value
* @sc: bInterfaceSubClass value
* @pr: bInterfaceProtocol value
@@ -817,9 +839,11 @@
* This macro is used to create a struct usb_device_id that matches a
* specific class of interfaces.
*/
-#define USB_INTERFACE_INFO(cl,sc,pr) \
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
- .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+#define USB_INTERFACE_INFO(cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr)
/**
* USB_DEVICE_AND_INTERFACE_INFO - macro used to describe a specific usb device
@@ -836,12 +860,14 @@
* This is especially useful when explicitly matching devices that have
* vendor specific bDeviceClass values, but standards-compliant interfaces.
*/
-#define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \
+#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
| USB_DEVICE_ID_MATCH_DEVICE, \
- .idVendor = (vend), .idProduct = (prod), \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
.bInterfaceClass = (cl), \
- .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr)
/* ----------------------------------------------------------------------- */
@@ -1119,7 +1145,7 @@
* transferred. It will normally be the same as requested, unless
* either an error was reported or a short read was performed.
* The URB_SHORT_NOT_OK transfer flag may be used to make such
- * short reads be reported as errors.
+ * short reads be reported as errors.
* @setup_packet: Only used for control transfers, this points to eight bytes
* of setup data. Control transfers always start by sending this data
* to the device. Then transfer_buffer is read or written, if needed.
@@ -1138,7 +1164,7 @@
* @complete: Completion handler. This URB is passed as the parameter to the
* completion function. The completion function may then do what
* it likes with the URB, including resubmitting or freeing it.
- * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to
+ * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to
* collect the transfer status for each buffer.
*
* This structure identifies USB transfer requests. URBs must be allocated by
@@ -1242,8 +1268,7 @@
* when the urb is owned by the hcd, that is, since the call to
* usb_submit_urb() till the entry into the completion routine.
*/
-struct urb
-{
+struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
void *hcpriv; /* private data for host controller */
@@ -1254,10 +1279,10 @@
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
- struct list_head anchor_list; /* the URB may be anchored by the driver */
+ struct list_head anchor_list; /* the URB may be anchored */
struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */
- struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */
+ struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
@@ -1294,14 +1319,14 @@
* Initializes a control urb with the proper information needed to submit
* it to a device.
*/
-static inline void usb_fill_control_urb (struct urb *urb,
- struct usb_device *dev,
- unsigned int pipe,
- unsigned char *setup_packet,
- void *transfer_buffer,
- int buffer_length,
- usb_complete_t complete_fn,
- void *context)
+static inline void usb_fill_control_urb(struct urb *urb,
+ struct usb_device *dev,
+ unsigned int pipe,
+ unsigned char *setup_packet,
+ void *transfer_buffer,
+ int buffer_length,
+ usb_complete_t complete_fn,
+ void *context)
{
urb->dev = dev;
urb->pipe = pipe;
@@ -1325,13 +1350,13 @@
* Initializes a bulk urb with the proper information needed to submit it
* to a device.
*/
-static inline void usb_fill_bulk_urb (struct urb *urb,
- struct usb_device *dev,
- unsigned int pipe,
- void *transfer_buffer,
- int buffer_length,
- usb_complete_t complete_fn,
- void *context)
+static inline void usb_fill_bulk_urb(struct urb *urb,
+ struct usb_device *dev,
+ unsigned int pipe,
+ void *transfer_buffer,
+ int buffer_length,
+ usb_complete_t complete_fn,
+ void *context)
{
urb->dev = dev;
urb->pipe = pipe;
@@ -1359,14 +1384,14 @@
* the endpoint interval, and express polling intervals in microframes
* (eight per millisecond) rather than in frames (one per millisecond).
*/
-static inline void usb_fill_int_urb (struct urb *urb,
- struct usb_device *dev,
- unsigned int pipe,
- void *transfer_buffer,
- int buffer_length,
- usb_complete_t complete_fn,
- void *context,
- int interval)
+static inline void usb_fill_int_urb(struct urb *urb,
+ struct usb_device *dev,
+ unsigned int pipe,
+ void *transfer_buffer,
+ int buffer_length,
+ usb_complete_t complete_fn,
+ void *context,
+ int interval)
{
urb->dev = dev;
urb->pipe = pipe;
@@ -1419,15 +1444,15 @@
return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
}
-void *usb_buffer_alloc (struct usb_device *dev, size_t size,
+void *usb_buffer_alloc(struct usb_device *dev, size_t size,
gfp_t mem_flags, dma_addr_t *dma);
-void usb_buffer_free (struct usb_device *dev, size_t size,
+void usb_buffer_free(struct usb_device *dev, size_t size,
void *addr, dma_addr_t dma);
#if 0
-struct urb *usb_buffer_map (struct urb *urb);
-void usb_buffer_dmasync (struct urb *urb);
-void usb_buffer_unmap (struct urb *urb);
+struct urb *usb_buffer_map(struct urb *urb);
+void usb_buffer_dmasync(struct urb *urb);
+void usb_buffer_unmap(struct urb *urb);
#endif
struct scatterlist;
@@ -1499,7 +1524,7 @@
int status;
size_t bytes;
- /*
+ /*
* members below are private: to usbcore,
* and are not provided for driver access!
*/
@@ -1517,18 +1542,18 @@
struct completion complete;
};
-int usb_sg_init (
+int usb_sg_init(
struct usb_sg_request *io,
struct usb_device *dev,
- unsigned pipe,
+ unsigned pipe,
unsigned period,
struct scatterlist *sg,
int nents,
size_t length,
gfp_t mem_flags
);
-void usb_sg_cancel (struct usb_sg_request *io);
-void usb_sg_wait (struct usb_sg_request *io);
+void usb_sg_cancel(struct usb_sg_request *io);
+void usb_sg_wait(struct usb_sg_request *io);
/* ----------------------------------------------------------------------- */
@@ -1585,21 +1610,21 @@
/* Create various pipes... */
#define usb_sndctrlpipe(dev,endpoint) \
- ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
+ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
#define usb_rcvctrlpipe(dev,endpoint) \
- ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev,endpoint) \
- ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
+ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
#define usb_rcvisocpipe(dev,endpoint) \
- ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev,endpoint) \
- ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
+ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
#define usb_rcvbulkpipe(dev,endpoint) \
- ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev,endpoint) \
- ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
#define usb_rcvintpipe(dev,endpoint) \
- ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index 6ce42bf..b8cba1d 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -1,6 +1,7 @@
-unifdef-y += audio.h
-unifdef-y += cdc.h
-unifdef-y += ch9.h
-unifdef-y += gadgetfs.h
-unifdef-y += midi.h
+header-y += audio.h
+header-y += cdc.h
+header-y += ch9.h
+header-y += gadgetfs.h
+header-y += midi.h
+unifdef-y += g_printer.h
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index 6bd2359..2dfeef1 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -27,13 +27,13 @@
/* 4.3.2 Class-Specific AC Interface Descriptor */
struct usb_ac_header_descriptor {
- __u8 bLength; // 8+n
- __u8 bDescriptorType; // USB_DT_CS_INTERFACE
- __u8 bDescriptorSubtype; // USB_MS_HEADER
- __le16 bcdADC; // 0x0100
- __le16 wTotalLength; // includes Unit and Terminal desc.
- __u8 bInCollection; // n
- __u8 baInterfaceNr[]; // [n]
+ __u8 bLength; /* 8+n */
+ __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
+ __u8 bDescriptorSubtype; /* USB_MS_HEADER */
+ __le16 bcdADC; /* 0x0100 */
+ __le16 wTotalLength; /* includes Unit and Terminal desc. */
+ __u8 bInCollection; /* n */
+ __u8 baInterfaceNr[]; /* [n] */
} __attribute__ ((packed));
#define USB_DT_AC_HEADER_SIZE(n) (8+(n))
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 2204ae2..94ee4ec 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -29,16 +29,16 @@
* Class-Specific descriptors ... there are a couple dozen of them
*/
-#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
-#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
-#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
-#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
+#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
+#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
#define USB_CDC_COUNTRY_TYPE 0x07
-#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */
-#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
+#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */
+#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
#define USB_CDC_WHCM_TYPE 0x11
-#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */
-#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */
+#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */
+#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */
#define USB_CDC_DMM_TYPE 0x14
#define USB_CDC_OBEX_TYPE 0x15
diff --git a/include/linux/usb/g_printer.h b/include/linux/usb/g_printer.h
new file mode 100644
index 0000000..0c5ea1e
--- /dev/null
+++ b/include/linux/usb/g_printer.h
@@ -0,0 +1,31 @@
+/*
+ * g_printer.h -- Header file for USB Printer gadget driver
+ *
+ * Copyright (C) 2007 Craig W. Nadler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#define PRINTER_NOT_ERROR 0x08
+#define PRINTER_SELECTED 0x10
+#define PRINTER_PAPER_EMPTY 0x20
+
+/* The 'g' code is also used by gadgetfs ioctl requests.
+ * Don't add any colliding codes to either driver, and keep
+ * them in unique ranges (size 0x20 for now).
+ */
+#define GADGET_GET_PRINTER_STATUS _IOR('g', 0x21, unsigned char)
+#define GADGET_SET_PRINTER_STATUS _IOWR('g', 0x22, unsigned char)
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index c1527c2..aa3047f 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -70,9 +70,10 @@
*
* Bulk endpoints can use any size buffers, and can also be used for interrupt
* transfers. interrupt-only endpoints can be much less functional.
+ *
+ * NOTE: this is analagous to 'struct urb' on the host side, except that
+ * it's thinner and promotes more pre-allocation.
*/
- // NOTE this is analagous to 'struct urb' on the host side,
- // except that it's thinner and promotes more pre-allocation.
struct usb_request {
void *buf;
@@ -168,10 +169,10 @@
*
* returns zero, or a negative error code.
*/
-static inline int
-usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+static inline int usb_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
{
- return ep->ops->enable (ep, desc);
+ return ep->ops->enable(ep, desc);
}
/**
@@ -186,10 +187,9 @@
*
* returns zero, or a negative error code.
*/
-static inline int
-usb_ep_disable (struct usb_ep *ep)
+static inline int usb_ep_disable(struct usb_ep *ep)
{
- return ep->ops->disable (ep);
+ return ep->ops->disable(ep);
}
/**
@@ -206,10 +206,10 @@
*
* Returns the request, or null if one could not be allocated.
*/
-static inline struct usb_request *
-usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
+static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
{
- return ep->ops->alloc_request (ep, gfp_flags);
+ return ep->ops->alloc_request(ep, gfp_flags);
}
/**
@@ -221,10 +221,10 @@
* Caller guarantees the request is not queued, and that it will
* no longer be requeued (or otherwise used).
*/
-static inline void
-usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
+static inline void usb_ep_free_request(struct usb_ep *ep,
+ struct usb_request *req)
{
- ep->ops->free_request (ep, req);
+ ep->ops->free_request(ep, req);
}
/**
@@ -281,10 +281,10 @@
* report errors; errors will also be
* reported when the usb peripheral is disconnected.
*/
-static inline int
-usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
+static inline int usb_ep_queue(struct usb_ep *ep,
+ struct usb_request *req, gfp_t gfp_flags)
{
- return ep->ops->queue (ep, req, gfp_flags);
+ return ep->ops->queue(ep, req, gfp_flags);
}
/**
@@ -301,9 +301,9 @@
* restrictions prevent drivers from supporting configuration changes,
* even to configuration zero (a "chapter 9" requirement).
*/
-static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
+static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
- return ep->ops->dequeue (ep, req);
+ return ep->ops->dequeue(ep, req);
}
/**
@@ -327,10 +327,9 @@
* transfer requests are still queued, or if the controller hardware
* (usually a FIFO) still holds bytes that the host hasn't collected.
*/
-static inline int
-usb_ep_set_halt (struct usb_ep *ep)
+static inline int usb_ep_set_halt(struct usb_ep *ep)
{
- return ep->ops->set_halt (ep, 1);
+ return ep->ops->set_halt(ep, 1);
}
/**
@@ -346,10 +345,9 @@
* Note that some hardware can't support this request (like pxa2xx_udc),
* and accordingly can't correctly implement interface altsettings.
*/
-static inline int
-usb_ep_clear_halt (struct usb_ep *ep)
+static inline int usb_ep_clear_halt(struct usb_ep *ep)
{
- return ep->ops->set_halt (ep, 0);
+ return ep->ops->set_halt(ep, 0);
}
/**
@@ -367,11 +365,10 @@
* errno if the endpoint doesn't use a FIFO or doesn't support such
* precise handling.
*/
-static inline int
-usb_ep_fifo_status (struct usb_ep *ep)
+static inline int usb_ep_fifo_status(struct usb_ep *ep)
{
if (ep->ops->fifo_status)
- return ep->ops->fifo_status (ep);
+ return ep->ops->fifo_status(ep);
else
return -EOPNOTSUPP;
}
@@ -385,11 +382,10 @@
* must never be used except when endpoint is not being used for any
* protocol translation.
*/
-static inline void
-usb_ep_fifo_flush (struct usb_ep *ep)
+static inline void usb_ep_fifo_flush(struct usb_ep *ep)
{
if (ep->ops->fifo_flush)
- ep->ops->fifo_flush (ep);
+ ep->ops->fifo_flush(ep);
}
@@ -469,10 +465,10 @@
struct device dev;
};
-static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
- { dev_set_drvdata (&gadget->dev, data); }
-static inline void *get_gadget_data (struct usb_gadget *gadget)
- { return dev_get_drvdata (&gadget->dev); }
+static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
+ { dev_set_drvdata(&gadget->dev, data); }
+static inline void *get_gadget_data(struct usb_gadget *gadget)
+ { return dev_get_drvdata(&gadget->dev); }
/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
#define gadget_for_each_ep(tmp,gadget) \
@@ -511,7 +507,6 @@
#endif
}
-
/**
* usb_gadget_frame_number - returns the current frame number
* @gadget: controller that reports the frame number
@@ -519,9 +514,9 @@
* Returns the usb frame number, normally eleven bits from a SOF packet,
* or negative errno if this device doesn't support this capability.
*/
-static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
+static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
{
- return gadget->ops->get_frame (gadget);
+ return gadget->ops->get_frame(gadget);
}
/**
@@ -537,11 +532,11 @@
* even if OTG isn't otherwise in use. OTG devices may also start
* remote wakeup even when hosts don't explicitly enable it.
*/
-static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
+static inline int usb_gadget_wakeup(struct usb_gadget *gadget)
{
if (!gadget->ops->wakeup)
return -EOPNOTSUPP;
- return gadget->ops->wakeup (gadget);
+ return gadget->ops->wakeup(gadget);
}
/**
@@ -553,12 +548,11 @@
*
* returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_set_selfpowered (struct usb_gadget *gadget)
+static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
{
if (!gadget->ops->set_selfpowered)
return -EOPNOTSUPP;
- return gadget->ops->set_selfpowered (gadget, 1);
+ return gadget->ops->set_selfpowered(gadget, 1);
}
/**
@@ -571,12 +565,11 @@
*
* returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
+static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
{
if (!gadget->ops->set_selfpowered)
return -EOPNOTSUPP;
- return gadget->ops->set_selfpowered (gadget, 0);
+ return gadget->ops->set_selfpowered(gadget, 0);
}
/**
@@ -591,12 +584,11 @@
*
* Returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_vbus_connect(struct usb_gadget *gadget)
+static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
{
if (!gadget->ops->vbus_session)
return -EOPNOTSUPP;
- return gadget->ops->vbus_session (gadget, 1);
+ return gadget->ops->vbus_session(gadget, 1);
}
/**
@@ -611,12 +603,11 @@
*
* Returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
if (!gadget->ops->vbus_draw)
return -EOPNOTSUPP;
- return gadget->ops->vbus_draw (gadget, mA);
+ return gadget->ops->vbus_draw(gadget, mA);
}
/**
@@ -629,12 +620,11 @@
*
* Returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
{
if (!gadget->ops->vbus_session)
return -EOPNOTSUPP;
- return gadget->ops->vbus_session (gadget, 0);
+ return gadget->ops->vbus_session(gadget, 0);
}
/**
@@ -648,12 +638,11 @@
*
* Returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_connect (struct usb_gadget *gadget)
+static inline int usb_gadget_connect(struct usb_gadget *gadget)
{
if (!gadget->ops->pullup)
return -EOPNOTSUPP;
- return gadget->ops->pullup (gadget, 1);
+ return gadget->ops->pullup(gadget, 1);
}
/**
@@ -671,16 +660,14 @@
*
* Returns zero on success, else negative errno.
*/
-static inline int
-usb_gadget_disconnect (struct usb_gadget *gadget)
+static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
{
if (!gadget->ops->pullup)
return -EOPNOTSUPP;
- return gadget->ops->pullup (gadget, 0);
+ return gadget->ops->pullup(gadget, 0);
}
-
/*-------------------------------------------------------------------------*/
/**
@@ -764,7 +751,7 @@
void (*suspend)(struct usb_gadget *);
void (*resume)(struct usb_gadget *);
- // FIXME support safe rmmod
+ /* FIXME support safe rmmod */
struct device_driver driver;
};
@@ -790,7 +777,7 @@
* the bind() functions will be in init sections.
* This function must be called in a context that can sleep.
*/
-int usb_gadget_register_driver (struct usb_gadget_driver *driver);
+int usb_gadget_register_driver(struct usb_gadget_driver *driver);
/**
* usb_gadget_unregister_driver - unregister a gadget driver
@@ -805,7 +792,7 @@
* will in in exit sections, so may not be linked in some kernels.
* This function must be called in a context that can sleep.
*/
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
/*-------------------------------------------------------------------------*/
@@ -838,7 +825,7 @@
};
/* put descriptor for string with that id into buf (buflen >= 256) */
-int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
+int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf);
/*-------------------------------------------------------------------------*/
@@ -856,10 +843,10 @@
/* utility wrapping a simple endpoint selection policy */
-extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
+extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
struct usb_endpoint_descriptor *) __devinit;
-extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit;
+extern void usb_ep_autoconfig_reset(struct usb_gadget *) __devinit;
#endif /* __KERNEL__ */
diff --git a/include/linux/usb/gadgetfs.h b/include/linux/usb/gadgetfs.h
index e8654c3..c291ab1 100644
--- a/include/linux/usb/gadgetfs.h
+++ b/include/linux/usb/gadgetfs.h
@@ -36,7 +36,7 @@
GADGETFS_DISCONNECT,
GADGETFS_SETUP,
GADGETFS_SUSPEND,
- // and likely more !
+ /* and likely more ! */
};
/* NOTE: this structure must stay the same size and layout on
@@ -44,21 +44,28 @@
*/
struct usb_gadgetfs_event {
union {
- // NOP, DISCONNECT, SUSPEND: nothing
- // ... some hardware can't report disconnection
+ /* NOP, DISCONNECT, SUSPEND: nothing
+ * ... some hardware can't report disconnection
+ */
- // CONNECT: just the speed
+ /* CONNECT: just the speed */
enum usb_device_speed speed;
- // SETUP: packet; DATA phase i/o precedes next event
- // (setup.bmRequestType & USB_DIR_IN) flags direction
- // ... includes SET_CONFIGURATION, SET_INTERFACE
+ /* SETUP: packet; DATA phase i/o precedes next event
+ *(setup.bmRequestType & USB_DIR_IN) flags direction
+ * ... includes SET_CONFIGURATION, SET_INTERFACE
+ */
struct usb_ctrlrequest setup;
} u;
enum usb_gadgetfs_event_type type;
};
+/* The 'g' code is also used by printer gadget ioctl requests.
+ * Don't add any colliding codes to either driver, and keep
+ * them in unique ranges (size 0x20 for now).
+ */
+
/* endpoint ioctls */
/* IN transfers may be reported to the gadget driver as complete
@@ -68,14 +75,14 @@
* THIS returns how many bytes are "unclaimed" in the endpoint fifo
* (needed for precise fault handling, when the hardware allows it)
*/
-#define GADGETFS_FIFO_STATUS _IO('g',1)
+#define GADGETFS_FIFO_STATUS _IO('g', 1)
/* discards any unclaimed data in the fifo. */
-#define GADGETFS_FIFO_FLUSH _IO('g',2)
+#define GADGETFS_FIFO_FLUSH _IO('g', 2)
/* resets endpoint halt+toggle; used to implement set_interface.
* some hardware (like pxa2xx) can't support this.
*/
-#define GADGETFS_CLEAR_HALT _IO('g',3)
+#define GADGETFS_CLEAR_HALT _IO('g', 3)
#endif /* __LINUX_USB_GADGETFS_H */
diff --git a/include/linux/usb/iowarrior.h b/include/linux/usb/iowarrior.h
index cbbe020..de6f380 100644
--- a/include/linux/usb/iowarrior.h
+++ b/include/linux/usb/iowarrior.h
@@ -14,14 +14,23 @@
this information.
*/
struct iowarrior_info {
- __u32 vendor; /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
- __u32 product; /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_XXXXX) */
- __u8 serial[9]; /* the serial number of our chip (if a serial-number is not available this is empty string) */
- __u32 revision; /* revision number of the chip */
- __u32 speed; /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
- __u32 power; /* power consumption of the device in mA */
- __u32 if_num; /* the number of the endpoint */
- __u32 report_size; /* size of the data-packets on this interface */
+ /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
+ __u32 vendor;
+ /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_X) */
+ __u32 product;
+ /* the serial number of our chip (if a serial-number is not available
+ * this is empty string) */
+ __u8 serial[9];
+ /* revision number of the chip */
+ __u32 revision;
+ /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
+ __u32 speed;
+ /* power consumption of the device in mA */
+ __u32 power;
+ /* the number of the endpoint */
+ __u32 if_num;
+ /* size of the data-packets on this interface */
+ __u32 report_size;
};
/*
diff --git a/include/linux/usb/isp116x.h b/include/linux/usb/isp116x.h
index 436dd8a..67d2826 100644
--- a/include/linux/usb/isp116x.h
+++ b/include/linux/usb/isp116x.h
@@ -25,5 +25,5 @@
300ns delay between access to ADDR_REG and DATA_REG
OE, WE MUST NOT be changed during these intervals
*/
- void (*delay) (struct device * dev, int delay);
+ void (*delay) (struct device *dev, int delay);
};
diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h
index 11a97d5..80624c5 100644
--- a/include/linux/usb/midi.h
+++ b/include/linux/usb/midi.h
@@ -47,9 +47,9 @@
/* 6.1.2.2 MIDI IN Jack Descriptor */
struct usb_midi_in_jack_descriptor {
__u8 bLength;
- __u8 bDescriptorType; // USB_DT_CS_INTERFACE
- __u8 bDescriptorSubtype; // USB_MS_MIDI_IN_JACK
- __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL
+ __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
+ __u8 bDescriptorSubtype; /* USB_MS_MIDI_IN_JACK */
+ __u8 bJackType; /* USB_MS_EMBEDDED/EXTERNAL */
__u8 bJackID;
__u8 iJack;
} __attribute__ ((packed));
@@ -64,12 +64,12 @@
/* 6.1.2.3 MIDI OUT Jack Descriptor */
struct usb_midi_out_jack_descriptor {
__u8 bLength;
- __u8 bDescriptorType; // USB_DT_CS_INTERFACE
- __u8 bDescriptorSubtype; // USB_MS_MIDI_OUT_JACK
- __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL
+ __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
+ __u8 bDescriptorSubtype; /* USB_MS_MIDI_OUT_JACK */
+ __u8 bJackType; /* USB_MS_EMBEDDED/EXTERNAL */
__u8 bJackID;
- __u8 bNrInputPins; // p
- struct usb_midi_source_pin pins[]; // [p]
+ __u8 bNrInputPins; /* p */
+ struct usb_midi_source_pin pins[]; /* [p] */
/*__u8 iJack; -- ommitted due to variable-sized pins[] */
} __attribute__ ((packed));
@@ -90,11 +90,11 @@
/* 6.2.2 Class-Specific MS Bulk Data Endpoint Descriptor */
struct usb_ms_endpoint_descriptor {
- __u8 bLength; // 4+n
- __u8 bDescriptorType; // USB_DT_CS_ENDPOINT
- __u8 bDescriptorSubtype; // USB_MS_GENERAL
- __u8 bNumEmbMIDIJack; // n
- __u8 baAssocJackID[]; // [n]
+ __u8 bLength; /* 4+n */
+ __u8 bDescriptorType; /* USB_DT_CS_ENDPOINT */
+ __u8 bDescriptorSubtype; /* USB_MS_GENERAL */
+ __u8 bNumEmbMIDIJack; /* n */
+ __u8 baAssocJackID[]; /* [n] */
} __attribute__ ((packed));
#define USB_DT_MS_ENDPOINT_SIZE(n) (4 + (n))
diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h
index c602f88..ec897cb 100644
--- a/include/linux/usb/net2280.h
+++ b/include/linux/usb/net2280.h
@@ -37,7 +37,7 @@
/* main registers, BAR0 + 0x0000 */
struct net2280_regs {
- // offset 0x0000
+ /* offset 0x0000 */
u32 devinit;
#define LOCAL_CLOCK_FREQUENCY 8
#define FORCE_PCI_RESET 7
@@ -61,7 +61,7 @@
#define EEPROM_WRITE_DATA 0
u32 eeclkfreq;
u32 _unused0;
- // offset 0x0010
+ /* offset 0x0010 */
u32 pciirqenb0; /* interrupt PCI master ... */
#define SETUP_PACKET_INTERRUPT_ENABLE 7
@@ -131,7 +131,7 @@
#define RESUME_INTERRUPT_ENABLE 1
#define SOF_INTERRUPT_ENABLE 0
- // offset 0x0020
+ /* offset 0x0020 */
u32 _unused1;
u32 usbirqenb1;
#define USB_INTERRUPT_ENABLE 31
@@ -195,7 +195,7 @@
#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2
#define RESUME_INTERRUPT 1
#define SOF_INTERRUPT 0
- // offset 0x0030
+ /* offset 0x0030 */
u32 idxaddr;
u32 idxdata;
u32 fifoctl;
@@ -204,7 +204,7 @@
#define PCI_BASE2_SELECT 2
#define FIFO_CONFIGURATION_SELECT 0
u32 _unused2;
- // offset 0x0040
+ /* offset 0x0040 */
u32 memaddr;
#define START 28
#define DIRECTION 27
@@ -213,7 +213,7 @@
u32 memdata0;
u32 memdata1;
u32 _unused3;
- // offset 0x0050
+ /* offset 0x0050 */
u32 gpioctl;
#define GPIO3_LED_SELECT 12
#define GPIO3_INTERRUPT_ENABLE 11
@@ -237,7 +237,7 @@
/* usb control, BAR0 + 0x0080 */
struct net2280_usb_regs {
- // offset 0x0080
+ /* offset 0x0080 */
u32 stdrsp;
#define STALL_UNSUPPORTED_REQUESTS 31
#define SET_TEST_MODE 16
@@ -275,7 +275,7 @@
#define PME_WAKEUP_ENABLE 2
#define DEVICE_REMOTE_WAKEUP_ENABLE 1
#define SELF_POWERED_STATUS 0
- // offset 0x0090
+ /* offset 0x0090 */
u32 usbstat;
#define HIGH_SPEED 7
#define FULL_SPEED 6
@@ -291,7 +291,7 @@
#define TERMINATION_SELECT 0
u32 setup0123;
u32 setup4567;
- // offset 0x0090
+ /* offset 0x0090 */
u32 _unused0;
u32 ouraddr;
#define FORCE_IMMEDIATE 7
@@ -301,7 +301,7 @@
/* pci control, BAR0 + 0x0100 */
struct net2280_pci_regs {
- // offset 0x0100
+ /* offset 0x0100 */
u32 pcimstctl;
#define PCI_ARBITER_PARK_SELECT 13
#define PCI_MULTI LEVEL_ARBITER 12
@@ -331,7 +331,7 @@
* that can be loaded into some of these registers.
*/
struct net2280_dma_regs { /* [11.7] */
- // offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
+ /* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */
u32 dmactl;
#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25
#define DMA_CLEAR_COUNT_ENABLE 21
@@ -355,7 +355,7 @@
#define DMA_ABORT 1
#define DMA_START 0
u32 _unused0 [2];
- // offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
+ /* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */
u32 dmacount;
#define VALID_BIT 31
#define DMA_DIRECTION 30
@@ -371,9 +371,9 @@
/* dedicated endpoint registers, BAR0 + 0x0200 */
struct net2280_dep_regs { /* [11.8] */
- // offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+ /* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */
u32 dep_cfg;
- // offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+ /* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
u32 dep_rsp;
u32 _unused [2];
} __attribute__ ((packed));
@@ -383,7 +383,7 @@
* ep0 reserved for control; E and F have only 64 bytes of fifo
*/
struct net2280_ep_regs { /* [11.9] */
- // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+ /* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */
u32 ep_cfg;
#define ENDPOINT_BYTE_COUNT 16
#define ENDPOINT_ENABLE 10
@@ -435,7 +435,7 @@
#define DATA_PACKET_TRANSMITTED_INTERRUPT 2
#define DATA_OUT_PING_TOKEN_INTERRUPT 1
#define DATA_IN_TOKEN_INTERRUPT 0
- // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+ /* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */
u32 ep_avail;
u32 ep_data;
u32 _unused0 [2];
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 9897f7a..e007074 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -1,4 +1,4 @@
-// include/linux/usb/otg.h
+/* USB OTG (On The Go) defines */
/*
* These APIs may be used between USB controllers. USB device drivers
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 488ce12..21b4a1c 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -20,7 +20,8 @@
#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
#define SERIAL_TTY_MINORS 255 /* loads of devices :) */
-#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
+/* The maximum number of ports one device can grab at once */
+#define MAX_NUM_PORTS 8
/* parity check flag */
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
@@ -61,29 +62,29 @@
* ports of a device.
*/
struct usb_serial_port {
- struct usb_serial * serial;
- struct tty_struct * tty;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
spinlock_t lock;
struct mutex mutex;
unsigned char number;
- unsigned char * interrupt_in_buffer;
- struct urb * interrupt_in_urb;
+ unsigned char *interrupt_in_buffer;
+ struct urb *interrupt_in_urb;
__u8 interrupt_in_endpointAddress;
- unsigned char * interrupt_out_buffer;
+ unsigned char *interrupt_out_buffer;
int interrupt_out_size;
- struct urb * interrupt_out_urb;
+ struct urb *interrupt_out_urb;
__u8 interrupt_out_endpointAddress;
- unsigned char * bulk_in_buffer;
+ unsigned char *bulk_in_buffer;
int bulk_in_size;
- struct urb * read_urb;
+ struct urb *read_urb;
__u8 bulk_in_endpointAddress;
- unsigned char * bulk_out_buffer;
+ unsigned char *bulk_out_buffer;
int bulk_out_size;
- struct urb * write_urb;
+ struct urb *write_urb;
int write_urb_busy;
__u8 bulk_out_endpointAddress;
@@ -92,17 +93,19 @@
int open_count;
char throttled;
char throttle_req;
+ char console;
struct device dev;
};
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
/* get and set the port private data pointer helper functions */
-static inline void *usb_get_serial_port_data (struct usb_serial_port *port)
+static inline void *usb_get_serial_port_data(struct usb_serial_port *port)
{
return dev_get_drvdata(&port->dev);
}
-static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data)
+static inline void usb_set_serial_port_data(struct usb_serial_port *port,
+ void *data)
{
dev_set_drvdata(&port->dev, data);
}
@@ -125,9 +128,10 @@
* usb_set_serial_data() to access this.
*/
struct usb_serial {
- struct usb_device * dev;
- struct usb_serial_driver * type;
- struct usb_interface * interface;
+ struct usb_device *dev;
+ struct usb_serial_driver *type;
+ struct usb_interface *interface;
+ unsigned char disconnected;
unsigned char minor;
unsigned char num_ports;
unsigned char num_port_pointers;
@@ -135,29 +139,30 @@
char num_interrupt_out;
char num_bulk_in;
char num_bulk_out;
- struct usb_serial_port * port[MAX_NUM_PORTS];
+ struct usb_serial_port *port[MAX_NUM_PORTS];
struct kref kref;
- void * private;
+ struct mutex disc_mutex;
+ void *private;
};
#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
#define NUM_DONT_CARE 99
/* get and set the serial private data pointer helper functions */
-static inline void *usb_get_serial_data (struct usb_serial *serial)
+static inline void *usb_get_serial_data(struct usb_serial *serial)
{
return serial->private;
}
-static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
+static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
{
serial->private = data;
}
/**
* usb_serial_driver - describes a usb serial driver
- * @description: pointer to a string that describes this driver. This string used
- * in the syslog messages when a device is inserted or removed.
+ * @description: pointer to a string that describes this driver. This string
+ * used in the syslog messages when a device is inserted or removed.
* @id_table: pointer to a list of usb_device_id structures that define all
* of the devices this structure can support.
* @num_interrupt_in: If a device doesn't have this many interrupt-in
@@ -218,82 +223,91 @@
struct usb_driver *usb_driver;
struct usb_dynids dynids;
- int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
- int (*attach) (struct usb_serial *serial);
+ int (*probe)(struct usb_serial *serial, const struct usb_device_id *id);
+ int (*attach)(struct usb_serial *serial);
int (*calc_num_ports) (struct usb_serial *serial);
- void (*shutdown) (struct usb_serial *serial);
+ void (*shutdown)(struct usb_serial *serial);
- int (*port_probe) (struct usb_serial_port *port);
- int (*port_remove) (struct usb_serial_port *port);
+ int (*port_probe)(struct usb_serial_port *port);
+ int (*port_remove)(struct usb_serial_port *port);
- int (*suspend) (struct usb_serial *serial, pm_message_t message);
- int (*resume) (struct usb_serial *serial);
+ int (*suspend)(struct usb_serial *serial, pm_message_t message);
+ int (*resume)(struct usb_serial *serial);
/* serial function calls */
- int (*open) (struct usb_serial_port *port, struct file * filp);
- void (*close) (struct usb_serial_port *port, struct file * filp);
- int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count);
- int (*write_room) (struct usb_serial_port *port);
- int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios) (struct usb_serial_port *port, struct ktermios * old);
- void (*break_ctl) (struct usb_serial_port *port, int break_state);
- int (*chars_in_buffer) (struct usb_serial_port *port);
- void (*throttle) (struct usb_serial_port *port);
- void (*unthrottle) (struct usb_serial_port *port);
- int (*tiocmget) (struct usb_serial_port *port, struct file *file);
- int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
+ int (*open)(struct usb_serial_port *port, struct file *filp);
+ void (*close)(struct usb_serial_port *port, struct file *filp);
+ int (*write)(struct usb_serial_port *port, const unsigned char *buf,
+ int count);
+ int (*write_room)(struct usb_serial_port *port);
+ int (*ioctl)(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg);
+ void (*set_termios)(struct usb_serial_port *port, struct ktermios *old);
+ void (*break_ctl)(struct usb_serial_port *port, int break_state);
+ int (*chars_in_buffer)(struct usb_serial_port *port);
+ void (*throttle)(struct usb_serial_port *port);
+ void (*unthrottle)(struct usb_serial_port *port);
+ int (*tiocmget)(struct usb_serial_port *port, struct file *file);
+ int (*tiocmset)(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear);
void (*read_int_callback)(struct urb *urb);
void (*write_int_callback)(struct urb *urb);
void (*read_bulk_callback)(struct urb *urb);
void (*write_bulk_callback)(struct urb *urb);
};
-#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
+#define to_usb_serial_driver(d) \
+ container_of(d, struct usb_serial_driver, driver)
extern int usb_serial_register(struct usb_serial_driver *driver);
extern void usb_serial_deregister(struct usb_serial_driver *driver);
extern void usb_serial_port_softint(struct usb_serial_port *port);
-extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
+extern int usb_serial_probe(struct usb_interface *iface,
+ const struct usb_device_id *id);
extern void usb_serial_disconnect(struct usb_interface *iface);
extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
extern int usb_serial_resume(struct usb_interface *intf);
-extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
-extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
+extern int ezusb_writememory(struct usb_serial *serial, int address,
+ unsigned char *data, int length, __u8 bRequest);
+extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit);
/* USB Serial console functions */
#ifdef CONFIG_USB_SERIAL_CONSOLE
-extern void usb_serial_console_init (int debug, int minor);
-extern void usb_serial_console_exit (void);
+extern void usb_serial_console_init(int debug, int minor);
+extern void usb_serial_console_exit(void);
extern void usb_serial_console_disconnect(struct usb_serial *serial);
#else
-static inline void usb_serial_console_init (int debug, int minor) { }
-static inline void usb_serial_console_exit (void) { }
+static inline void usb_serial_console_init(int debug, int minor) { }
+static inline void usb_serial_console_exit(void) { }
static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
#endif
/* Functions needed by other parts of the usbserial core */
-extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
+extern struct usb_serial *usb_serial_get_by_index(unsigned int minor);
extern void usb_serial_put(struct usb_serial *serial);
-extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
-extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_resume (struct usb_serial *serial);
-extern int usb_serial_generic_write_room (struct usb_serial_port *port);
-extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
-extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
-extern void usb_serial_generic_write_bulk_callback (struct urb *urb);
-extern void usb_serial_generic_throttle (struct usb_serial_port *port);
-extern void usb_serial_generic_unthrottle (struct usb_serial_port *port);
-extern void usb_serial_generic_shutdown (struct usb_serial *serial);
-extern int usb_serial_generic_register (int debug);
-extern void usb_serial_generic_deregister (void);
+extern int usb_serial_generic_open(struct usb_serial_port *port,
+ struct file *filp);
+extern int usb_serial_generic_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count);
+extern void usb_serial_generic_close(struct usb_serial_port *port,
+ struct file *filp);
+extern int usb_serial_generic_resume(struct usb_serial *serial);
+extern int usb_serial_generic_write_room(struct usb_serial_port *port);
+extern int usb_serial_generic_chars_in_buffer(struct usb_serial_port *port);
+extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
+extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
+extern void usb_serial_generic_throttle(struct usb_serial_port *port);
+extern void usb_serial_generic_unthrottle(struct usb_serial_port *port);
+extern void usb_serial_generic_shutdown(struct usb_serial *serial);
+extern int usb_serial_generic_register(int debug);
+extern void usb_serial_generic_deregister(void);
-extern int usb_serial_bus_register (struct usb_serial_driver *device);
-extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
+extern int usb_serial_bus_register(struct usb_serial_driver *device);
+extern void usb_serial_bus_deregister(struct usb_serial_driver *device);
extern struct usb_serial_driver usb_serial_generic_device;
extern struct bus_type usb_serial_bus_type;
@@ -307,16 +321,22 @@
int i;
if (debug) {
- dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size);
+ dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ",
+ function, size);
for (i = 0; i < size; ++i)
- printk ("%.2x ", data[i]);
- printk ("\n");
+ printk("%.2x ", data[i]);
+ printk("\n");
}
}
/* Use our own dbg macro */
#undef dbg
-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0)
+#define dbg(format, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , \
+ ## arg); \
+ } while (0)
diff --git a/include/linux/usb/sl811.h b/include/linux/usb/sl811.h
index 397ee3b..877373d 100644
--- a/include/linux/usb/sl811.h
+++ b/include/linux/usb/sl811.h
@@ -19,8 +19,8 @@
/* pulse sl811 nRST (probably with a GPIO) */
void (*reset)(struct device *dev);
- // some boards need something like these:
- // int (*check_overcurrent)(struct device *dev);
- // void (*clock_enable)(struct device *dev, int is_on);
+ /* some boards need something like these: */
+ /* int (*check_overcurrent)(struct device *dev); */
+ /* void (*clock_enable)(struct device *dev, int is_on); */
};
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index a417b09..cee0623 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -80,10 +80,9 @@
#define US_SC_UFI 0x04 /* Floppy */
#define US_SC_8070 0x05 /* Removable media */
#define US_SC_SCSI 0x06 /* Transparent */
-#define US_SC_ISD200 0x07 /* ISD200 ATA */
-#define US_SC_MIN US_SC_RBC
-#define US_SC_MAX US_SC_ISD200
+#define US_SC_LOCKABLE 0x07 /* Password-protected */
+#define US_SC_ISD200 0xf0 /* ISD200 ATA */
#define US_SC_DEVICE 0xff /* Use device's value */
/* Protocols */
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 8ca5a7f..17cb108 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -104,7 +104,7 @@
int error_count;
unsigned int signr; /* signal to be sent on completion,
or 0 if none should be sent. */
- void *usercontext;
+ void __user *usercontext;
struct usbdevfs_iso_packet_desc iso_frame_desc[0];
};
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 14e1379..260d1fc 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -11,15 +11,13 @@
/**
* virtqueue - a queue to register buffers for sending or receiving.
* @callback: the function to call when buffers are consumed (can be NULL).
- * If this returns false, callbacks are suppressed until vq_ops->restart
- * is called.
* @vdev: the virtio device this queue was created for.
* @vq_ops: the operations for this virtqueue (see below).
* @priv: a pointer for the virtqueue implementation to use.
*/
struct virtqueue
{
- bool (*callback)(struct virtqueue *vq);
+ void (*callback)(struct virtqueue *vq);
struct virtio_device *vdev;
struct virtqueue_ops *vq_ops;
void *priv;
@@ -41,13 +39,12 @@
* vq: the struct virtqueue we're talking about.
* len: the length written into the buffer
* Returns NULL or the "data" token handed to add_buf.
- * @restart: restart callbacks after callback returned false.
+ * @disable_cb: disable callbacks
+ * vq: the struct virtqueue we're talking about.
+ * @enable_cb: restart callbacks after disable_cb.
* vq: the struct virtqueue we're talking about.
* This returns "false" (and doesn't re-enable) if there are pending
* buffers in the queue, to avoid a race.
- * @shutdown: "unadd" all buffers.
- * vq: the struct virtqueue we're talking about.
- * Remove everything from the queue.
*
* Locking rules are straightforward: the driver is responsible for
* locking. No two operations may be invoked simultaneously.
@@ -65,9 +62,8 @@
void *(*get_buf)(struct virtqueue *vq, unsigned int *len);
- bool (*restart)(struct virtqueue *vq);
-
- void (*shutdown)(struct virtqueue *vq);
+ void (*disable_cb)(struct virtqueue *vq);
+ bool (*enable_cb)(struct virtqueue *vq);
};
/**
@@ -97,12 +93,15 @@
* @probe: the function to call when a device is found. Returns a token for
* remove, or PTR_ERR().
* @remove: the function when a device is removed.
+ * @config_changed: optional function to call when the device configuration
+ * changes; may be called in interrupt context.
*/
struct virtio_driver {
struct device_driver driver;
const struct virtio_device_id *id_table;
int (*probe)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
+ void (*config_changed)(struct virtio_device *dev);
};
int register_virtio_driver(struct virtio_driver *drv);
diff --git a/include/linux/virtio_balloon.h b/include/linux/virtio_balloon.h
new file mode 100644
index 0000000..979524e
--- /dev/null
+++ b/include/linux/virtio_balloon.h
@@ -0,0 +1,18 @@
+#ifndef _LINUX_VIRTIO_BALLOON_H
+#define _LINUX_VIRTIO_BALLOON_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio_balloon */
+#define VIRTIO_ID_BALLOON 5
+
+/* The feature bitmap for virtio balloon */
+#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
+
+struct virtio_balloon_config
+{
+ /* Number of pages host wants Guest to give up. */
+ __le32 num_pages;
+ /* Number of pages we've actually got in balloon. */
+ __le32 actual;
+};
+#endif /* _LINUX_VIRTIO_BALLOON_H */
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index 7bd2bce..bca0b10 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -6,15 +6,19 @@
#define VIRTIO_ID_BLOCK 2
/* Feature bits */
-#define VIRTIO_CONFIG_BLK_F 0x40
-#define VIRTIO_BLK_F_BARRIER 1 /* Does host support barriers? */
+#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
+#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
-/* The capacity (in 512-byte sectors). */
-#define VIRTIO_CONFIG_BLK_F_CAPACITY 0x41
-/* The maximum segment size. */
-#define VIRTIO_CONFIG_BLK_F_SIZE_MAX 0x42
-/* The maximum number of segments. */
-#define VIRTIO_CONFIG_BLK_F_SEG_MAX 0x43
+struct virtio_blk_config
+{
+ /* The capacity (in 512-byte sectors). */
+ __le64 capacity;
+ /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+ __le32 size_max;
+ /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+ __le32 seg_max;
+} __attribute__((packed));
/* These two define direction. */
#define VIRTIO_BLK_T_IN 0
@@ -35,8 +39,6 @@
__u32 ioprio;
/* Sector (ie. 512 byte offset) */
__u64 sector;
- /* Where to put reply. */
- __u64 id;
};
#define VIRTIO_BLK_S_OK 0
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index bcc0188..d581b29 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -5,7 +5,7 @@
* store and access that space differently. */
#include <linux/types.h>
-/* Status byte for guest to report progress, and synchronize config. */
+/* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
/* We have found a driver for the device. */
@@ -15,34 +15,27 @@
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80
-/* Feature byte (actually 7 bits availabe): */
-/* Requirements/features of the virtio implementation. */
-#define VIRTIO_CONFIG_F_VIRTIO 1
-/* Requirements/features of the virtqueue (may have more than one). */
-#define VIRTIO_CONFIG_F_VIRTQUEUE 2
-
#ifdef __KERNEL__
struct virtio_device;
/**
* virtio_config_ops - operations for configuring a virtio device
- * @find: search for the next configuration field of the given type.
+ * @feature: search for a feature in this config
* vdev: the virtio_device
- * type: the feature type
- * len: the (returned) length of the field if found.
- * Returns a token if found, or NULL. Never returnes the same field twice
- * (ie. it's used up).
- * @get: read the value of a configuration field after find().
+ * bit: the feature bit
+ * Returns true if the feature is supported. Acknowledges the feature
+ * so the host can see it.
+ * @get: read the value of a configuration field
* vdev: the virtio_device
- * token: the token returned from find().
+ * offset: the offset of the configuration field
* buf: the buffer to write the field value into.
- * len: the length of the buffer (given by find()).
+ * len: the length of the buffer
* Note that contents are conventionally little-endian.
- * @set: write the value of a configuration field after find().
+ * @set: write the value of a configuration field
* vdev: the virtio_device
- * token: the token returned from find().
+ * offset: the offset of the configuration field
* buf: the buffer to read the field value from.
- * len: the length of the buffer (given by find()).
+ * len: the length of the buffer
* Note that contents are conventionally little-endian.
* @get_status: read the status byte
* vdev: the virtio_device
@@ -50,62 +43,67 @@
* @set_status: write the status byte
* vdev: the virtio_device
* status: the new status byte
- * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue.
+ * @reset: reset the device
+ * vdev: the virtio device
+ * After this, status and feature negotiation must be done again
+ * @find_vq: find a virtqueue and instantiate it.
* vdev: the virtio_device
+ * index: the 0-based virtqueue number in case there's more than one.
* callback: the virqtueue callback
- * Returns the new virtqueue or ERR_PTR().
+ * Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
* @del_vq: free a virtqueue found by find_vq().
*/
struct virtio_config_ops
{
- void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);
- void (*get)(struct virtio_device *vdev, void *token,
+ bool (*feature)(struct virtio_device *vdev, unsigned bit);
+ void (*get)(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len);
- void (*set)(struct virtio_device *vdev, void *token,
+ void (*set)(struct virtio_device *vdev, unsigned offset,
const void *buf, unsigned len);
u8 (*get_status)(struct virtio_device *vdev);
void (*set_status)(struct virtio_device *vdev, u8 status);
+ void (*reset)(struct virtio_device *vdev);
struct virtqueue *(*find_vq)(struct virtio_device *vdev,
- bool (*callback)(struct virtqueue *));
+ unsigned index,
+ void (*callback)(struct virtqueue *));
void (*del_vq)(struct virtqueue *vq);
};
/**
- * virtio_config_val - get a single virtio config and mark it used.
- * @config: the virtio config space
- * @type: the type to search for.
+ * virtio_config_val - look for a feature and get a single virtio config.
+ * @vdev: the virtio device
+ * @fbit: the feature bit
+ * @offset: the type to search for.
* @val: a pointer to the value to fill in.
*
- * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
- * be found again. This version does endian conversion. */
-#define virtio_config_val(vdev, type, v) ({ \
- int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
- \
- BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \
- && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \
- if (!_err) { \
- switch (sizeof(*(v))) { \
- case 2: le16_to_cpus((__u16 *) v); break; \
- case 4: le32_to_cpus((__u32 *) v); break; \
- case 8: le64_to_cpus((__u64 *) v); break; \
- } \
- } \
+ * The return value is -ENOENT if the feature doesn't exist. Otherwise
+ * the value is endian-corrected and returned in v. */
+#define virtio_config_val(vdev, fbit, offset, v) ({ \
+ int _err; \
+ if ((vdev)->config->feature((vdev), (fbit))) { \
+ __virtio_config_val((vdev), (offset), (v)); \
+ _err = 0; \
+ } else \
+ _err = -ENOENT; \
_err; \
})
-int __virtio_config_val(struct virtio_device *dev,
- u8 type, void *val, size_t size);
-
/**
- * virtio_use_bit - helper to use a feature bit in a bitfield value.
- * @dev: the virtio device
- * @token: the token as returned from vdev->config->find().
- * @len: the length of the field.
- * @bitnum: the bit to test.
+ * __virtio_config_val - get a single virtio config without feature check.
+ * @vdev: the virtio device
+ * @offset: the type to search for.
+ * @val: a pointer to the value to fill in.
*
- * If handed a NULL token, it returns false, otherwise returns bit status.
- * If it's one, it sets the mirroring acknowledgement bit. */
-int virtio_use_bit(struct virtio_device *vdev,
- void *token, unsigned int len, unsigned int bitnum);
+ * The value is endian-corrected and returned in v. */
+#define __virtio_config_val(vdev, offset, v) do { \
+ BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \
+ && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \
+ (vdev)->config->get((vdev), (offset), (v), sizeof(*(v))); \
+ switch (sizeof(*(v))) { \
+ case 2: le16_to_cpus((__u16 *) v); break; \
+ case 4: le32_to_cpus((__u32 *) v); break; \
+ case 8: le64_to_cpus((__u64 *) v); break; \
+ } \
+} while(0)
#endif /* __KERNEL__ */
#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index ae469ae..1ea3351 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -5,32 +5,32 @@
/* The ID for virtio_net */
#define VIRTIO_ID_NET 1
-/* The bitmap of config for virtio net */
-#define VIRTIO_CONFIG_NET_F 0x40
-#define VIRTIO_NET_F_NO_CSUM 0
-#define VIRTIO_NET_F_TSO4 1
-#define VIRTIO_NET_F_UFO 2
-#define VIRTIO_NET_F_TSO4_ECN 3
-#define VIRTIO_NET_F_TSO6 4
+/* The feature bitmap for virtio net */
+#define VIRTIO_NET_F_CSUM 0 /* Can handle pkts w/ partial csum */
+#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */
+#define VIRTIO_NET_F_GSO 6 /* Can handle pkts w/ any GSO type */
-/* The config defining mac address. */
-#define VIRTIO_CONFIG_NET_MAC_F 0x41
+struct virtio_net_config
+{
+ /* The config defining mac address (if VIRTIO_NET_F_MAC) */
+ __u8 mac[6];
+} __attribute__((packed));
/* This is the first element of the scatter-gather list. If you don't
* specify GSO or CSUM features, you can simply ignore the header. */
struct virtio_net_hdr
{
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
- __u8 flags;
+ __u8 flags;
#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
-/* FIXME: Do we need this? If they said they can handle ECN, do they care? */
-#define VIRTIO_NET_HDR_GSO_TCPV4_ECN 2 // GSO frame, IPv4 TCP w/ ECN
#define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO)
#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP
- __u8 gso_type;
- __u16 gso_size;
- __u16 csum_start;
- __u16 csum_offset;
+#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set
+ __u8 gso_type;
+ __u16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
+ __u16 gso_size; /* Bytes to append to gso_hdr_len per frame */
+ __u16 csum_start; /* Position to start checksumming from */
+ __u16 csum_offset; /* Offset after that to place checksum */
};
#endif /* _LINUX_VIRTIO_NET_H */
diff --git a/include/linux/virtio_pci.h b/include/linux/virtio_pci.h
new file mode 100644
index 0000000..b315165
--- /dev/null
+++ b/include/linux/virtio_pci.h
@@ -0,0 +1,57 @@
+/*
+ * Virtio PCI driver
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _LINUX_VIRTIO_PCI_H
+#define _LINUX_VIRTIO_PCI_H
+
+#include <linux/virtio_config.h>
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES 0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES 4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN 8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM 12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL 14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY 16
+
+/* An 8-bit device status register. */
+#define VIRTIO_PCI_STATUS 18
+
+/* An 8-bit r/o interrupt status register. Reading the value will return the
+ * current contents of the ISR and will also clear it. This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR 19
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG 0x2
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG 20
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION 0
+#endif
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index 1a4ed49..abe481e 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -15,9 +15,13 @@
/* This marks a buffer as write-only (otherwise read-only). */
#define VRING_DESC_F_WRITE 2
-/* This means don't notify other side when buffer added. */
+/* The Host uses this in used->flags to advise the Guest: don't kick me when
+ * you add a buffer. It's unreliable, so it's simply an optimization. Guest
+ * will still kick if it's out of buffers. */
#define VRING_USED_F_NO_NOTIFY 1
-/* This means don't interrupt guest when buffer consumed. */
+/* The Guest uses this in avail->flags to advise the Host: don't interrupt me
+ * when you consume a buffer. It's unreliable, so it's simply an
+ * optimization. */
#define VRING_AVAIL_F_NO_INTERRUPT 1
/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */
@@ -89,7 +93,7 @@
* };
*/
static inline void vring_init(struct vring *vr, unsigned int num, void *p,
- unsigned int pagesize)
+ unsigned long pagesize)
{
vr->num = num;
vr->desc = p;
@@ -98,7 +102,7 @@
& ~(pagesize - 1));
}
-static inline unsigned vring_size(unsigned int num, unsigned int pagesize)
+static inline unsigned vring_size(unsigned int num, unsigned long pagesize)
{
return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+ pagesize - 1) & ~(pagesize - 1))
@@ -114,7 +118,7 @@
struct virtio_device *vdev,
void *pages,
void (*notify)(struct virtqueue *vq),
- bool (*callback)(struct virtqueue *vq));
+ void (*callback)(struct virtqueue *vq));
void vring_del_virtqueue(struct virtqueue *vq);
irqreturn_t vring_interrupt(int irq, void *_vq);
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 89338b4..ce8e7da 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -45,11 +45,11 @@
extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot);
-extern void vfree(void *addr);
+extern void vfree(const void *addr);
extern void *vmap(struct page **pages, unsigned int count,
unsigned long flags, pgprot_t prot);
-extern void vunmap(void *addr);
+extern void vunmap(const void *addr);
extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
unsigned long pgoff);
@@ -71,7 +71,7 @@
extern struct vm_struct *get_vm_area_node(unsigned long size,
unsigned long flags, int node,
gfp_t gfp_mask);
-extern struct vm_struct *remove_vm_area(void *addr);
+extern struct vm_struct *remove_vm_area(const void *addr);
extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
struct page ***pages);
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index feb5e99..9448ffb 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -77,6 +77,7 @@
void reset_vc(struct vc_data *vc);
extern int unbind_con_driver(const struct consw *csw, int first, int last,
int deflt);
+int vty_init(void);
/*
* vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
new file mode 100644
index 0000000..9797fec
--- /dev/null
+++ b/include/linux/w1-gpio.h
@@ -0,0 +1,23 @@
+/*
+ * w1-gpio interface to platform code
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_W1_GPIO_H
+#define _LINUX_W1_GPIO_H
+
+/**
+ * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio
+ * @pin: GPIO pin to use
+ * @is_open_drain: GPIO pin is configured as open drain
+ */
+struct w1_gpio_platform_data {
+ unsigned int pin;
+ unsigned int is_open_drain:1;
+};
+
+#endif /* _LINUX_W1_GPIO_H */
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 1f4fb0a..33a2aa9 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -162,6 +162,22 @@
#define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
#define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+/*
+ * macro to avoid include hell
+ */
+#define wake_up_nested(x, s) \
+do { \
+ unsigned long flags; \
+ \
+ spin_lock_irqsave_nested(&(x)->lock, flags, (s)); \
+ wake_up_locked(x); \
+ spin_unlock_irqrestore(&(x)->lock, flags); \
+} while (0)
+#else
+#define wake_up_nested(x, s) wake_up(x)
+#endif
+
#define __wait_event(wq, condition) \
do { \
DEFINE_WAIT(__wait); \
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 74e84ca..3160dfed 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -1079,7 +1079,7 @@
*/
struct iw_event
{
- __u16 len; /* Real lenght of this stuff */
+ __u16 len; /* Real length of this stuff */
__u16 cmd; /* Wireless IOCTL */
union iwreq_data u; /* IOCTL fixed payload */
};
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index c6148bb..b7b3362 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -62,6 +62,7 @@
unsigned for_reclaim:1; /* Invoked from the page allocator */
unsigned for_writepages:1; /* This is a writepages() call */
unsigned range_cyclic:1; /* range_start is cyclic */
+ unsigned more_io:1; /* more io to be dispatched */
};
/*
@@ -100,6 +101,7 @@
extern int vm_dirty_ratio;
extern int dirty_writeback_interval;
extern int dirty_expire_interval;
+extern int vm_highmem_is_dirtyable;
extern int block_dump;
extern int laptop_mode;
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index def131a..df6b95d 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -46,6 +46,7 @@
size_t size, int flags);
};
+ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
diff --git a/include/media/rds.h b/include/media/rds.h
index 951c1ae0..a894266 100644
--- a/include/media/rds.h
+++ b/include/media/rds.h
@@ -4,7 +4,7 @@
saa6588.c and every driver (e.g. bttv-driver.c) that wants
to use the saa6588 module.
- Instead of having a seperate rds.h, I'd prefer to include
+ Instead of having a separate rds.h, I'd prefer to include
this stuff in one of the already existing files like tuner.h
(c) 2005 by Hans J. Koch
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 625346c..585eb44 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -124,6 +124,7 @@
P9_DMSOCKET = 0x00100000,
P9_DMSETUID = 0x00080000,
P9_DMSETGID = 0x00040000,
+ P9_DMSETVTX = 0x00010000,
};
/* qid.types */
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 9b9221a..e52f93d 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -3,6 +3,7 @@
*
* 9P Client Definitions
*
+ * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +30,7 @@
spinlock_t lock; /* protect client structure */
int msize;
unsigned char dotu;
+ struct p9_trans_module *trans_mod;
struct p9_trans *trans;
struct p9_conn *conn;
@@ -52,8 +54,7 @@
struct list_head dlist; /* list of all fids attached to a dentry */
};
-struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
- int dotu);
+struct p9_client *p9_client_create(const char *dev_name, char *options);
void p9_client_destroy(struct p9_client *clnt);
void p9_client_disconnect(struct p9_client *clnt);
struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
diff --git a/include/net/9p/conn.h b/include/net/9p/conn.h
deleted file mode 100644
index 756d878..0000000
--- a/include/net/9p/conn.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * include/net/9p/conn.h
- *
- * Connection Definitions
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#ifndef NET_9P_CONN_H
-#define NET_9P_CONN_H
-
-#undef P9_NONBLOCK
-
-struct p9_conn;
-struct p9_req;
-
-/**
- * p9_mux_req_callback - callback function that is called when the
- * response of a request is received. The callback is called from
- * a workqueue and shouldn't block.
- *
- * @req - request
- * @a - the pointer that was specified when the request was send to be
- * passed to the callback
- */
-typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
-
-struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
- unsigned char *dotu);
-void p9_conn_destroy(struct p9_conn *);
-int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc);
-
-#ifdef P9_NONBLOCK
-int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
- p9_conn_req_callback cb, void *a);
-#endif /* P9_NONBLOCK */
-
-void p9_conn_cancel(struct p9_conn *m, int err);
-
-#endif /* NET_9P_CONN_H */
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 9dd4a05..d2209ae9 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -4,7 +4,7 @@
* Transport Definition
*
* Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -34,11 +34,12 @@
struct p9_trans {
enum p9_trans_status status;
+ int msize;
+ unsigned char extended;
void *priv;
- int (*write) (struct p9_trans *, void *, int);
- int (*read) (struct p9_trans *, void *, int);
void (*close) (struct p9_trans *);
- unsigned int (*poll)(struct p9_trans *, struct poll_table_struct *);
+ int (*rpc) (struct p9_trans *t, struct p9_fcall *tc,
+ struct p9_fcall **rc);
};
struct p9_trans_module {
@@ -46,7 +47,7 @@
char *name; /* name of transport */
int maxsize; /* max message size of transport */
int def; /* this transport should be default */
- struct p9_trans * (*create)(const char *devname, char *options);
+ struct p9_trans * (*create)(const char *, char *, int, unsigned char);
};
void v9fs_register_trans(struct p9_trans_module *m);
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index b24508a..b2cfc49 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -112,13 +112,13 @@
struct ip6_sf_list *mca_sources;
struct ip6_sf_list *mca_tomb;
unsigned int mca_sfmode;
+ unsigned char mca_crcount;
unsigned long mca_sfcount[2];
struct timer_list mca_timer;
unsigned mca_flags;
int mca_users;
atomic_t mca_refcnt;
spinlock_t mca_lock;
- unsigned char mca_crcount;
unsigned long mca_cstamp;
unsigned long mca_tstamp;
};
@@ -166,11 +166,11 @@
struct ifmcaddr6 *mc_list;
struct ifmcaddr6 *mc_tomb;
rwlock_t mc_lock;
- unsigned long mc_v1_seen;
- unsigned long mc_maxdelay;
unsigned char mc_qrv;
unsigned char mc_gq_running;
unsigned char mc_ifc_count;
+ unsigned long mc_v1_seen;
+ unsigned long mc_maxdelay;
struct timer_list mc_gq_timer; /* general query timer */
struct timer_list mc_ifc_timer; /* interface change timer */
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index fdff630..62a5b69 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -49,7 +49,7 @@
return inet6_ehashfn(laddr, lport, faddr, fport);
}
-extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
+extern void __inet6_hash(struct sock *sk);
/*
* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 133cf30..f00f057 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -29,7 +29,6 @@
#undef INET_CSK_CLEAR_TIMERS
struct inet_bind_bucket;
-struct inet_hashinfo;
struct tcp_congestion_ops;
/*
@@ -59,6 +58,8 @@
int level, int optname,
char __user *optval, int __user *optlen);
void (*addr2sockaddr)(struct sock *sk, struct sockaddr *);
+ int (*bind_conflict)(const struct sock *sk,
+ const struct inet_bind_bucket *tb);
};
/** inet_connection_sock - INET connection oriented sock
@@ -244,10 +245,7 @@
const __be32 laddr);
extern int inet_csk_bind_conflict(const struct sock *sk,
const struct inet_bind_bucket *tb);
-extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
- struct sock *sk, unsigned short snum,
- int (*bind_conflict)(const struct sock *sk,
- const struct inet_bind_bucket *tb));
+extern int inet_csk_get_port(struct sock *sk, unsigned short snum);
extern struct dst_entry* inet_csk_route_req(struct sock *sk,
const struct request_sock *req);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index c23c4ed..97dc35a 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -221,9 +221,9 @@
}
/* Caller must disable local BH processing. */
-static inline void __inet_inherit_port(struct inet_hashinfo *table,
- struct sock *sk, struct sock *child)
+static inline void __inet_inherit_port(struct sock *sk, struct sock *child)
{
+ struct inet_hashinfo *table = sk->sk_prot->hashinfo;
const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size);
struct inet_bind_hashbucket *head = &table->bhash[bhash];
struct inet_bind_bucket *tb;
@@ -235,15 +235,14 @@
spin_unlock(&head->lock);
}
-static inline void inet_inherit_port(struct inet_hashinfo *table,
- struct sock *sk, struct sock *child)
+static inline void inet_inherit_port(struct sock *sk, struct sock *child)
{
local_bh_disable();
- __inet_inherit_port(table, sk, child);
+ __inet_inherit_port(sk, child);
local_bh_enable();
}
-extern void inet_put_port(struct inet_hashinfo *table, struct sock *sk);
+extern void inet_put_port(struct sock *sk);
extern void inet_listen_wlock(struct inet_hashinfo *hashinfo);
@@ -266,41 +265,9 @@
wake_up(&hashinfo->lhash_wait);
}
-extern void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
-extern void __inet_hash_nolisten(struct inet_hashinfo *hinfo, struct sock *sk);
-
-static inline void inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
-{
- if (sk->sk_state != TCP_CLOSE) {
- local_bh_disable();
- __inet_hash(hashinfo, sk);
- local_bh_enable();
- }
-}
-
-static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk)
-{
- rwlock_t *lock;
-
- if (sk_unhashed(sk))
- goto out;
-
- if (sk->sk_state == TCP_LISTEN) {
- local_bh_disable();
- inet_listen_wlock(hashinfo);
- lock = &hashinfo->lhash_lock;
- } else {
- lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
- write_lock_bh(lock);
- }
-
- if (__sk_del_node_init(sk))
- sock_prot_inuse_add(sk->sk_prot, -1);
- write_unlock_bh(lock);
-out:
- if (sk->sk_state == TCP_LISTEN)
- wake_up(&hashinfo->lhash_wait);
-}
+extern void __inet_hash_nolisten(struct sock *sk);
+extern void inet_hash(struct sock *sk);
+extern void inet_unhash(struct sock *sk);
extern struct sock *__inet_lookup_listener(struct net *net,
struct inet_hashinfo *hashinfo,
@@ -422,10 +389,10 @@
}
extern int __inet_hash_connect(struct inet_timewait_death_row *death_row,
- struct sock *sk,
+ struct sock *sk, u32 port_offset,
int (*check_established)(struct inet_timewait_death_row *,
struct sock *, __u16, struct inet_timewait_sock **),
- void (*hash)(struct inet_hashinfo *, struct sock *));
+ void (*hash)(struct sock *sk));
extern int inet_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk);
#endif /* _INET_HASHTABLES_H */
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 67e9250..296547b 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -116,6 +116,7 @@
#define tw_hash __tw_common.skc_hash
#define tw_prot __tw_common.skc_prot
#define tw_net __tw_common.skc_net
+ int tw_timeout;
volatile unsigned char tw_substate;
/* 3 bits hole, try to pack */
unsigned char tw_rcv_wscale;
@@ -130,7 +131,6 @@
__u8 tw_ipv6only:1;
/* 15 bits hole, try to pack */
__u16 tw_ipv6_offset;
- int tw_timeout;
unsigned long tw_ttd;
struct inet_bind_bucket *tw_tb;
struct hlist_node tw_death_node;
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 90d1175..8b12667 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -266,6 +266,14 @@
#ifdef CONFIG_PROC_FS
extern int __net_init fib_proc_init(struct net *net);
extern void __net_exit fib_proc_exit(struct net *net);
+#else
+static inline int fib_proc_init(struct net *net)
+{
+ return 0;
+}
+static inline void fib_proc_exit(struct net *net)
+{
+}
#endif
#endif /* _NET_FIB_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index fa80ea4..c0c019f 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -110,7 +110,6 @@
/* sysctls */
extern int sysctl_mld_max_msf;
-
extern struct ctl_path net_ipv6_ctl_path[];
#define _DEVINC(statname, modifier, idev, field) \
@@ -586,9 +585,6 @@
int __user *optlen);
#ifdef CONFIG_PROC_FS
-extern struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
-extern struct ctl_table *ipv6_route_sysctl_init(struct net *net);
-
extern int ac6_proc_init(void);
extern void ac6_proc_exit(void);
extern int raw6_proc_init(void);
@@ -621,6 +617,8 @@
extern ctl_table ipv6_route_table_template[];
extern ctl_table ipv6_icmp_table_template[];
+extern struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
+extern struct ctl_table *ipv6_route_sysctl_init(struct net *net);
extern int ipv6_sysctl_register(void);
extern void ipv6_sysctl_unregister(void);
#endif
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index b3213c7..0ca67d7 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -36,6 +36,8 @@
#include <net/netlink.h>
#include <asm/atomic.h>
+struct cipso_v4_doi;
+
/*
* NetLabel - A management interface for maintaining network packet label
* mapping tables for explicit packet labling protocols.
@@ -103,12 +105,6 @@
uid_t loginuid;
};
-/* Domain mapping definition struct */
-struct netlbl_dom_map;
-
-/* Domain mapping operations */
-int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
-
/*
* LSM security attributes
*/
@@ -344,6 +340,19 @@
#ifdef CONFIG_NETLABEL
/*
+ * LSM configuration operations
+ */
+int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
+int netlbl_cfg_unlbl_add_map(const char *domain,
+ struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+ struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+ const char *domain,
+ struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
+
+/*
* LSM security attribute operations
*/
int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
@@ -378,6 +387,32 @@
int netlbl_cache_add(const struct sk_buff *skb,
const struct netlbl_lsm_secattr *secattr);
#else
+static inline int netlbl_cfg_map_del(const char *domain,
+ struct netlbl_audit *audit_info)
+{
+ return -ENOSYS;
+}
+static inline int netlbl_cfg_unlbl_add_map(const char *domain,
+ struct netlbl_audit *audit_info)
+{
+ return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+ struct netlbl_audit *audit_info)
+{
+ return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+ const char *domain,
+ struct netlbl_audit *audit_info)
+{
+ return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_del(u32 doi,
+ struct netlbl_audit *audit_info)
+{
+ return -ENOSYS;
+}
static inline int netlbl_secattr_catmap_walk(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
diff --git a/include/net/sock.h b/include/net/sock.h
index e3fb4c0..8a7889b 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -496,6 +496,7 @@
struct request_sock_ops;
struct timewait_sock_ops;
+struct inet_hashinfo;
/* Networking protocol blocks we attach to sockets.
* socket layer -> transport layer interface
@@ -578,6 +579,8 @@
struct request_sock_ops *rsk_prot;
struct timewait_sock_ops *twsk_prot;
+ struct inet_hashinfo *hashinfo;
+
struct module *owner;
char name[32];
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index d5838c3..87a260e 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -147,11 +147,11 @@
/* For RequestIO and ReleaseIO */
typedef struct io_req_t {
- ioaddr_t BasePort1;
- ioaddr_t NumPorts1;
+ u_int BasePort1;
+ u_int NumPorts1;
u_int Attributes1;
- ioaddr_t BasePort2;
- ioaddr_t NumPorts2;
+ u_int BasePort2;
+ u_int NumPorts2;
u_int Attributes2;
u_int IOAddrLines;
} io_req_t;
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
index 5f38803..9a6bcc4 100644
--- a/include/pcmcia/cs_types.h
+++ b/include/pcmcia/cs_types.h
@@ -27,7 +27,6 @@
#else
typedef u_short ioaddr_t;
#endif
-typedef unsigned long kio_addr_t;
typedef u_short socket_t;
typedef u_int event_t;
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 6e84258..f95dca0 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -92,7 +92,7 @@
u_char map;
u_char flags;
u_short speed;
- kio_addr_t start, stop;
+ u_int start, stop;
} pccard_io_map;
typedef struct pccard_mem_map {
@@ -155,7 +155,7 @@
struct pcmcia_socket;
typedef struct io_window_t {
- kio_addr_t InUse, Config;
+ u_int InUse, Config;
struct resource *res;
} io_window_t;
@@ -208,7 +208,7 @@
u_int features;
u_int irq_mask;
u_int map_size;
- kio_addr_t io_offset;
+ u_int io_offset;
u_char pci_irq;
struct pci_dev * cb_dev;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index e466d88..4769efd4d 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -176,7 +176,7 @@
* ports has a unique presense on the SAN, and may be instantiated via
* NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
* unique presense, each vport has it's own view of the fabric,
- * authentication priviledge, and priorities.
+ * authentication privilege, and priorities.
*
* A virtual port may support 1 or more FC4 roles. Typically it is a
* FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
index 4eea637..336c20d 100644
--- a/include/video/atmel_lcdc.h
+++ b/include/video/atmel_lcdc.h
@@ -22,7 +22,7 @@
#ifndef __ATMEL_LCDC_H__
#define __ATMEL_LCDC_H__
- /* LCD Controller info data structure */
+ /* LCD Controller info data structure, stored in device platform_data */
struct atmel_lcdfb_info {
spinlock_t lock;
struct fb_info *info;
@@ -33,7 +33,14 @@
struct platform_device *pdev;
struct clk *bus_clk;
struct clk *lcdc_clk;
- unsigned int default_bpp;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+ struct backlight_device *backlight;
+ u8 bl_power;
+#endif
+ bool lcdcon_is_backlight;
+
+ u8 default_bpp;
unsigned int default_lcdcon2;
unsigned int default_dmacon;
void (*atmel_lcdfb_power_control)(int on);
@@ -115,20 +122,20 @@
#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31)
#define ATMEL_LCDC_TIM1 0x0808
-#define ATMEL_LCDC_VFP (0xff << 0)
+#define ATMEL_LCDC_VFP (0xffU << 0)
#define ATMEL_LCDC_VBP_OFFSET 8
-#define ATMEL_LCDC_VBP (0xff << ATMEL_LCDC_VBP_OFFSET)
+#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET)
#define ATMEL_LCDC_VPW_OFFSET 16
-#define ATMEL_LCDC_VPW (0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET)
#define ATMEL_LCDC_VHDLY_OFFSET 24
-#define ATMEL_LCDC_VHDLY (0xf << ATMEL_LCDC_VHDLY_OFFSET)
+#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET)
#define ATMEL_LCDC_TIM2 0x080c
-#define ATMEL_LCDC_HBP (0xff << 0)
+#define ATMEL_LCDC_HBP (0xffU << 0)
#define ATMEL_LCDC_HPW_OFFSET 8
-#define ATMEL_LCDC_HPW (0x3f << ATMEL_LCDC_HPW_OFFSET)
+#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET)
#define ATMEL_LCDC_HFP_OFFSET 21
-#define ATMEL_LCDC_HFP (0x7ff << ATMEL_LCDC_HFP_OFFSET)
+#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
#define ATMEL_LCDC_LCDFRMCFG 0x0810
#define ATMEL_LCDC_LINEVAL (0x7ff << 0)
diff --git a/init/Kconfig b/init/Kconfig
index dcc96a8..92b23e2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -541,6 +541,18 @@
help
Enable support for generating core dumps. Disabling saves about 4k.
+config COMPAT_BRK
+ bool "Disable heap randomization"
+ default y
+ help
+ Randomizing heap placement makes heap exploits harder, but it
+ also breaks ancient binaries (including anything libc5 based).
+ This option changes the bootup default to heap randomization
+ disabled, and can be overriden runtime by setting
+ /proc/sys/kernel/randomize_va_space to 2.
+
+ On non-ancient distros (post-2000 ones) Y is usually a safe choice.
+
config BASE_FULL
default y
bool "Enable full-sized data structures for core" if EMBEDDED
@@ -582,7 +594,6 @@
config TIMERFD
bool "Enable timerfd() system call" if EMBEDDED
select ANON_INODES
- depends on BROKEN
default y
help
Enable the timerfd() system call that allows to receive timer
@@ -657,14 +668,36 @@
depends on EMBEDDED
bool "SLOB (Simple Allocator)"
help
- SLOB replaces the SLAB allocator with a drastically simpler
- allocator. SLOB is more space efficient than SLAB but does not
- scale well (single lock for all operations) and is also highly
- susceptible to fragmentation. SLUB can accomplish a higher object
- density. It is usually better to use SLUB instead of SLOB.
+ SLOB replaces the stock allocator with a drastically simpler
+ allocator. SLOB is generally more space efficient but
+ does not perform as well on large systems.
endchoice
+config PROFILING
+ bool "Profiling support (EXPERIMENTAL)"
+ help
+ Say Y here to enable the extended profiling support mechanisms used
+ by profilers such as OProfile.
+
+config MARKERS
+ bool "Activate markers"
+ help
+ Place an empty function call at each marker site. Can be
+ dynamically changed for a probe function.
+
+source "arch/Kconfig"
+
+config PROC_PAGE_MONITOR
+ default y
+ depends on PROC_FS && MMU
+ bool "Enable /proc page monitoring" if EMBEDDED
+ help
+ Various /proc files exist to monitor process memory utilization:
+ /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+ /proc/kpagecount, and /proc/kpageflags. Disabling these
+ interfaces will reduce the size of the kernel by approximately 4kb.
+
endmenu # General setup
config SLABINFO
diff --git a/init/calibrate.c b/init/calibrate.c
index 2d3d73b..ecb3822 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -7,8 +7,7 @@
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/init.h>
-
-#include <asm/timex.h>
+#include <linux/timex.h>
unsigned long preset_lpj;
static int __init lpj_setup(char *str)
@@ -29,7 +28,7 @@
#define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100))
#define MAX_DIRECT_CALIBRATION_RETRIES 5
-static unsigned long __devinit calibrate_delay_direct(void)
+static unsigned long __cpuinit calibrate_delay_direct(void)
{
unsigned long pre_start, start, post_start;
unsigned long pre_end, end, post_end;
@@ -102,7 +101,7 @@
return 0;
}
#else
-static unsigned long __devinit calibrate_delay_direct(void) {return 0;}
+static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
#endif
/*
@@ -112,7 +111,7 @@
*/
#define LPS_PREC 8
-void __devinit calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
{
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 1161dfd..f865731 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -11,6 +11,7 @@
#include <linux/mount.h>
#include <linux/device.h>
#include <linux/init.h>
+#include <linux/fs.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
@@ -18,8 +19,6 @@
#include "do_mounts.h"
-extern int get_filesystem_list(char * buf);
-
int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
int root_mountflags = MS_RDONLY | MS_SILENT;
diff --git a/init/initramfs.c b/init/initramfs.c
index 1db02a0..d53fee8 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -503,7 +503,6 @@
__setup("retain_initrd", retain_initrd_param);
extern char __initramfs_start[], __initramfs_end[];
-#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/initrd.h>
#include <linux/kexec.h>
@@ -539,15 +538,12 @@
initrd_end = 0;
}
-#endif
-
static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end - __initramfs_start, 0);
if (err)
panic(err);
-#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) {
#ifdef CONFIG_BLK_DEV_RAM
int fd;
@@ -579,7 +575,6 @@
free_initrd();
#endif
}
-#endif
return 0;
}
rootfs_initcall(populate_rootfs);
diff --git a/init/main.c b/init/main.c
index cb81ed1..c691f5f 100644
--- a/init/main.c
+++ b/init/main.c
@@ -57,6 +57,7 @@
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/sched.h>
+#include <linux/signal.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -83,7 +84,6 @@
extern void fork_init(unsigned long);
extern void mca_init(void);
extern void sbus_init(void);
-extern void signals_init(void);
extern void pidhash_init(void);
extern void pidmap_init(void);
extern void prio_tree_init(void);
diff --git a/ipc/msg.c b/ipc/msg.c
index fdf3db5..ec0c724 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -105,6 +105,7 @@
void msg_exit_ns(struct ipc_namespace *ns)
{
struct msg_queue *msq;
+ struct kern_ipc_perm *perm;
int next_id;
int total, in_use;
@@ -113,10 +114,11 @@
in_use = msg_ids(ns).in_use;
for (total = 0, next_id = 0; total < in_use; next_id++) {
- msq = idr_find(&msg_ids(ns).ipcs_idr, next_id);
- if (msq == NULL)
+ perm = idr_find(&msg_ids(ns).ipcs_idr, next_id);
+ if (perm == NULL)
continue;
- ipc_lock_by_ptr(&msq->q_perm);
+ ipc_lock_by_ptr(perm);
+ msq = container_of(perm, struct msg_queue, q_perm);
freeque(ns, msq);
total++;
}
@@ -144,6 +146,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct msg_queue *)ipcp;
+
return container_of(ipcp, struct msg_queue, q_perm);
}
@@ -155,6 +160,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct msg_queue *)ipcp;
+
return container_of(ipcp, struct msg_queue, q_perm);
}
@@ -163,6 +171,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct msg_queue *)ipcp;
+
return container_of(ipcp, struct msg_queue, q_perm);
}
diff --git a/ipc/sem.c b/ipc/sem.c
index 35952c0..d65e285 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -143,6 +143,7 @@
void sem_exit_ns(struct ipc_namespace *ns)
{
struct sem_array *sma;
+ struct kern_ipc_perm *perm;
int next_id;
int total, in_use;
@@ -151,10 +152,11 @@
in_use = sem_ids(ns).in_use;
for (total = 0, next_id = 0; total < in_use; next_id++) {
- sma = idr_find(&sem_ids(ns).ipcs_idr, next_id);
- if (sma == NULL)
+ perm = idr_find(&sem_ids(ns).ipcs_idr, next_id);
+ if (perm == NULL)
continue;
- ipc_lock_by_ptr(&sma->sem_perm);
+ ipc_lock_by_ptr(perm);
+ sma = container_of(perm, struct sem_array, sem_perm);
freeary(ns, sma);
total++;
}
@@ -181,6 +183,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct sem_array *)ipcp;
+
return container_of(ipcp, struct sem_array, sem_perm);
}
@@ -192,6 +197,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct sem_array *)ipcp;
+
return container_of(ipcp, struct sem_array, sem_perm);
}
@@ -200,6 +208,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct sem_array *)ipcp;
+
return container_of(ipcp, struct sem_array, sem_perm);
}
diff --git a/ipc/shm.c b/ipc/shm.c
index 3818fae..65c3a29 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -111,6 +111,7 @@
void shm_exit_ns(struct ipc_namespace *ns)
{
struct shmid_kernel *shp;
+ struct kern_ipc_perm *perm;
int next_id;
int total, in_use;
@@ -119,10 +120,11 @@
in_use = shm_ids(ns).in_use;
for (total = 0, next_id = 0; total < in_use; next_id++) {
- shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
- if (shp == NULL)
+ perm = idr_find(&shm_ids(ns).ipcs_idr, next_id);
+ if (perm == NULL)
continue;
- ipc_lock_by_ptr(&shp->shm_perm);
+ ipc_lock_by_ptr(perm);
+ shp = container_of(perm, struct shmid_kernel, shm_perm);
do_shm_rmid(ns, shp);
total++;
}
@@ -149,6 +151,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct shmid_kernel *)ipcp;
+
return container_of(ipcp, struct shmid_kernel, shm_perm);
}
@@ -158,6 +163,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct shmid_kernel *)ipcp;
+
return container_of(ipcp, struct shmid_kernel, shm_perm);
}
@@ -169,6 +177,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct shmid_kernel *)ipcp;
+
return container_of(ipcp, struct shmid_kernel, shm_perm);
}
@@ -177,6 +188,9 @@
{
struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
+ if (IS_ERR(ipcp))
+ return (struct shmid_kernel *)ipcp;
+
return container_of(ipcp, struct shmid_kernel, shm_perm);
}
diff --git a/ipc/util.c b/ipc/util.c
index 1aa0ebf..76c1f34 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -802,8 +802,8 @@
/*
* This routine locks the ipc structure found at least at position pos.
*/
-struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
- loff_t *new_pos)
+static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
+ loff_t *new_pos)
{
struct kern_ipc_perm *ipc;
int total, id;
diff --git a/kernel/Kconfig.instrumentation b/kernel/Kconfig.instrumentation
deleted file mode 100644
index 468f47a..0000000
--- a/kernel/Kconfig.instrumentation
+++ /dev/null
@@ -1,49 +0,0 @@
-menuconfig INSTRUMENTATION
- bool "Instrumentation Support"
- default y
- ---help---
- Say Y here to get to see options related to performance measurement,
- system-wide debugging, and testing. This option alone does not add any
- kernel code.
-
- If you say N, all options in this submenu will be skipped and
- disabled. If you're trying to debug the kernel itself, go see the
- Kernel Hacking menu.
-
-if INSTRUMENTATION
-
-config PROFILING
- bool "Profiling support (EXPERIMENTAL)"
- help
- Say Y here to enable the extended profiling support mechanisms used
- by profilers such as OProfile.
-
-config OPROFILE
- tristate "OProfile system profiling (EXPERIMENTAL)"
- depends on PROFILING && !UML
- depends on ARCH_SUPPORTS_OPROFILE || ALPHA || ARM || BLACKFIN || IA64 || M32R || PARISC || PPC || S390 || SUPERH || SPARC
- help
- OProfile is a profiling system capable of profiling the
- whole system, include the kernel, kernel modules, libraries,
- and applications.
-
- If unsure, say N.
-
-config KPROBES
- bool "Kprobes"
- depends on KALLSYMS && MODULES && !UML
- depends on X86_32 || IA64 || PPC || S390 || SPARC64 || X86_64 || AVR32
- help
- Kprobes allows you to trap at almost any kernel address and
- execute a callback function. register_kprobe() establishes
- a probepoint and specifies the callback. Kprobes is useful
- for kernel debugging, non-intrusive instrumentation and testing.
- If in doubt, say "N".
-
-config MARKERS
- bool "Activate markers"
- help
- Place an empty function call at each marker site. Can be
- dynamically changed for a probe function.
-
-endif # INSTRUMENTATION
diff --git a/kernel/Makefile b/kernel/Makefile
index 8885627..135a1b9 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -8,8 +8,8 @@
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
- hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \
- utsname.o notifier.o
+ hrtimer.o rwsem.o nsproxy.o srcu.o \
+ utsname.o notifier.o ksysfs.o pm_qos_params.o
obj-$(CONFIG_SYSCTL) += sysctl_check.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
@@ -49,7 +49,6 @@
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_SYSFS) += ksysfs.o
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
diff --git a/kernel/capability.c b/kernel/capability.c
index efbd9cd..39e8193 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -22,6 +22,37 @@
static DEFINE_SPINLOCK(task_capability_lock);
/*
+ * Leveraged for setting/resetting capabilities
+ */
+
+const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
+const kernel_cap_t __cap_full_set = CAP_FULL_SET;
+const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET;
+
+EXPORT_SYMBOL(__cap_empty_set);
+EXPORT_SYMBOL(__cap_full_set);
+EXPORT_SYMBOL(__cap_init_eff_set);
+
+/*
+ * More recent versions of libcap are available from:
+ *
+ * http://www.kernel.org/pub/linux/libs/security/linux-privs/
+ */
+
+static void warn_legacy_capability_use(void)
+{
+ static int warned;
+ if (!warned) {
+ char name[sizeof(current->comm)];
+
+ printk(KERN_INFO "warning: `%s' uses 32-bit capabilities"
+ " (legacy support in use)\n",
+ get_task_comm(name, current));
+ warned = 1;
+ }
+}
+
+/*
* For sys_getproccap() and sys_setproccap(), any of the three
* capability set pointers may be NULL -- indicating that that set is
* uninteresting and/or not to be changed.
@@ -42,12 +73,21 @@
pid_t pid;
__u32 version;
struct task_struct *target;
- struct __user_cap_data_struct data;
+ unsigned tocopy;
+ kernel_cap_t pE, pI, pP;
if (get_user(version, &header->version))
return -EFAULT;
- if (version != _LINUX_CAPABILITY_VERSION) {
+ switch (version) {
+ case _LINUX_CAPABILITY_VERSION_1:
+ warn_legacy_capability_use();
+ tocopy = _LINUX_CAPABILITY_U32S_1;
+ break;
+ case _LINUX_CAPABILITY_VERSION_2:
+ tocopy = _LINUX_CAPABILITY_U32S_2;
+ break;
+ default:
if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
return -EFAULT;
return -EINVAL;
@@ -71,14 +111,47 @@
} else
target = current;
- ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted);
+ ret = security_capget(target, &pE, &pI, &pP);
out:
read_unlock(&tasklist_lock);
spin_unlock(&task_capability_lock);
- if (!ret && copy_to_user(dataptr, &data, sizeof data))
- return -EFAULT;
+ if (!ret) {
+ struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S];
+ unsigned i;
+
+ for (i = 0; i < tocopy; i++) {
+ kdata[i].effective = pE.cap[i];
+ kdata[i].permitted = pP.cap[i];
+ kdata[i].inheritable = pI.cap[i];
+ }
+
+ /*
+ * Note, in the case, tocopy < _LINUX_CAPABILITY_U32S,
+ * we silently drop the upper capabilities here. This
+ * has the effect of making older libcap
+ * implementations implicitly drop upper capability
+ * bits when they perform a: capget/modify/capset
+ * sequence.
+ *
+ * This behavior is considered fail-safe
+ * behavior. Upgrading the application to a newer
+ * version of libcap will enable access to the newer
+ * capabilities.
+ *
+ * An alternative would be to return an error here
+ * (-ERANGE), but that causes legacy applications to
+ * unexpectidly fail; the capget/modify/capset aborts
+ * before modification is attempted and the application
+ * fails.
+ */
+
+ if (copy_to_user(dataptr, kdata, tocopy
+ * sizeof(struct __user_cap_data_struct))) {
+ return -EFAULT;
+ }
+ }
return ret;
}
@@ -167,6 +240,8 @@
*/
asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
{
+ struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S];
+ unsigned i, tocopy;
kernel_cap_t inheritable, permitted, effective;
__u32 version;
struct task_struct *target;
@@ -176,7 +251,15 @@
if (get_user(version, &header->version))
return -EFAULT;
- if (version != _LINUX_CAPABILITY_VERSION) {
+ switch (version) {
+ case _LINUX_CAPABILITY_VERSION_1:
+ warn_legacy_capability_use();
+ tocopy = _LINUX_CAPABILITY_U32S_1;
+ break;
+ case _LINUX_CAPABILITY_VERSION_2:
+ tocopy = _LINUX_CAPABILITY_U32S_2;
+ break;
+ default:
if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
return -EFAULT;
return -EINVAL;
@@ -188,10 +271,22 @@
if (pid && pid != task_pid_vnr(current) && !capable(CAP_SETPCAP))
return -EPERM;
- if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
- copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
- copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
+ if (copy_from_user(&kdata, data, tocopy
+ * sizeof(struct __user_cap_data_struct))) {
return -EFAULT;
+ }
+
+ for (i = 0; i < tocopy; i++) {
+ effective.cap[i] = kdata[i].effective;
+ permitted.cap[i] = kdata[i].permitted;
+ inheritable.cap[i] = kdata[i].inheritable;
+ }
+ while (i < _LINUX_CAPABILITY_U32S) {
+ effective.cap[i] = 0;
+ permitted.cap[i] = 0;
+ inheritable.cap[i] = 0;
+ i++;
+ }
spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);
diff --git a/kernel/exit.c b/kernel/exit.c
index bfb1c0e..eb9934a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -50,8 +50,6 @@
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
-extern void sem_exit (void);
-
static void exit_mm(struct task_struct * tsk);
static void __unhash_process(struct task_struct *p)
@@ -1085,11 +1083,12 @@
struct signal_struct *const sig = current->signal;
struct sighand_struct *const sighand = current->sighand;
spin_lock_irq(&sighand->siglock);
- if (sig->flags & SIGNAL_GROUP_EXIT)
+ if (signal_group_exit(sig))
/* Another thread got here before we took the lock. */
exit_code = sig->group_exit_code;
else {
sig->group_exit_code = exit_code;
+ sig->flags = SIGNAL_GROUP_EXIT;
zap_other_threads(current);
}
spin_unlock_irq(&sighand->siglock);
@@ -1591,8 +1590,6 @@
goto repeat;
if (retval != 0) /* He released the lock. */
goto end;
- } else if (p->exit_state == EXIT_DEAD) {
- continue;
} else if (p->exit_state == EXIT_ZOMBIE) {
/*
* Eligible but we cannot release it yet:
@@ -1607,7 +1604,7 @@
/* He released the lock. */
if (retval != 0)
goto end;
- } else {
+ } else if (p->exit_state != EXIT_DEAD) {
check_continued:
/*
* It's running now, so it might later
diff --git a/kernel/fork.c b/kernel/fork.c
index 05e0b6f..3995297 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -325,7 +325,7 @@
static inline void mm_free_pgd(struct mm_struct * mm)
{
- pgd_free(mm->pgd);
+ pgd_free(mm, mm->pgd);
}
#else
#define dup_mmap(mm, oldmm) (0)
@@ -1118,6 +1118,7 @@
#ifdef CONFIG_SECURITY
p->security = NULL;
#endif
+ p->cap_bset = current->cap_bset;
p->io_context = NULL;
p->audit_context = NULL;
cgroup_fork(p);
@@ -1398,7 +1399,7 @@
return ERR_PTR(retval);
}
-noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
+noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
{
memset(regs, 0, sizeof(struct pt_regs));
return regs;
@@ -1450,6 +1451,23 @@
int trace = 0;
long nr;
+ /*
+ * We hope to recycle these flags after 2.6.26
+ */
+ if (unlikely(clone_flags & CLONE_STOPPED)) {
+ static int __read_mostly count = 100;
+
+ if (count > 0 && printk_ratelimit()) {
+ char comm[TASK_COMM_LEN];
+
+ count--;
+ printk(KERN_INFO "fork(): process `%s' used deprecated "
+ "clone flags 0x%lx\n",
+ get_task_comm(comm, current),
+ clone_flags & CLONE_STOPPED);
+ }
+ }
+
if (unlikely(current->ptrace)) {
trace = fork_traceflag (clone_flags);
if (trace)
@@ -1492,7 +1510,7 @@
if (!(clone_flags & CLONE_STOPPED))
wake_up_new_task(p, clone_flags);
else
- p->state = TASK_STOPPED;
+ __set_task_state(p, TASK_STOPPED);
if (unlikely (trace)) {
current->ptrace_message = nr;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 1069998..668f396 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -306,7 +306,7 @@
/*
* Divide a ktime value by a nanosecond value
*/
-unsigned long ktime_divns(const ktime_t kt, s64 div)
+u64 ktime_divns(const ktime_t kt, s64 div)
{
u64 dclc, inc, dns;
int sft = 0;
@@ -321,7 +321,7 @@
dclc >>= sft;
do_div(dclc, (unsigned long) div);
- return (unsigned long) dclc;
+ return dclc;
}
#endif /* BITS_PER_LONG >= 64 */
@@ -656,10 +656,9 @@
* Forward the timer expiry so it will expire in the future.
* Returns the number of overruns.
*/
-unsigned long
-hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
+u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
{
- unsigned long orun = 1;
+ u64 orun = 1;
ktime_t delta;
delta = ktime_sub(now, timer->expires);
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 7dadc71..f091d13 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -53,14 +53,6 @@
return 0;
}
-static inline int is_kernel_extratext(unsigned long addr)
-{
- if (addr >= (unsigned long)_sextratext
- && addr <= (unsigned long)_eextratext)
- return 1;
- return 0;
-}
-
static inline int is_kernel_text(unsigned long addr)
{
if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
@@ -80,8 +72,7 @@
if (all_var)
return is_kernel(addr);
- return is_kernel_text(addr) || is_kernel_inittext(addr) ||
- is_kernel_extratext(addr);
+ return is_kernel_text(addr) || is_kernel_inittext(addr);
}
/* expand a compressed symbol data into the resulting uncompressed string,
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index d0493ea..7a86e64 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -699,6 +699,12 @@
struct kretprobe_instance, uflist);
ri->rp = rp;
ri->task = current;
+
+ if (rp->entry_handler && rp->entry_handler(ri, regs)) {
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ return 0;
+ }
+
arch_prepare_kretprobe(ri, regs);
/* XXX(hch): why is there no hlist_move_head? */
@@ -745,7 +751,8 @@
INIT_HLIST_HEAD(&rp->used_instances);
INIT_HLIST_HEAD(&rp->free_instances);
for (i = 0; i < rp->maxactive; i++) {
- inst = kmalloc(sizeof(struct kretprobe_instance), GFP_KERNEL);
+ inst = kmalloc(sizeof(struct kretprobe_instance) +
+ rp->data_size, GFP_KERNEL);
if (inst == NULL) {
free_rp_inst(rp);
return -ENOMEM;
diff --git a/kernel/latency.c b/kernel/latency.c
deleted file mode 100644
index e63fcac..0000000
--- a/kernel/latency.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * latency.c: Explicit system-wide latency-expectation infrastructure
- *
- * The purpose of this infrastructure is to allow device drivers to set
- * latency constraint they have and to collect and summarize these
- * expectations globally. The cummulated result can then be used by
- * power management and similar users to make decisions that have
- * tradoffs with a latency component.
- *
- * An example user of this are the x86 C-states; each higher C state saves
- * more power, but has a higher exit latency. For the idle loop power
- * code to make a good decision which C-state to use, information about
- * acceptable latencies is required.
- *
- * An example announcer of latency is an audio driver that knowns it
- * will get an interrupt when the hardware has 200 usec of samples
- * left in the DMA buffer; in that case the driver can set a latency
- * constraint of, say, 150 usec.
- *
- * Multiple drivers can each announce their maximum accepted latency,
- * to keep these appart, a string based identifier is used.
- *
- *
- * (C) Copyright 2006 Intel Corporation
- * Author: Arjan van de Ven <arjan@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-
-#include <linux/latency.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-#include <asm/atomic.h>
-
-struct latency_info {
- struct list_head list;
- int usecs;
- char *identifier;
-};
-
-/*
- * locking rule: all modifications to current_max_latency and
- * latency_list need to be done while holding the latency_lock.
- * latency_lock needs to be taken _irqsave.
- */
-static atomic_t current_max_latency;
-static DEFINE_SPINLOCK(latency_lock);
-
-static LIST_HEAD(latency_list);
-static BLOCKING_NOTIFIER_HEAD(latency_notifier);
-
-/*
- * This function returns the maximum latency allowed, which
- * happens to be the minimum of all maximum latencies on the
- * list.
- */
-static int __find_max_latency(void)
-{
- int min = INFINITE_LATENCY;
- struct latency_info *info;
-
- list_for_each_entry(info, &latency_list, list) {
- if (info->usecs < min)
- min = info->usecs;
- }
- return min;
-}
-
-/**
- * set_acceptable_latency - sets the maximum latency acceptable
- * @identifier: string that identifies this driver
- * @usecs: maximum acceptable latency for this driver
- *
- * This function informs the kernel that this device(driver)
- * can accept at most usecs latency. This setting is used for
- * power management and similar tradeoffs.
- *
- * This function sleeps and can only be called from process
- * context.
- * Calling this function with an existing identifier is valid
- * and will cause the existing latency setting to be changed.
- */
-void set_acceptable_latency(char *identifier, int usecs)
-{
- struct latency_info *info, *iter;
- unsigned long flags;
- int found_old = 0;
-
- info = kzalloc(sizeof(struct latency_info), GFP_KERNEL);
- if (!info)
- return;
- info->usecs = usecs;
- info->identifier = kstrdup(identifier, GFP_KERNEL);
- if (!info->identifier)
- goto free_info;
-
- spin_lock_irqsave(&latency_lock, flags);
- list_for_each_entry(iter, &latency_list, list) {
- if (strcmp(iter->identifier, identifier)==0) {
- found_old = 1;
- iter->usecs = usecs;
- break;
- }
- }
- if (!found_old)
- list_add(&info->list, &latency_list);
-
- if (usecs < atomic_read(¤t_max_latency))
- atomic_set(¤t_max_latency, usecs);
-
- spin_unlock_irqrestore(&latency_lock, flags);
-
- blocking_notifier_call_chain(&latency_notifier,
- atomic_read(¤t_max_latency), NULL);
-
- /*
- * if we inserted the new one, we're done; otherwise there was
- * an existing one so we need to free the redundant data
- */
- if (!found_old)
- return;
-
- kfree(info->identifier);
-free_info:
- kfree(info);
-}
-EXPORT_SYMBOL_GPL(set_acceptable_latency);
-
-/**
- * modify_acceptable_latency - changes the maximum latency acceptable
- * @identifier: string that identifies this driver
- * @usecs: maximum acceptable latency for this driver
- *
- * This function informs the kernel that this device(driver)
- * can accept at most usecs latency. This setting is used for
- * power management and similar tradeoffs.
- *
- * This function does not sleep and can be called in any context.
- * Trying to use a non-existing identifier silently gets ignored.
- *
- * Due to the atomic nature of this function, the modified latency
- * value will only be used for future decisions; past decisions
- * can still lead to longer latencies in the near future.
- */
-void modify_acceptable_latency(char *identifier, int usecs)
-{
- struct latency_info *iter;
- unsigned long flags;
-
- spin_lock_irqsave(&latency_lock, flags);
- list_for_each_entry(iter, &latency_list, list) {
- if (strcmp(iter->identifier, identifier) == 0) {
- iter->usecs = usecs;
- break;
- }
- }
- if (usecs < atomic_read(¤t_max_latency))
- atomic_set(¤t_max_latency, usecs);
- spin_unlock_irqrestore(&latency_lock, flags);
-}
-EXPORT_SYMBOL_GPL(modify_acceptable_latency);
-
-/**
- * remove_acceptable_latency - removes the maximum latency acceptable
- * @identifier: string that identifies this driver
- *
- * This function removes a previously set maximum latency setting
- * for the driver and frees up any resources associated with the
- * bookkeeping needed for this.
- *
- * This function does not sleep and can be called in any context.
- * Trying to use a non-existing identifier silently gets ignored.
- */
-void remove_acceptable_latency(char *identifier)
-{
- unsigned long flags;
- int newmax = 0;
- struct latency_info *iter, *temp;
-
- spin_lock_irqsave(&latency_lock, flags);
-
- list_for_each_entry_safe(iter, temp, &latency_list, list) {
- if (strcmp(iter->identifier, identifier) == 0) {
- list_del(&iter->list);
- newmax = iter->usecs;
- kfree(iter->identifier);
- kfree(iter);
- break;
- }
- }
-
- /* If we just deleted the system wide value, we need to
- * recalculate with a full search
- */
- if (newmax == atomic_read(¤t_max_latency)) {
- newmax = __find_max_latency();
- atomic_set(¤t_max_latency, newmax);
- }
- spin_unlock_irqrestore(&latency_lock, flags);
-}
-EXPORT_SYMBOL_GPL(remove_acceptable_latency);
-
-/**
- * system_latency_constraint - queries the system wide latency maximum
- *
- * This function returns the system wide maximum latency in
- * microseconds.
- *
- * This function does not sleep and can be called in any context.
- */
-int system_latency_constraint(void)
-{
- return atomic_read(¤t_max_latency);
-}
-EXPORT_SYMBOL_GPL(system_latency_constraint);
-
-/**
- * synchronize_acceptable_latency - recalculates all latency decisions
- *
- * This function will cause a callback to various kernel pieces that
- * will make those pieces rethink their latency decisions. This implies
- * that if there are overlong latencies in hardware state already, those
- * latencies get taken right now. When this call completes no overlong
- * latency decisions should be active anymore.
- *
- * Typical usecase of this is after a modify_acceptable_latency() call,
- * which in itself is non-blocking and non-synchronizing.
- *
- * This function blocks and should not be called with locks held.
- */
-
-void synchronize_acceptable_latency(void)
-{
- blocking_notifier_call_chain(&latency_notifier,
- atomic_read(¤t_max_latency), NULL);
-}
-EXPORT_SYMBOL_GPL(synchronize_acceptable_latency);
-
-/*
- * Latency notifier: this notifier gets called when a non-atomic new
- * latency value gets set. The expectation nof the caller of the
- * non-atomic set is that when the call returns, future latencies
- * are within bounds, so the functions on the notifier list are
- * expected to take the overlong latencies immediately, inside the
- * callback, and not make a overlong latency decision anymore.
- *
- * The callback gets called when the new latency value is made
- * active so system_latency_constraint() returns the new latency.
- */
-int register_latency_notifier(struct notifier_block * nb)
-{
- return blocking_notifier_chain_register(&latency_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(register_latency_notifier);
-
-int unregister_latency_notifier(struct notifier_block * nb)
-{
- return blocking_notifier_chain_unregister(&latency_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_latency_notifier);
-
-static __init int latency_init(void)
-{
- atomic_set(¤t_max_latency, INFINITE_LATENCY);
- /*
- * we don't want by default to have longer latencies than 2 ticks,
- * since that would cause lost ticks
- */
- set_acceptable_latency("kernel", 2*1000000/HZ);
- return 0;
-}
-
-module_init(latency_init);
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 4253f47..643360d 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -4,6 +4,7 @@
#include <linux/notifier.h>
#include <linux/rcupdate.h>
#include <linux/vmalloc.h>
+#include <linux/reboot.h>
/*
* Notifier list for kernel code which wants to be called
diff --git a/kernel/params.c b/kernel/params.c
index 42fe5e6..e28c706 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -272,7 +272,7 @@
unsigned int min, unsigned int max,
void *elem, int elemsize,
int (*set)(const char *, struct kernel_param *kp),
- int *num)
+ unsigned int *num)
{
int ret;
struct kernel_param kp;
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
new file mode 100644
index 0000000..0afe32b
--- /dev/null
+++ b/kernel/pm_qos_params.c
@@ -0,0 +1,425 @@
+/*
+ * This module exposes the interface to kernel space for specifying
+ * QoS dependencies. It provides infrastructure for registration of:
+ *
+ * Dependents on a QoS value : register requirements
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based. Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ *
+ * There are 3 basic classes of QoS parameter: latency, timeout, throughput
+ * each have defined units:
+ * latency: usec
+ * timeout: usec <-- currently not used.
+ * throughput: kbs (kilo byte / sec)
+ *
+ * There are lists of pm_qos_objects each one wrapping requirements, notifiers
+ *
+ * User mode requirements on a QOS parameter register themselves to the
+ * subsystem by opening the device node /dev/... and writing there request to
+ * the node. As long as the process holds a file handle open to the node the
+ * client continues to be accounted for. Upon file release the usermode
+ * requirement is removed and a new qos target is computed. This way when the
+ * requirement that the application has is cleaned up when closes the file
+ * pointer or exits the pm_qos_object will get an opportunity to clean up.
+ *
+ * mark gross mgross@linux.intel.com
+ */
+
+#include <linux/pm_qos_params.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+
+#include <linux/uaccess.h>
+
+/*
+ * locking rule: all changes to target_value or requirements or notifiers lists
+ * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
+ * held, taken with _irqsave. One lock to rule them all
+ */
+struct requirement_list {
+ struct list_head list;
+ union {
+ s32 value;
+ s32 usec;
+ s32 kbps;
+ };
+ char *name;
+};
+
+static s32 max_compare(s32 v1, s32 v2);
+static s32 min_compare(s32 v1, s32 v2);
+
+struct pm_qos_object {
+ struct requirement_list requirements;
+ struct blocking_notifier_head *notifiers;
+ struct miscdevice pm_qos_power_miscdev;
+ char *name;
+ s32 default_value;
+ s32 target_value;
+ s32 (*comparitor)(s32, s32);
+};
+
+static struct pm_qos_object null_pm_qos;
+static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
+static struct pm_qos_object cpu_dma_pm_qos = {
+ .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)},
+ .notifiers = &cpu_dma_lat_notifier,
+ .name = "cpu_dma_latency",
+ .default_value = 2000 * USEC_PER_SEC,
+ .target_value = 2000 * USEC_PER_SEC,
+ .comparitor = min_compare
+};
+
+static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
+static struct pm_qos_object network_lat_pm_qos = {
+ .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)},
+ .notifiers = &network_lat_notifier,
+ .name = "network_latency",
+ .default_value = 2000 * USEC_PER_SEC,
+ .target_value = 2000 * USEC_PER_SEC,
+ .comparitor = min_compare
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
+static struct pm_qos_object network_throughput_pm_qos = {
+ .requirements =
+ {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
+ .notifiers = &network_throughput_notifier,
+ .name = "network_throughput",
+ .default_value = 0,
+ .target_value = 0,
+ .comparitor = max_compare
+};
+
+
+static struct pm_qos_object *pm_qos_array[] = {
+ &null_pm_qos,
+ &cpu_dma_pm_qos,
+ &network_lat_pm_qos,
+ &network_throughput_pm_qos
+};
+
+static DEFINE_SPINLOCK(pm_qos_lock);
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos);
+static int pm_qos_power_open(struct inode *inode, struct file *filp);
+static int pm_qos_power_release(struct inode *inode, struct file *filp);
+
+static const struct file_operations pm_qos_power_fops = {
+ .write = pm_qos_power_write,
+ .open = pm_qos_power_open,
+ .release = pm_qos_power_release,
+};
+
+/* static helper functions */
+static s32 max_compare(s32 v1, s32 v2)
+{
+ return max(v1, v2);
+}
+
+static s32 min_compare(s32 v1, s32 v2)
+{
+ return min(v1, v2);
+}
+
+
+static void update_target(int target)
+{
+ s32 extreme_value;
+ struct requirement_list *node;
+ unsigned long flags;
+ int call_notifier = 0;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ extreme_value = pm_qos_array[target]->default_value;
+ list_for_each_entry(node,
+ &pm_qos_array[target]->requirements.list, list) {
+ extreme_value = pm_qos_array[target]->comparitor(
+ extreme_value, node->value);
+ }
+ if (pm_qos_array[target]->target_value != extreme_value) {
+ call_notifier = 1;
+ pm_qos_array[target]->target_value = extreme_value;
+ pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
+ pm_qos_array[target]->target_value);
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+ if (call_notifier)
+ blocking_notifier_call_chain(pm_qos_array[target]->notifiers,
+ (unsigned long) extreme_value, NULL);
+}
+
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+ qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+ qos->pm_qos_power_miscdev.name = qos->name;
+ qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+ return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+ int pm_qos_class;
+
+ for (pm_qos_class = 0;
+ pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+ if (minor ==
+ pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+ return pm_qos_class;
+ }
+ return -1;
+}
+
+/**
+ * pm_qos_requirement - returns current system wide qos expectation
+ * @pm_qos_class: identification of which qos value is requested
+ *
+ * This function returns the current target value in an atomic manner.
+ */
+int pm_qos_requirement(int pm_qos_class)
+{
+ int ret_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ ret_val = pm_qos_array[pm_qos_class]->target_value;
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+ return ret_val;
+}
+EXPORT_SYMBOL_GPL(pm_qos_requirement);
+
+/**
+ * pm_qos_add_requirement - inserts new qos request into the list
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * This function inserts a new entry in the pm_qos_class list of requested qos
+ * performance charactoistics. It recomputes the agregate QoS expectations for
+ * the pm_qos_class of parrameters.
+ */
+int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
+{
+ struct requirement_list *dep;
+ unsigned long flags;
+
+ dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
+ if (dep) {
+ if (value == PM_QOS_DEFAULT_VALUE)
+ dep->value = pm_qos_array[pm_qos_class]->default_value;
+ else
+ dep->value = value;
+ dep->name = kstrdup(name, GFP_KERNEL);
+ if (!dep->name)
+ goto cleanup;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ list_add(&dep->list,
+ &pm_qos_array[pm_qos_class]->requirements.list);
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ update_target(pm_qos_class);
+
+ return 0;
+ }
+
+cleanup:
+ kfree(dep);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
+
+/**
+ * pm_qos_update_requirement - modifies an existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * Updates an existing qos requierement for the pm_qos_class of parameters along
+ * with updating the target pm_qos_class value.
+ *
+ * If the named request isn't in the lest then no change is made.
+ */
+int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value)
+{
+ unsigned long flags;
+ struct requirement_list *node;
+ int pending_update = 0;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ list_for_each_entry(node,
+ &pm_qos_array[pm_qos_class]->requirements.list, list) {
+ if (strcmp(node->name, name) == 0) {
+ if (new_value == PM_QOS_DEFAULT_VALUE)
+ node->value =
+ pm_qos_array[pm_qos_class]->default_value;
+ else
+ node->value = new_value;
+ pending_update = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ if (pending_update)
+ update_target(pm_qos_class);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
+
+/**
+ * pm_qos_remove_requirement - modifies an existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ *
+ * Will remove named qos request from pm_qos_class list of parrameters and
+ * recompute the current target value for the pm_qos_class.
+ */
+void pm_qos_remove_requirement(int pm_qos_class, char *name)
+{
+ unsigned long flags;
+ struct requirement_list *node;
+ int pending_update = 0;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ list_for_each_entry(node,
+ &pm_qos_array[pm_qos_class]->requirements.list, list) {
+ if (strcmp(node->name, name) == 0) {
+ kfree(node->name);
+ list_del(&node->list);
+ kfree(node);
+ pending_update = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ if (pending_update)
+ update_target(pm_qos_class);
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
+
+/**
+ * pm_qos_add_notifier - sets notification entry for changes to target value
+ * @pm_qos_class: identifies which qos target changes should be notified.
+ * @notifier: notifier block managed by caller.
+ *
+ * will register the notifier into a notification chain that gets called
+ * uppon changes to the pm_qos_class target value.
+ */
+ int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+ int retval;
+
+ retval = blocking_notifier_chain_register(
+ pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
+
+/**
+ * pm_qos_remove_notifier - deletes notification entry from chain.
+ * @pm_qos_class: identifies which qos target changes are notified.
+ * @notifier: notifier block to be removed.
+ *
+ * will remove the notifier from the notification chain that gets called
+ * uppon changes to the pm_qos_class target value.
+ */
+int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+ int retval;
+
+ retval = blocking_notifier_chain_unregister(
+ pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
+
+#define PID_NAME_LEN sizeof("process_1234567890")
+static char name[PID_NAME_LEN];
+
+static int pm_qos_power_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ long pm_qos_class;
+
+ pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
+ if (pm_qos_class >= 0) {
+ filp->private_data = (void *)pm_qos_class;
+ sprintf(name, "process_%d", current->pid);
+ ret = pm_qos_add_requirement(pm_qos_class, name,
+ PM_QOS_DEFAULT_VALUE);
+ if (ret >= 0)
+ return 0;
+ }
+
+ return -EPERM;
+}
+
+static int pm_qos_power_release(struct inode *inode, struct file *filp)
+{
+ int pm_qos_class;
+
+ pm_qos_class = (long)filp->private_data;
+ sprintf(name, "process_%d", current->pid);
+ pm_qos_remove_requirement(pm_qos_class, name);
+
+ return 0;
+}
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ s32 value;
+ int pm_qos_class;
+
+ pm_qos_class = (long)filp->private_data;
+ if (count != sizeof(s32))
+ return -EINVAL;
+ if (copy_from_user(&value, buf, sizeof(s32)))
+ return -EFAULT;
+ sprintf(name, "process_%d", current->pid);
+ pm_qos_update_requirement(pm_qos_class, name, value);
+
+ return sizeof(s32);
+}
+
+
+static int __init pm_qos_power_init(void)
+{
+ int ret = 0;
+
+ ret = register_pm_qos_misc(&cpu_dma_pm_qos);
+ if (ret < 0) {
+ printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
+ return ret;
+ }
+ ret = register_pm_qos_misc(&network_lat_pm_qos);
+ if (ret < 0) {
+ printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
+ return ret;
+ }
+ ret = register_pm_qos_misc(&network_throughput_pm_qos);
+ if (ret < 0)
+ printk(KERN_ERR
+ "pm_qos_param: network_throughput setup failed\n");
+
+ return ret;
+}
+
+late_initcall(pm_qos_power_init);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 35b4bbf..122d5c7 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -256,8 +256,9 @@
if (timr->it.real.interval.tv64 == 0)
return;
- timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(),
- timr->it.real.interval);
+ timr->it_overrun += (unsigned int) hrtimer_forward(timer,
+ timer->base->get_time(),
+ timr->it.real.interval);
timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1;
@@ -386,7 +387,7 @@
now = ktime_add(now, kj);
}
#endif
- timr->it_overrun +=
+ timr->it_overrun += (unsigned int)
hrtimer_forward(timer, now,
timr->it.real.interval);
ret = HRTIMER_RESTART;
@@ -493,7 +494,7 @@
goto retry;
else if (error) {
/*
- * Wierd looking, but we return EAGAIN if the IDR is
+ * Weird looking, but we return EAGAIN if the IDR is
* full (proper POSIX return value for this)
*/
error = -EAGAIN;
@@ -662,7 +663,7 @@
*/
if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
(timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
- timr->it_overrun += hrtimer_forward(timer, now, iv);
+ timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
remaining = ktime_sub(timer->expires, now);
/* Return 0 only, when the timer is expired and not pending */
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 8e186c6..7983317 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -44,17 +44,38 @@
---help---
This option enables verbose messages from the Power Management code.
+config CAN_PM_TRACE
+ def_bool y
+ depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL
+
config PM_TRACE
+ bool
+ help
+ This enables code to save the last PM event point across
+ reboot. The architecture needs to support this, x86 for
+ example does by saving things in the RTC, see below.
+
+ The architecture specific code must provide the extern
+ functions from <linux/resume-trace.h> as well as the
+ <asm/resume-trace.h> header with a TRACE_RESUME() macro.
+
+ The way the information is presented is architecture-
+ dependent, x86 will print the information during a
+ late_initcall.
+
+config PM_TRACE_RTC
bool "Suspend/resume event tracing"
- depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL
+ depends on CAN_PM_TRACE
+ depends on X86
+ select PM_TRACE
default n
---help---
This enables some cheesy code to save the last PM event point in the
RTC across reboots, so that you can debug a machine that just hangs
during suspend (or more commonly, during resume).
- To use this debugging feature you should attempt to suspend the machine,
- then reboot it, then run
+ To use this debugging feature you should attempt to suspend the
+ machine, reboot it and then run
dmesg -s 1000000 | grep 'hash matches'
@@ -63,7 +84,8 @@
config PM_SLEEP_SMP
bool
- depends on SUSPEND_SMP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
+ depends on SMP
+ depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
depends on PM_SLEEP
select HOTPLUG_CPU
default y
@@ -73,52 +95,38 @@
depends on SUSPEND || HIBERNATION
default y
-config SUSPEND_UP_POSSIBLE
- bool
- depends on (X86 && !X86_VOYAGER) || PPC || ARM || BLACKFIN || MIPS \
- || SUPERH || FRV
- depends on !SMP
- default y
-
-config SUSPEND_SMP_POSSIBLE
- bool
- depends on (X86 && !X86_VOYAGER) \
- || (PPC && (PPC_PSERIES || PPC_PMAC)) || ARM
- depends on SMP
- default y
-
config SUSPEND
bool "Suspend to RAM and standby"
- depends on PM
- depends on SUSPEND_UP_POSSIBLE || SUSPEND_SMP_POSSIBLE
+ depends on PM && ARCH_SUSPEND_POSSIBLE
default y
---help---
Allow the system to enter sleep states in which main memory is
powered and thus its contents are preserved, such as the
- suspend-to-RAM state (i.e. the ACPI S3 state).
+ suspend-to-RAM state (e.g. the ACPI S3 state).
-config HIBERNATION_UP_POSSIBLE
- bool
- depends on X86 || PPC64_SWSUSP || PPC32
- depends on !SMP
+config SUSPEND_FREEZER
+ bool "Enable freezer for suspend to RAM/standby" \
+ if ARCH_WANTS_FREEZER_CONTROL || BROKEN
+ depends on SUSPEND
default y
+ help
+ This allows you to turn off the freezer for suspend. If this is
+ done, no tasks are frozen for suspend to RAM/standby.
-config HIBERNATION_SMP_POSSIBLE
- bool
- depends on (X86 && !X86_VOYAGER) || PPC64_SWSUSP
- depends on SMP
- default y
+ Turning OFF this setting is NOT recommended! If in doubt, say Y.
config HIBERNATION
bool "Hibernation (aka 'suspend to disk')"
- depends on PM && SWAP
- depends on HIBERNATION_UP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
+ depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
---help---
Enable the suspend to disk (STD) functionality, which is usually
called "hibernation" in user interfaces. STD checkpoints the
system and powers it off; and restores that checkpoint on reboot.
- You can suspend your machine with 'echo disk > /sys/power/state'.
+ You can suspend your machine with 'echo disk > /sys/power/state'
+ after placing resume=/dev/swappartition on the kernel command line
+ in your bootloader's configuration file.
+
Alternatively, you can use the additional userland tools available
from <http://suspend.sf.net>.
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index b138b43..859a8e5 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -26,7 +26,7 @@
static int noresume = 0;
-char resume_file[256] = CONFIG_PM_STD_PARTITION;
+static char resume_file[256] = CONFIG_PM_STD_PARTITION;
dev_t swsusp_resume_device;
sector_t swsusp_resume_block;
@@ -54,8 +54,8 @@
void hibernation_set_ops(struct platform_hibernation_ops *ops)
{
- if (ops && !(ops->start && ops->pre_snapshot && ops->finish
- && ops->prepare && ops->enter && ops->pre_restore
+ if (ops && !(ops->begin && ops->end && ops->pre_snapshot
+ && ops->prepare && ops->finish && ops->enter && ops->pre_restore
&& ops->restore_cleanup)) {
WARN_ON(1);
return;
@@ -70,15 +70,55 @@
mutex_unlock(&pm_mutex);
}
+#ifdef CONFIG_PM_DEBUG
+static void hibernation_debug_sleep(void)
+{
+ printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+}
+
+static int hibernation_testmode(int mode)
+{
+ if (hibernation_mode == mode) {
+ hibernation_debug_sleep();
+ return 1;
+ }
+ return 0;
+}
+
+static int hibernation_test(int level)
+{
+ if (pm_test_level == level) {
+ hibernation_debug_sleep();
+ return 1;
+ }
+ return 0;
+}
+#else /* !CONFIG_PM_DEBUG */
+static int hibernation_testmode(int mode) { return 0; }
+static int hibernation_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
/**
- * platform_start - tell the platform driver that we're starting
+ * platform_begin - tell the platform driver that we're starting
* hibernation
*/
-static int platform_start(int platform_mode)
+static int platform_begin(int platform_mode)
{
return (platform_mode && hibernation_ops) ?
- hibernation_ops->start() : 0;
+ hibernation_ops->begin() : 0;
+}
+
+/**
+ * platform_end - tell the platform driver that we've entered the
+ * working state
+ */
+
+static void platform_end(int platform_mode)
+{
+ if (platform_mode && hibernation_ops)
+ hibernation_ops->end();
}
/**
@@ -145,7 +185,7 @@
* reappears in this routine after a restore.
*/
-int create_image(int platform_mode)
+static int create_image(int platform_mode)
{
int error;
@@ -162,19 +202,25 @@
*/
error = device_power_down(PMSG_FREEZE);
if (error) {
- printk(KERN_ERR "Some devices failed to power down, "
- KERN_ERR "aborting suspend\n");
+ printk(KERN_ERR "PM: Some devices failed to power down, "
+ "aborting hibernation\n");
goto Enable_irqs;
}
+ if (hibernation_test(TEST_CORE))
+ goto Power_up;
+
+ in_suspend = 1;
save_processor_state();
error = swsusp_arch_suspend();
if (error)
- printk(KERN_ERR "Error %d while creating the image\n", error);
+ printk(KERN_ERR "PM: Error %d creating hibernation image\n",
+ error);
/* Restore control flow magically appears here */
restore_processor_state();
if (!in_suspend)
platform_leave(platform_mode);
+ Power_up:
/* NOTE: device_power_up() is just a resume() for devices
* that suspended with irqs off ... no overall powerup.
*/
@@ -202,36 +248,90 @@
if (error)
return error;
- error = platform_start(platform_mode);
+ error = platform_begin(platform_mode);
if (error)
- return error;
+ goto Close;
suspend_console();
error = device_suspend(PMSG_FREEZE);
if (error)
goto Resume_console;
- error = platform_pre_snapshot(platform_mode);
- if (error)
+ if (hibernation_test(TEST_DEVICES))
goto Resume_devices;
+ error = platform_pre_snapshot(platform_mode);
+ if (error || hibernation_test(TEST_PLATFORM))
+ goto Finish;
+
error = disable_nonboot_cpus();
if (!error) {
- if (hibernation_mode != HIBERNATION_TEST) {
- in_suspend = 1;
- error = create_image(platform_mode);
- /* Control returns here after successful restore */
- } else {
- printk("swsusp debug: Waiting for 5 seconds.\n");
- mdelay(5000);
- }
+ if (hibernation_test(TEST_CPUS))
+ goto Enable_cpus;
+
+ if (hibernation_testmode(HIBERNATION_TEST))
+ goto Enable_cpus;
+
+ error = create_image(platform_mode);
+ /* Control returns here after successful restore */
}
+ Enable_cpus:
enable_nonboot_cpus();
- Resume_devices:
+ Finish:
platform_finish(platform_mode);
+ Resume_devices:
device_resume();
Resume_console:
resume_console();
+ Close:
+ platform_end(platform_mode);
+ return error;
+}
+
+/**
+ * resume_target_kernel - prepare devices that need to be suspended with
+ * interrupts off, restore the contents of highmem that have not been
+ * restored yet from the image and run the low level code that will restore
+ * the remaining contents of memory and switch to the just restored target
+ * kernel.
+ */
+
+static int resume_target_kernel(void)
+{
+ int error;
+
+ local_irq_disable();
+ error = device_power_down(PMSG_PRETHAW);
+ if (error) {
+ printk(KERN_ERR "PM: Some devices failed to power down, "
+ "aborting resume\n");
+ goto Enable_irqs;
+ }
+ /* We'll ignore saved state, but this gets preempt count (etc) right */
+ save_processor_state();
+ error = restore_highmem();
+ if (!error) {
+ error = swsusp_arch_resume();
+ /*
+ * The code below is only ever reached in case of a failure.
+ * Otherwise execution continues at place where
+ * swsusp_arch_suspend() was called
+ */
+ BUG_ON(!error);
+ /* This call to restore_highmem() undos the previous one */
+ restore_highmem();
+ }
+ /*
+ * The only reason why swsusp_arch_resume() can fail is memory being
+ * very tight, so we have to free it as soon as we can to avoid
+ * subsequent failures
+ */
+ swsusp_free();
+ restore_processor_state();
+ touch_softlockup_watchdog();
+ device_power_up();
+ Enable_irqs:
+ local_irq_enable();
return error;
}
@@ -258,7 +358,7 @@
if (!error) {
error = disable_nonboot_cpus();
if (!error)
- error = swsusp_resume();
+ error = resume_target_kernel();
enable_nonboot_cpus();
}
platform_restore_cleanup(platform_mode);
@@ -286,9 +386,9 @@
* hibernation_ops->finish() before saving the image, so we should let
* the firmware know that we're going to enter the sleep state after all
*/
- error = hibernation_ops->start();
+ error = hibernation_ops->begin();
if (error)
- return error;
+ goto Close;
suspend_console();
error = device_suspend(PMSG_SUSPEND);
@@ -322,6 +422,8 @@
device_resume();
Resume_console:
resume_console();
+ Close:
+ hibernation_ops->end();
return error;
}
@@ -352,24 +454,17 @@
* Valid image is on the disk, if we continue we risk serious data
* corruption after resume.
*/
- printk(KERN_CRIT "Please power me down manually\n");
+ printk(KERN_CRIT "PM: Please power down manually\n");
while(1);
}
-static void unprepare_processes(void)
-{
- thaw_processes();
- pm_restore_console();
-}
-
static int prepare_processes(void)
{
int error = 0;
- pm_prepare_console();
if (freeze_processes()) {
error = -EBUSY;
- unprepare_processes();
+ thaw_processes();
}
return error;
}
@@ -389,6 +484,7 @@
goto Unlock;
}
+ pm_prepare_console();
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
if (error)
goto Exit;
@@ -398,7 +494,7 @@
if (error)
goto Exit;
- printk("Syncing filesystems ... ");
+ printk(KERN_INFO "PM: Syncing filesystems ... ");
sys_sync();
printk("done.\n");
@@ -406,11 +502,12 @@
if (error)
goto Finish;
- if (hibernation_mode == HIBERNATION_TESTPROC) {
- printk("swsusp debug: Waiting for 5 seconds.\n");
- mdelay(5000);
+ if (hibernation_test(TEST_FREEZER))
goto Thaw;
- }
+
+ if (hibernation_testmode(HIBERNATION_TESTPROC))
+ goto Thaw;
+
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
if (in_suspend && !error) {
unsigned int flags = 0;
@@ -427,11 +524,12 @@
swsusp_free();
}
Thaw:
- unprepare_processes();
+ thaw_processes();
Finish:
free_basic_memory_bitmaps();
Exit:
pm_notifier_call_chain(PM_POST_HIBERNATION);
+ pm_restore_console();
atomic_inc(&snapshot_device_available);
Unlock:
mutex_unlock(&pm_mutex);
@@ -473,22 +571,23 @@
return -ENOENT;
}
swsusp_resume_device = name_to_dev_t(resume_file);
- pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+ pr_debug("PM: Resume from partition %s\n", resume_file);
} else {
- pr_debug("swsusp: Resume From Partition %d:%d\n",
- MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+ pr_debug("PM: Resume from partition %d:%d\n",
+ MAJOR(swsusp_resume_device),
+ MINOR(swsusp_resume_device));
}
if (noresume) {
/**
- * FIXME: If noresume is specified, we need to find the partition
- * and reset it back to normal swap space.
+ * FIXME: If noresume is specified, we need to find the
+ * partition and reset it back to normal swap space.
*/
mutex_unlock(&pm_mutex);
return 0;
}
- pr_debug("PM: Checking swsusp image.\n");
+ pr_debug("PM: Checking hibernation image.\n");
error = swsusp_check();
if (error)
goto Unlock;
@@ -499,6 +598,11 @@
goto Unlock;
}
+ pm_prepare_console();
+ error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+ if (error)
+ goto Finish;
+
error = create_basic_memory_bitmaps();
if (error)
goto Finish;
@@ -510,7 +614,7 @@
goto Done;
}
- pr_debug("PM: Reading swsusp image.\n");
+ pr_debug("PM: Reading hibernation image.\n");
error = swsusp_read(&flags);
if (!error)
@@ -518,10 +622,12 @@
printk(KERN_ERR "PM: Restore failed, recovering.\n");
swsusp_free();
- unprepare_processes();
+ thaw_processes();
Done:
free_basic_memory_bitmaps();
Finish:
+ pm_notifier_call_chain(PM_POST_RESTORE);
+ pm_restore_console();
atomic_inc(&snapshot_device_available);
/* For success case, the suspend path will release the lock */
Unlock:
@@ -636,7 +742,7 @@
error = -EINVAL;
if (!error)
- pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+ pr_debug("PM: Hibernation mode set to '%s'\n",
hibernation_modes[mode]);
mutex_unlock(&pm_mutex);
return error ? error : n;
@@ -668,7 +774,7 @@
mutex_lock(&pm_mutex);
swsusp_resume_device = res;
mutex_unlock(&pm_mutex);
- printk("Attempting manual resume\n");
+ printk(KERN_INFO "PM: Starting manual resume from disk\n");
noresume = 0;
software_resume();
ret = n;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index efc0836..6a6d5eb 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -24,13 +24,112 @@
#include "power.h"
-BLOCKING_NOTIFIER_HEAD(pm_chain_head);
-
DEFINE_MUTEX(pm_mutex);
unsigned int pm_flags;
EXPORT_SYMBOL(pm_flags);
+#ifdef CONFIG_PM_SLEEP
+
+/* Routines for PM-transition notifications */
+
+static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+
+int register_pm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&pm_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(register_pm_notifier);
+
+int unregister_pm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&pm_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_pm_notifier);
+
+int pm_notifier_call_chain(unsigned long val)
+{
+ return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
+ == NOTIFY_BAD) ? -EINVAL : 0;
+}
+
+#ifdef CONFIG_PM_DEBUG
+int pm_test_level = TEST_NONE;
+
+static int suspend_test(int level)
+{
+ if (pm_test_level == level) {
+ printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+ return 1;
+ }
+ return 0;
+}
+
+static const char * const pm_tests[__TEST_AFTER_LAST] = {
+ [TEST_NONE] = "none",
+ [TEST_CORE] = "core",
+ [TEST_CPUS] = "processors",
+ [TEST_PLATFORM] = "platform",
+ [TEST_DEVICES] = "devices",
+ [TEST_FREEZER] = "freezer",
+};
+
+static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char *s = buf;
+ int level;
+
+ for (level = TEST_FIRST; level <= TEST_MAX; level++)
+ if (pm_tests[level]) {
+ if (level == pm_test_level)
+ s += sprintf(s, "[%s] ", pm_tests[level]);
+ else
+ s += sprintf(s, "%s ", pm_tests[level]);
+ }
+
+ if (s != buf)
+ /* convert the last space to a newline */
+ *(s-1) = '\n';
+
+ return (s - buf);
+}
+
+static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ const char * const *s;
+ int level;
+ char *p;
+ int len;
+ int error = -EINVAL;
+
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+
+ mutex_lock(&pm_mutex);
+
+ level = TEST_FIRST;
+ for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
+ if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
+ pm_test_level = level;
+ error = 0;
+ break;
+ }
+
+ mutex_unlock(&pm_mutex);
+
+ return error ? error : n;
+}
+
+power_attr(pm_test);
+#else /* !CONFIG_PM_DEBUG */
+static inline int suspend_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
+#endif /* CONFIG_PM_SLEEP */
+
#ifdef CONFIG_SUSPEND
/* This is just an arbitrary number */
@@ -76,13 +175,13 @@
if (!suspend_ops || !suspend_ops->enter)
return -EPERM;
+ pm_prepare_console();
+
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
if (error)
goto Finish;
- pm_prepare_console();
-
- if (freeze_processes()) {
+ if (suspend_freeze_processes()) {
error = -EAGAIN;
goto Thaw;
}
@@ -100,10 +199,10 @@
return 0;
Thaw:
- thaw_processes();
- pm_restore_console();
+ suspend_thaw_processes();
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
+ pm_restore_console();
return error;
}
@@ -133,10 +232,13 @@
BUG_ON(!irqs_disabled());
if ((error = device_power_down(PMSG_SUSPEND))) {
- printk(KERN_ERR "Some devices failed to power down\n");
+ printk(KERN_ERR "PM: Some devices failed to power down\n");
goto Done;
}
- error = suspend_ops->enter(state);
+
+ if (!suspend_test(TEST_CORE))
+ error = suspend_ops->enter(state);
+
device_power_up();
Done:
arch_suspend_enable_irqs();
@@ -145,8 +247,8 @@
}
/**
- * suspend_devices_and_enter - suspend devices and enter the desired system sleep
- * state.
+ * suspend_devices_and_enter - suspend devices and enter the desired system
+ * sleep state.
* @state: state to enter
*/
int suspend_devices_and_enter(suspend_state_t state)
@@ -156,33 +258,45 @@
if (!suspend_ops)
return -ENOSYS;
- if (suspend_ops->set_target) {
- error = suspend_ops->set_target(state);
+ if (suspend_ops->begin) {
+ error = suspend_ops->begin(state);
if (error)
- return error;
+ goto Close;
}
suspend_console();
error = device_suspend(PMSG_SUSPEND);
if (error) {
- printk(KERN_ERR "Some devices failed to suspend\n");
+ printk(KERN_ERR "PM: Some devices failed to suspend\n");
goto Resume_console;
}
+
+ if (suspend_test(TEST_DEVICES))
+ goto Resume_devices;
+
if (suspend_ops->prepare) {
error = suspend_ops->prepare();
if (error)
goto Resume_devices;
}
+
+ if (suspend_test(TEST_PLATFORM))
+ goto Finish;
+
error = disable_nonboot_cpus();
- if (!error)
+ if (!error && !suspend_test(TEST_CPUS))
suspend_enter(state);
enable_nonboot_cpus();
+ Finish:
if (suspend_ops->finish)
suspend_ops->finish();
Resume_devices:
device_resume();
Resume_console:
resume_console();
+ Close:
+ if (suspend_ops->end)
+ suspend_ops->end();
return error;
}
@@ -194,9 +308,9 @@
*/
static void suspend_finish(void)
{
- thaw_processes();
- pm_restore_console();
+ suspend_thaw_processes();
pm_notifier_call_chain(PM_POST_SUSPEND);
+ pm_restore_console();
}
@@ -238,17 +352,22 @@
if (!mutex_trylock(&pm_mutex))
return -EBUSY;
- printk("Syncing filesystems ... ");
+ printk(KERN_INFO "PM: Syncing filesystems ... ");
sys_sync();
printk("done.\n");
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
- if ((error = suspend_prepare()))
+ error = suspend_prepare();
+ if (error)
goto Unlock;
+ if (suspend_test(TEST_FREEZER))
+ goto Finish;
+
pr_debug("PM: Entering %s sleep\n", pm_states[state]);
error = suspend_devices_and_enter(state);
+ Finish:
pr_debug("PM: Finishing wakeup.\n");
suspend_finish();
Unlock:
@@ -369,18 +488,18 @@
}
power_attr(pm_trace);
+#endif /* CONFIG_PM_TRACE */
static struct attribute * g[] = {
&state_attr.attr,
+#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
+#endif
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
+ &pm_test_attr.attr,
+#endif
NULL,
};
-#else
-static struct attribute * g[] = {
- &state_attr.attr,
- NULL,
-};
-#endif /* CONFIG_PM_TRACE */
static struct attribute_group attr_group = {
.attrs = g,
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 2093c3a..700f44e 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -1,5 +1,7 @@
#include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
#include <linux/utsname.h>
+#include <linux/freezer.h>
struct swsusp_info {
struct new_utsname uts;
@@ -128,42 +130,12 @@
#define data_of(handle) ((handle).buffer + (handle).buf_offset)
extern unsigned int snapshot_additional_pages(struct zone *zone);
+extern unsigned long snapshot_get_image_size(void);
extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
extern void snapshot_write_finalize(struct snapshot_handle *handle);
extern int snapshot_image_loaded(struct snapshot_handle *handle);
-/*
- * This structure is used to pass the values needed for the identification
- * of the resume swap area from a user space to the kernel via the
- * SNAPSHOT_SET_SWAP_AREA ioctl
- */
-struct resume_swap_area {
- loff_t offset;
- u_int32_t dev;
-} __attribute__((packed));
-
-#define SNAPSHOT_IOC_MAGIC '3'
-#define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
-#define SNAPSHOT_UNFREEZE _IO(SNAPSHOT_IOC_MAGIC, 2)
-#define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
-#define SNAPSHOT_ATOMIC_RESTORE _IO(SNAPSHOT_IOC_MAGIC, 4)
-#define SNAPSHOT_FREE _IO(SNAPSHOT_IOC_MAGIC, 5)
-#define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
-#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
-#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
-#define SNAPSHOT_FREE_SWAP_PAGES _IO(SNAPSHOT_IOC_MAGIC, 9)
-#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
-#define SNAPSHOT_S2RAM _IO(SNAPSHOT_IOC_MAGIC, 11)
-#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
-#define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \
- struct resume_swap_area)
-#define SNAPSHOT_IOC_MAXNR 13
-
-#define PMOPS_PREPARE 1
-#define PMOPS_ENTER 2
-#define PMOPS_FINISH 3
-
/* If unset, the snapshot device cannot be open. */
extern atomic_t snapshot_device_available;
@@ -181,7 +153,6 @@
extern int swsusp_check(void);
extern int swsusp_shrink_memory(void);
extern void swsusp_free(void);
-extern int swsusp_resume(void);
extern int swsusp_read(unsigned int *flags_p);
extern int swsusp_write(unsigned int flags);
extern void swsusp_close(void);
@@ -201,11 +172,56 @@
}
#endif /* !CONFIG_SUSPEND */
-/* kernel/power/common.c */
-extern struct blocking_notifier_head pm_chain_head;
+#ifdef CONFIG_PM_SLEEP
+/* kernel/power/main.c */
+extern int pm_notifier_call_chain(unsigned long val);
+#endif
-static inline int pm_notifier_call_chain(unsigned long val)
+#ifdef CONFIG_HIGHMEM
+unsigned int count_highmem_pages(void);
+int restore_highmem(void);
+#else
+static inline unsigned int count_highmem_pages(void) { return 0; }
+static inline int restore_highmem(void) { return 0; }
+#endif
+
+/*
+ * Suspend test levels
+ */
+enum {
+ /* keep first */
+ TEST_NONE,
+ TEST_CORE,
+ TEST_CPUS,
+ TEST_PLATFORM,
+ TEST_DEVICES,
+ TEST_FREEZER,
+ /* keep last */
+ __TEST_AFTER_LAST
+};
+
+#define TEST_FIRST TEST_NONE
+#define TEST_MAX (__TEST_AFTER_LAST - 1)
+
+extern int pm_test_level;
+
+#ifdef CONFIG_SUSPEND_FREEZER
+static inline int suspend_freeze_processes(void)
{
- return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
- == NOTIFY_BAD) ? -EINVAL : 0;
+ return freeze_processes();
}
+
+static inline void suspend_thaw_processes(void)
+{
+ thaw_processes();
+}
+#else
+static inline int suspend_freeze_processes(void)
+{
+ return 0;
+}
+
+static inline void suspend_thaw_processes(void)
+{
+}
+#endif
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 78039b4..95250d7 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -635,7 +635,7 @@
region->end_pfn = end_pfn;
list_add_tail(®ion->list, &nosave_regions);
Report:
- printk("swsusp: Registered nosave memory region: %016lx - %016lx\n",
+ printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n",
start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
}
@@ -704,7 +704,7 @@
list_for_each_entry(region, &nosave_regions, list) {
unsigned long pfn;
- printk("swsusp: Marking nosave pages: %016lx - %016lx\n",
+ pr_debug("PM: Marking nosave pages: %016lx - %016lx\n",
region->start_pfn << PAGE_SHIFT,
region->end_pfn << PAGE_SHIFT);
@@ -749,7 +749,7 @@
free_pages_map = bm2;
mark_nosave_pages(forbidden_pages_map);
- printk("swsusp: Basic memory bitmaps created\n");
+ pr_debug("PM: Basic memory bitmaps created\n");
return 0;
@@ -784,7 +784,7 @@
memory_bm_free(bm2, PG_UNSAFE_CLEAR);
kfree(bm2);
- printk("swsusp: Basic memory bitmaps freed\n");
+ pr_debug("PM: Basic memory bitmaps freed\n");
}
/**
@@ -872,7 +872,6 @@
}
#else
static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
-static inline unsigned int count_highmem_pages(void) { return 0; }
#endif /* CONFIG_HIGHMEM */
/**
@@ -1089,7 +1088,7 @@
}
nr_pages += count_pages_for_highmem(nr_highmem);
- pr_debug("swsusp: Normal pages needed: %u + %u + %u, available pages: %u\n",
+ pr_debug("PM: Normal pages needed: %u + %u + %u, available pages: %u\n",
nr_pages, PAGES_FOR_IO, meta, free);
return free > nr_pages + PAGES_FOR_IO + meta;
@@ -1202,27 +1201,27 @@
{
unsigned int nr_pages, nr_highmem;
- printk("swsusp: critical section: \n");
+ printk(KERN_INFO "PM: Creating hibernation image: \n");
- drain_local_pages();
+ drain_local_pages(NULL);
nr_pages = count_data_pages();
nr_highmem = count_highmem_pages();
- printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem);
+ printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem);
if (!enough_free_mem(nr_pages, nr_highmem)) {
- printk(KERN_ERR "swsusp: Not enough free memory\n");
+ printk(KERN_ERR "PM: Not enough free memory\n");
return -ENOMEM;
}
if (swsusp_alloc(&orig_bm, ©_bm, nr_pages, nr_highmem)) {
- printk(KERN_ERR "swsusp: Memory allocation failed\n");
+ printk(KERN_ERR "PM: Memory allocation failed\n");
return -ENOMEM;
}
/* During allocating of suspend pagedir, new cold pages may appear.
* Kill them.
*/
- drain_local_pages();
+ drain_local_pages(NULL);
copy_data_pages(©_bm, &orig_bm);
/*
@@ -1235,7 +1234,8 @@
nr_copy_pages = nr_pages;
nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
- printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
+ printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n",
+ nr_pages);
return 0;
}
@@ -1264,12 +1264,17 @@
}
#endif /* CONFIG_ARCH_HIBERNATION_HEADER */
+unsigned long snapshot_get_image_size(void)
+{
+ return nr_copy_pages + nr_meta_pages + 1;
+}
+
static int init_header(struct swsusp_info *info)
{
memset(info, 0, sizeof(struct swsusp_info));
info->num_physpages = num_physpages;
info->image_pages = nr_copy_pages;
- info->pages = nr_copy_pages + nr_meta_pages + 1;
+ info->pages = snapshot_get_image_size();
info->size = info->pages;
info->size <<= PAGE_SHIFT;
return init_header_complete(info);
@@ -1429,7 +1434,7 @@
if (!reason && info->num_physpages != num_physpages)
reason = "memory size";
if (reason) {
- printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
+ printk(KERN_ERR "PM: Image mismatch: %s\n", reason);
return -EPERM;
}
return 0;
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 917aba1..a0abf9a 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -28,8 +28,6 @@
#include "power.h"
-extern char resume_file[];
-
#define SWSUSP_SIG "S1SUSPEND"
struct swsusp_header {
@@ -73,7 +71,8 @@
bio->bi_end_io = end_swap_bio_read;
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
- printk("swsusp: ERROR: adding page to bio at %ld\n", page_off);
+ printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
+ page_off);
bio_put(bio);
return -EFAULT;
}
@@ -153,7 +152,7 @@
error = bio_write_page(swsusp_resume_block,
swsusp_header, NULL);
} else {
- printk(KERN_ERR "swsusp: Swap header not found!\n");
+ printk(KERN_ERR "PM: Swap header not found!\n");
error = -ENODEV;
}
return error;
@@ -325,7 +324,8 @@
struct timeval start;
struct timeval stop;
- printk("Saving image data pages (%u pages) ... ", nr_to_write);
+ printk(KERN_INFO "PM: Saving image data pages (%u pages) ... ",
+ nr_to_write);
m = nr_to_write / 100;
if (!m)
m = 1;
@@ -365,7 +365,7 @@
{
unsigned int free_swap = count_swap_pages(root_swap, 1);
- pr_debug("swsusp: free swap pages: %u\n", free_swap);
+ pr_debug("PM: Free swap pages: %u\n", free_swap);
return free_swap > nr_pages + PAGES_FOR_IO;
}
@@ -388,7 +388,7 @@
error = swsusp_swap_check();
if (error) {
- printk(KERN_ERR "swsusp: Cannot find swap device, try "
+ printk(KERN_ERR "PM: Cannot find swap device, try "
"swapon -a.\n");
return error;
}
@@ -402,7 +402,7 @@
}
header = (struct swsusp_info *)data_of(snapshot);
if (!enough_swap(header->pages)) {
- printk(KERN_ERR "swsusp: Not enough free swap\n");
+ printk(KERN_ERR "PM: Not enough free swap\n");
error = -ENOSPC;
goto out;
}
@@ -417,7 +417,7 @@
if (!error) {
flush_swap_writer(&handle);
- printk("S");
+ printk(KERN_INFO "PM: S");
error = mark_swapfiles(start, flags);
printk("|\n");
}
@@ -507,7 +507,8 @@
int err2;
unsigned nr_pages;
- printk("Loading image data pages (%u pages) ... ", nr_to_read);
+ printk(KERN_INFO "PM: Loading image data pages (%u pages) ... ",
+ nr_to_read);
m = nr_to_read / 100;
if (!m)
m = 1;
@@ -558,7 +559,7 @@
*flags_p = swsusp_header->flags;
if (IS_ERR(resume_bdev)) {
- pr_debug("swsusp: block device not initialised\n");
+ pr_debug("PM: Image device not initialised\n");
return PTR_ERR(resume_bdev);
}
@@ -577,9 +578,9 @@
blkdev_put(resume_bdev);
if (!error)
- pr_debug("swsusp: Reading resume file was successful\n");
+ pr_debug("PM: Image successfully loaded\n");
else
- pr_debug("swsusp: Error %d resuming\n", error);
+ pr_debug("PM: Error %d resuming\n", error);
return error;
}
@@ -611,13 +612,13 @@
if (error)
blkdev_put(resume_bdev);
else
- pr_debug("swsusp: Signature found, resuming\n");
+ pr_debug("PM: Signature found, resuming\n");
} else {
error = PTR_ERR(resume_bdev);
}
if (error)
- pr_debug("swsusp: Error %d check for resume file\n", error);
+ pr_debug("PM: Error %d checking image file\n", error);
return error;
}
@@ -629,7 +630,7 @@
void swsusp_close(void)
{
if (IS_ERR(resume_bdev)) {
- pr_debug("swsusp: block device not initialised\n");
+ pr_debug("PM: Image device not initialised\n");
return;
}
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index e1722d3..023ff2a 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -64,14 +64,6 @@
int in_suspend __nosavedata = 0;
-#ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void);
-int restore_highmem(void);
-#else
-static inline int restore_highmem(void) { return 0; }
-static inline unsigned int count_highmem_pages(void) { return 0; }
-#endif
-
/**
* The following functions are used for tracing the allocated
* swap pages, so that they can be freed in case of an error.
@@ -196,7 +188,8 @@
centisecs = 1; /* avoid div-by-zero */
k = nr_pages * (PAGE_SIZE / 1024);
kps = (k * 100) / centisecs;
- printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k,
+ printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+ msg, k,
centisecs / 100, centisecs % 100,
kps / 1000, (kps % 1000) / 10);
}
@@ -227,7 +220,7 @@
char *p = "-\\|/";
struct timeval start, stop;
- printk("Shrinking memory... ");
+ printk(KERN_INFO "PM: Shrinking memory... ");
do_gettimeofday(&start);
do {
long size, highmem_size;
@@ -269,38 +262,3 @@
return 0;
}
-
-int swsusp_resume(void)
-{
- int error;
-
- local_irq_disable();
- /* NOTE: device_power_down() is just a suspend() with irqs off;
- * it has no special "power things down" semantics
- */
- if (device_power_down(PMSG_PRETHAW))
- printk(KERN_ERR "Some devices failed to power down, very bad\n");
- /* We'll ignore saved state, but this gets preempt count (etc) right */
- save_processor_state();
- error = restore_highmem();
- if (!error) {
- error = swsusp_arch_resume();
- /* The code below is only ever reached in case of a failure.
- * Otherwise execution continues at place where
- * swsusp_arch_suspend() was called
- */
- BUG_ON(!error);
- /* This call to restore_highmem() undos the previous one */
- restore_highmem();
- }
- /* The only reason why swsusp_arch_resume() can fail is memory being
- * very tight, so we have to free it as soon as we can to avoid
- * subsequent failures
- */
- swsusp_free();
- restore_processor_state();
- touch_softlockup_watchdog();
- device_power_up();
- local_irq_enable();
- return error;
-}
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 5bd321b..f5512cb 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -28,6 +28,29 @@
#include "power.h"
+/*
+ * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
+ * will be removed in the future. They are only preserved here for
+ * compatibility with existing userland utilities.
+ */
+#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
+#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
+
+#define PMOPS_PREPARE 1
+#define PMOPS_ENTER 2
+#define PMOPS_FINISH 3
+
+/*
+ * NOTE: The following ioctl definitions are wrong and have been replaced with
+ * correct ones. They are only preserved here for compatibility with existing
+ * userland utilities and will be removed in the future.
+ */
+#define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
+#define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
+#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
+#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
+
+
#define SNAPSHOT_MINOR 231
static struct snapshot_data {
@@ -36,7 +59,7 @@
int mode;
char frozen;
char ready;
- char platform_suspend;
+ char platform_support;
} snapshot_state;
atomic_t snapshot_device_available = ATOMIC_INIT(1);
@@ -44,6 +67,7 @@
static int snapshot_open(struct inode *inode, struct file *filp)
{
struct snapshot_data *data;
+ int error;
if (!atomic_add_unless(&snapshot_device_available, -1, 0))
return -EBUSY;
@@ -64,13 +88,23 @@
data->swap = swsusp_resume_device ?
swap_type_of(swsusp_resume_device, 0, NULL) : -1;
data->mode = O_RDONLY;
+ error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+ if (error)
+ pm_notifier_call_chain(PM_POST_RESTORE);
} else {
data->swap = -1;
data->mode = O_WRONLY;
+ error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+ if (error)
+ pm_notifier_call_chain(PM_POST_HIBERNATION);
+ }
+ if (error) {
+ atomic_inc(&snapshot_device_available);
+ return error;
}
data->frozen = 0;
data->ready = 0;
- data->platform_suspend = 0;
+ data->platform_support = 0;
return 0;
}
@@ -88,6 +122,8 @@
thaw_processes();
mutex_unlock(&pm_mutex);
}
+ pm_notifier_call_chain(data->mode == O_WRONLY ?
+ PM_POST_HIBERNATION : PM_POST_RESTORE);
atomic_inc(&snapshot_device_available);
return 0;
}
@@ -133,7 +169,7 @@
{
int error = 0;
struct snapshot_data *data;
- loff_t avail;
+ loff_t size;
sector_t offset;
if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
@@ -151,18 +187,13 @@
if (data->frozen)
break;
mutex_lock(&pm_mutex);
- error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
- if (!error) {
- printk("Syncing filesystems ... ");
- sys_sync();
- printk("done.\n");
+ printk("Syncing filesystems ... ");
+ sys_sync();
+ printk("done.\n");
- error = freeze_processes();
- if (error)
- thaw_processes();
- }
+ error = freeze_processes();
if (error)
- pm_notifier_call_chain(PM_POST_HIBERNATION);
+ thaw_processes();
mutex_unlock(&pm_mutex);
if (!error)
data->frozen = 1;
@@ -173,19 +204,19 @@
break;
mutex_lock(&pm_mutex);
thaw_processes();
- pm_notifier_call_chain(PM_POST_HIBERNATION);
mutex_unlock(&pm_mutex);
data->frozen = 0;
break;
+ case SNAPSHOT_CREATE_IMAGE:
case SNAPSHOT_ATOMIC_SNAPSHOT:
if (data->mode != O_RDONLY || !data->frozen || data->ready) {
error = -EPERM;
break;
}
- error = hibernation_snapshot(data->platform_suspend);
+ error = hibernation_snapshot(data->platform_support);
if (!error)
- error = put_user(in_suspend, (unsigned int __user *)arg);
+ error = put_user(in_suspend, (int __user *)arg);
if (!error)
data->ready = 1;
break;
@@ -197,7 +228,7 @@
error = -EPERM;
break;
}
- error = hibernation_restore(data->platform_suspend);
+ error = hibernation_restore(data->platform_support);
break;
case SNAPSHOT_FREE:
@@ -206,16 +237,29 @@
data->ready = 0;
break;
+ case SNAPSHOT_PREF_IMAGE_SIZE:
case SNAPSHOT_SET_IMAGE_SIZE:
image_size = arg;
break;
- case SNAPSHOT_AVAIL_SWAP:
- avail = count_swap_pages(data->swap, 1);
- avail <<= PAGE_SHIFT;
- error = put_user(avail, (loff_t __user *)arg);
+ case SNAPSHOT_GET_IMAGE_SIZE:
+ if (!data->ready) {
+ error = -ENODATA;
+ break;
+ }
+ size = snapshot_get_image_size();
+ size <<= PAGE_SHIFT;
+ error = put_user(size, (loff_t __user *)arg);
break;
+ case SNAPSHOT_AVAIL_SWAP_SIZE:
+ case SNAPSHOT_AVAIL_SWAP:
+ size = count_swap_pages(data->swap, 1);
+ size <<= PAGE_SHIFT;
+ error = put_user(size, (loff_t __user *)arg);
+ break;
+
+ case SNAPSHOT_ALLOC_SWAP_PAGE:
case SNAPSHOT_GET_SWAP_PAGE:
if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
error = -ENODEV;
@@ -224,7 +268,7 @@
offset = alloc_swapdev_block(data->swap);
if (offset) {
offset <<= PAGE_SHIFT;
- error = put_user(offset, (sector_t __user *)arg);
+ error = put_user(offset, (loff_t __user *)arg);
} else {
error = -ENOSPC;
}
@@ -238,7 +282,7 @@
free_all_swap_pages(data->swap);
break;
- case SNAPSHOT_SET_SWAP_FILE:
+ case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
if (!swsusp_swap_in_use()) {
/*
* User space encodes device types as two-byte values,
@@ -275,26 +319,33 @@
mutex_unlock(&pm_mutex);
break;
- case SNAPSHOT_PMOPS:
+ case SNAPSHOT_PLATFORM_SUPPORT:
+ data->platform_support = !!arg;
+ break;
+
+ case SNAPSHOT_POWER_OFF:
+ if (data->platform_support)
+ error = hibernation_platform_enter();
+ break;
+
+ case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
error = -EINVAL;
switch (arg) {
case PMOPS_PREPARE:
- data->platform_suspend = 1;
+ data->platform_support = 1;
error = 0;
break;
case PMOPS_ENTER:
- if (data->platform_suspend)
+ if (data->platform_support)
error = hibernation_platform_enter();
-
break;
case PMOPS_FINISH:
- if (data->platform_suspend)
+ if (data->platform_support)
error = 0;
-
break;
default:
diff --git a/kernel/printk.c b/kernel/printk.c
index 29ae1e99..4a09062 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -93,16 +93,16 @@
*/
static DEFINE_SPINLOCK(logbuf_lock);
-#define LOG_BUF_MASK (log_buf_len-1)
+#define LOG_BUF_MASK (log_buf_len-1)
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
/*
* The indices into log_buf are not constrained to log_buf_len - they
* must be masked before subscripting
*/
-static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */
-static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */
-static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */
+static unsigned log_start; /* Index into log_buf: next char to be read by syslog() */
+static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */
+static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */
/*
* Array of consoles built from command line options (console=)
@@ -128,17 +128,17 @@
static char __log_buf[__LOG_BUF_LEN];
static char *log_buf = __log_buf;
static int log_buf_len = __LOG_BUF_LEN;
-static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
+static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
static int __init log_buf_len_setup(char *str)
{
- unsigned long size = memparse(str, &str);
+ unsigned size = memparse(str, &str);
unsigned long flags;
if (size)
size = roundup_pow_of_two(size);
if (size > log_buf_len) {
- unsigned long start, dest_idx, offset;
+ unsigned start, dest_idx, offset;
char *new_log_buf;
new_log_buf = alloc_bootmem(size);
@@ -295,7 +295,7 @@
*/
int do_syslog(int type, char __user *buf, int len)
{
- unsigned long i, j, limit, count;
+ unsigned i, j, limit, count;
int do_clear = 0;
char c;
int error = 0;
@@ -436,7 +436,7 @@
/*
* Call the console drivers on a range of log_buf
*/
-static void __call_console_drivers(unsigned long start, unsigned long end)
+static void __call_console_drivers(unsigned start, unsigned end)
{
struct console *con;
@@ -463,8 +463,8 @@
/*
* Write out chars from start to end - 1 inclusive
*/
-static void _call_console_drivers(unsigned long start,
- unsigned long end, int msg_log_level)
+static void _call_console_drivers(unsigned start,
+ unsigned end, int msg_log_level)
{
if ((msg_log_level < console_loglevel || ignore_loglevel) &&
console_drivers && start != end) {
@@ -484,12 +484,12 @@
* log_buf[start] to log_buf[end - 1].
* The console_sem must be held.
*/
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
{
- unsigned long cur_index, start_print;
+ unsigned cur_index, start_print;
static int msg_level = -1;
- BUG_ON(((long)(start - end)) > 0);
+ BUG_ON(((int)(start - end)) > 0);
cur_index = start;
start_print = start;
@@ -790,7 +790,7 @@
return -ENOSYS;
}
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
{
}
@@ -983,8 +983,8 @@
void release_console_sem(void)
{
unsigned long flags;
- unsigned long _con_start, _log_end;
- unsigned long wake_klogd = 0;
+ unsigned _con_start, _log_end;
+ unsigned wake_klogd = 0;
if (console_suspended) {
up(&secondary_console_sem);
@@ -1275,7 +1275,7 @@
int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
static DEFINE_SPINLOCK(ratelimit_lock);
- static unsigned long toks = 10 * 5 * HZ;
+ static unsigned toks = 10 * 5 * HZ;
static unsigned long last_msg;
static int missed;
unsigned long flags;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b0d4ab4..628b03a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -20,6 +20,7 @@
#include <linux/signal.h>
#include <linux/audit.h>
#include <linux/pid_namespace.h>
+#include <linux/syscalls.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -53,7 +54,7 @@
spin_lock(&child->sighand->siglock);
if (task_is_traced(child)) {
if (child->signal->flags & SIGNAL_STOP_STOPPED) {
- child->state = TASK_STOPPED;
+ __set_task_state(child, TASK_STOPPED);
} else {
signal_wake_up(child, 1);
}
@@ -103,18 +104,16 @@
&& child->signal != NULL) {
ret = 0;
spin_lock_irq(&child->sighand->siglock);
- if (task_is_stopped(child)) {
+ if (task_is_stopped(child))
child->state = TASK_TRACED;
- } else if (!task_is_traced(child) && !kill) {
+ else if (!task_is_traced(child) && !kill)
ret = -ESRCH;
- }
spin_unlock_irq(&child->sighand->siglock);
}
read_unlock(&tasklist_lock);
- if (!ret && !kill) {
+ if (!ret && !kill)
wait_task_inactive(child);
- }
/* All systems go.. */
return ret;
diff --git a/kernel/relay.c b/kernel/relay.c
index 61134eb..d080b9d 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -37,37 +37,31 @@
}
/*
- * nopage() vm_op implementation for relay file mapping.
+ * fault() vm_op implementation for relay file mapping.
*/
-static struct page *relay_buf_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int *type)
+static int relay_buf_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct page *page;
struct rchan_buf *buf = vma->vm_private_data;
- unsigned long offset = address - vma->vm_start;
+ pgoff_t pgoff = vmf->pgoff;
- if (address > vma->vm_end)
- return NOPAGE_SIGBUS; /* Disallow mremap */
if (!buf)
- return NOPAGE_OOM;
+ return VM_FAULT_OOM;
- page = vmalloc_to_page(buf->start + offset);
+ page = vmalloc_to_page(buf->start + (pgoff << PAGE_SHIFT));
if (!page)
- return NOPAGE_OOM;
+ return VM_FAULT_SIGBUS;
get_page(page);
+ vmf->page = page;
- if (type)
- *type = VM_FAULT_MINOR;
-
- return page;
+ return 0;
}
/*
* vm_ops for relay file mappings.
*/
static struct vm_operations_struct relay_file_mmap_ops = {
- .nopage = relay_buf_nopage,
+ .fault = relay_buf_fault,
.close = relay_file_mmap_close,
};
@@ -92,6 +86,7 @@
return -EINVAL;
vma->vm_ops = &relay_file_mmap_ops;
+ vma->vm_flags |= VM_DONTEXPAND;
vma->vm_private_data = buf;
buf->chan->cb->buf_mapped(buf, filp);
diff --git a/kernel/signal.c b/kernel/signal.c
index 4333b6d..5d30ff5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -911,27 +911,6 @@
} while_each_thread(p, t);
return;
}
-
- /*
- * There will be a core dump. We make all threads other
- * than the chosen one go into a group stop so that nothing
- * happens until it gets scheduled, takes the signal off
- * the shared queue, and does the core dump. This is a
- * little more complicated than strictly necessary, but it
- * keeps the signal state that winds up in the core dump
- * unchanged from the death state, e.g. which thread had
- * the core-dump signal unblocked.
- */
- rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
- rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
- p->signal->group_stop_count = 0;
- p->signal->group_exit_task = t;
- p = t;
- do {
- p->signal->group_stop_count++;
- signal_wake_up(t, t == p);
- } while_each_thread(p, t);
- return;
}
/*
@@ -978,7 +957,6 @@
{
struct task_struct *t;
- p->signal->flags = SIGNAL_GROUP_EXIT;
p->signal->group_stop_count = 0;
for (t = next_thread(p); t != p; t = next_thread(t)) {
@@ -1600,6 +1578,17 @@
}
/*
+ * Return nonzero if there is a SIGKILL that should be waking us up.
+ * Called with the siglock held.
+ */
+static int sigkill_pending(struct task_struct *tsk)
+{
+ return ((sigismember(&tsk->pending.signal, SIGKILL) ||
+ sigismember(&tsk->signal->shared_pending.signal, SIGKILL)) &&
+ !unlikely(sigismember(&tsk->blocked, SIGKILL)));
+}
+
+/*
* This must be called with current->sighand->siglock held.
*
* This should be the path for all ptrace stops.
@@ -1612,6 +1601,26 @@
*/
static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
{
+ int killed = 0;
+
+ if (arch_ptrace_stop_needed(exit_code, info)) {
+ /*
+ * The arch code has something special to do before a
+ * ptrace stop. This is allowed to block, e.g. for faults
+ * on user stack pages. We can't keep the siglock while
+ * calling arch_ptrace_stop, so we must release it now.
+ * To preserve proper semantics, we must do this before
+ * any signal bookkeeping like checking group_stop_count.
+ * Meanwhile, a SIGKILL could come in before we retake the
+ * siglock. That must prevent us from sleeping in TASK_TRACED.
+ * So after regaining the lock, we must check for SIGKILL.
+ */
+ spin_unlock_irq(¤t->sighand->siglock);
+ arch_ptrace_stop(exit_code, info);
+ spin_lock_irq(¤t->sighand->siglock);
+ killed = sigkill_pending(current);
+ }
+
/*
* If there is a group stop in progress,
* we must participate in the bookkeeping.
@@ -1623,11 +1632,11 @@
current->exit_code = exit_code;
/* Let the debugger run. */
- set_current_state(TASK_TRACED);
+ __set_current_state(TASK_TRACED);
spin_unlock_irq(¤t->sighand->siglock);
try_to_freeze();
read_lock(&tasklist_lock);
- if (may_ptrace_stop()) {
+ if (!unlikely(killed) && may_ptrace_stop()) {
do_notify_parent_cldstop(current, CLD_TRAPPED);
read_unlock(&tasklist_lock);
schedule();
@@ -1709,9 +1718,6 @@
struct signal_struct *sig = current->signal;
int stop_count;
- if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED))
- return 0;
-
if (sig->group_stop_count > 0) {
/*
* There is a group stop in progress. We don't need to
@@ -1719,12 +1725,15 @@
*/
stop_count = --sig->group_stop_count;
} else {
+ struct task_struct *t;
+
+ if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) ||
+ unlikely(sig->group_exit_task))
+ return 0;
/*
* There is no group stop already in progress.
* We must initiate one now.
*/
- struct task_struct *t;
-
sig->group_exit_code = signr;
stop_count = 0;
@@ -1752,47 +1761,6 @@
return 1;
}
-/*
- * Do appropriate magic when group_stop_count > 0.
- * We return nonzero if we stopped, after releasing the siglock.
- * We return zero if we still hold the siglock and should look
- * for another signal without checking group_stop_count again.
- */
-static int handle_group_stop(void)
-{
- int stop_count;
-
- if (current->signal->group_exit_task == current) {
- /*
- * Group stop is so we can do a core dump,
- * We are the initiating thread, so get on with it.
- */
- current->signal->group_exit_task = NULL;
- return 0;
- }
-
- if (current->signal->flags & SIGNAL_GROUP_EXIT)
- /*
- * Group stop is so another thread can do a core dump,
- * or else we are racing against a death signal.
- * Just punt the stop so we can get the next signal.
- */
- return 0;
-
- /*
- * There is a group stop in progress. We stop
- * without any associated signal being in our queue.
- */
- stop_count = --current->signal->group_stop_count;
- if (stop_count == 0)
- current->signal->flags = SIGNAL_STOP_STOPPED;
- current->exit_code = current->signal->group_exit_code;
- set_current_state(TASK_STOPPED);
- spin_unlock_irq(¤t->sighand->siglock);
- finish_stop(stop_count);
- return 1;
-}
-
int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
struct pt_regs *regs, void *cookie)
{
@@ -1807,7 +1775,7 @@
struct k_sigaction *ka;
if (unlikely(current->signal->group_stop_count > 0) &&
- handle_group_stop())
+ do_signal_stop(0))
goto relock;
signr = dequeue_signal(current, mask, info);
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index c1d7655..7c2da88 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -101,6 +101,10 @@
now = get_timestamp(this_cpu);
+ /* Wake up the high-prio watchdog task every second: */
+ if (now > (touch_timestamp + 1))
+ wake_up_process(per_cpu(watchdog_task, this_cpu));
+
/* Warn about unreasonable delays: */
if (now <= (touch_timestamp + softlockup_thresh))
return;
@@ -191,11 +195,11 @@
read_lock(&tasklist_lock);
do_each_thread(g, t) {
if (!--max_count)
- break;
+ goto unlock;
if (t->state & TASK_UNINTERRUPTIBLE)
check_hung_task(t, now);
} while_each_thread(g, t);
-
+ unlock:
read_unlock(&tasklist_lock);
}
@@ -218,14 +222,19 @@
* debug-printout triggers in softlockup_tick().
*/
while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
touch_softlockup_watchdog();
- msleep_interruptible(10000);
+ schedule();
+
+ if (kthread_should_stop())
+ break;
if (this_cpu != check_cpu)
continue;
if (sysctl_hung_task_timeout_secs)
check_hung_uninterruptible_tasks(this_cpu);
+
}
return 0;
@@ -259,13 +268,6 @@
wake_up_process(per_cpu(watchdog_task, hotcpu));
break;
#ifdef CONFIG_HOTPLUG_CPU
- case CPU_UP_CANCELED:
- case CPU_UP_CANCELED_FROZEN:
- if (!per_cpu(watchdog_task, hotcpu))
- break;
- /* Unbind so it can run. Fall thru. */
- kthread_bind(per_cpu(watchdog_task, hotcpu),
- any_online_cpu(cpu_online_map));
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
if (hotcpu == check_cpu) {
@@ -275,6 +277,14 @@
check_cpu = any_online_cpu(temp_cpu_online_map);
}
break;
+
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ if (!per_cpu(watchdog_task, hotcpu))
+ break;
+ /* Unbind so it can run. Fall thru. */
+ kthread_bind(per_cpu(watchdog_task, hotcpu),
+ any_online_cpu(cpu_online_map));
case CPU_DEAD:
case CPU_DEAD_FROZEN:
p = per_cpu(watchdog_task, hotcpu);
diff --git a/kernel/srcu.c b/kernel/srcu.c
index 3507cabe..b0aeeaf 100644
--- a/kernel/srcu.c
+++ b/kernel/srcu.c
@@ -74,7 +74,7 @@
* severe errors when invoked on an active srcu_struct. That said, it
* can be useful as an error check at cleanup time.
*/
-int srcu_readers_active(struct srcu_struct *sp)
+static int srcu_readers_active(struct srcu_struct *sp)
{
return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
}
@@ -255,4 +255,3 @@
EXPORT_SYMBOL_GPL(srcu_read_unlock);
EXPORT_SYMBOL_GPL(synchronize_srcu);
EXPORT_SYMBOL_GPL(srcu_batches_completed);
-EXPORT_SYMBOL_GPL(srcu_readers_active);
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 51b5ee5..6f4e0e1 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -29,7 +29,6 @@
static enum stopmachine_state stopmachine_state;
static unsigned int stopmachine_num_threads;
static atomic_t stopmachine_thread_ack;
-static DECLARE_MUTEX(stopmachine_mutex);
static int stopmachine(void *cpu)
{
@@ -170,6 +169,7 @@
struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
unsigned int cpu)
{
+ static DEFINE_MUTEX(stopmachine_mutex);
struct stop_machine_data smdata;
struct task_struct *p;
@@ -177,7 +177,7 @@
smdata.data = data;
init_completion(&smdata.done);
- down(&stopmachine_mutex);
+ mutex_lock(&stopmachine_mutex);
/* If they don't care which CPU fn runs on, bind to any online one. */
if (cpu == NR_CPUS)
@@ -193,7 +193,7 @@
wake_up_process(p);
wait_for_completion(&smdata.done);
}
- up(&stopmachine_mutex);
+ mutex_unlock(&stopmachine_mutex);
return p;
}
diff --git a/kernel/sys.c b/kernel/sys.c
index d1fe71e..e3c08d4 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -315,7 +315,7 @@
#endif
}
-void kernel_shutdown_prepare(enum system_states state)
+static void kernel_shutdown_prepare(enum system_states state)
{
blocking_notifier_call_chain(&reboot_notifier_list,
(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
@@ -1145,16 +1145,16 @@
struct group_info *group_info)
{
int i;
- int count = group_info->ngroups;
+ unsigned int count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
- int cp_count = min(NGROUPS_PER_BLOCK, count);
- int off = i * NGROUPS_PER_BLOCK;
- int len = cp_count * sizeof(*grouplist);
+ unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+ unsigned int len = cp_count * sizeof(*grouplist);
- if (copy_to_user(grouplist+off, group_info->blocks[i], len))
+ if (copy_to_user(grouplist, group_info->blocks[i], len))
return -EFAULT;
+ grouplist += NGROUPS_PER_BLOCK;
count -= cp_count;
}
return 0;
@@ -1165,16 +1165,16 @@
gid_t __user *grouplist)
{
int i;
- int count = group_info->ngroups;
+ unsigned int count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
- int cp_count = min(NGROUPS_PER_BLOCK, count);
- int off = i * NGROUPS_PER_BLOCK;
- int len = cp_count * sizeof(*grouplist);
+ unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+ unsigned int len = cp_count * sizeof(*grouplist);
- if (copy_from_user(group_info->blocks[i], grouplist+off, len))
+ if (copy_from_user(group_info->blocks[i], grouplist, len))
return -EFAULT;
+ grouplist += NGROUPS_PER_BLOCK;
count -= cp_count;
}
return 0;
@@ -1472,7 +1472,7 @@
if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
!capable(CAP_SYS_RESOURCE))
return -EPERM;
- if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN)
+ if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
return -EPERM;
retval = security_task_setrlimit(resource, &new_rlim);
@@ -1637,7 +1637,7 @@
mask = xchg(¤t->fs->umask, mask & S_IRWXUGO);
return mask;
}
-
+
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
@@ -1742,6 +1742,17 @@
error = prctl_set_seccomp(arg2);
break;
+ case PR_CAPBSET_READ:
+ if (!cap_valid(arg2))
+ return -EINVAL;
+ return !!cap_raised(current->cap_bset, arg2);
+ case PR_CAPBSET_DROP:
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+ return cap_prctl_drop(arg2);
+#else
+ return -EINVAL;
+#endif
+
default:
error = -EINVAL;
break;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index beee5b3..5b9b467 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -154,7 +154,10 @@
/* New file descriptors */
cond_syscall(sys_signalfd);
-cond_syscall(sys_timerfd);
cond_syscall(compat_sys_signalfd);
-cond_syscall(compat_sys_timerfd);
+cond_syscall(sys_timerfd_create);
+cond_syscall(sys_timerfd_settime);
+cond_syscall(sys_timerfd_gettime);
+cond_syscall(compat_sys_timerfd_settime);
+cond_syscall(compat_sys_timerfd_gettime);
cond_syscall(sys_eventfd);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 7cb1ac3..86daaa2 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -84,8 +84,11 @@
extern int latencytop_enabled;
/* Constants used for minimum and maximum */
-#ifdef CONFIG_DETECT_SOFTLOCKUP
+#if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM)
static int one = 1;
+#endif
+
+#ifdef CONFIG_DETECT_SOFTLOCKUP
static int sixty = 60;
#endif
@@ -416,15 +419,6 @@
.proc_handler = &proc_dointvec,
},
#endif
-#ifdef CONFIG_SECURITY_CAPABILITIES
- {
- .procname = "cap-bound",
- .data = &cap_bset,
- .maxlen = sizeof(kernel_cap_t),
- .mode = 0600,
- .proc_handler = &proc_dointvec_bset,
- },
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
#ifdef CONFIG_BLK_DEV_INITRD
{
.ctl_name = KERN_REALROOTDEV,
@@ -1150,6 +1144,19 @@
.extra1 = &zero,
},
#endif
+#ifdef CONFIG_HIGHMEM
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "highmem_is_dirtyable",
+ .data = &vm_highmem_is_dirtyable,
+ .maxlen = sizeof(vm_highmem_is_dirtyable),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+#endif
/*
* NOTE: do not add new entries to this table unless you have read
* Documentation/sysctl/ctl_unnumbered.txt
@@ -1196,6 +1203,14 @@
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nr_open",
+ .data = &sysctl_nr_open,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = FS_DENTRY,
.procname = "dentry-state",
.data = &dentry_stat,
@@ -2080,26 +2095,6 @@
return 0;
}
-#ifdef CONFIG_SECURITY_CAPABILITIES
-/*
- * init may raise the set.
- */
-
-int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- int op;
-
- if (write && !capable(CAP_SYS_MODULE)) {
- return -EPERM;
- }
-
- op = is_global_init(current) ? OP_SET : OP_AND;
- return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
- do_proc_dointvec_bset_conv,&op);
-}
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
-
/*
* Taint values can only be increased
*/
@@ -2513,12 +2508,6 @@
return -ENOSYS;
}
-int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
int proc_dointvec_minmax(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index c3206fa..006365b 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -37,10 +37,6 @@
{ KERN_NODENAME, "hostname" },
{ KERN_DOMAINNAME, "domainname" },
-#ifdef CONFIG_SECURITY_CAPABILITIES
- { KERN_CAP_BSET, "cap-bound" },
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
-
{ KERN_PANIC, "panic" },
{ KERN_REALROOTDEV, "real-root-dev" },
@@ -1498,9 +1494,6 @@
(table->strategy == sysctl_ms_jiffies) ||
(table->proc_handler == proc_dostring) ||
(table->proc_handler == proc_dointvec) ||
-#ifdef CONFIG_SECURITY_CAPABILITIES
- (table->proc_handler == proc_dointvec_bset) ||
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
(table->proc_handler == proc_dointvec_minmax) ||
(table->proc_handler == proc_dointvec_jiffies) ||
(table->proc_handler == proc_dointvec_userhz_jiffies) ||
diff --git a/kernel/test_kprobes.c b/kernel/test_kprobes.c
index 88cdb10..06b6395 100644
--- a/kernel/test_kprobes.c
+++ b/kernel/test_kprobes.c
@@ -135,6 +135,12 @@
#ifdef CONFIG_KRETPROBES
static u32 krph_val;
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+ krph_val = (rand1 / div_factor);
+ return 0;
+}
+
static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
unsigned long ret = regs_return_value(regs);
@@ -144,13 +150,19 @@
printk(KERN_ERR "Kprobe smoke test failed: "
"incorrect value in kretprobe handler\n");
}
+ if (krph_val == 0) {
+ handler_errors++;
+ printk(KERN_ERR "Kprobe smoke test failed: "
+ "call to kretprobe entry handler failed\n");
+ }
- krph_val = (rand1 / div_factor);
+ krph_val = rand1;
return 0;
}
static struct kretprobe rp = {
.handler = return_handler,
+ .entry_handler = entry_handler,
.kp.symbol_name = "kprobe_target"
};
@@ -167,7 +179,7 @@
ret = kprobe_target(rand1);
unregister_kretprobe(&rp);
- if (krph_val == 0) {
+ if (krph_val != rand1) {
printk(KERN_ERR "Kprobe smoke test failed: "
"kretprobe handler not called\n");
handler_errors++;
diff --git a/kernel/time.c b/kernel/time.c
index 4064c05..33af3e5 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -566,7 +566,11 @@
clock_t jiffies_to_clock_t(long x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+# if HZ < USER_HZ
+ return x * (USER_HZ / HZ);
+# else
return x / (HZ / USER_HZ);
+# endif
#else
u64 tmp = (u64)x * TICK_NSEC;
do_div(tmp, (NSEC_PER_SEC / USER_HZ));
@@ -599,7 +603,14 @@
u64 jiffies_64_to_clock_t(u64 x)
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+# if HZ < USER_HZ
+ x *= USER_HZ;
+ do_div(x, HZ);
+# elif HZ > USER_HZ
do_div(x, HZ / USER_HZ);
+# else
+ /* Nothing to do */
+# endif
#else
/*
* There are better ways that don't overflow early,
@@ -611,7 +622,6 @@
#endif
return x;
}
-
EXPORT_SYMBOL(jiffies_64_to_clock_t);
u64 nsec_to_clock_t(u64 x)
@@ -646,7 +656,6 @@
} while (read_seqretry(&xtime_lock, seq));
return ret;
}
-
EXPORT_SYMBOL(get_jiffies_64);
#endif
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 6e9259a..81afb39 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -363,15 +363,13 @@
static ssize_t
sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
{
- char *curr = buf;
+ ssize_t count = 0;
spin_lock_irq(&clocksource_lock);
- curr += sprintf(curr, "%s ", curr_clocksource->name);
+ count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name);
spin_unlock_irq(&clocksource_lock);
- curr += sprintf(curr, "\n");
-
- return curr - buf;
+ return count;
}
/**
@@ -439,17 +437,20 @@
sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
{
struct clocksource *src;
- char *curr = buf;
+ ssize_t count = 0;
spin_lock_irq(&clocksource_lock);
list_for_each_entry(src, &clocksource_list, list) {
- curr += sprintf(curr, "%s ", src->name);
+ count += snprintf(buf + count,
+ max((ssize_t)PAGE_SIZE - count, (ssize_t)0),
+ "%s ", src->name);
}
spin_unlock_irq(&clocksource_lock);
- curr += sprintf(curr, "\n");
+ count += snprintf(buf + count,
+ max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n");
- return curr - buf;
+ return count;
}
/*
diff --git a/kernel/timer.c b/kernel/timer.c
index 9fbb472..70b29b5 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -818,12 +818,14 @@
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
void account_process_tick(struct task_struct *p, int user_tick)
{
+ cputime_t one_jiffy = jiffies_to_cputime(1);
+
if (user_tick) {
- account_user_time(p, jiffies_to_cputime(1));
- account_user_time_scaled(p, jiffies_to_cputime(1));
+ account_user_time(p, one_jiffy);
+ account_user_time_scaled(p, cputime_to_scaled(one_jiffy));
} else {
- account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
- account_system_time_scaled(p, jiffies_to_cputime(1));
+ account_system_time(p, HARDIRQ_OFFSET, one_jiffy);
+ account_system_time_scaled(p, cputime_to_scaled(one_jiffy));
}
}
#endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0d8a5a4..0d385be 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -81,7 +81,7 @@
config DEBUG_SECTION_MISMATCH
bool "Enable full Section mismatch analysis"
- default n
+ depends on UNDEFINED
help
The section mismatch analysis checks if there are illegal
references from one section to another section.
@@ -90,19 +90,19 @@
most likely result in an oops.
In the code functions and variables are annotated with
__init, __devinit etc. (see full list in include/linux/init.h)
- which result in the code/data being placed in specific sections.
- The section mismatch anaylsis are always done after a full
- kernel build but enabling this options will in addition
+ which results in the code/data being placed in specific sections.
+ The section mismatch analysis is always done after a full
+ kernel build but enabling this option will in addition
do the following:
- Add the option -fno-inline-functions-called-once to gcc
When inlining a function annotated __init in a non-init
- function we would loose the section information and thus
+ function we would lose the section information and thus
the analysis would not catch the illegal reference.
- This options tell gcc to inline less but will also
+ This option tells gcc to inline less but will also
result in a larger kernel.
- Run the section mismatch analysis for each module/built-in.o
When we run the section mismatch analysis on vmlinux.o we
- looses valueable information about where the mismatch was
+ lose valueble information about where the mismatch was
introduced.
Running the analysis for each module/built-in.o file
will tell where the mismatch happens much closer to the
diff --git a/lib/Makefile b/lib/Makefile
index 543f2502..a18062e4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -65,6 +65,7 @@
obj-$(CONFIG_AUDIT_GENERIC) += audit.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
+obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
lib-$(CONFIG_GENERIC_BUG) += bug.o
diff --git a/lib/crc32.c b/lib/crc32.c
index d2c2f25..49d1c9e 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -348,7 +348,7 @@
* but again the multiple of the polynomial to subtract depends only on
* the high bits, the high 8 bits in this case.
*
- * The multile we need in that case is the low 32 bits of a 40-bit
+ * The multiple we need in that case is the low 32 bits of a 40-bit
* value whose high 8 bits are given, and which is a multiple of the
* generator polynomial. This is simply the CRC-32 of the given
* one-byte message.
diff --git a/lib/extable.c b/lib/extable.c
index 463f456..179c087 100644
--- a/lib/extable.c
+++ b/lib/extable.c
@@ -57,10 +57,10 @@
while (first <= last) {
const struct exception_table_entry *mid;
- mid = (last - first) / 2 + first;
+ mid = ((last - first) >> 1) + first;
/*
- * careful, the distance between entries can be
- * larger than 2GB:
+ * careful, the distance between value and insn
+ * can be larger than MAX_LONG:
*/
if (mid->insn < value)
first = mid + 1;
diff --git a/lib/iommu-helper.c b/lib/iommu-helper.c
new file mode 100644
index 0000000..495575a
--- /dev/null
+++ b/lib/iommu-helper.c
@@ -0,0 +1,80 @@
+/*
+ * IOMMU helper functions for the free area management
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+
+static unsigned long find_next_zero_area(unsigned long *map,
+ unsigned long size,
+ unsigned long start,
+ unsigned int nr,
+ unsigned long align_mask)
+{
+ unsigned long index, end, i;
+again:
+ index = find_next_zero_bit(map, size, start);
+
+ /* Align allocation */
+ index = (index + align_mask) & ~align_mask;
+
+ end = index + nr;
+ if (end >= size)
+ return -1;
+ for (i = index; i < end; i++) {
+ if (test_bit(i, map)) {
+ start = i+1;
+ goto again;
+ }
+ }
+ return index;
+}
+
+static inline void set_bit_area(unsigned long *map, unsigned long i,
+ int len)
+{
+ unsigned long end = i + len;
+ while (i < end) {
+ __set_bit(i, map);
+ i++;
+ }
+}
+
+static inline int is_span_boundary(unsigned int index, unsigned int nr,
+ unsigned long shift,
+ unsigned long boundary_size)
+{
+ shift = (shift + index) & (boundary_size - 1);
+ return shift + nr > boundary_size;
+}
+
+unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
+ unsigned long start, unsigned int nr,
+ unsigned long shift, unsigned long boundary_size,
+ unsigned long align_mask)
+{
+ unsigned long index;
+again:
+ index = find_next_zero_area(map, size, start, nr, align_mask);
+ if (index != -1) {
+ if (is_span_boundary(index, nr, shift, boundary_size)) {
+ /* we could do more effectively */
+ start = index + 1;
+ goto again;
+ }
+ set_bit_area(map, index, nr);
+ }
+ return index;
+}
+EXPORT_SYMBOL(iommu_area_alloc);
+
+void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
+{
+ unsigned long end = start + nr;
+
+ while (start < end) {
+ __clear_bit(start, map);
+ start++;
+ }
+}
+EXPORT_SYMBOL(iommu_area_free);
diff --git a/lib/kobject.c b/lib/kobject.c
index 1d63ead..d784dae 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -637,7 +637,7 @@
* @name: the name for the kset
* @parent: the parent kobject of this kobject, if any.
*
- * This function creates a kset structure dynamically and registers it
+ * This function creates a kobject structure dynamically and registers it
* with sysfs. When you are finished with this structure, call
* kobject_put() and the structure will be dynamically freed when
* it is no longer being used.
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 48c250f..65f0e75 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -95,14 +95,17 @@
static struct radix_tree_node *
radix_tree_node_alloc(struct radix_tree_root *root)
{
- struct radix_tree_node *ret;
+ struct radix_tree_node *ret = NULL;
gfp_t gfp_mask = root_gfp_mask(root);
- ret = kmem_cache_alloc(radix_tree_node_cachep,
- set_migrateflags(gfp_mask, __GFP_RECLAIMABLE));
- if (ret == NULL && !(gfp_mask & __GFP_WAIT)) {
+ if (!(gfp_mask & __GFP_WAIT)) {
struct radix_tree_preload *rtp;
+ /*
+ * Provided the caller has preloaded here, we will always
+ * succeed in getting a node here (and never reach
+ * kmem_cache_alloc)
+ */
rtp = &__get_cpu_var(radix_tree_preloads);
if (rtp->nr) {
ret = rtp->nodes[rtp->nr - 1];
@@ -110,6 +113,10 @@
rtp->nr--;
}
}
+ if (ret == NULL)
+ ret = kmem_cache_alloc(radix_tree_node_cachep,
+ set_migrateflags(gfp_mask, __GFP_RECLAIMABLE));
+
BUG_ON(radix_tree_is_indirect_ptr(ret));
return ret;
}
diff --git a/lib/smp_processor_id.c b/lib/smp_processor_id.c
index eddc9b3..6c90fb9 100644
--- a/lib/smp_processor_id.c
+++ b/lib/smp_processor_id.c
@@ -42,7 +42,9 @@
if (!printk_ratelimit())
goto out_enable;
- printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid);
+ printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] "
+ "code: %s/%d\n",
+ preempt_count() - 1, current->comm, current->pid);
print_symbol("caller is %s\n", (long)__builtin_return_address(0));
dump_stack();
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 1a8050a..4bb5a11 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -282,6 +282,15 @@
return (addr & ~mask) != 0;
}
+static inline unsigned int is_span_boundary(unsigned int index,
+ unsigned int nslots,
+ unsigned long offset_slots,
+ unsigned long max_slots)
+{
+ unsigned long offset = (offset_slots + index) & (max_slots - 1);
+ return offset + nslots > max_slots;
+}
+
/*
* Allocates bounce buffer and returns its kernel virtual address.
*/
@@ -292,6 +301,16 @@
char *dma_addr;
unsigned int nslots, stride, index, wrap;
int i;
+ unsigned long start_dma_addr;
+ unsigned long mask;
+ unsigned long offset_slots;
+ unsigned long max_slots;
+
+ mask = dma_get_seg_boundary(hwdev);
+ start_dma_addr = virt_to_bus(io_tlb_start) & mask;
+
+ offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+ max_slots = ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
/*
* For mappings greater than a page, we limit the stride (and
@@ -311,10 +330,17 @@
*/
spin_lock_irqsave(&io_tlb_lock, flags);
{
- wrap = index = ALIGN(io_tlb_index, stride);
-
+ index = ALIGN(io_tlb_index, stride);
if (index >= io_tlb_nslabs)
- wrap = index = 0;
+ index = 0;
+
+ while (is_span_boundary(index, nslots, offset_slots,
+ max_slots)) {
+ index += stride;
+ if (index >= io_tlb_nslabs)
+ index = 0;
+ }
+ wrap = index;
do {
/*
@@ -341,9 +367,12 @@
goto found;
}
- index += stride;
- if (index >= io_tlb_nslabs)
- index = 0;
+ do {
+ index += stride;
+ if (index >= io_tlb_nslabs)
+ index = 0;
+ } while (is_span_boundary(index, nslots, offset_slots,
+ max_slots));
} while (index != wrap);
spin_unlock_irqrestore(&io_tlb_lock, flags);
diff --git a/lib/zlib_deflate/defutil.h b/lib/zlib_deflate/defutil.h
index d9feaf6..6b15a90 100644
--- a/lib/zlib_deflate/defutil.h
+++ b/lib/zlib_deflate/defutil.h
@@ -164,7 +164,7 @@
int nice_match; /* Stop searching when current match exceeds this */
/* used by trees.c: */
- /* Didn't use ct_data typedef below to supress compiler warning */
+ /* Didn't use ct_data typedef below to suppress compiler warning */
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
diff --git a/mm/Makefile b/mm/Makefile
index 5c0b0ea..4af5dff 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -13,8 +13,10 @@
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
page_isolation.o $(mmu-y)
+obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o
obj-$(CONFIG_BOUNCE) += bounce.o
obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o
+obj-$(CONFIG_HAS_DMA) += dmapool.o
obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
index 00b0262..7e58322 100644
--- a/mm/allocpercpu.c
+++ b/mm/allocpercpu.c
@@ -98,7 +98,7 @@
*/
void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
{
- void *pdata = kzalloc(sizeof(struct percpu_data), gfp);
+ void *pdata = kzalloc(nr_cpu_ids * sizeof(void *), gfp);
void *__pdata = __percpu_disguise(pdata);
if (unlikely(!pdata))
diff --git a/mm/dmapool.c b/mm/dmapool.c
new file mode 100644
index 0000000..34aaac4
--- /dev/null
+++ b/mm/dmapool.c
@@ -0,0 +1,500 @@
+/*
+ * DMA Pool allocator
+ *
+ * Copyright 2001 David Brownell
+ * Copyright 2007 Intel Corporation
+ * Author: Matthew Wilcox <willy@linux.intel.com>
+ *
+ * This software may be redistributed and/or modified under the terms of
+ * the GNU General Public License ("GPL") version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This allocator returns small blocks of a given size which are DMA-able by
+ * the given device. It uses the dma_alloc_coherent page allocator to get
+ * new pages, then splits them up into blocks of the required size.
+ * Many older drivers still have their own code to do this.
+ *
+ * The current design of this allocator is fairly simple. The pool is
+ * represented by the 'struct dma_pool' which keeps a doubly-linked list of
+ * allocated pages. Each page in the page_list is split into blocks of at
+ * least 'size' bytes. Free blocks are tracked in an unsorted singly-linked
+ * list of free blocks within the page. Used blocks aren't tracked, but we
+ * keep a count of how many are currently allocated from each page.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poison.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+struct dma_pool { /* the pool */
+ struct list_head page_list;
+ spinlock_t lock;
+ size_t size;
+ struct device *dev;
+ size_t allocation;
+ size_t boundary;
+ char name[32];
+ wait_queue_head_t waitq;
+ struct list_head pools;
+};
+
+struct dma_page { /* cacheable header for 'allocation' bytes */
+ struct list_head page_list;
+ void *vaddr;
+ dma_addr_t dma;
+ unsigned int in_use;
+ unsigned int offset;
+};
+
+#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
+
+static DEFINE_MUTEX(pools_lock);
+
+static ssize_t
+show_pools(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ unsigned temp;
+ unsigned size;
+ char *next;
+ struct dma_page *page;
+ struct dma_pool *pool;
+
+ next = buf;
+ size = PAGE_SIZE;
+
+ temp = scnprintf(next, size, "poolinfo - 0.1\n");
+ size -= temp;
+ next += temp;
+
+ mutex_lock(&pools_lock);
+ list_for_each_entry(pool, &dev->dma_pools, pools) {
+ unsigned pages = 0;
+ unsigned blocks = 0;
+
+ list_for_each_entry(page, &pool->page_list, page_list) {
+ pages++;
+ blocks += page->in_use;
+ }
+
+ /* per-pool info, no real statistics yet */
+ temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
+ pool->name, blocks,
+ pages * (pool->allocation / pool->size),
+ pool->size, pages);
+ size -= temp;
+ next += temp;
+ }
+ mutex_unlock(&pools_lock);
+
+ return PAGE_SIZE - size;
+}
+
+static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
+
+/**
+ * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @boundary: returned blocks won't cross this power of two boundary
+ * Context: !in_interrupt()
+ *
+ * Returns a dma allocation pool with the requested characteristics, or
+ * null if one can't be created. Given one of these pools, dma_pool_alloc()
+ * may be used to allocate memory. Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives. The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If @boundary is nonzero, objects returned from dma_pool_alloc() won't
+ * cross that size boundary. This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct dma_pool *dma_pool_create(const char *name, struct device *dev,
+ size_t size, size_t align, size_t boundary)
+{
+ struct dma_pool *retval;
+ size_t allocation;
+
+ if (align == 0) {
+ align = 1;
+ } else if (align & (align - 1)) {
+ return NULL;
+ }
+
+ if (size == 0) {
+ return NULL;
+ } else if (size < 4) {
+ size = 4;
+ }
+
+ if ((size % align) != 0)
+ size = ALIGN(size, align);
+
+ allocation = max_t(size_t, size, PAGE_SIZE);
+
+ if (!boundary) {
+ boundary = allocation;
+ } else if ((boundary < size) || (boundary & (boundary - 1))) {
+ return NULL;
+ }
+
+ retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev));
+ if (!retval)
+ return retval;
+
+ strlcpy(retval->name, name, sizeof(retval->name));
+
+ retval->dev = dev;
+
+ INIT_LIST_HEAD(&retval->page_list);
+ spin_lock_init(&retval->lock);
+ retval->size = size;
+ retval->boundary = boundary;
+ retval->allocation = allocation;
+ init_waitqueue_head(&retval->waitq);
+
+ if (dev) {
+ int ret;
+
+ mutex_lock(&pools_lock);
+ if (list_empty(&dev->dma_pools))
+ ret = device_create_file(dev, &dev_attr_pools);
+ else
+ ret = 0;
+ /* note: not currently insisting "name" be unique */
+ if (!ret)
+ list_add(&retval->pools, &dev->dma_pools);
+ else {
+ kfree(retval);
+ retval = NULL;
+ }
+ mutex_unlock(&pools_lock);
+ } else
+ INIT_LIST_HEAD(&retval->pools);
+
+ return retval;
+}
+EXPORT_SYMBOL(dma_pool_create);
+
+static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page)
+{
+ unsigned int offset = 0;
+ unsigned int next_boundary = pool->boundary;
+
+ do {
+ unsigned int next = offset + pool->size;
+ if (unlikely((next + pool->size) >= next_boundary)) {
+ next = next_boundary;
+ next_boundary += pool->boundary;
+ }
+ *(int *)(page->vaddr + offset) = next;
+ offset = next;
+ } while (offset < pool->allocation);
+}
+
+static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)
+{
+ struct dma_page *page;
+
+ page = kmalloc(sizeof(*page), mem_flags);
+ if (!page)
+ return NULL;
+ page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation,
+ &page->dma, mem_flags);
+ if (page->vaddr) {
+#ifdef CONFIG_DEBUG_SLAB
+ memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
+#endif
+ pool_initialise_page(pool, page);
+ list_add(&page->page_list, &pool->page_list);
+ page->in_use = 0;
+ page->offset = 0;
+ } else {
+ kfree(page);
+ page = NULL;
+ }
+ return page;
+}
+
+static inline int is_page_busy(struct dma_page *page)
+{
+ return page->in_use != 0;
+}
+
+static void pool_free_page(struct dma_pool *pool, struct dma_page *page)
+{
+ dma_addr_t dma = page->dma;
+
+#ifdef CONFIG_DEBUG_SLAB
+ memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
+#endif
+ dma_free_coherent(pool->dev, pool->allocation, page->vaddr, dma);
+ list_del(&page->page_list);
+ kfree(page);
+}
+
+/**
+ * dma_pool_destroy - destroys a pool of dma memory blocks.
+ * @pool: dma pool that will be destroyed
+ * Context: !in_interrupt()
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void dma_pool_destroy(struct dma_pool *pool)
+{
+ mutex_lock(&pools_lock);
+ list_del(&pool->pools);
+ if (pool->dev && list_empty(&pool->dev->dma_pools))
+ device_remove_file(pool->dev, &dev_attr_pools);
+ mutex_unlock(&pools_lock);
+
+ while (!list_empty(&pool->page_list)) {
+ struct dma_page *page;
+ page = list_entry(pool->page_list.next,
+ struct dma_page, page_list);
+ if (is_page_busy(page)) {
+ if (pool->dev)
+ dev_err(pool->dev,
+ "dma_pool_destroy %s, %p busy\n",
+ pool->name, page->vaddr);
+ else
+ printk(KERN_ERR
+ "dma_pool_destroy %s, %p busy\n",
+ pool->name, page->vaddr);
+ /* leak the still-in-use consistent memory */
+ list_del(&page->page_list);
+ kfree(page);
+ } else
+ pool_free_page(pool, page);
+ }
+
+ kfree(pool);
+}
+EXPORT_SYMBOL(dma_pool_destroy);
+
+/**
+ * dma_pool_alloc - get a block of consistent memory
+ * @pool: dma pool that will produce the block
+ * @mem_flags: GFP_* bitmask
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, %NULL is returned.
+ */
+void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
+ dma_addr_t *handle)
+{
+ unsigned long flags;
+ struct dma_page *page;
+ size_t offset;
+ void *retval;
+
+ spin_lock_irqsave(&pool->lock, flags);
+ restart:
+ list_for_each_entry(page, &pool->page_list, page_list) {
+ if (page->offset < pool->allocation)
+ goto ready;
+ }
+ page = pool_alloc_page(pool, GFP_ATOMIC);
+ if (!page) {
+ if (mem_flags & __GFP_WAIT) {
+ DECLARE_WAITQUEUE(wait, current);
+
+ __set_current_state(TASK_INTERRUPTIBLE);
+ __add_wait_queue(&pool->waitq, &wait);
+ spin_unlock_irqrestore(&pool->lock, flags);
+
+ schedule_timeout(POOL_TIMEOUT_JIFFIES);
+
+ spin_lock_irqsave(&pool->lock, flags);
+ __remove_wait_queue(&pool->waitq, &wait);
+ goto restart;
+ }
+ retval = NULL;
+ goto done;
+ }
+
+ ready:
+ page->in_use++;
+ offset = page->offset;
+ page->offset = *(int *)(page->vaddr + offset);
+ retval = offset + page->vaddr;
+ *handle = offset + page->dma;
+#ifdef CONFIG_DEBUG_SLAB
+ memset(retval, POOL_POISON_ALLOCATED, pool->size);
+#endif
+ done:
+ spin_unlock_irqrestore(&pool->lock, flags);
+ return retval;
+}
+EXPORT_SYMBOL(dma_pool_alloc);
+
+static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)
+{
+ unsigned long flags;
+ struct dma_page *page;
+
+ spin_lock_irqsave(&pool->lock, flags);
+ list_for_each_entry(page, &pool->page_list, page_list) {
+ if (dma < page->dma)
+ continue;
+ if (dma < (page->dma + pool->allocation))
+ goto done;
+ }
+ page = NULL;
+ done:
+ spin_unlock_irqrestore(&pool->lock, flags);
+ return page;
+}
+
+/**
+ * dma_pool_free - put block back into dma pool
+ * @pool: the dma pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
+{
+ struct dma_page *page;
+ unsigned long flags;
+ unsigned int offset;
+
+ page = pool_find_page(pool, dma);
+ if (!page) {
+ if (pool->dev)
+ dev_err(pool->dev,
+ "dma_pool_free %s, %p/%lx (bad dma)\n",
+ pool->name, vaddr, (unsigned long)dma);
+ else
+ printk(KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n",
+ pool->name, vaddr, (unsigned long)dma);
+ return;
+ }
+
+ offset = vaddr - page->vaddr;
+#ifdef CONFIG_DEBUG_SLAB
+ if ((dma - page->dma) != offset) {
+ if (pool->dev)
+ dev_err(pool->dev,
+ "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
+ pool->name, vaddr, (unsigned long long)dma);
+ else
+ printk(KERN_ERR
+ "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
+ pool->name, vaddr, (unsigned long long)dma);
+ return;
+ }
+ {
+ unsigned int chain = page->offset;
+ while (chain < pool->allocation) {
+ if (chain != offset) {
+ chain = *(int *)(page->vaddr + chain);
+ continue;
+ }
+ if (pool->dev)
+ dev_err(pool->dev, "dma_pool_free %s, dma %Lx "
+ "already free\n", pool->name,
+ (unsigned long long)dma);
+ else
+ printk(KERN_ERR "dma_pool_free %s, dma %Lx "
+ "already free\n", pool->name,
+ (unsigned long long)dma);
+ return;
+ }
+ }
+ memset(vaddr, POOL_POISON_FREED, pool->size);
+#endif
+
+ spin_lock_irqsave(&pool->lock, flags);
+ page->in_use--;
+ *(int *)vaddr = page->offset;
+ page->offset = offset;
+ if (waitqueue_active(&pool->waitq))
+ wake_up_locked(&pool->waitq);
+ /*
+ * Resist a temptation to do
+ * if (!is_page_busy(page)) pool_free_page(pool, page);
+ * Better have a few empty pages hang around.
+ */
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+EXPORT_SYMBOL(dma_pool_free);
+
+/*
+ * Managed DMA pool
+ */
+static void dmam_pool_release(struct device *dev, void *res)
+{
+ struct dma_pool *pool = *(struct dma_pool **)res;
+
+ dma_pool_destroy(pool);
+}
+
+static int dmam_pool_match(struct device *dev, void *res, void *match_data)
+{
+ return *(struct dma_pool **)res == match_data;
+}
+
+/**
+ * dmam_pool_create - Managed dma_pool_create()
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ *
+ * Managed dma_pool_create(). DMA pool created with this function is
+ * automatically destroyed on driver detach.
+ */
+struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
+ size_t size, size_t align, size_t allocation)
+{
+ struct dma_pool **ptr, *pool;
+
+ ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
+ if (pool)
+ devres_add(dev, ptr);
+ else
+ devres_free(ptr);
+
+ return pool;
+}
+EXPORT_SYMBOL(dmam_pool_create);
+
+/**
+ * dmam_pool_destroy - Managed dma_pool_destroy()
+ * @pool: dma pool that will be destroyed
+ *
+ * Managed dma_pool_destroy().
+ */
+void dmam_pool_destroy(struct dma_pool *pool)
+{
+ struct device *dev = pool->dev;
+
+ dma_pool_destroy(pool);
+ WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
+}
+EXPORT_SYMBOL(dmam_pool_destroy);
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 0df4c89..3c0f1e9 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -49,9 +49,21 @@
goto out;
}
- if (mapping->a_ops->get_xip_page)
- /* no bad return value, but ignore advice */
+ if (mapping->a_ops->get_xip_page) {
+ switch (advice) {
+ case POSIX_FADV_NORMAL:
+ case POSIX_FADV_RANDOM:
+ case POSIX_FADV_SEQUENTIAL:
+ case POSIX_FADV_WILLNEED:
+ case POSIX_FADV_NOREUSE:
+ case POSIX_FADV_DONTNEED:
+ /* no bad return value, but ignore advice */
+ break;
+ default:
+ ret = -EINVAL;
+ }
goto out;
+ }
/* Careful about overflows. Len == 0 means "as much as possible" */
endbyte = offset + len;
diff --git a/mm/filemap.c b/mm/filemap.c
index 89ce6fe..81fb9bf 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -65,7 +65,6 @@
* ->private_lock (__free_pte->__set_page_dirty_buffers)
* ->swap_lock (exclusive_swap_page, others)
* ->mapping->tree_lock
- * ->zone.lock
*
* ->i_mutex
* ->i_mmap_lock (truncate->unmap_mapping_range)
@@ -528,7 +527,7 @@
__wake_up_bit(page_waitqueue(page), &page->flags, bit);
}
-void fastcall wait_on_page_bit(struct page *page, int bit_nr)
+void wait_on_page_bit(struct page *page, int bit_nr)
{
DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
@@ -552,7 +551,7 @@
* the clear_bit and the read of the waitqueue (to avoid SMP races with a
* parallel wait_on_page_locked()).
*/
-void fastcall unlock_page(struct page *page)
+void unlock_page(struct page *page)
{
smp_mb__before_clear_bit();
if (!TestClearPageLocked(page))
@@ -586,7 +585,7 @@
* chances are that on the second loop, the block layer's plug list is empty,
* so sync_page() will then return in state TASK_UNINTERRUPTIBLE.
*/
-void fastcall __lock_page(struct page *page)
+void __lock_page(struct page *page)
{
DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
@@ -607,7 +606,7 @@
* Variant of lock_page that does not require the caller to hold a reference
* on the page's mapping.
*/
-void fastcall __lock_page_nosync(struct page *page)
+void __lock_page_nosync(struct page *page)
{
DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
__wait_on_bit_lock(page_waitqueue(page), &wait, __sleep_on_page_lock,
@@ -1277,7 +1276,7 @@
* This adds the requested page to the page cache if it isn't already there,
* and schedules an I/O to read in its contents from disk.
*/
-static int fastcall page_cache_read(struct file * file, pgoff_t offset)
+static int page_cache_read(struct file *file, pgoff_t offset)
{
struct address_space *mapping = file->f_mapping;
struct page *page;
@@ -1750,7 +1749,11 @@
const struct iovec *iov = i->iov;
size_t base = i->iov_offset;
- while (bytes) {
+ /*
+ * The !iov->iov_len check ensures we skip over unlikely
+ * zero-length segments.
+ */
+ while (bytes || !iov->iov_len) {
int copy = min(bytes, iov->iov_len - base);
bytes -= copy;
@@ -2268,6 +2271,7 @@
cond_resched();
+ iov_iter_advance(i, copied);
if (unlikely(copied == 0)) {
/*
* If we were unable to copy any data at all, we must
@@ -2281,7 +2285,6 @@
iov_iter_single_seg_count(i));
goto again;
}
- iov_iter_advance(i, copied);
pos += copied;
written += copied;
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index f874ae8..0420a02 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -431,7 +431,7 @@
else
return PTR_ERR(page);
}
- zero_user_page(page, offset, length, KM_USER0);
+ zero_user(page, offset, length);
return 0;
}
EXPORT_SYMBOL_GPL(xip_truncate_page);
diff --git a/mm/fremap.c b/mm/fremap.c
index 14bd3bf..69a37c2 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -190,10 +190,13 @@
*/
if (mapping_cap_account_dirty(mapping)) {
unsigned long addr;
+ struct file *file = vma->vm_file;
flags &= MAP_NONBLOCK;
- addr = mmap_region(vma->vm_file, start, size,
+ get_file(file);
+ addr = mmap_region(file, start, size,
flags, vma->vm_flags, pgoff, 1);
+ fput(file);
if (IS_ERR_VALUE(addr)) {
err = addr;
} else {
diff --git a/mm/highmem.c b/mm/highmem.c
index 7a967bc..35d4773 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -163,7 +163,7 @@
return vaddr;
}
-void fastcall *kmap_high(struct page *page)
+void *kmap_high(struct page *page)
{
unsigned long vaddr;
@@ -185,7 +185,7 @@
EXPORT_SYMBOL(kmap_high);
-void fastcall kunmap_high(struct page *page)
+void kunmap_high(struct page *page)
{
unsigned long vaddr;
unsigned long nr;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index db861d8..1a56420 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -813,6 +813,7 @@
spin_unlock(&mm->page_table_lock);
copy_huge_page(new_page, old_page, address, vma);
+ __SetPageUptodate(new_page);
spin_lock(&mm->page_table_lock);
ptep = huge_pte_offset(mm, address & HPAGE_MASK);
@@ -858,6 +859,7 @@
goto out;
}
clear_huge_page(page, address);
+ __SetPageUptodate(page);
if (vma->vm_flags & VM_SHARED) {
int err;
diff --git a/mm/internal.h b/mm/internal.h
index 953f941..5a9a620 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -24,7 +24,7 @@
*/
static inline void set_page_refcounted(struct page *page)
{
- VM_BUG_ON(PageCompound(page) && PageTail(page));
+ VM_BUG_ON(PageTail(page));
VM_BUG_ON(atomic_read(&page->_count));
set_page_count(page, 1);
}
@@ -34,7 +34,7 @@
atomic_dec(&page->_count);
}
-extern void fastcall __init __free_pages_bootmem(struct page *page,
+extern void __init __free_pages_bootmem(struct page *page,
unsigned int order);
/*
diff --git a/mm/memory.c b/mm/memory.c
index d902d0e..9d073fa 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -82,7 +82,18 @@
EXPORT_SYMBOL(num_physpages);
EXPORT_SYMBOL(high_memory);
-int randomize_va_space __read_mostly = 1;
+/*
+ * Randomize the address space (stacks, mmaps, brk, etc.).
+ *
+ * ( When CONFIG_COMPAT_BRK=y we exclude brk from randomization,
+ * as ancient (libc5 based) binaries can segfault. )
+ */
+int randomize_va_space __read_mostly =
+#ifdef CONFIG_COMPAT_BRK
+ 1;
+#else
+ 2;
+#endif
static int __init disable_randmaps(char *s)
{
@@ -305,7 +316,7 @@
spin_lock(&mm->page_table_lock);
if (pmd_present(*pmd)) { /* Another has populated it */
pte_lock_deinit(new);
- pte_free(new);
+ pte_free(mm, new);
} else {
mm->nr_ptes++;
inc_zone_page_state(new, NR_PAGETABLE);
@@ -323,7 +334,7 @@
spin_lock(&init_mm.page_table_lock);
if (pmd_present(*pmd)) /* Another has populated it */
- pte_free_kernel(new);
+ pte_free_kernel(&init_mm, new);
else
pmd_populate_kernel(&init_mm, pmd, new);
spin_unlock(&init_mm.page_table_lock);
@@ -1109,7 +1120,8 @@
}
EXPORT_SYMBOL(get_user_pages);
-pte_t * fastcall get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl)
+pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
+ spinlock_t **ptl)
{
pgd_t * pgd = pgd_offset(mm, addr);
pud_t * pud = pud_alloc(mm, pgd, addr);
@@ -1517,10 +1529,8 @@
memset(kaddr, 0, PAGE_SIZE);
kunmap_atomic(kaddr, KM_USER0);
flush_dcache_page(dst);
- return;
-
- }
- copy_user_highpage(dst, src, va, vma);
+ } else
+ copy_user_highpage(dst, src, va, vma);
}
/*
@@ -1629,6 +1639,7 @@
if (!new_page)
goto oom;
cow_user_page(new_page, old_page, address, vma);
+ __SetPageUptodate(new_page);
/*
* Re-check the pte - we dropped the lock
@@ -1909,50 +1920,49 @@
*/
int vmtruncate(struct inode * inode, loff_t offset)
{
- struct address_space *mapping = inode->i_mapping;
- unsigned long limit;
+ if (inode->i_size < offset) {
+ unsigned long limit;
- if (inode->i_size < offset)
- goto do_expand;
- /*
- * truncation of in-use swapfiles is disallowed - it would cause
- * subsequent swapout to scribble on the now-freed blocks.
- */
- if (IS_SWAPFILE(inode))
- goto out_busy;
- i_size_write(inode, offset);
+ limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit != RLIM_INFINITY && offset > limit)
+ goto out_sig;
+ if (offset > inode->i_sb->s_maxbytes)
+ goto out_big;
+ i_size_write(inode, offset);
+ } else {
+ struct address_space *mapping = inode->i_mapping;
- /*
- * unmap_mapping_range is called twice, first simply for efficiency
- * so that truncate_inode_pages does fewer single-page unmaps. However
- * after this first call, and before truncate_inode_pages finishes,
- * it is possible for private pages to be COWed, which remain after
- * truncate_inode_pages finishes, hence the second unmap_mapping_range
- * call must be made for correctness.
- */
- unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
- truncate_inode_pages(mapping, offset);
- unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
- goto out_truncate;
+ /*
+ * truncation of in-use swapfiles is disallowed - it would
+ * cause subsequent swapout to scribble on the now-freed
+ * blocks.
+ */
+ if (IS_SWAPFILE(inode))
+ return -ETXTBSY;
+ i_size_write(inode, offset);
-do_expand:
- limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
- if (limit != RLIM_INFINITY && offset > limit)
- goto out_sig;
- if (offset > inode->i_sb->s_maxbytes)
- goto out_big;
- i_size_write(inode, offset);
+ /*
+ * unmap_mapping_range is called twice, first simply for
+ * efficiency so that truncate_inode_pages does fewer
+ * single-page unmaps. However after this first call, and
+ * before truncate_inode_pages finishes, it is possible for
+ * private pages to be COWed, which remain after
+ * truncate_inode_pages finishes, hence the second
+ * unmap_mapping_range call must be made for correctness.
+ */
+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+ truncate_inode_pages(mapping, offset);
+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+ }
-out_truncate:
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
return 0;
+
out_sig:
send_sig(SIGXFSZ, current, 0);
out_big:
return -EFBIG;
-out_busy:
- return -ETXTBSY;
}
EXPORT_SYMBOL(vmtruncate);
@@ -1980,67 +1990,6 @@
return 0;
}
-/**
- * swapin_readahead - swap in pages in hope we need them soon
- * @entry: swap entry of this memory
- * @addr: address to start
- * @vma: user vma this addresses belong to
- *
- * Primitive swap readahead code. We simply read an aligned block of
- * (1 << page_cluster) entries in the swap area. This method is chosen
- * because it doesn't cost us any seek time. We also make sure to queue
- * the 'original' request together with the readahead ones...
- *
- * This has been extended to use the NUMA policies from the mm triggering
- * the readahead.
- *
- * Caller must hold down_read on the vma->vm_mm if vma is not NULL.
- */
-void swapin_readahead(swp_entry_t entry, unsigned long addr,struct vm_area_struct *vma)
-{
-#ifdef CONFIG_NUMA
- struct vm_area_struct *next_vma = vma ? vma->vm_next : NULL;
-#endif
- int i, num;
- struct page *new_page;
- unsigned long offset;
-
- /*
- * Get the number of handles we should do readahead io to.
- */
- num = valid_swaphandles(entry, &offset);
- for (i = 0; i < num; offset++, i++) {
- /* Ok, do the async read-ahead now */
- new_page = read_swap_cache_async(swp_entry(swp_type(entry),
- offset), vma, addr);
- if (!new_page)
- break;
- page_cache_release(new_page);
-#ifdef CONFIG_NUMA
- /*
- * Find the next applicable VMA for the NUMA policy.
- */
- addr += PAGE_SIZE;
- if (addr == 0)
- vma = NULL;
- if (vma) {
- if (addr >= vma->vm_end) {
- vma = next_vma;
- next_vma = vma ? vma->vm_next : NULL;
- }
- if (vma && addr < vma->vm_start)
- vma = NULL;
- } else {
- if (next_vma && addr >= next_vma->vm_start) {
- vma = next_vma;
- next_vma = vma->vm_next;
- }
- }
-#endif
- }
- lru_add_drain(); /* Push any new pages onto the LRU now */
-}
-
/*
* We enter with non-exclusive mmap_sem (to exclude vma changes,
* but allow concurrent faults), and pte mapped but not yet locked.
@@ -2068,8 +2017,8 @@
page = lookup_swap_cache(entry);
if (!page) {
grab_swap_token(); /* Contend for token _before_ read-in */
- swapin_readahead(entry, address, vma);
- page = read_swap_cache_async(entry, vma, address);
+ page = swapin_readahead(entry,
+ GFP_HIGHUSER_MOVABLE, vma, address);
if (!page) {
/*
* Back out if somebody else faulted in this pte
@@ -2163,6 +2112,7 @@
page = alloc_zeroed_user_highpage_movable(vma, address);
if (!page)
goto oom;
+ __SetPageUptodate(page);
entry = mk_pte(page, vma->vm_page_prot);
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
@@ -2263,6 +2213,7 @@
goto out;
}
copy_user_highpage(page, vmf.page, address, vma);
+ __SetPageUptodate(page);
} else {
/*
* If the page will be shareable, see if the backing
@@ -2563,7 +2514,7 @@
spin_lock(&mm->page_table_lock);
if (pgd_present(*pgd)) /* Another has populated it */
- pud_free(new);
+ pud_free(mm, new);
else
pgd_populate(mm, pgd, new);
spin_unlock(&mm->page_table_lock);
@@ -2585,12 +2536,12 @@
spin_lock(&mm->page_table_lock);
#ifndef __ARCH_HAS_4LEVEL_HACK
if (pud_present(*pud)) /* Another has populated it */
- pmd_free(new);
+ pmd_free(mm, new);
else
pud_populate(mm, pud, new);
#else
if (pgd_present(*pud)) /* Another has populated it */
- pmd_free(new);
+ pmd_free(mm, new);
else
pgd_populate(mm, pud, new);
#endif /* __ARCH_HAS_4LEVEL_HACK */
@@ -2618,46 +2569,6 @@
return ret == len ? 0 : -1;
}
-/*
- * Map a vmalloc()-space virtual address to the physical page.
- */
-struct page * vmalloc_to_page(void * vmalloc_addr)
-{
- unsigned long addr = (unsigned long) vmalloc_addr;
- struct page *page = NULL;
- pgd_t *pgd = pgd_offset_k(addr);
- pud_t *pud;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- if (!pgd_none(*pgd)) {
- pud = pud_offset(pgd, addr);
- if (!pud_none(*pud)) {
- pmd = pmd_offset(pud, addr);
- if (!pmd_none(*pmd)) {
- ptep = pte_offset_map(pmd, addr);
- pte = *ptep;
- if (pte_present(pte))
- page = pte_page(pte);
- pte_unmap(ptep);
- }
- }
- }
- return page;
-}
-
-EXPORT_SYMBOL(vmalloc_to_page);
-
-/*
- * Map a vmalloc()-space virtual address to the physical page frame number.
- */
-unsigned long vmalloc_to_pfn(void * vmalloc_addr)
-{
- return page_to_pfn(vmalloc_to_page(vmalloc_addr));
-}
-
-EXPORT_SYMBOL(vmalloc_to_pfn);
-
#if !defined(__HAVE_ARCH_GATE_AREA)
#if defined(AT_SYSINFO_EHDR)
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 9512a54..7469c50 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -481,8 +481,6 @@
return offlined;
}
-extern void drain_all_local_pages(void);
-
int offline_pages(unsigned long start_pfn,
unsigned long end_pfn, unsigned long timeout)
{
@@ -540,7 +538,7 @@
lru_add_drain_all();
flush_scheduled_work();
cond_resched();
- drain_all_local_pages();
+ drain_all_pages();
}
pfn = scan_lru_pages(start_pfn, end_pfn);
@@ -563,7 +561,7 @@
flush_scheduled_work();
yield();
/* drain pcp pages , this is synchrouns. */
- drain_all_local_pages();
+ drain_all_pages();
/* check again */
offlined_pages = check_pages_isolated(start_pfn, end_pfn);
if (offlined_pages < 0) {
diff --git a/mm/migrate.c b/mm/migrate.c
index 6a207e8..857a987 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -115,11 +115,6 @@
return count;
}
-static inline int is_swap_pte(pte_t pte)
-{
- return !pte_none(pte) && !pte_present(pte) && !pte_file(pte);
-}
-
/*
* Restore a potential migration pte to a working pte entry
*/
@@ -645,15 +640,33 @@
rcu_read_lock();
rcu_locked = 1;
}
+
/*
- * This is a corner case handling.
- * When a new swap-cache is read into, it is linked to LRU
- * and treated as swapcache but has no rmap yet.
- * Calling try_to_unmap() against a page->mapping==NULL page is
- * BUG. So handle it here.
+ * Corner case handling:
+ * 1. When a new swap-cache page is read into, it is added to the LRU
+ * and treated as swapcache but it has no rmap yet.
+ * Calling try_to_unmap() against a page->mapping==NULL page will
+ * trigger a BUG. So handle it here.
+ * 2. An orphaned page (see truncate_complete_page) might have
+ * fs-private metadata. The page can be picked up due to memory
+ * offlining. Everywhere else except page reclaim, the page is
+ * invisible to the vm, so the page can not be migrated. So try to
+ * free the metadata, so the page can be freed.
*/
- if (!page->mapping)
+ if (!page->mapping) {
+ if (!PageAnon(page) && PagePrivate(page)) {
+ /*
+ * Go direct to try_to_free_buffers() here because
+ * a) that's what try_to_release_page() would do anyway
+ * b) we may be under rcu_read_lock() here, so we can't
+ * use GFP_KERNEL which is what try_to_release_page()
+ * needs to be effective.
+ */
+ try_to_free_buffers(page);
+ }
goto rcu_unlock;
+ }
+
/* Establish migration ptes or remove ptes */
try_to_unmap(page, 1);
diff --git a/mm/mmap.c b/mm/mmap.c
index d2b6d44..ad6e4ea 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -36,6 +36,10 @@
#define arch_mmap_check(addr, len, flags) (0)
#endif
+#ifndef arch_rebalance_pgtables
+#define arch_rebalance_pgtables(addr, len) (addr)
+#endif
+
static void unmap_region(struct mm_struct *mm,
struct vm_area_struct *vma, struct vm_area_struct *prev,
unsigned long start, unsigned long end);
@@ -241,7 +245,7 @@
down_write(&mm->mmap_sem);
- if (brk < mm->end_code)
+ if (brk < mm->start_brk)
goto out;
/*
@@ -1424,7 +1428,7 @@
if (addr & ~PAGE_MASK)
return -EINVAL;
- return addr;
+ return arch_rebalance_pgtables(addr, len);
}
EXPORT_SYMBOL(get_unmapped_area);
@@ -2216,7 +2220,7 @@
vma->vm_start = addr;
vma->vm_end = addr + len;
- vma->vm_flags = vm_flags | mm->def_flags;
+ vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
vma->vm_ops = &special_mapping_vmops;
diff --git a/mm/nommu.c b/mm/nommu.c
index b989cb9..5d8ae08 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -10,6 +10,7 @@
* Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com>
* Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org>
* Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (c) 2007 Paul Mundt <lethal@linux-sh.org>
*/
#include <linux/module.h>
@@ -167,7 +168,7 @@
DEFINE_RWLOCK(vmlist_lock);
struct vm_struct *vmlist;
-void vfree(void *addr)
+void vfree(const void *addr)
{
kfree(addr);
}
@@ -183,13 +184,33 @@
}
EXPORT_SYMBOL(__vmalloc);
-struct page * vmalloc_to_page(void *addr)
+void *vmalloc_user(unsigned long size)
+{
+ void *ret;
+
+ ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+ PAGE_KERNEL);
+ if (ret) {
+ struct vm_area_struct *vma;
+
+ down_write(¤t->mm->mmap_sem);
+ vma = find_vma(current->mm, (unsigned long)ret);
+ if (vma)
+ vma->vm_flags |= VM_USERMAP;
+ up_write(¤t->mm->mmap_sem);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(vmalloc_user);
+
+struct page *vmalloc_to_page(const void *addr)
{
return virt_to_page(addr);
}
EXPORT_SYMBOL(vmalloc_to_page);
-unsigned long vmalloc_to_pfn(void *addr)
+unsigned long vmalloc_to_pfn(const void *addr)
{
return page_to_pfn(virt_to_page(addr));
}
@@ -253,10 +274,17 @@
*
* The resulting memory area is 32bit addressable and zeroed so it can be
* mapped to userspace without leaking data.
+ *
+ * VM_USERMAP is set on the corresponding VMA so that subsequent calls to
+ * remap_vmalloc_range() are permissible.
*/
void *vmalloc_32_user(unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ /*
+ * We'll have to sort out the ZONE_DMA bits for 64-bit,
+ * but for now this can simply use vmalloc_user() directly.
+ */
+ return vmalloc_user(size);
}
EXPORT_SYMBOL(vmalloc_32_user);
@@ -267,7 +295,7 @@
}
EXPORT_SYMBOL(vmap);
-void vunmap(void *addr)
+void vunmap(const void *addr)
{
BUG();
}
@@ -1216,6 +1244,21 @@
}
EXPORT_SYMBOL(remap_pfn_range);
+int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
+ unsigned long pgoff)
+{
+ unsigned int size = vma->vm_end - vma->vm_start;
+
+ if (!(vma->vm_flags & VM_USERMAP))
+ return -EINVAL;
+
+ vma->vm_start = (unsigned long)(addr + (pgoff << PAGE_SHIFT));
+ vma->vm_end = vma->vm_start + size;
+
+ return 0;
+}
+EXPORT_SYMBOL(remap_vmalloc_range);
+
void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
{
}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 96473b4..c1850bf 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -125,8 +125,7 @@
* Superuser processes are usually more important, so we make it
* less likely that we kill those.
*/
- if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
- p->uid == 0 || p->euid == 0)
+ if (__capable(p, CAP_SYS_ADMIN) || __capable(p, CAP_SYS_RESOURCE))
points /= 4;
/*
@@ -135,7 +134,7 @@
* tend to only have this flag set on applications they think
* of as important.
*/
- if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
+ if (__capable(p, CAP_SYS_RAWIO))
points /= 4;
/*
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 3d3848f..5e00f17 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -69,6 +69,12 @@
int dirty_background_ratio = 5;
/*
+ * free highmem will not be subtracted from the total free memory
+ * for calculating free ratios if vm_highmem_is_dirtyable is true
+ */
+int vm_highmem_is_dirtyable;
+
+/*
* The generator of dirty data starts writeback at this percentage
*/
int vm_dirty_ratio = 10;
@@ -219,7 +225,7 @@
*
* dirty -= (dirty/8) * p_{t}
*/
-void task_dirty_limit(struct task_struct *tsk, long *pdirty)
+static void task_dirty_limit(struct task_struct *tsk, long *pdirty)
{
long numerator, denominator;
long dirty = *pdirty;
@@ -287,7 +293,10 @@
x = global_page_state(NR_FREE_PAGES)
+ global_page_state(NR_INACTIVE)
+ global_page_state(NR_ACTIVE);
- x -= highmem_dirtyable_memory(x);
+
+ if (!vm_highmem_is_dirtyable)
+ x -= highmem_dirtyable_memory(x);
+
return x + 1; /* Ensure that we never return 0 */
}
@@ -558,6 +567,7 @@
global_page_state(NR_UNSTABLE_NFS) < background_thresh
&& min_pages <= 0)
break;
+ wbc.more_io = 0;
wbc.encountered_congestion = 0;
wbc.nr_to_write = MAX_WRITEBACK_PAGES;
wbc.pages_skipped = 0;
@@ -565,8 +575,9 @@
min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
/* Wrote less than expected */
- congestion_wait(WRITE, HZ/10);
- if (!wbc.encountered_congestion)
+ if (wbc.encountered_congestion || wbc.more_io)
+ congestion_wait(WRITE, HZ/10);
+ else
break;
}
}
@@ -631,11 +642,12 @@
global_page_state(NR_UNSTABLE_NFS) +
(inodes_stat.nr_inodes - inodes_stat.nr_unused);
while (nr_to_write > 0) {
+ wbc.more_io = 0;
wbc.encountered_congestion = 0;
wbc.nr_to_write = MAX_WRITEBACK_PAGES;
writeback_inodes(&wbc);
if (wbc.nr_to_write > 0) {
- if (wbc.encountered_congestion)
+ if (wbc.encountered_congestion || wbc.more_io)
congestion_wait(WRITE, HZ/10);
else
break; /* All the old data is written */
@@ -1064,7 +1076,7 @@
return 0;
}
-int fastcall set_page_dirty(struct page *page)
+int set_page_dirty(struct page *page)
{
int ret = __set_page_dirty(page);
if (ret)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index b2838c2..37576b8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -537,7 +537,7 @@
/*
* permit the bootmem allocator to evade page validation on high-order frees
*/
-void fastcall __init __free_pages_bootmem(struct page *page, unsigned int order)
+void __init __free_pages_bootmem(struct page *page, unsigned int order)
{
if (order == 0) {
__ClearPageReserved(page);
@@ -890,31 +890,51 @@
}
#endif
-static void __drain_pages(unsigned int cpu)
+/*
+ * Drain pages of the indicated processor.
+ *
+ * The processor must either be the current processor and the
+ * thread pinned to the current processor or a processor that
+ * is not online.
+ */
+static void drain_pages(unsigned int cpu)
{
unsigned long flags;
struct zone *zone;
- int i;
for_each_zone(zone) {
struct per_cpu_pageset *pset;
+ struct per_cpu_pages *pcp;
if (!populated_zone(zone))
continue;
pset = zone_pcp(zone, cpu);
- for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
- struct per_cpu_pages *pcp;
- pcp = &pset->pcp[i];
- local_irq_save(flags);
- free_pages_bulk(zone, pcp->count, &pcp->list, 0);
- pcp->count = 0;
- local_irq_restore(flags);
- }
+ pcp = &pset->pcp;
+ local_irq_save(flags);
+ free_pages_bulk(zone, pcp->count, &pcp->list, 0);
+ pcp->count = 0;
+ local_irq_restore(flags);
}
}
+/*
+ * Spill all of this CPU's per-cpu pages back into the buddy allocator.
+ */
+void drain_local_pages(void *arg)
+{
+ drain_pages(smp_processor_id());
+}
+
+/*
+ * Spill all the per-cpu pages from all CPUs back into the buddy allocator
+ */
+void drain_all_pages(void)
+{
+ on_each_cpu(drain_local_pages, NULL, 0, 1);
+}
+
#ifdef CONFIG_HIBERNATION
void mark_free_pages(struct zone *zone)
@@ -952,40 +972,9 @@
#endif /* CONFIG_PM */
/*
- * Spill all of this CPU's per-cpu pages back into the buddy allocator.
- */
-void drain_local_pages(void)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- __drain_pages(smp_processor_id());
- local_irq_restore(flags);
-}
-
-void smp_drain_local_pages(void *arg)
-{
- drain_local_pages();
-}
-
-/*
- * Spill all the per-cpu pages from all CPUs back into the buddy allocator
- */
-void drain_all_local_pages(void)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- __drain_pages(smp_processor_id());
- local_irq_restore(flags);
-
- smp_call_function(smp_drain_local_pages, NULL, 0, 1);
-}
-
-/*
* Free a 0-order page
*/
-static void fastcall free_hot_cold_page(struct page *page, int cold)
+static void free_hot_cold_page(struct page *page, int cold)
{
struct zone *zone = page_zone(page);
struct per_cpu_pages *pcp;
@@ -1001,10 +990,13 @@
arch_free_page(page, 0);
kernel_map_pages(page, 1, 0);
- pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
+ pcp = &zone_pcp(zone, get_cpu())->pcp;
local_irq_save(flags);
__count_vm_event(PGFREE);
- list_add(&page->lru, &pcp->list);
+ if (cold)
+ list_add_tail(&page->lru, &pcp->list);
+ else
+ list_add(&page->lru, &pcp->list);
set_page_private(page, get_pageblock_migratetype(page));
pcp->count++;
if (pcp->count >= pcp->high) {
@@ -1015,12 +1007,12 @@
put_cpu();
}
-void fastcall free_hot_page(struct page *page)
+void free_hot_page(struct page *page)
{
free_hot_cold_page(page, 0);
}
-void fastcall free_cold_page(struct page *page)
+void free_cold_page(struct page *page)
{
free_hot_cold_page(page, 1);
}
@@ -1062,7 +1054,7 @@
if (likely(order == 0)) {
struct per_cpu_pages *pcp;
- pcp = &zone_pcp(zone, cpu)->pcp[cold];
+ pcp = &zone_pcp(zone, cpu)->pcp;
local_irq_save(flags);
if (!pcp->count) {
pcp->count = rmqueue_bulk(zone, 0,
@@ -1072,9 +1064,15 @@
}
/* Find a page of the appropriate migrate type */
- list_for_each_entry(page, &pcp->list, lru)
- if (page_private(page) == migratetype)
- break;
+ if (cold) {
+ list_for_each_entry_reverse(page, &pcp->list, lru)
+ if (page_private(page) == migratetype)
+ break;
+ } else {
+ list_for_each_entry(page, &pcp->list, lru)
+ if (page_private(page) == migratetype)
+ break;
+ }
/* Allocate more to the pcp list if necessary */
if (unlikely(&page->lru == &pcp->list)) {
@@ -1569,7 +1567,7 @@
cond_resched();
if (order != 0)
- drain_all_local_pages();
+ drain_all_pages();
if (likely(did_some_progress)) {
page = get_page_from_freelist(gfp_mask, order,
@@ -1643,7 +1641,7 @@
/*
* Common helper functions.
*/
-fastcall unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
+unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{
struct page * page;
page = alloc_pages(gfp_mask, order);
@@ -1654,7 +1652,7 @@
EXPORT_SYMBOL(__get_free_pages);
-fastcall unsigned long get_zeroed_page(gfp_t gfp_mask)
+unsigned long get_zeroed_page(gfp_t gfp_mask)
{
struct page * page;
@@ -1680,7 +1678,7 @@
free_hot_cold_page(pvec->pages[i], pvec->cold);
}
-fastcall void __free_pages(struct page *page, unsigned int order)
+void __free_pages(struct page *page, unsigned int order)
{
if (put_page_testzero(page)) {
if (order == 0)
@@ -1692,7 +1690,7 @@
EXPORT_SYMBOL(__free_pages);
-fastcall void free_pages(unsigned long addr, unsigned int order)
+void free_pages(unsigned long addr, unsigned int order)
{
if (addr != 0) {
VM_BUG_ON(!virt_addr_valid((void *)addr));
@@ -1801,12 +1799,9 @@
pageset = zone_pcp(zone, cpu);
- printk("CPU %4d: Hot: hi:%5d, btch:%4d usd:%4d "
- "Cold: hi:%5d, btch:%4d usd:%4d\n",
- cpu, pageset->pcp[0].high,
- pageset->pcp[0].batch, pageset->pcp[0].count,
- pageset->pcp[1].high, pageset->pcp[1].batch,
- pageset->pcp[1].count);
+ printk("CPU %4d: hi:%5d, btch:%4d usd:%4d\n",
+ cpu, pageset->pcp.high,
+ pageset->pcp.batch, pageset->pcp.count);
}
}
@@ -1879,6 +1874,8 @@
printk("= %lukB\n", K(total));
}
+ printk("%ld total pagecache pages\n", global_page_state(NR_FILE_PAGES));
+
show_swap_cache_info();
}
@@ -2551,8 +2548,7 @@
}
}
-static void __meminit zone_init_free_lists(struct pglist_data *pgdat,
- struct zone *zone, unsigned long size)
+static void __meminit zone_init_free_lists(struct zone *zone)
{
int order, t;
for_each_migratetype_order(order, t) {
@@ -2604,17 +2600,11 @@
memset(p, 0, sizeof(*p));
- pcp = &p->pcp[0]; /* hot */
+ pcp = &p->pcp;
pcp->count = 0;
pcp->high = 6 * batch;
pcp->batch = max(1UL, 1 * batch);
INIT_LIST_HEAD(&pcp->list);
-
- pcp = &p->pcp[1]; /* cold*/
- pcp->count = 0;
- pcp->high = 2 * batch;
- pcp->batch = max(1UL, batch/2);
- INIT_LIST_HEAD(&pcp->list);
}
/*
@@ -2627,7 +2617,7 @@
{
struct per_cpu_pages *pcp;
- pcp = &p->pcp[0]; /* hot list */
+ pcp = &p->pcp;
pcp->high = high;
pcp->batch = max(1UL, high/4);
if ((high/4) > (PAGE_SHIFT * 8))
@@ -2831,7 +2821,7 @@
memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn);
- zone_init_free_lists(pgdat, zone, zone->spanned_pages);
+ zone_init_free_lists(zone);
return 0;
}
@@ -3978,10 +3968,23 @@
int cpu = (unsigned long)hcpu;
if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
- local_irq_disable();
- __drain_pages(cpu);
+ drain_pages(cpu);
+
+ /*
+ * Spill the event counters of the dead processor
+ * into the current processors event counters.
+ * This artificially elevates the count of the current
+ * processor.
+ */
vm_events_fold_cpu(cpu);
- local_irq_enable();
+
+ /*
+ * Zero the differential counters of the dead processor
+ * so that the vm statistics are consistent.
+ *
+ * This is only okay since the processor is dead and cannot
+ * race with what we are doing.
+ */
refresh_cpu_vm_stats(cpu);
}
return NOTIFY_OK;
@@ -4480,7 +4483,7 @@
out:
spin_unlock_irqrestore(&zone->lock, flags);
if (!ret)
- drain_all_local_pages();
+ drain_all_pages();
return ret;
}
diff --git a/mm/page_io.c b/mm/page_io.c
index 3b97f68..065c448 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -126,7 +126,7 @@
int ret = 0;
BUG_ON(!PageLocked(page));
- ClearPageUptodate(page);
+ BUG_ON(PageUptodate(page));
bio = get_swap_bio(GFP_KERNEL, page_private(page), page,
end_swap_bio_read);
if (bio == NULL) {
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
new file mode 100644
index 0000000..b4f27d2
--- /dev/null
+++ b/mm/pagewalk.c
@@ -0,0 +1,131 @@
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/sched.h>
+
+static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+ const struct mm_walk *walk, void *private)
+{
+ pte_t *pte;
+ int err = 0;
+
+ pte = pte_offset_map(pmd, addr);
+ do {
+ err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private);
+ if (err)
+ break;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+
+ pte_unmap(pte);
+ return err;
+}
+
+static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
+ const struct mm_walk *walk, void *private)
+{
+ pmd_t *pmd;
+ unsigned long next;
+ int err = 0;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if (pmd_none_or_clear_bad(pmd)) {
+ if (walk->pte_hole)
+ err = walk->pte_hole(addr, next, private);
+ if (err)
+ break;
+ continue;
+ }
+ if (walk->pmd_entry)
+ err = walk->pmd_entry(pmd, addr, next, private);
+ if (!err && walk->pte_entry)
+ err = walk_pte_range(pmd, addr, next, walk, private);
+ if (err)
+ break;
+ } while (pmd++, addr = next, addr != end);
+
+ return err;
+}
+
+static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
+ const struct mm_walk *walk, void *private)
+{
+ pud_t *pud;
+ unsigned long next;
+ int err = 0;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud)) {
+ if (walk->pte_hole)
+ err = walk->pte_hole(addr, next, private);
+ if (err)
+ break;
+ continue;
+ }
+ if (walk->pud_entry)
+ err = walk->pud_entry(pud, addr, next, private);
+ if (!err && (walk->pmd_entry || walk->pte_entry))
+ err = walk_pmd_range(pud, addr, next, walk, private);
+ if (err)
+ break;
+ } while (pud++, addr = next, addr != end);
+
+ return err;
+}
+
+/**
+ * walk_page_range - walk a memory map's page tables with a callback
+ * @mm - memory map to walk
+ * @addr - starting address
+ * @end - ending address
+ * @walk - set of callbacks to invoke for each level of the tree
+ * @private - private data passed to the callback function
+ *
+ * Recursively walk the page table for the memory area in a VMA,
+ * calling supplied callbacks. Callbacks are called in-order (first
+ * PGD, first PUD, first PMD, first PTE, second PTE... second PMD,
+ * etc.). If lower-level callbacks are omitted, walking depth is reduced.
+ *
+ * Each callback receives an entry pointer, the start and end of the
+ * associated range, and a caller-supplied private data pointer.
+ *
+ * No locks are taken, but the bottom level iterator will map PTE
+ * directories from highmem if necessary.
+ *
+ * If any callback returns a non-zero value, the walk is aborted and
+ * the return value is propagated back to the caller. Otherwise 0 is returned.
+ */
+int walk_page_range(const struct mm_struct *mm,
+ unsigned long addr, unsigned long end,
+ const struct mm_walk *walk, void *private)
+{
+ pgd_t *pgd;
+ unsigned long next;
+ int err = 0;
+
+ if (addr >= end)
+ return err;
+
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd)) {
+ if (walk->pte_hole)
+ err = walk->pte_hole(addr, next, private);
+ if (err)
+ break;
+ continue;
+ }
+ if (walk->pgd_entry)
+ err = walk->pgd_entry(pgd, addr, next, private);
+ if (!err &&
+ (walk->pud_entry || walk->pmd_entry || walk->pte_entry))
+ err = walk_pud_range(pgd, addr, next, walk, private);
+ if (err)
+ break;
+ } while (pgd++, addr = next, addr != end);
+
+ return err;
+}
diff --git a/mm/rmap.c b/mm/rmap.c
index dbc2ca2..57ad276 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -36,7 +36,6 @@
* mapping->tree_lock (widely used, in set_page_dirty,
* in arch-dependent flush_dcache_mmap_lock,
* within inode_lock in __sync_single_inode)
- * zone->lock (within radix tree node alloc)
*/
#include <linux/mm.h>
@@ -284,7 +283,10 @@
if (!pte)
goto out;
- if (ptep_clear_flush_young(vma, address, pte))
+ if (vma->vm_flags & VM_LOCKED) {
+ referenced++;
+ *mapcount = 1; /* break early from loop */
+ } else if (ptep_clear_flush_young(vma, address, pte))
referenced++;
/* Pretend the page is referenced if the task has the
diff --git a/mm/shmem.c b/mm/shmem.c
index 51b3d6c..0f246c4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -78,11 +78,10 @@
/* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
enum sgp_type {
- SGP_QUICK, /* don't try more than file page cache lookup */
SGP_READ, /* don't exceed i_size, don't allocate page */
SGP_CACHE, /* don't exceed i_size, may allocate page */
+ SGP_DIRTY, /* like SGP_CACHE, but set new page dirty */
SGP_WRITE, /* may exceed i_size, may allocate page */
- SGP_FAULT, /* same as SGP_CACHE, return with page locked */
};
static int shmem_getpage(struct inode *inode, unsigned long idx,
@@ -194,7 +193,7 @@
};
static LIST_HEAD(shmem_swaplist);
-static DEFINE_SPINLOCK(shmem_swaplist_lock);
+static DEFINE_MUTEX(shmem_swaplist_mutex);
static void shmem_free_blocks(struct inode *inode, long pages)
{
@@ -207,6 +206,31 @@
}
}
+static int shmem_reserve_inode(struct super_block *sb)
+{
+ struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+ if (sbinfo->max_inodes) {
+ spin_lock(&sbinfo->stat_lock);
+ if (!sbinfo->free_inodes) {
+ spin_unlock(&sbinfo->stat_lock);
+ return -ENOSPC;
+ }
+ sbinfo->free_inodes--;
+ spin_unlock(&sbinfo->stat_lock);
+ }
+ return 0;
+}
+
+static void shmem_free_inode(struct super_block *sb)
+{
+ struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+ if (sbinfo->max_inodes) {
+ spin_lock(&sbinfo->stat_lock);
+ sbinfo->free_inodes++;
+ spin_unlock(&sbinfo->stat_lock);
+ }
+}
+
/*
* shmem_recalc_inode - recalculate the size of an inode
*
@@ -731,6 +755,8 @@
(void) shmem_getpage(inode,
attr->ia_size>>PAGE_CACHE_SHIFT,
&page, SGP_READ, NULL);
+ if (page)
+ unlock_page(page);
}
/*
* Reset SHMEM_PAGEIN flag so that shmem_truncate can
@@ -762,7 +788,6 @@
static void shmem_delete_inode(struct inode *inode)
{
- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
struct shmem_inode_info *info = SHMEM_I(inode);
if (inode->i_op->truncate == shmem_truncate) {
@@ -771,17 +796,13 @@
inode->i_size = 0;
shmem_truncate(inode);
if (!list_empty(&info->swaplist)) {
- spin_lock(&shmem_swaplist_lock);
+ mutex_lock(&shmem_swaplist_mutex);
list_del_init(&info->swaplist);
- spin_unlock(&shmem_swaplist_lock);
+ mutex_unlock(&shmem_swaplist_mutex);
}
}
BUG_ON(inode->i_blocks);
- if (sbinfo->max_inodes) {
- spin_lock(&sbinfo->stat_lock);
- sbinfo->free_inodes++;
- spin_unlock(&sbinfo->stat_lock);
- }
+ shmem_free_inode(inode->i_sb);
clear_inode(inode);
}
@@ -807,19 +828,22 @@
struct page *subdir;
swp_entry_t *ptr;
int offset;
+ int error;
idx = 0;
ptr = info->i_direct;
spin_lock(&info->lock);
+ if (!info->swapped) {
+ list_del_init(&info->swaplist);
+ goto lost2;
+ }
limit = info->next_index;
size = limit;
if (size > SHMEM_NR_DIRECT)
size = SHMEM_NR_DIRECT;
offset = shmem_find_swp(entry, ptr, ptr+size);
- if (offset >= 0) {
- shmem_swp_balance_unmap();
+ if (offset >= 0)
goto found;
- }
if (!info->i_indirect)
goto lost2;
@@ -829,6 +853,14 @@
for (idx = SHMEM_NR_DIRECT; idx < limit; idx += ENTRIES_PER_PAGE, dir++) {
if (unlikely(idx == stage)) {
shmem_dir_unmap(dir-1);
+ if (cond_resched_lock(&info->lock)) {
+ /* check it has not been truncated */
+ if (limit > info->next_index) {
+ limit = info->next_index;
+ if (idx >= limit)
+ goto lost2;
+ }
+ }
dir = shmem_dir_map(info->i_indirect) +
ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE;
while (!*dir) {
@@ -849,11 +881,11 @@
if (size > ENTRIES_PER_PAGE)
size = ENTRIES_PER_PAGE;
offset = shmem_find_swp(entry, ptr, ptr+size);
+ shmem_swp_unmap(ptr);
if (offset >= 0) {
shmem_dir_unmap(dir);
goto found;
}
- shmem_swp_unmap(ptr);
}
}
lost1:
@@ -863,19 +895,63 @@
return 0;
found:
idx += offset;
- inode = &info->vfs_inode;
- if (move_from_swap_cache(page, idx, inode->i_mapping) == 0) {
- info->flags |= SHMEM_PAGEIN;
- shmem_swp_set(info, ptr + offset, 0);
- }
- shmem_swp_unmap(ptr);
+ inode = igrab(&info->vfs_inode);
spin_unlock(&info->lock);
+
/*
- * Decrement swap count even when the entry is left behind:
- * try_to_unuse will skip over mms, then reincrement count.
+ * Move _head_ to start search for next from here.
+ * But be careful: shmem_delete_inode checks list_empty without taking
+ * mutex, and there's an instant in list_move_tail when info->swaplist
+ * would appear empty, if it were the only one on shmem_swaplist. We
+ * could avoid doing it if inode NULL; or use this minor optimization.
*/
- swap_free(entry);
- return 1;
+ if (shmem_swaplist.next != &info->swaplist)
+ list_move_tail(&shmem_swaplist, &info->swaplist);
+ mutex_unlock(&shmem_swaplist_mutex);
+
+ error = 1;
+ if (!inode)
+ goto out;
+ error = radix_tree_preload(GFP_KERNEL);
+ if (error)
+ goto out;
+ error = 1;
+
+ spin_lock(&info->lock);
+ ptr = shmem_swp_entry(info, idx, NULL);
+ if (ptr && ptr->val == entry.val)
+ error = add_to_page_cache(page, inode->i_mapping,
+ idx, GFP_NOWAIT);
+ if (error == -EEXIST) {
+ struct page *filepage = find_get_page(inode->i_mapping, idx);
+ error = 1;
+ if (filepage) {
+ /*
+ * There might be a more uptodate page coming down
+ * from a stacked writepage: forget our swappage if so.
+ */
+ if (PageUptodate(filepage))
+ error = 0;
+ page_cache_release(filepage);
+ }
+ }
+ if (!error) {
+ delete_from_swap_cache(page);
+ set_page_dirty(page);
+ info->flags |= SHMEM_PAGEIN;
+ shmem_swp_set(info, ptr, 0);
+ swap_free(entry);
+ error = 1; /* not an error, but entry was found */
+ }
+ if (ptr)
+ shmem_swp_unmap(ptr);
+ spin_unlock(&info->lock);
+ radix_tree_preload_end();
+out:
+ unlock_page(page);
+ page_cache_release(page);
+ iput(inode); /* allows for NULL */
+ return error;
}
/*
@@ -887,20 +963,16 @@
struct shmem_inode_info *info;
int found = 0;
- spin_lock(&shmem_swaplist_lock);
+ mutex_lock(&shmem_swaplist_mutex);
list_for_each_safe(p, next, &shmem_swaplist) {
info = list_entry(p, struct shmem_inode_info, swaplist);
- if (!info->swapped)
- list_del_init(&info->swaplist);
- else if (shmem_unuse_inode(info, entry, page)) {
- /* move head to start search for next from here */
- list_move_tail(&shmem_swaplist, &info->swaplist);
- found = 1;
- break;
- }
+ found = shmem_unuse_inode(info, entry, page);
+ cond_resched();
+ if (found)
+ goto out;
}
- spin_unlock(&shmem_swaplist_lock);
- return found;
+ mutex_unlock(&shmem_swaplist_mutex);
+out: return found; /* 0 or 1 or -ENOMEM */
}
/*
@@ -915,54 +987,65 @@
struct inode *inode;
BUG_ON(!PageLocked(page));
- /*
- * shmem_backing_dev_info's capabilities prevent regular writeback or
- * sync from ever calling shmem_writepage; but a stacking filesystem
- * may use the ->writepage of its underlying filesystem, in which case
- * we want to do nothing when that underlying filesystem is tmpfs
- * (writing out to swap is useful as a response to memory pressure, but
- * of no use to stabilize the data) - just redirty the page, unlock it
- * and claim success in this case. AOP_WRITEPAGE_ACTIVATE, and the
- * page_mapped check below, must be avoided unless we're in reclaim.
- */
- if (!wbc->for_reclaim) {
- set_page_dirty(page);
- unlock_page(page);
- return 0;
- }
- BUG_ON(page_mapped(page));
-
mapping = page->mapping;
index = page->index;
inode = mapping->host;
info = SHMEM_I(inode);
if (info->flags & VM_LOCKED)
goto redirty;
- swap = get_swap_page();
- if (!swap.val)
+ if (!total_swap_pages)
goto redirty;
+ /*
+ * shmem_backing_dev_info's capabilities prevent regular writeback or
+ * sync from ever calling shmem_writepage; but a stacking filesystem
+ * may use the ->writepage of its underlying filesystem, in which case
+ * tmpfs should write out to swap only in response to memory pressure,
+ * and not for pdflush or sync. However, in those cases, we do still
+ * want to check if there's a redundant swappage to be discarded.
+ */
+ if (wbc->for_reclaim)
+ swap = get_swap_page();
+ else
+ swap.val = 0;
+
spin_lock(&info->lock);
- shmem_recalc_inode(inode);
if (index >= info->next_index) {
BUG_ON(!(info->flags & SHMEM_TRUNCATE));
goto unlock;
}
entry = shmem_swp_entry(info, index, NULL);
- BUG_ON(!entry);
- BUG_ON(entry->val);
+ if (entry->val) {
+ /*
+ * The more uptodate page coming down from a stacked
+ * writepage should replace our old swappage.
+ */
+ free_swap_and_cache(*entry);
+ shmem_swp_set(info, entry, 0);
+ }
+ shmem_recalc_inode(inode);
- if (move_to_swap_cache(page, swap) == 0) {
+ if (swap.val && add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
+ remove_from_page_cache(page);
shmem_swp_set(info, entry, swap.val);
shmem_swp_unmap(entry);
+ if (list_empty(&info->swaplist))
+ inode = igrab(inode);
+ else
+ inode = NULL;
spin_unlock(&info->lock);
- if (list_empty(&info->swaplist)) {
- spin_lock(&shmem_swaplist_lock);
+ swap_duplicate(swap);
+ BUG_ON(page_mapped(page));
+ page_cache_release(page); /* pagecache ref */
+ set_page_dirty(page);
+ unlock_page(page);
+ if (inode) {
+ mutex_lock(&shmem_swaplist_mutex);
/* move instead of add in case we're racing */
list_move_tail(&info->swaplist, &shmem_swaplist);
- spin_unlock(&shmem_swaplist_lock);
+ mutex_unlock(&shmem_swaplist_mutex);
+ iput(inode);
}
- unlock_page(page);
return 0;
}
@@ -972,7 +1055,10 @@
swap_free(swap);
redirty:
set_page_dirty(page);
- return AOP_WRITEPAGE_ACTIVATE; /* Return with the page locked */
+ if (wbc->for_reclaim)
+ return AOP_WRITEPAGE_ACTIVATE; /* Return with page locked */
+ unlock_page(page);
+ return 0;
}
#ifdef CONFIG_NUMA
@@ -1025,53 +1111,33 @@
return err;
}
-static struct page *shmem_swapin_async(struct shared_policy *p,
- swp_entry_t entry, unsigned long idx)
+static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
+ struct shmem_inode_info *info, unsigned long idx)
{
- struct page *page;
struct vm_area_struct pvma;
+ struct page *page;
/* Create a pseudo vma that just contains the policy */
- memset(&pvma, 0, sizeof(struct vm_area_struct));
- pvma.vm_end = PAGE_SIZE;
+ pvma.vm_start = 0;
pvma.vm_pgoff = idx;
- pvma.vm_policy = mpol_shared_policy_lookup(p, idx);
- page = read_swap_cache_async(entry, &pvma, 0);
+ pvma.vm_ops = NULL;
+ pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
+ page = swapin_readahead(entry, gfp, &pvma, 0);
mpol_free(pvma.vm_policy);
return page;
}
-static struct page *shmem_swapin(struct shmem_inode_info *info,
- swp_entry_t entry, unsigned long idx)
-{
- struct shared_policy *p = &info->policy;
- int i, num;
- struct page *page;
- unsigned long offset;
-
- num = valid_swaphandles(entry, &offset);
- for (i = 0; i < num; offset++, i++) {
- page = shmem_swapin_async(p,
- swp_entry(swp_type(entry), offset), idx);
- if (!page)
- break;
- page_cache_release(page);
- }
- lru_add_drain(); /* Push any new pages onto the LRU now */
- return shmem_swapin_async(p, entry, idx);
-}
-
-static struct page *
-shmem_alloc_page(gfp_t gfp, struct shmem_inode_info *info,
- unsigned long idx)
+static struct page *shmem_alloc_page(gfp_t gfp,
+ struct shmem_inode_info *info, unsigned long idx)
{
struct vm_area_struct pvma;
struct page *page;
- memset(&pvma, 0, sizeof(struct vm_area_struct));
- pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
+ /* Create a pseudo vma that just contains the policy */
+ pvma.vm_start = 0;
pvma.vm_pgoff = idx;
- pvma.vm_end = PAGE_SIZE;
+ pvma.vm_ops = NULL;
+ pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
page = alloc_page_vma(gfp, &pvma, 0);
mpol_free(pvma.vm_policy);
return page;
@@ -1083,15 +1149,14 @@
return 1;
}
-static inline struct page *
-shmem_swapin(struct shmem_inode_info *info,swp_entry_t entry,unsigned long idx)
+static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
+ struct shmem_inode_info *info, unsigned long idx)
{
- swapin_readahead(entry, 0, NULL);
- return read_swap_cache_async(entry, NULL, 0);
+ return swapin_readahead(entry, gfp, NULL, 0);
}
-static inline struct page *
-shmem_alloc_page(gfp_t gfp,struct shmem_inode_info *info, unsigned long idx)
+static inline struct page *shmem_alloc_page(gfp_t gfp,
+ struct shmem_inode_info *info, unsigned long idx)
{
return alloc_page(gfp);
}
@@ -1114,6 +1179,7 @@
struct page *swappage;
swp_entry_t *entry;
swp_entry_t swap;
+ gfp_t gfp;
int error;
if (idx >= SHMEM_MAX_INDEX)
@@ -1126,7 +1192,7 @@
* Normally, filepage is NULL on entry, and either found
* uptodate immediately, or allocated and zeroed, or read
* in under swappage, which is then assigned to filepage.
- * But shmem_readpage and shmem_write_begin pass in a locked
+ * But shmem_readpage (required for splice) passes in a locked
* filepage, which may be found not uptodate by other callers
* too, and may need to be copied from the swappage read in.
*/
@@ -1136,8 +1202,17 @@
if (filepage && PageUptodate(filepage))
goto done;
error = 0;
- if (sgp == SGP_QUICK)
- goto failed;
+ gfp = mapping_gfp_mask(mapping);
+ if (!filepage) {
+ /*
+ * Try to preload while we can wait, to not make a habit of
+ * draining atomic reserves; but don't latch on to this cpu.
+ */
+ error = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
+ if (error)
+ goto failed;
+ radix_tree_preload_end();
+ }
spin_lock(&info->lock);
shmem_recalc_inode(inode);
@@ -1160,7 +1235,7 @@
*type |= VM_FAULT_MAJOR;
}
spin_unlock(&info->lock);
- swappage = shmem_swapin(info, swap, idx);
+ swappage = shmem_swapin(swap, gfp, info, idx);
if (!swappage) {
spin_lock(&info->lock);
entry = shmem_swp_alloc(info, idx, sgp);
@@ -1218,23 +1293,21 @@
SetPageUptodate(filepage);
set_page_dirty(filepage);
swap_free(swap);
- } else if (!(error = move_from_swap_cache(
- swappage, idx, mapping))) {
+ } else if (!(error = add_to_page_cache(
+ swappage, mapping, idx, GFP_NOWAIT))) {
info->flags |= SHMEM_PAGEIN;
shmem_swp_set(info, entry, 0);
shmem_swp_unmap(entry);
+ delete_from_swap_cache(swappage);
spin_unlock(&info->lock);
filepage = swappage;
+ set_page_dirty(filepage);
swap_free(swap);
} else {
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
unlock_page(swappage);
page_cache_release(swappage);
- if (error == -ENOMEM) {
- /* let kswapd refresh zone for GFP_ATOMICs */
- congestion_wait(WRITE, HZ/50);
- }
goto repeat;
}
} else if (sgp == SGP_READ && !filepage) {
@@ -1272,9 +1345,7 @@
if (!filepage) {
spin_unlock(&info->lock);
- filepage = shmem_alloc_page(mapping_gfp_mask(mapping),
- info,
- idx);
+ filepage = shmem_alloc_page(gfp, info, idx);
if (!filepage) {
shmem_unacct_blocks(info->flags, 1);
shmem_free_blocks(inode, 1);
@@ -1291,7 +1362,7 @@
shmem_swp_unmap(entry);
}
if (error || swap.val || 0 != add_to_page_cache_lru(
- filepage, mapping, idx, GFP_ATOMIC)) {
+ filepage, mapping, idx, GFP_NOWAIT)) {
spin_unlock(&info->lock);
page_cache_release(filepage);
shmem_unacct_blocks(info->flags, 1);
@@ -1309,14 +1380,11 @@
clear_highpage(filepage);
flush_dcache_page(filepage);
SetPageUptodate(filepage);
+ if (sgp == SGP_DIRTY)
+ set_page_dirty(filepage);
}
done:
- if (*pagep != filepage) {
- *pagep = filepage;
- if (sgp != SGP_FAULT)
- unlock_page(filepage);
-
- }
+ *pagep = filepage;
return 0;
failed:
@@ -1336,7 +1404,7 @@
if (((loff_t)vmf->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
return VM_FAULT_SIGBUS;
- error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_FAULT, &ret);
+ error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
if (error)
return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
@@ -1399,15 +1467,8 @@
struct shmem_inode_info *info;
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- if (sbinfo->max_inodes) {
- spin_lock(&sbinfo->stat_lock);
- if (!sbinfo->free_inodes) {
- spin_unlock(&sbinfo->stat_lock);
- return NULL;
- }
- sbinfo->free_inodes--;
- spin_unlock(&sbinfo->stat_lock);
- }
+ if (shmem_reserve_inode(sb))
+ return NULL;
inode = new_inode(sb);
if (inode) {
@@ -1451,11 +1512,8 @@
NULL);
break;
}
- } else if (sbinfo->max_inodes) {
- spin_lock(&sbinfo->stat_lock);
- sbinfo->free_inodes++;
- spin_unlock(&sbinfo->stat_lock);
- }
+ } else
+ shmem_free_inode(sb);
return inode;
}
@@ -1494,123 +1552,30 @@
{
struct inode *inode = mapping->host;
+ if (pos + copied > inode->i_size)
+ i_size_write(inode, pos + copied);
+
+ unlock_page(page);
set_page_dirty(page);
page_cache_release(page);
- if (pos+copied > inode->i_size)
- i_size_write(inode, pos+copied);
-
return copied;
}
-static ssize_t
-shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
- struct inode *inode = file->f_path.dentry->d_inode;
- loff_t pos;
- unsigned long written;
- ssize_t err;
-
- if ((ssize_t) count < 0)
- return -EINVAL;
-
- if (!access_ok(VERIFY_READ, buf, count))
- return -EFAULT;
-
- mutex_lock(&inode->i_mutex);
-
- pos = *ppos;
- written = 0;
-
- err = generic_write_checks(file, &pos, &count, 0);
- if (err || !count)
- goto out;
-
- err = remove_suid(file->f_path.dentry);
- if (err)
- goto out;
-
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-
- do {
- struct page *page = NULL;
- unsigned long bytes, index, offset;
- char *kaddr;
- int left;
-
- offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
- index = pos >> PAGE_CACHE_SHIFT;
- bytes = PAGE_CACHE_SIZE - offset;
- if (bytes > count)
- bytes = count;
-
- /*
- * We don't hold page lock across copy from user -
- * what would it guard against? - so no deadlock here.
- * But it still may be a good idea to prefault below.
- */
-
- err = shmem_getpage(inode, index, &page, SGP_WRITE, NULL);
- if (err)
- break;
-
- left = bytes;
- if (PageHighMem(page)) {
- volatile unsigned char dummy;
- __get_user(dummy, buf);
- __get_user(dummy, buf + bytes - 1);
-
- kaddr = kmap_atomic(page, KM_USER0);
- left = __copy_from_user_inatomic(kaddr + offset,
- buf, bytes);
- kunmap_atomic(kaddr, KM_USER0);
- }
- if (left) {
- kaddr = kmap(page);
- left = __copy_from_user(kaddr + offset, buf, bytes);
- kunmap(page);
- }
-
- written += bytes;
- count -= bytes;
- pos += bytes;
- buf += bytes;
- if (pos > inode->i_size)
- i_size_write(inode, pos);
-
- flush_dcache_page(page);
- set_page_dirty(page);
- mark_page_accessed(page);
- page_cache_release(page);
-
- if (left) {
- pos -= left;
- written -= left;
- err = -EFAULT;
- break;
- }
-
- /*
- * Our dirty pages are not counted in nr_dirty,
- * and we do not attempt to balance dirty pages.
- */
-
- cond_resched();
- } while (count);
-
- *ppos = pos;
- if (written)
- err = written;
-out:
- mutex_unlock(&inode->i_mutex);
- return err;
-}
-
static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
{
struct inode *inode = filp->f_path.dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned long index, offset;
+ enum sgp_type sgp = SGP_READ;
+
+ /*
+ * Might this read be for a stacking filesystem? Then when reading
+ * holes of a sparse file, we actually need to allocate those pages,
+ * and even mark them dirty, so it cannot exceed the max_blocks limit.
+ */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ sgp = SGP_DIRTY;
index = *ppos >> PAGE_CACHE_SHIFT;
offset = *ppos & ~PAGE_CACHE_MASK;
@@ -1629,12 +1594,14 @@
break;
}
- desc->error = shmem_getpage(inode, index, &page, SGP_READ, NULL);
+ desc->error = shmem_getpage(inode, index, &page, sgp, NULL);
if (desc->error) {
if (desc->error == -EINVAL)
desc->error = 0;
break;
}
+ if (page)
+ unlock_page(page);
/*
* We must evaluate after, since reads (unlike writes)
@@ -1798,22 +1765,16 @@
static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+ int ret;
/*
* No ordinary (disk based) filesystem counts links as inodes;
* but each new link needs a new dentry, pinning lowmem, and
* tmpfs dentries cannot be pruned until they are unlinked.
*/
- if (sbinfo->max_inodes) {
- spin_lock(&sbinfo->stat_lock);
- if (!sbinfo->free_inodes) {
- spin_unlock(&sbinfo->stat_lock);
- return -ENOSPC;
- }
- sbinfo->free_inodes--;
- spin_unlock(&sbinfo->stat_lock);
- }
+ ret = shmem_reserve_inode(inode->i_sb);
+ if (ret)
+ goto out;
dir->i_size += BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1821,21 +1782,16 @@
atomic_inc(&inode->i_count); /* New dentry reference */
dget(dentry); /* Extra pinning count for the created dentry */
d_instantiate(dentry, inode);
- return 0;
+out:
+ return ret;
}
static int shmem_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) {
- struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
- if (sbinfo->max_inodes) {
- spin_lock(&sbinfo->stat_lock);
- sbinfo->free_inodes++;
- spin_unlock(&sbinfo->stat_lock);
- }
- }
+ if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
+ shmem_free_inode(inode->i_sb);
dir->i_size -= BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1924,6 +1880,7 @@
iput(inode);
return error;
}
+ unlock_page(page);
inode->i_op = &shmem_symlink_inode_operations;
kaddr = kmap_atomic(page, KM_USER0);
memcpy(kaddr, symname, len);
@@ -1951,6 +1908,8 @@
struct page *page = NULL;
int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
+ if (page)
+ unlock_page(page);
return page;
}
@@ -1996,8 +1955,7 @@
{
if (strcmp(name, "") == 0)
return -EINVAL;
- return security_inode_getsecurity(inode, name, buffer, size,
- -EOPNOTSUPP);
+ return xattr_getsecurity(inode, name, buffer, size);
}
static int shmem_xattr_security_set(struct inode *inode, const char *name,
@@ -2138,7 +2096,7 @@
}
if (*rest)
goto bad_val;
- *blocks = size >> PAGE_CACHE_SHIFT;
+ *blocks = DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
} else if (!strcmp(this_char,"nr_blocks")) {
*blocks = memparse(value,&rest);
if (*rest)
@@ -2375,7 +2333,8 @@
#ifdef CONFIG_TMPFS
.llseek = generic_file_llseek,
.read = shmem_file_read,
- .write = shmem_file_write,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.fsync = simple_sync_file,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
diff --git a/mm/slob.c b/mm/slob.c
index 773a7aa..e2c3c0e 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -12,10 +12,17 @@
* allocator is as little as 2 bytes, however typically most architectures
* will require 4 bytes on 32-bit and 8 bytes on 64-bit.
*
- * The slob heap is a linked list of pages from alloc_pages(), and
- * within each page, there is a singly-linked list of free blocks (slob_t).
- * The heap is grown on demand and allocation from the heap is currently
- * first-fit.
+ * The slob heap is a set of linked list of pages from alloc_pages(),
+ * and within each page, there is a singly-linked list of free blocks
+ * (slob_t). The heap is grown on demand. To reduce fragmentation,
+ * heap pages are segregated into three lists, with objects less than
+ * 256 bytes, objects less than 1024 bytes, and all other objects.
+ *
+ * Allocation from heap involves first searching for a page with
+ * sufficient free blocks (using a next-fit-like approach) followed by
+ * a first-fit scan of the page. Deallocation inserts objects back
+ * into the free list in address order, so this is effectively an
+ * address-ordered first fit.
*
* Above this is an implementation of kmalloc/kfree. Blocks returned
* from kmalloc are prepended with a 4-byte header with the kmalloc size.
@@ -110,9 +117,13 @@
}
/*
- * All (partially) free slob pages go on this list.
+ * All partially free slob pages go on these lists.
*/
-static LIST_HEAD(free_slob_pages);
+#define SLOB_BREAK1 256
+#define SLOB_BREAK2 1024
+static LIST_HEAD(free_slob_small);
+static LIST_HEAD(free_slob_medium);
+static LIST_HEAD(free_slob_large);
/*
* slob_page: True for all slob pages (false for bigblock pages)
@@ -140,9 +151,9 @@
return test_bit(PG_private, &sp->flags);
}
-static inline void set_slob_page_free(struct slob_page *sp)
+static void set_slob_page_free(struct slob_page *sp, struct list_head *list)
{
- list_add(&sp->list, &free_slob_pages);
+ list_add(&sp->list, list);
__set_bit(PG_private, &sp->flags);
}
@@ -294,12 +305,20 @@
{
struct slob_page *sp;
struct list_head *prev;
+ struct list_head *slob_list;
slob_t *b = NULL;
unsigned long flags;
+ if (size < SLOB_BREAK1)
+ slob_list = &free_slob_small;
+ else if (size < SLOB_BREAK2)
+ slob_list = &free_slob_medium;
+ else
+ slob_list = &free_slob_large;
+
spin_lock_irqsave(&slob_lock, flags);
/* Iterate through each partially free page, try to find room */
- list_for_each_entry(sp, &free_slob_pages, list) {
+ list_for_each_entry(sp, slob_list, list) {
#ifdef CONFIG_NUMA
/*
* If there's a node specification, search for a partial
@@ -321,9 +340,9 @@
/* Improve fragment distribution and reduce our average
* search time by starting our next search here. (see
* Knuth vol 1, sec 2.5, pg 449) */
- if (prev != free_slob_pages.prev &&
- free_slob_pages.next != prev->next)
- list_move_tail(&free_slob_pages, prev->next);
+ if (prev != slob_list->prev &&
+ slob_list->next != prev->next)
+ list_move_tail(slob_list, prev->next);
break;
}
spin_unlock_irqrestore(&slob_lock, flags);
@@ -341,7 +360,7 @@
sp->free = b;
INIT_LIST_HEAD(&sp->list);
set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
- set_slob_page_free(sp);
+ set_slob_page_free(sp, slob_list);
b = slob_page_alloc(sp, size, align);
BUG_ON(!b);
spin_unlock_irqrestore(&slob_lock, flags);
@@ -387,7 +406,7 @@
set_slob(b, units,
(void *)((unsigned long)(b +
SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
- set_slob_page_free(sp);
+ set_slob_page_free(sp, &free_slob_small);
goto out;
}
@@ -398,6 +417,10 @@
sp->units += units;
if (b < sp->free) {
+ if (b + units == sp->free) {
+ units += slob_units(sp->free);
+ sp->free = slob_next(sp->free);
+ }
set_slob(b, units, sp->free);
sp->free = b;
} else {
diff --git a/mm/slub.c b/mm/slub.c
index 5cc4b7d..3f05667 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -247,7 +247,10 @@
static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; }
static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
{ return 0; }
-static inline void sysfs_slab_remove(struct kmem_cache *s) {}
+static inline void sysfs_slab_remove(struct kmem_cache *s)
+{
+ kfree(s);
+}
#endif
/********************************************************************
@@ -354,22 +357,22 @@
printk(KERN_ERR "%8s 0x%p: ", text, addr + i);
newline = 0;
}
- printk(" %02x", addr[i]);
+ printk(KERN_CONT " %02x", addr[i]);
offset = i % 16;
ascii[offset] = isgraph(addr[i]) ? addr[i] : '.';
if (offset == 15) {
- printk(" %s\n",ascii);
+ printk(KERN_CONT " %s\n", ascii);
newline = 1;
}
}
if (!newline) {
i %= 16;
while (i < 16) {
- printk(" ");
+ printk(KERN_CONT " ");
ascii[i] = ' ';
i++;
}
- printk(" %s\n", ascii);
+ printk(KERN_CONT " %s\n", ascii);
}
}
@@ -529,7 +532,7 @@
if (s->flags & __OBJECT_POISON) {
memset(p, POISON_FREE, s->objsize - 1);
- p[s->objsize -1] = POISON_END;
+ p[s->objsize - 1] = POISON_END;
}
if (s->flags & SLAB_RED_ZONE)
@@ -558,7 +561,7 @@
static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
u8 *object, char *what,
- u8* start, unsigned int value, unsigned int bytes)
+ u8 *start, unsigned int value, unsigned int bytes)
{
u8 *fault;
u8 *end;
@@ -692,7 +695,7 @@
(!check_bytes_and_report(s, page, p, "Poison", p,
POISON_FREE, s->objsize - 1) ||
!check_bytes_and_report(s, page, p, "Poison",
- p + s->objsize -1, POISON_END, 1)))
+ p + s->objsize - 1, POISON_END, 1)))
return 0;
/*
* check_pad_bytes cleans up on its own.
@@ -900,8 +903,7 @@
"SLUB <none>: no slab for object 0x%p.\n",
object);
dump_stack();
- }
- else
+ } else
object_err(s, page, object,
"page slab pointer corrupt.");
goto fail;
@@ -947,7 +949,7 @@
/*
* Determine which debug features should be switched on
*/
- for ( ;*str && *str != ','; str++) {
+ for (; *str && *str != ','; str++) {
switch (tolower(*str)) {
case 'f':
slub_debug |= SLAB_DEBUG_FREE;
@@ -966,7 +968,7 @@
break;
default:
printk(KERN_ERR "slub_debug option '%c' "
- "unknown. skipped\n",*str);
+ "unknown. skipped\n", *str);
}
}
@@ -1039,7 +1041,7 @@
*/
static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
- struct page * page;
+ struct page *page;
int pages = 1 << s->order;
if (s->order)
@@ -1135,7 +1137,7 @@
mod_zone_page_state(page_zone(page),
(s->flags & SLAB_RECLAIM_ACCOUNT) ?
NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
- - pages);
+ -pages);
__free_pages(page, s->order);
}
@@ -1195,19 +1197,15 @@
/*
* Management of partially allocated slabs
*/
-static void add_partial_tail(struct kmem_cache_node *n, struct page *page)
+static void add_partial(struct kmem_cache_node *n,
+ struct page *page, int tail)
{
spin_lock(&n->list_lock);
n->nr_partial++;
- list_add_tail(&page->lru, &n->partial);
- spin_unlock(&n->list_lock);
-}
-
-static void add_partial(struct kmem_cache_node *n, struct page *page)
-{
- spin_lock(&n->list_lock);
- n->nr_partial++;
- list_add(&page->lru, &n->partial);
+ if (tail)
+ list_add_tail(&page->lru, &n->partial);
+ else
+ list_add(&page->lru, &n->partial);
spin_unlock(&n->list_lock);
}
@@ -1292,7 +1290,8 @@
* expensive if we do it every time we are trying to find a slab
* with available objects.
*/
- if (!s->defrag_ratio || get_cycles() % 1024 > s->defrag_ratio)
+ if (!s->remote_node_defrag_ratio ||
+ get_cycles() % 1024 > s->remote_node_defrag_ratio)
return NULL;
zonelist = &NODE_DATA(slab_node(current->mempolicy))
@@ -1335,7 +1334,7 @@
*
* On exit the slab lock will have been dropped.
*/
-static void unfreeze_slab(struct kmem_cache *s, struct page *page)
+static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
{
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
@@ -1343,7 +1342,7 @@
if (page->inuse) {
if (page->freelist)
- add_partial(n, page);
+ add_partial(n, page, tail);
else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER))
add_full(n, page);
slab_unlock(page);
@@ -1358,7 +1357,7 @@
* partial list stays small. kmem_cache_shrink can
* reclaim empty slabs from the partial list.
*/
- add_partial_tail(n, page);
+ add_partial(n, page, 1);
slab_unlock(page);
} else {
slab_unlock(page);
@@ -1373,6 +1372,7 @@
static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
struct page *page = c->page;
+ int tail = 1;
/*
* Merge cpu freelist into freelist. Typically we get here
* because both freelists are empty. So this is unlikely
@@ -1381,6 +1381,8 @@
while (unlikely(c->freelist)) {
void **object;
+ tail = 0; /* Hot objects. Put the slab first */
+
/* Retrieve object from cpu_freelist */
object = c->freelist;
c->freelist = c->freelist[c->offset];
@@ -1391,7 +1393,7 @@
page->inuse--;
}
c->page = NULL;
- unfreeze_slab(s, page);
+ unfreeze_slab(s, page, tail);
}
static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
@@ -1539,7 +1541,7 @@
*
* Otherwise we can simply pick the next object from the lockless free list.
*/
-static void __always_inline *slab_alloc(struct kmem_cache *s,
+static __always_inline void *slab_alloc(struct kmem_cache *s,
gfp_t gfpflags, int node, void *addr)
{
void **object;
@@ -1613,7 +1615,7 @@
* then add it.
*/
if (unlikely(!prior))
- add_partial_tail(get_node(s, page_to_nid(page)), page);
+ add_partial(get_node(s, page_to_nid(page)), page, 1);
out_unlock:
slab_unlock(page);
@@ -1647,7 +1649,7 @@
* If fastpath is not possible then fall back to __slab_free where we deal
* with all sorts of special processing.
*/
-static void __always_inline slab_free(struct kmem_cache *s,
+static __always_inline void slab_free(struct kmem_cache *s,
struct page *page, void *x, void *addr)
{
void **object = (void *)x;
@@ -1997,6 +1999,7 @@
{
struct page *page;
struct kmem_cache_node *n;
+ unsigned long flags;
BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node));
@@ -2021,7 +2024,14 @@
#endif
init_kmem_cache_node(n);
atomic_long_inc(&n->nr_slabs);
- add_partial(n, page);
+ /*
+ * lockdep requires consistent irq usage for each lock
+ * so even though there cannot be a race this early in
+ * the boot sequence, we still disable irqs.
+ */
+ local_irq_save(flags);
+ add_partial(n, page, 0);
+ local_irq_restore(flags);
return n;
}
@@ -2206,7 +2216,7 @@
s->refcount = 1;
#ifdef CONFIG_NUMA
- s->defrag_ratio = 100;
+ s->remote_node_defrag_ratio = 100;
#endif
if (!init_kmem_cache_nodes(s, gfpflags & ~SLUB_DMA))
goto error;
@@ -2228,7 +2238,7 @@
*/
int kmem_ptr_validate(struct kmem_cache *s, const void *object)
{
- struct page * page;
+ struct page *page;
page = get_object_page(object);
@@ -2322,7 +2332,6 @@
if (kmem_cache_close(s))
WARN_ON(1);
sysfs_slab_remove(s);
- kfree(s);
} else
up_write(&slub_lock);
}
@@ -2341,7 +2350,7 @@
static int __init setup_slub_min_order(char *str)
{
- get_option (&str, &slub_min_order);
+ get_option(&str, &slub_min_order);
return 1;
}
@@ -2350,7 +2359,7 @@
static int __init setup_slub_max_order(char *str)
{
- get_option (&str, &slub_max_order);
+ get_option(&str, &slub_max_order);
return 1;
}
@@ -2359,7 +2368,7 @@
static int __init setup_slub_min_objects(char *str)
{
- get_option (&str, &slub_min_objects);
+ get_option(&str, &slub_min_objects);
return 1;
}
@@ -2605,6 +2614,19 @@
}
EXPORT_SYMBOL(kfree);
+static unsigned long count_partial(struct kmem_cache_node *n)
+{
+ unsigned long flags;
+ unsigned long x = 0;
+ struct page *page;
+
+ spin_lock_irqsave(&n->list_lock, flags);
+ list_for_each_entry(page, &n->partial, lru)
+ x += page->inuse;
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ return x;
+}
+
/*
* kmem_cache_shrink removes empty slabs from the partial lists and sorts
* the remaining slabs by the number of items in use. The slabs with the
@@ -2931,7 +2953,7 @@
* Check if alignment is compatible.
* Courtesy of Adrian Drzewiecki
*/
- if ((s->size & ~(align -1)) != s->size)
+ if ((s->size & ~(align - 1)) != s->size)
continue;
if (s->size - size >= sizeof(void *))
@@ -3040,8 +3062,9 @@
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata slab_notifier =
- { &slab_cpuup_callback, NULL, 0 };
+static struct notifier_block __cpuinitdata slab_notifier = {
+ &slab_cpuup_callback, NULL, 0
+};
#endif
@@ -3076,19 +3099,6 @@
return slab_alloc(s, gfpflags, node, caller);
}
-static unsigned long count_partial(struct kmem_cache_node *n)
-{
- unsigned long flags;
- unsigned long x = 0;
- struct page *page;
-
- spin_lock_irqsave(&n->list_lock, flags);
- list_for_each_entry(page, &n->partial, lru)
- x += page->inuse;
- spin_unlock_irqrestore(&n->list_lock, flags);
- return x;
-}
-
#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
static int validate_slab(struct kmem_cache *s, struct page *page,
unsigned long *map)
@@ -3390,7 +3400,7 @@
static int list_locations(struct kmem_cache *s, char *buf,
enum track_item alloc)
{
- int n = 0;
+ int len = 0;
unsigned long i;
struct loc_track t = { 0, 0, NULL };
int node;
@@ -3421,54 +3431,54 @@
for (i = 0; i < t.count; i++) {
struct location *l = &t.loc[i];
- if (n > PAGE_SIZE - 100)
+ if (len > PAGE_SIZE - 100)
break;
- n += sprintf(buf + n, "%7ld ", l->count);
+ len += sprintf(buf + len, "%7ld ", l->count);
if (l->addr)
- n += sprint_symbol(buf + n, (unsigned long)l->addr);
+ len += sprint_symbol(buf + len, (unsigned long)l->addr);
else
- n += sprintf(buf + n, "<not-available>");
+ len += sprintf(buf + len, "<not-available>");
if (l->sum_time != l->min_time) {
unsigned long remainder;
- n += sprintf(buf + n, " age=%ld/%ld/%ld",
+ len += sprintf(buf + len, " age=%ld/%ld/%ld",
l->min_time,
div_long_long_rem(l->sum_time, l->count, &remainder),
l->max_time);
} else
- n += sprintf(buf + n, " age=%ld",
+ len += sprintf(buf + len, " age=%ld",
l->min_time);
if (l->min_pid != l->max_pid)
- n += sprintf(buf + n, " pid=%ld-%ld",
+ len += sprintf(buf + len, " pid=%ld-%ld",
l->min_pid, l->max_pid);
else
- n += sprintf(buf + n, " pid=%ld",
+ len += sprintf(buf + len, " pid=%ld",
l->min_pid);
if (num_online_cpus() > 1 && !cpus_empty(l->cpus) &&
- n < PAGE_SIZE - 60) {
- n += sprintf(buf + n, " cpus=");
- n += cpulist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+ len < PAGE_SIZE - 60) {
+ len += sprintf(buf + len, " cpus=");
+ len += cpulist_scnprintf(buf + len, PAGE_SIZE - len - 50,
l->cpus);
}
if (num_online_nodes() > 1 && !nodes_empty(l->nodes) &&
- n < PAGE_SIZE - 60) {
- n += sprintf(buf + n, " nodes=");
- n += nodelist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+ len < PAGE_SIZE - 60) {
+ len += sprintf(buf + len, " nodes=");
+ len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50,
l->nodes);
}
- n += sprintf(buf + n, "\n");
+ len += sprintf(buf + len, "\n");
}
free_loc_track(&t);
if (!t.count)
- n += sprintf(buf, "No data\n");
- return n;
+ len += sprintf(buf, "No data\n");
+ return len;
}
enum slab_stat_type {
@@ -3498,7 +3508,6 @@
for_each_possible_cpu(cpu) {
struct page *page;
- int node;
struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
if (!c)
@@ -3510,8 +3519,6 @@
continue;
if (page) {
if (flags & SO_CPU) {
- int x = 0;
-
if (flags & SO_OBJECTS)
x = page->inuse;
else
@@ -3848,24 +3855,24 @@
SLAB_ATTR_RO(free_calls);
#ifdef CONFIG_NUMA
-static ssize_t defrag_ratio_show(struct kmem_cache *s, char *buf)
+static ssize_t remote_node_defrag_ratio_show(struct kmem_cache *s, char *buf)
{
- return sprintf(buf, "%d\n", s->defrag_ratio / 10);
+ return sprintf(buf, "%d\n", s->remote_node_defrag_ratio / 10);
}
-static ssize_t defrag_ratio_store(struct kmem_cache *s,
+static ssize_t remote_node_defrag_ratio_store(struct kmem_cache *s,
const char *buf, size_t length)
{
int n = simple_strtoul(buf, NULL, 10);
if (n < 100)
- s->defrag_ratio = n * 10;
+ s->remote_node_defrag_ratio = n * 10;
return length;
}
-SLAB_ATTR(defrag_ratio);
+SLAB_ATTR(remote_node_defrag_ratio);
#endif
-static struct attribute * slab_attrs[] = {
+static struct attribute *slab_attrs[] = {
&slab_size_attr.attr,
&object_size_attr.attr,
&objs_per_slab_attr.attr,
@@ -3893,7 +3900,7 @@
&cache_dma_attr.attr,
#endif
#ifdef CONFIG_NUMA
- &defrag_ratio_attr.attr,
+ &remote_node_defrag_ratio_attr.attr,
#endif
NULL
};
@@ -3940,6 +3947,13 @@
return err;
}
+static void kmem_cache_release(struct kobject *kobj)
+{
+ struct kmem_cache *s = to_slab(kobj);
+
+ kfree(s);
+}
+
static struct sysfs_ops slab_sysfs_ops = {
.show = slab_attr_show,
.store = slab_attr_store,
@@ -3947,6 +3961,7 @@
static struct kobj_type slab_ktype = {
.sysfs_ops = &slab_sysfs_ops,
+ .release = kmem_cache_release
};
static int uevent_filter(struct kset *kset, struct kobject *kobj)
@@ -4048,6 +4063,7 @@
{
kobject_uevent(&s->kobj, KOBJ_REMOVE);
kobject_del(&s->kobj);
+ kobject_put(&s->kobj);
}
/*
diff --git a/mm/sparse.c b/mm/sparse.c
index a2183cb..f6a43c0 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -237,7 +237,7 @@
}
#endif /* CONFIG_MEMORY_HOTPLUG */
-static unsigned long *sparse_early_usemap_alloc(unsigned long pnum)
+static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
{
unsigned long *usemap;
struct mem_section *ms = __nr_to_section(pnum);
@@ -353,17 +353,9 @@
return __kmalloc_section_memmap(nr_pages);
}
-static int vaddr_in_vmalloc_area(void *addr)
-{
- if (addr >= (void *)VMALLOC_START &&
- addr < (void *)VMALLOC_END)
- return 1;
- return 0;
-}
-
static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
{
- if (vaddr_in_vmalloc_area(memmap))
+ if (is_vmalloc_addr(memmap))
vfree(memmap);
else
free_pages((unsigned long)memmap,
diff --git a/mm/swap.c b/mm/swap.c
index 9ac8832..57b7e25 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -41,7 +41,7 @@
* This path almost never happens for VM activity - pages are normally
* freed via pagevecs. But it gets used by networking.
*/
-static void fastcall __page_cache_release(struct page *page)
+static void __page_cache_release(struct page *page)
{
if (PageLRU(page)) {
unsigned long flags;
@@ -165,7 +165,7 @@
/*
* FIXME: speed this up?
*/
-void fastcall activate_page(struct page *page)
+void activate_page(struct page *page)
{
struct zone *zone = page_zone(page);
@@ -186,7 +186,7 @@
* inactive,referenced -> active,unreferenced
* active,unreferenced -> active,referenced
*/
-void fastcall mark_page_accessed(struct page *page)
+void mark_page_accessed(struct page *page)
{
if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) {
activate_page(page);
@@ -202,7 +202,7 @@
* lru_cache_add: add a page to the page lists
* @page: the page to add
*/
-void fastcall lru_cache_add(struct page *page)
+void lru_cache_add(struct page *page)
{
struct pagevec *pvec = &get_cpu_var(lru_add_pvecs);
@@ -212,7 +212,7 @@
put_cpu_var(lru_add_pvecs);
}
-void fastcall lru_cache_add_active(struct page *page)
+void lru_cache_add_active(struct page *page)
{
struct pagevec *pvec = &get_cpu_var(lru_add_active_pvecs);
diff --git a/mm/swap_state.c b/mm/swap_state.c
index b526356..ec42f01 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/kernel_stat.h>
#include <linux/swap.h>
+#include <linux/swapops.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
@@ -51,26 +52,22 @@
unsigned long del_total;
unsigned long find_success;
unsigned long find_total;
- unsigned long noent_race;
- unsigned long exist_race;
} swap_cache_info;
void show_swap_cache_info(void)
{
- printk("Swap cache: add %lu, delete %lu, find %lu/%lu, race %lu+%lu\n",
+ printk("Swap cache: add %lu, delete %lu, find %lu/%lu\n",
swap_cache_info.add_total, swap_cache_info.del_total,
- swap_cache_info.find_success, swap_cache_info.find_total,
- swap_cache_info.noent_race, swap_cache_info.exist_race);
+ swap_cache_info.find_success, swap_cache_info.find_total);
printk("Free swap = %lukB\n", nr_swap_pages << (PAGE_SHIFT - 10));
printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10));
}
/*
- * __add_to_swap_cache resembles add_to_page_cache on swapper_space,
+ * add_to_swap_cache resembles add_to_page_cache on swapper_space,
* but sets SwapCache flag and private instead of mapping and index.
*/
-static int __add_to_swap_cache(struct page *page, swp_entry_t entry,
- gfp_t gfp_mask)
+int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
{
int error;
@@ -88,6 +85,7 @@
set_page_private(page, entry.val);
total_swapcache_pages++;
__inc_zone_page_state(page, NR_FILE_PAGES);
+ INC_CACHE_INFO(add_total);
}
write_unlock_irq(&swapper_space.tree_lock);
radix_tree_preload_end();
@@ -95,31 +93,6 @@
return error;
}
-static int add_to_swap_cache(struct page *page, swp_entry_t entry)
-{
- int error;
-
- BUG_ON(PageLocked(page));
- if (!swap_duplicate(entry)) {
- INC_CACHE_INFO(noent_race);
- return -ENOENT;
- }
- SetPageLocked(page);
- error = __add_to_swap_cache(page, entry, GFP_KERNEL);
- /*
- * Anon pages are already on the LRU, we don't run lru_cache_add here.
- */
- if (error) {
- ClearPageLocked(page);
- swap_free(entry);
- if (error == -EEXIST)
- INC_CACHE_INFO(exist_race);
- return error;
- }
- INC_CACHE_INFO(add_total);
- return 0;
-}
-
/*
* This must be called only on pages that have
* been verified to be in the swap cache.
@@ -152,6 +125,7 @@
int err;
BUG_ON(!PageLocked(page));
+ BUG_ON(!PageUptodate(page));
for (;;) {
entry = get_swap_page();
@@ -169,18 +143,15 @@
/*
* Add it to the swap cache and mark it dirty
*/
- err = __add_to_swap_cache(page, entry,
+ err = add_to_swap_cache(page, entry,
gfp_mask|__GFP_NOMEMALLOC|__GFP_NOWARN);
switch (err) {
case 0: /* Success */
- SetPageUptodate(page);
SetPageDirty(page);
- INC_CACHE_INFO(add_total);
return 1;
case -EEXIST:
/* Raced with "speculative" read_swap_cache_async */
- INC_CACHE_INFO(exist_race);
swap_free(entry);
continue;
default:
@@ -211,40 +182,6 @@
page_cache_release(page);
}
-/*
- * Strange swizzling function only for use by shmem_writepage
- */
-int move_to_swap_cache(struct page *page, swp_entry_t entry)
-{
- int err = __add_to_swap_cache(page, entry, GFP_ATOMIC);
- if (!err) {
- remove_from_page_cache(page);
- page_cache_release(page); /* pagecache ref */
- if (!swap_duplicate(entry))
- BUG();
- SetPageDirty(page);
- INC_CACHE_INFO(add_total);
- } else if (err == -EEXIST)
- INC_CACHE_INFO(exist_race);
- return err;
-}
-
-/*
- * Strange swizzling function for shmem_getpage (and shmem_unuse)
- */
-int move_from_swap_cache(struct page *page, unsigned long index,
- struct address_space *mapping)
-{
- int err = add_to_page_cache(page, mapping, index, GFP_ATOMIC);
- if (!err) {
- delete_from_swap_cache(page);
- /* shift page from clean_pages to dirty_pages list */
- ClearPageDirty(page);
- set_page_dirty(page);
- }
- return err;
-}
-
/*
* If we are the only user, then try to free up the swap cache.
*
@@ -317,7 +254,7 @@
* A failure return means that either the page allocation failed or that
* the swap entry is no longer in use.
*/
-struct page *read_swap_cache_async(swp_entry_t entry,
+struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
struct vm_area_struct *vma, unsigned long addr)
{
struct page *found_page, *new_page = NULL;
@@ -337,23 +274,27 @@
* Get a new page to read into from swap.
*/
if (!new_page) {
- new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
- vma, addr);
+ new_page = alloc_page_vma(gfp_mask, vma, addr);
if (!new_page)
break; /* Out of memory */
}
/*
+ * Swap entry may have been freed since our caller observed it.
+ */
+ if (!swap_duplicate(entry))
+ break;
+
+ /*
* Associate the page with swap entry in the swap cache.
- * May fail (-ENOENT) if swap entry has been freed since
- * our caller observed it. May fail (-EEXIST) if there
- * is already a page associated with this entry in the
- * swap cache: added by a racing read_swap_cache_async,
- * or by try_to_swap_out (or shmem_writepage) re-using
- * the just freed swap entry for an existing page.
+ * May fail (-EEXIST) if there is already a page associated
+ * with this entry in the swap cache: added by a racing
+ * read_swap_cache_async, or add_to_swap or shmem_writepage
+ * re-using the just freed swap entry for an existing page.
* May fail (-ENOMEM) if radix-tree node allocation failed.
*/
- err = add_to_swap_cache(new_page, entry);
+ SetPageLocked(new_page);
+ err = add_to_swap_cache(new_page, entry, gfp_mask & GFP_KERNEL);
if (!err) {
/*
* Initiate read into locked page and return.
@@ -362,9 +303,57 @@
swap_readpage(NULL, new_page);
return new_page;
}
- } while (err != -ENOENT && err != -ENOMEM);
+ ClearPageLocked(new_page);
+ swap_free(entry);
+ } while (err != -ENOMEM);
if (new_page)
page_cache_release(new_page);
return found_page;
}
+
+/**
+ * swapin_readahead - swap in pages in hope we need them soon
+ * @entry: swap entry of this memory
+ * @vma: user vma this address belongs to
+ * @addr: target address for mempolicy
+ *
+ * Returns the struct page for entry and addr, after queueing swapin.
+ *
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time. We also make sure to queue
+ * the 'original' request together with the readahead ones...
+ *
+ * This has been extended to use the NUMA policies from the mm triggering
+ * the readahead.
+ *
+ * Caller must hold down_read on the vma->vm_mm if vma is not NULL.
+ */
+struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
+ struct vm_area_struct *vma, unsigned long addr)
+{
+ int nr_pages;
+ struct page *page;
+ unsigned long offset;
+ unsigned long end_offset;
+
+ /*
+ * Get starting offset for readaround, and number of pages to read.
+ * Adjust starting address by readbehind (for NUMA interleave case)?
+ * No, it's very unlikely that swap layout would follow vma layout,
+ * more likely that neighbouring swap pages came from the same node:
+ * so use the same "addr" to choose the same node for each swap read.
+ */
+ nr_pages = valid_swaphandles(entry, &offset);
+ for (end_offset = offset + nr_pages; offset < end_offset; offset++) {
+ /* Ok, do the async read-ahead now */
+ page = read_swap_cache_async(swp_entry(swp_type(entry), offset),
+ gfp_mask, vma, addr);
+ if (!page)
+ break;
+ page_cache_release(page);
+ }
+ lru_add_drain(); /* Push any new pages onto the LRU now */
+ return read_swap_cache_async(entry, gfp_mask, vma, addr);
+}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f071648..eade24d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -506,9 +506,19 @@
* just let do_wp_page work it out if a write is requested later - to
* force COW, vm_page_prot omits write permission from any private vma.
*/
-static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
+static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
unsigned long addr, swp_entry_t entry, struct page *page)
{
+ spinlock_t *ptl;
+ pte_t *pte;
+ int found = 1;
+
+ pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+ if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
+ found = 0;
+ goto out;
+ }
+
inc_mm_counter(vma->vm_mm, anon_rss);
get_page(page);
set_pte_at(vma->vm_mm, addr, pte,
@@ -520,6 +530,9 @@
* immediately swapped out again after swapon.
*/
activate_page(page);
+out:
+ pte_unmap_unlock(pte, ptl);
+ return found;
}
static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
@@ -528,22 +541,33 @@
{
pte_t swp_pte = swp_entry_to_pte(entry);
pte_t *pte;
- spinlock_t *ptl;
int found = 0;
- pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+ /*
+ * We don't actually need pte lock while scanning for swp_pte: since
+ * we hold page lock and mmap_sem, swp_pte cannot be inserted into the
+ * page table while we're scanning; though it could get zapped, and on
+ * some architectures (e.g. x86_32 with PAE) we might catch a glimpse
+ * of unmatched parts which look like swp_pte, so unuse_pte must
+ * recheck under pte lock. Scanning without pte lock lets it be
+ * preemptible whenever CONFIG_PREEMPT but not CONFIG_HIGHPTE.
+ */
+ pte = pte_offset_map(pmd, addr);
do {
/*
* swapoff spends a _lot_ of time in this loop!
* Test inline before going to call unuse_pte.
*/
if (unlikely(pte_same(*pte, swp_pte))) {
- unuse_pte(vma, pte++, addr, entry, page);
- found = 1;
- break;
+ pte_unmap(pte);
+ found = unuse_pte(vma, pmd, addr, entry, page);
+ if (found)
+ goto out;
+ pte = pte_offset_map(pmd, addr);
}
} while (pte++, addr += PAGE_SIZE, addr != end);
- pte_unmap_unlock(pte - 1, ptl);
+ pte_unmap(pte - 1);
+out:
return found;
}
@@ -730,7 +754,8 @@
*/
swap_map = &si->swap_map[i];
entry = swp_entry(type, i);
- page = read_swap_cache_async(entry, NULL, 0);
+ page = read_swap_cache_async(entry,
+ GFP_HIGHUSER_MOVABLE, NULL, 0);
if (!page) {
/*
* Either swap_duplicate() failed because entry
@@ -789,7 +814,7 @@
atomic_inc(&new_start_mm->mm_users);
atomic_inc(&prev_mm->mm_users);
spin_lock(&mmlist_lock);
- while (*swap_map > 1 && !retval &&
+ while (*swap_map > 1 && !retval && !shmem &&
(p = p->next) != &start_mm->mmlist) {
mm = list_entry(p, struct mm_struct, mmlist);
if (!atomic_inc_not_zero(&mm->mm_users))
@@ -821,6 +846,13 @@
mmput(start_mm);
start_mm = new_start_mm;
}
+ if (shmem) {
+ /* page has already been unlocked and released */
+ if (shmem > 0)
+ continue;
+ retval = shmem;
+ break;
+ }
if (retval) {
unlock_page(page);
page_cache_release(page);
@@ -859,12 +891,6 @@
* read from disk into another page. Splitting into two
* pages would be incorrect if swap supported "shared
* private" pages, but they are handled by tmpfs files.
- *
- * Note shmem_unuse already deleted a swappage from
- * the swap cache, unless the move to filepage failed:
- * in which case it left swappage in cache, lowered its
- * swap count to pass quickly through the loops above,
- * and now we must reincrement count to try again later.
*/
if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
struct writeback_control wbc = {
@@ -875,12 +901,8 @@
lock_page(page);
wait_on_page_writeback(page);
}
- if (PageSwapCache(page)) {
- if (shmem)
- swap_duplicate(entry);
- else
- delete_from_swap_cache(page);
- }
+ if (PageSwapCache(page))
+ delete_from_swap_cache(page);
/*
* So we could skip searching mms once swap count went
@@ -1768,31 +1790,48 @@
*/
int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
{
+ struct swap_info_struct *si;
int our_page_cluster = page_cluster;
- int ret = 0, i = 1 << our_page_cluster;
- unsigned long toff;
- struct swap_info_struct *swapdev = swp_type(entry) + swap_info;
+ pgoff_t target, toff;
+ pgoff_t base, end;
+ int nr_pages = 0;
if (!our_page_cluster) /* no readahead */
return 0;
- toff = (swp_offset(entry) >> our_page_cluster) << our_page_cluster;
- if (!toff) /* first page is swap header */
- toff++, i--;
- *offset = toff;
+
+ si = &swap_info[swp_type(entry)];
+ target = swp_offset(entry);
+ base = (target >> our_page_cluster) << our_page_cluster;
+ end = base + (1 << our_page_cluster);
+ if (!base) /* first page is swap header */
+ base++;
spin_lock(&swap_lock);
- do {
- /* Don't read-ahead past the end of the swap area */
- if (toff >= swapdev->max)
- break;
+ if (end > si->max) /* don't go beyond end of map */
+ end = si->max;
+
+ /* Count contiguous allocated slots above our target */
+ for (toff = target; ++toff < end; nr_pages++) {
/* Don't read in free or bad pages */
- if (!swapdev->swap_map[toff])
+ if (!si->swap_map[toff])
break;
- if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
+ if (si->swap_map[toff] == SWAP_MAP_BAD)
break;
- toff++;
- ret++;
- } while (--i);
+ }
+ /* Count contiguous allocated slots below our target */
+ for (toff = target; --toff >= base; nr_pages++) {
+ /* Don't read in free or bad pages */
+ if (!si->swap_map[toff])
+ break;
+ if (si->swap_map[toff] == SWAP_MAP_BAD)
+ break;
+ }
spin_unlock(&swap_lock);
- return ret;
+
+ /*
+ * Indicate starting offset, and return number of pages to get:
+ * if only 1, say 0, since there's then no readahead to be done.
+ */
+ *offset = ++toff;
+ return nr_pages? ++nr_pages: 0;
}
diff --git a/mm/tiny-shmem.c b/mm/tiny-shmem.c
index d436a9c..7020836 100644
--- a/mm/tiny-shmem.c
+++ b/mm/tiny-shmem.c
@@ -121,18 +121,6 @@
return 0;
}
-#if 0
-int shmem_mmap(struct file *file, struct vm_area_struct *vma)
-{
- file_accessed(file);
-#ifndef CONFIG_MMU
- return ramfs_nommu_mmap(file, vma);
-#else
- return 0;
-#endif
-}
-#endif /* 0 */
-
#ifndef CONFIG_MMU
unsigned long shmem_get_unmapped_area(struct file *file,
unsigned long addr,
diff --git a/mm/truncate.c b/mm/truncate.c
index cadc156..c35c49e 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -21,7 +21,7 @@
/**
- * do_invalidatepage - invalidate part of all of a page
+ * do_invalidatepage - invalidate part or all of a page
* @page: the page which is affected
* @offset: the index of the truncation point
*
@@ -48,7 +48,7 @@
static inline void truncate_partial_page(struct page *page, unsigned partial)
{
- zero_user_page(page, partial, PAGE_CACHE_SIZE - partial, KM_USER0);
+ zero_user_segment(page, partial, PAGE_CACHE_SIZE);
if (PagePrivate(page))
do_invalidatepage(page, partial);
}
@@ -84,7 +84,7 @@
/*
* If truncate cannot remove the fs-private metadata from the page, the page
- * becomes anonymous. It will be left on the LRU and may even be mapped into
+ * becomes orphaned. It will be left on the LRU and may even be mapped into
* user pagetables if we're racing with filemap_fault().
*
* We need to bale out if page->mapping is no longer equal to the original
@@ -98,11 +98,11 @@
if (page->mapping != mapping)
return;
- cancel_dirty_page(page, PAGE_CACHE_SIZE);
-
if (PagePrivate(page))
do_invalidatepage(page, 0);
+ cancel_dirty_page(page, PAGE_CACHE_SIZE);
+
remove_from_page_cache(page);
ClearPageUptodate(page);
ClearPageMappedToDisk(page);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index af77e17..0536dde 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -166,6 +166,44 @@
}
EXPORT_SYMBOL_GPL(map_vm_area);
+/*
+ * Map a vmalloc()-space virtual address to the physical page.
+ */
+struct page *vmalloc_to_page(const void *vmalloc_addr)
+{
+ unsigned long addr = (unsigned long) vmalloc_addr;
+ struct page *page = NULL;
+ pgd_t *pgd = pgd_offset_k(addr);
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ pte = *ptep;
+ if (pte_present(pte))
+ page = pte_page(pte);
+ pte_unmap(ptep);
+ }
+ }
+ }
+ return page;
+}
+EXPORT_SYMBOL(vmalloc_to_page);
+
+/*
+ * Map a vmalloc()-space virtual address to the physical page frame number.
+ */
+unsigned long vmalloc_to_pfn(const void *vmalloc_addr)
+{
+ return page_to_pfn(vmalloc_to_page(vmalloc_addr));
+}
+EXPORT_SYMBOL(vmalloc_to_pfn);
+
static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end,
int node, gfp_t gfp_mask)
@@ -216,6 +254,10 @@
if (addr > end - size)
goto out;
}
+ if ((size + addr) < addr)
+ goto out;
+ if (addr > end - size)
+ goto out;
found:
area->next = *p;
@@ -268,7 +310,7 @@
}
/* Caller must hold vmlist_lock */
-static struct vm_struct *__find_vm_area(void *addr)
+static struct vm_struct *__find_vm_area(const void *addr)
{
struct vm_struct *tmp;
@@ -281,7 +323,7 @@
}
/* Caller must hold vmlist_lock */
-static struct vm_struct *__remove_vm_area(void *addr)
+static struct vm_struct *__remove_vm_area(const void *addr)
{
struct vm_struct **p, *tmp;
@@ -310,7 +352,7 @@
* This function returns the found VM area, but using it is NOT safe
* on SMP machines, except for its size or flags.
*/
-struct vm_struct *remove_vm_area(void *addr)
+struct vm_struct *remove_vm_area(const void *addr)
{
struct vm_struct *v;
write_lock(&vmlist_lock);
@@ -319,7 +361,7 @@
return v;
}
-static void __vunmap(void *addr, int deallocate_pages)
+static void __vunmap(const void *addr, int deallocate_pages)
{
struct vm_struct *area;
@@ -346,8 +388,10 @@
int i;
for (i = 0; i < area->nr_pages; i++) {
- BUG_ON(!area->pages[i]);
- __free_page(area->pages[i]);
+ struct page *page = area->pages[i];
+
+ BUG_ON(!page);
+ __free_page(page);
}
if (area->flags & VM_VPAGES)
@@ -370,7 +414,7 @@
*
* Must not be called in interrupt context.
*/
-void vfree(void *addr)
+void vfree(const void *addr)
{
BUG_ON(in_interrupt());
__vunmap(addr, 1);
@@ -386,7 +430,7 @@
*
* Must not be called in interrupt context.
*/
-void vunmap(void *addr)
+void vunmap(const void *addr)
{
BUG_ON(in_interrupt());
__vunmap(addr, 0);
@@ -423,8 +467,8 @@
}
EXPORT_SYMBOL(vmap);
-void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
- pgprot_t prot, int node)
+static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
+ pgprot_t prot, int node)
{
struct page **pages;
unsigned int nr_pages, array_size, i;
@@ -451,15 +495,19 @@
}
for (i = 0; i < area->nr_pages; i++) {
+ struct page *page;
+
if (node < 0)
- area->pages[i] = alloc_page(gfp_mask);
+ page = alloc_page(gfp_mask);
else
- area->pages[i] = alloc_pages_node(node, gfp_mask, 0);
- if (unlikely(!area->pages[i])) {
+ page = alloc_pages_node(node, gfp_mask, 0);
+
+ if (unlikely(!page)) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
+ area->pages[i] = page;
}
if (map_vm_area(area, prot, &pages))
diff --git a/mm/vmstat.c b/mm/vmstat.c
index e8d846f..422d960 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -21,21 +21,14 @@
static void sum_vm_events(unsigned long *ret, cpumask_t *cpumask)
{
- int cpu = 0;
+ int cpu;
int i;
memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
- cpu = first_cpu(*cpumask);
- while (cpu < NR_CPUS) {
+ for_each_cpu_mask(cpu, *cpumask) {
struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
- cpu = next_cpu(cpu, *cpumask);
-
- if (cpu < NR_CPUS)
- prefetch(&per_cpu(vm_event_states, cpu));
-
-
for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
ret[i] += this->event[i];
}
@@ -284,6 +277,10 @@
/*
* Update the zone counters for one cpu.
*
+ * The cpu specified must be either the current cpu or a processor that
+ * is not online. If it is the current cpu then the execution thread must
+ * be pinned to the current cpu.
+ *
* Note that refresh_cpu_vm_stats strives to only access
* node local memory. The per cpu pagesets on remote zones are placed
* in the memory local to the processor using that pageset. So the
@@ -299,7 +296,7 @@
{
struct zone *zone;
int i;
- unsigned long flags;
+ int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
for_each_zone(zone) {
struct per_cpu_pageset *p;
@@ -311,15 +308,19 @@
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
if (p->vm_stat_diff[i]) {
+ unsigned long flags;
+ int v;
+
local_irq_save(flags);
- zone_page_state_add(p->vm_stat_diff[i],
- zone, i);
+ v = p->vm_stat_diff[i];
p->vm_stat_diff[i] = 0;
+ local_irq_restore(flags);
+ atomic_long_add(v, &zone->vm_stat[i]);
+ global_diff[i] += v;
#ifdef CONFIG_NUMA
/* 3 seconds idle till flush */
p->expire = 3;
#endif
- local_irq_restore(flags);
}
#ifdef CONFIG_NUMA
/*
@@ -329,7 +330,7 @@
* Check if there are pages remaining in this pageset
* if not then there is nothing to expire.
*/
- if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count))
+ if (!p->expire || !p->pcp.count)
continue;
/*
@@ -344,13 +345,14 @@
if (p->expire)
continue;
- if (p->pcp[0].count)
- drain_zone_pages(zone, p->pcp + 0);
-
- if (p->pcp[1].count)
- drain_zone_pages(zone, p->pcp + 1);
+ if (p->pcp.count)
+ drain_zone_pages(zone, &p->pcp);
#endif
}
+
+ for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+ if (global_diff[i])
+ atomic_long_add(global_diff[i], &vm_stat[i]);
}
#endif
@@ -681,20 +683,17 @@
"\n pagesets");
for_each_online_cpu(i) {
struct per_cpu_pageset *pageset;
- int j;
pageset = zone_pcp(zone, i);
- for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
- seq_printf(m,
- "\n cpu: %i pcp: %i"
- "\n count: %i"
- "\n high: %i"
- "\n batch: %i",
- i, j,
- pageset->pcp[j].count,
- pageset->pcp[j].high,
- pageset->pcp[j].batch);
- }
+ seq_printf(m,
+ "\n cpu: %i"
+ "\n count: %i"
+ "\n high: %i"
+ "\n batch: %i",
+ i,
+ pageset->pcp.count,
+ pageset->pcp.high,
+ pageset->pcp.batch);
#ifdef CONFIG_SMP
seq_printf(m, "\n vm stats threshold: %d",
pageset->stat_threshold);
diff --git a/net/9p/Makefile b/net/9p/Makefile
index d3abb24..8a10511 100644
--- a/net/9p/Makefile
+++ b/net/9p/Makefile
@@ -4,7 +4,6 @@
9pnet-objs := \
mod.o \
- mux.o \
client.o \
conv.o \
error.o \
diff --git a/net/9p/client.c b/net/9p/client.c
index af91993..84e087e 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -3,6 +3,7 @@
*
* 9P Client
*
+ * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +26,7 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/poll.h>
#include <linux/idr.h>
#include <linux/mutex.h>
#include <linux/sched.h>
@@ -32,15 +34,97 @@
#include <net/9p/9p.h>
#include <linux/parser.h>
#include <net/9p/transport.h>
-#include <net/9p/conn.h>
#include <net/9p/client.h>
static struct p9_fid *p9_fid_create(struct p9_client *clnt);
static void p9_fid_destroy(struct p9_fid *fid);
static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
-struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
- int dotu)
+/*
+ * Client Option Parsing (code inspired by NFS code)
+ * - a little lazy - parse all client options
+ */
+
+enum {
+ Opt_msize,
+ Opt_trans,
+ Opt_legacy,
+ Opt_err,
+};
+
+static match_table_t tokens = {
+ {Opt_msize, "msize=%u"},
+ {Opt_legacy, "noextend"},
+ {Opt_trans, "trans=%s"},
+ {Opt_err, NULL},
+};
+
+/**
+ * v9fs_parse_options - parse mount options into session structure
+ * @options: options string passed from mount
+ * @v9ses: existing v9fs session information
+ *
+ */
+
+static void parse_opts(char *options, struct p9_client *clnt)
+{
+ char *p;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
+ int ret;
+
+ clnt->trans_mod = v9fs_default_trans();
+ clnt->dotu = 1;
+ clnt->msize = 8192;
+
+ if (!options)
+ return;
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
+ if (!*p)
+ continue;
+ token = match_token(p, tokens, args);
+ if (token < Opt_trans) {
+ ret = match_int(&args[0], &option);
+ if (ret < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ continue;
+ }
+ }
+ switch (token) {
+ case Opt_msize:
+ clnt->msize = option;
+ break;
+ case Opt_trans:
+ clnt->trans_mod = v9fs_match_trans(&args[0]);
+ break;
+ case Opt_legacy:
+ clnt->dotu = 0;
+ break;
+ default:
+ continue;
+ }
+ }
+}
+
+
+/**
+ * p9_client_rpc - sends 9P request and waits until a response is available.
+ * The function can be interrupted.
+ * @c: client data
+ * @tc: request to be sent
+ * @rc: pointer where a pointer to the response is stored
+ */
+int
+p9_client_rpc(struct p9_client *c, struct p9_fcall *tc,
+ struct p9_fcall **rc)
+{
+ return c->trans->rpc(c->trans, tc, rc);
+}
+
+struct p9_client *p9_client_create(const char *dev_name, char *options)
{
int err, n;
struct p9_client *clnt;
@@ -54,12 +138,7 @@
if (!clnt)
return ERR_PTR(-ENOMEM);
- P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
- clnt, trans, msize, dotu);
spin_lock_init(&clnt->lock);
- clnt->trans = trans;
- clnt->msize = msize;
- clnt->dotu = dotu;
INIT_LIST_HEAD(&clnt->fidlist);
clnt->fidpool = p9_idpool_create();
if (!clnt->fidpool) {
@@ -68,13 +147,29 @@
goto error;
}
- clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
- if (IS_ERR(clnt->conn)) {
- err = PTR_ERR(clnt->conn);
- clnt->conn = NULL;
+ parse_opts(options, clnt);
+ if (clnt->trans_mod == NULL) {
+ err = -EPROTONOSUPPORT;
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "No transport defined or default transport\n");
goto error;
}
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
+ clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
+
+
+ clnt->trans = clnt->trans_mod->create(dev_name, options, clnt->msize,
+ clnt->dotu);
+ if (IS_ERR(clnt->trans)) {
+ err = PTR_ERR(clnt->trans);
+ clnt->trans = NULL;
+ goto error;
+ }
+
+ if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
+ clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
+
tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
if (IS_ERR(tc)) {
err = PTR_ERR(tc);
@@ -82,7 +177,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -117,10 +212,6 @@
struct p9_fid *fid, *fidptr;
P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
- if (clnt->conn) {
- p9_conn_destroy(clnt->conn);
- clnt->conn = NULL;
- }
if (clnt->trans) {
clnt->trans->close(clnt->trans);
@@ -142,7 +233,6 @@
{
P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
clnt->trans->status = Disconnected;
- p9_conn_cancel(clnt->conn, -EIO);
}
EXPORT_SYMBOL(p9_client_disconnect);
@@ -174,7 +264,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -219,7 +309,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -270,7 +360,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err) {
if (rc && rc->id == P9_RWALK)
goto clunk_fid;
@@ -305,7 +395,7 @@
goto error;
}
- p9_conn_rpc(clnt->conn, tc, &rc);
+ p9_client_rpc(clnt, tc, &rc);
error:
kfree(tc);
@@ -339,7 +429,7 @@
goto done;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto done;
@@ -378,7 +468,7 @@
goto done;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto done;
@@ -411,7 +501,7 @@
goto done;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto done;
@@ -443,7 +533,7 @@
goto done;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto done;
@@ -485,7 +575,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -542,7 +632,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -596,7 +686,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -660,7 +750,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -731,7 +821,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -773,7 +863,7 @@
goto done;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
done:
kfree(tc);
@@ -830,7 +920,7 @@
goto error;
}
- err = p9_conn_rpc(clnt->conn, tc, &rc);
+ err = p9_client_rpc(clnt, tc, &rc);
if (err)
goto error;
@@ -901,16 +991,21 @@
memmove(ret, st, sizeof(struct p9_stat));
p = ((char *) ret) + sizeof(struct p9_stat);
memmove(p, st->name.str, st->name.len);
+ ret->name.str = p;
p += st->name.len;
memmove(p, st->uid.str, st->uid.len);
+ ret->uid.str = p;
p += st->uid.len;
memmove(p, st->gid.str, st->gid.len);
+ ret->gid.str = p;
p += st->gid.len;
memmove(p, st->muid.str, st->muid.len);
+ ret->muid.str = p;
p += st->muid.len;
if (dotu) {
memmove(p, st->extension.str, st->extension.len);
+ ret->extension.str = p;
p += st->extension.len;
}
diff --git a/net/9p/fcprint.c b/net/9p/fcprint.c
index b1ae8ec..40244fb 100644
--- a/net/9p/fcprint.c
+++ b/net/9p/fcprint.c
@@ -347,12 +347,12 @@
return ret;
}
-
#else
int
p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
{
return 0;
}
-EXPORT_SYMBOL(p9_printfcall);
#endif /* CONFIG_NET_9P_DEBUG */
+EXPORT_SYMBOL(p9_printfcall);
+
diff --git a/net/9p/mod.c b/net/9p/mod.c
index 8f9763a..c285aab 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -106,15 +106,10 @@
*/
static int __init init_p9(void)
{
- int ret;
+ int ret = 0;
p9_error_init();
printk(KERN_INFO "Installing 9P2000 support\n");
- ret = p9_mux_global_init();
- if (ret) {
- printk(KERN_WARNING "9p: starting mux failed\n");
- return ret;
- }
return ret;
}
@@ -126,7 +121,7 @@
static void __exit exit_p9(void)
{
- p9_mux_global_exit();
+ printk(KERN_INFO "Unloading 9P2000 support\n");
}
module_init(init_p9)
diff --git a/net/9p/mux.c b/net/9p/mux.c
deleted file mode 100644
index c9f0805..0000000
--- a/net/9p/mux.c
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * net/9p/mux.c
- *
- * Protocol Multiplexer
- *
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kthread.h>
-#include <linux/idr.h>
-#include <linux/mutex.h>
-#include <net/9p/9p.h>
-#include <linux/parser.h>
-#include <net/9p/transport.h>
-#include <net/9p/conn.h>
-
-#define ERREQFLUSH 1
-#define SCHED_TIMEOUT 10
-#define MAXPOLLWADDR 2
-
-enum {
- Rworksched = 1, /* read work scheduled or running */
- Rpending = 2, /* can read */
- Wworksched = 4, /* write work scheduled or running */
- Wpending = 8, /* can write */
-};
-
-enum {
- None,
- Flushing,
- Flushed,
-};
-
-struct p9_mux_poll_task;
-
-struct p9_req {
- spinlock_t lock; /* protect request structure */
- int tag;
- struct p9_fcall *tcall;
- struct p9_fcall *rcall;
- int err;
- p9_conn_req_callback cb;
- void *cba;
- int flush;
- struct list_head req_list;
-};
-
-struct p9_conn {
- spinlock_t lock; /* protect lock structure */
- struct list_head mux_list;
- struct p9_mux_poll_task *poll_task;
- int msize;
- unsigned char *extended;
- struct p9_trans *trans;
- struct p9_idpool *tagpool;
- int err;
- wait_queue_head_t equeue;
- struct list_head req_list;
- struct list_head unsent_req_list;
- struct p9_fcall *rcall;
- int rpos;
- char *rbuf;
- int wpos;
- int wsize;
- char *wbuf;
- wait_queue_t poll_wait[MAXPOLLWADDR];
- wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
- poll_table pt;
- struct work_struct rq;
- struct work_struct wq;
- unsigned long wsched;
-};
-
-struct p9_mux_poll_task {
- struct task_struct *task;
- struct list_head mux_list;
- int muxnum;
-};
-
-struct p9_mux_rpc {
- struct p9_conn *m;
- int err;
- struct p9_fcall *tcall;
- struct p9_fcall *rcall;
- wait_queue_head_t wqueue;
-};
-
-static int p9_poll_proc(void *);
-static void p9_read_work(struct work_struct *work);
-static void p9_write_work(struct work_struct *work);
-static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
- poll_table * p);
-static u16 p9_mux_get_tag(struct p9_conn *);
-static void p9_mux_put_tag(struct p9_conn *, u16);
-
-static DEFINE_MUTEX(p9_mux_task_lock);
-static struct workqueue_struct *p9_mux_wq;
-
-static int p9_mux_num;
-static int p9_mux_poll_task_num;
-static struct p9_mux_poll_task p9_mux_poll_tasks[100];
-
-int p9_mux_global_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
- p9_mux_poll_tasks[i].task = NULL;
-
- p9_mux_wq = create_workqueue("v9fs");
- if (!p9_mux_wq) {
- printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void p9_mux_global_exit(void)
-{
- destroy_workqueue(p9_mux_wq);
-}
-
-/**
- * p9_mux_calc_poll_procs - calculates the number of polling procs
- * based on the number of mounted v9fs filesystems.
- *
- * The current implementation returns sqrt of the number of mounts.
- */
-static int p9_mux_calc_poll_procs(int muxnum)
-{
- int n;
-
- if (p9_mux_poll_task_num)
- n = muxnum / p9_mux_poll_task_num +
- (muxnum % p9_mux_poll_task_num ? 1 : 0);
- else
- n = 1;
-
- if (n > ARRAY_SIZE(p9_mux_poll_tasks))
- n = ARRAY_SIZE(p9_mux_poll_tasks);
-
- return n;
-}
-
-static int p9_mux_poll_start(struct p9_conn *m)
-{
- int i, n;
- struct p9_mux_poll_task *vpt, *vptlast;
- struct task_struct *pproc;
-
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
- p9_mux_poll_task_num);
- mutex_lock(&p9_mux_task_lock);
-
- n = p9_mux_calc_poll_procs(p9_mux_num + 1);
- if (n > p9_mux_poll_task_num) {
- for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
- if (p9_mux_poll_tasks[i].task == NULL) {
- vpt = &p9_mux_poll_tasks[i];
- P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
- vpt);
- pproc = kthread_create(p9_poll_proc, vpt,
- "v9fs-poll");
-
- if (!IS_ERR(pproc)) {
- vpt->task = pproc;
- INIT_LIST_HEAD(&vpt->mux_list);
- vpt->muxnum = 0;
- p9_mux_poll_task_num++;
- wake_up_process(vpt->task);
- }
- break;
- }
- }
-
- if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
- P9_DPRINTK(P9_DEBUG_ERROR,
- "warning: no free poll slots\n");
- }
-
- n = (p9_mux_num + 1) / p9_mux_poll_task_num +
- ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
-
- vptlast = NULL;
- for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
- vpt = &p9_mux_poll_tasks[i];
- if (vpt->task != NULL) {
- vptlast = vpt;
- if (vpt->muxnum < n) {
- P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
- list_add(&m->mux_list, &vpt->mux_list);
- vpt->muxnum++;
- m->poll_task = vpt;
- memset(&m->poll_waddr, 0,
- sizeof(m->poll_waddr));
- init_poll_funcptr(&m->pt, p9_pollwait);
- break;
- }
- }
- }
-
- if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
- if (vptlast == NULL) {
- mutex_unlock(&p9_mux_task_lock);
- return -ENOMEM;
- }
-
- P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
- list_add(&m->mux_list, &vptlast->mux_list);
- vptlast->muxnum++;
- m->poll_task = vptlast;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- init_poll_funcptr(&m->pt, p9_pollwait);
- }
-
- p9_mux_num++;
- mutex_unlock(&p9_mux_task_lock);
-
- return 0;
-}
-
-static void p9_mux_poll_stop(struct p9_conn *m)
-{
- int i;
- struct p9_mux_poll_task *vpt;
-
- mutex_lock(&p9_mux_task_lock);
- vpt = m->poll_task;
- list_del(&m->mux_list);
- for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
- if (m->poll_waddr[i] != NULL) {
- remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
- m->poll_waddr[i] = NULL;
- }
- }
- vpt->muxnum--;
- if (!vpt->muxnum) {
- P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
- kthread_stop(vpt->task);
- vpt->task = NULL;
- p9_mux_poll_task_num--;
- }
- p9_mux_num--;
- mutex_unlock(&p9_mux_task_lock);
-}
-
-/**
- * p9_conn_create - allocate and initialize the per-session mux data
- * Creates the polling task if this is the first session.
- *
- * @trans - transport structure
- * @msize - maximum message size
- * @extended - pointer to the extended flag
- */
-struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
- unsigned char *extended)
-{
- int i, n;
- struct p9_conn *m, *mtmp;
-
- P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, msize);
- m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
- if (!m)
- return ERR_PTR(-ENOMEM);
-
- spin_lock_init(&m->lock);
- INIT_LIST_HEAD(&m->mux_list);
- m->msize = msize;
- m->extended = extended;
- m->trans = trans;
- m->tagpool = p9_idpool_create();
- if (IS_ERR(m->tagpool)) {
- mtmp = ERR_PTR(-ENOMEM);
- kfree(m);
- return mtmp;
- }
-
- m->err = 0;
- init_waitqueue_head(&m->equeue);
- INIT_LIST_HEAD(&m->req_list);
- INIT_LIST_HEAD(&m->unsent_req_list);
- m->rcall = NULL;
- m->rpos = 0;
- m->rbuf = NULL;
- m->wpos = m->wsize = 0;
- m->wbuf = NULL;
- INIT_WORK(&m->rq, p9_read_work);
- INIT_WORK(&m->wq, p9_write_work);
- m->wsched = 0;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- m->poll_task = NULL;
- n = p9_mux_poll_start(m);
- if (n) {
- kfree(m);
- return ERR_PTR(n);
- }
-
- n = trans->poll(trans, &m->pt);
- if (n & POLLIN) {
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
- set_bit(Rpending, &m->wsched);
- }
-
- if (n & POLLOUT) {
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
- set_bit(Wpending, &m->wsched);
- }
-
- for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
- if (IS_ERR(m->poll_waddr[i])) {
- p9_mux_poll_stop(m);
- mtmp = (void *)m->poll_waddr; /* the error code */
- kfree(m);
- m = mtmp;
- break;
- }
- }
-
- return m;
-}
-EXPORT_SYMBOL(p9_conn_create);
-
-/**
- * p9_mux_destroy - cancels all pending requests and frees mux resources
- */
-void p9_conn_destroy(struct p9_conn *m)
-{
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
- m->mux_list.prev, m->mux_list.next);
- p9_conn_cancel(m, -ECONNRESET);
-
- if (!list_empty(&m->req_list)) {
- /* wait until all processes waiting on this session exit */
- P9_DPRINTK(P9_DEBUG_MUX,
- "mux %p waiting for empty request queue\n", m);
- wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
- list_empty(&m->req_list));
- }
-
- p9_mux_poll_stop(m);
- m->trans = NULL;
- p9_idpool_destroy(m->tagpool);
- kfree(m);
-}
-EXPORT_SYMBOL(p9_conn_destroy);
-
-/**
- * p9_pollwait - called by files poll operation to add v9fs-poll task
- * to files wait queue
- */
-static void
-p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
- poll_table * p)
-{
- int i;
- struct p9_conn *m;
-
- m = container_of(p, struct p9_conn, pt);
- for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
- if (m->poll_waddr[i] == NULL)
- break;
-
- if (i >= ARRAY_SIZE(m->poll_waddr)) {
- P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
- return;
- }
-
- m->poll_waddr[i] = wait_address;
-
- if (!wait_address) {
- P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
- m->poll_waddr[i] = ERR_PTR(-EIO);
- return;
- }
-
- init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
- add_wait_queue(wait_address, &m->poll_wait[i]);
-}
-
-/**
- * p9_poll_mux - polls a mux and schedules read or write works if necessary
- */
-static void p9_poll_mux(struct p9_conn *m)
-{
- int n;
-
- if (m->err < 0)
- return;
-
- n = m->trans->poll(m->trans, NULL);
- if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
- P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
- if (n >= 0)
- n = -ECONNRESET;
- p9_conn_cancel(m, n);
- }
-
- if (n & POLLIN) {
- set_bit(Rpending, &m->wsched);
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
- if (!test_and_set_bit(Rworksched, &m->wsched)) {
- P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
- queue_work(p9_mux_wq, &m->rq);
- }
- }
-
- if (n & POLLOUT) {
- set_bit(Wpending, &m->wsched);
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
- if ((m->wsize || !list_empty(&m->unsent_req_list))
- && !test_and_set_bit(Wworksched, &m->wsched)) {
- P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
- queue_work(p9_mux_wq, &m->wq);
- }
- }
-}
-
-/**
- * p9_poll_proc - polls all v9fs transports for new events and queues
- * the appropriate work to the work queue
- */
-static int p9_poll_proc(void *a)
-{
- struct p9_conn *m, *mtmp;
- struct p9_mux_poll_task *vpt;
-
- vpt = a;
- P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
- p9_poll_mux(m);
- }
-
- P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
- schedule_timeout(SCHED_TIMEOUT * HZ);
- }
-
- __set_current_state(TASK_RUNNING);
- P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
- return 0;
-}
-
-/**
- * p9_write_work - called when a transport can send some data
- */
-static void p9_write_work(struct work_struct *work)
-{
- int n, err;
- struct p9_conn *m;
- struct p9_req *req;
-
- m = container_of(work, struct p9_conn, wq);
-
- if (m->err < 0) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
-
- if (!m->wsize) {
- if (list_empty(&m->unsent_req_list)) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
-
- spin_lock(&m->lock);
-again:
- req = list_entry(m->unsent_req_list.next, struct p9_req,
- req_list);
- list_move_tail(&req->req_list, &m->req_list);
- if (req->err == ERREQFLUSH)
- goto again;
-
- m->wbuf = req->tcall->sdata;
- m->wsize = req->tcall->size;
- m->wpos = 0;
- spin_unlock(&m->lock);
- }
-
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
- m->wsize);
- clear_bit(Wpending, &m->wsched);
- err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
- if (err == -EAGAIN) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
-
- if (err < 0)
- goto error;
- else if (err == 0) {
- err = -EREMOTEIO;
- goto error;
- }
-
- m->wpos += err;
- if (m->wpos == m->wsize)
- m->wpos = m->wsize = 0;
-
- if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
- if (test_and_clear_bit(Wpending, &m->wsched))
- n = POLLOUT;
- else
- n = m->trans->poll(m->trans, NULL);
-
- if (n & POLLOUT) {
- P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
- queue_work(p9_mux_wq, &m->wq);
- } else
- clear_bit(Wworksched, &m->wsched);
- } else
- clear_bit(Wworksched, &m->wsched);
-
- return;
-
-error:
- p9_conn_cancel(m, err);
- clear_bit(Wworksched, &m->wsched);
-}
-
-static void process_request(struct p9_conn *m, struct p9_req *req)
-{
- int ecode;
- struct p9_str *ename;
-
- if (!req->err && req->rcall->id == P9_RERROR) {
- ecode = req->rcall->params.rerror.errno;
- ename = &req->rcall->params.rerror.error;
-
- P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
- ename->str);
-
- if (*m->extended)
- req->err = -ecode;
-
- if (!req->err) {
- req->err = p9_errstr2errno(ename->str, ename->len);
-
- if (!req->err) { /* string match failed */
- PRINT_FCALL_ERROR("unknown error", req->rcall);
- }
-
- if (!req->err)
- req->err = -ESERVERFAULT;
- }
- } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
- P9_DPRINTK(P9_DEBUG_ERROR,
- "fcall mismatch: expected %d, got %d\n",
- req->tcall->id + 1, req->rcall->id);
- if (!req->err)
- req->err = -EIO;
- }
-}
-
-/**
- * p9_read_work - called when there is some data to be read from a transport
- */
-static void p9_read_work(struct work_struct *work)
-{
- int n, err;
- struct p9_conn *m;
- struct p9_req *req, *rptr, *rreq;
- struct p9_fcall *rcall;
- char *rbuf;
-
- m = container_of(work, struct p9_conn, rq);
-
- if (m->err < 0)
- return;
-
- rcall = NULL;
- P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
-
- if (!m->rcall) {
- m->rcall =
- kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
- if (!m->rcall) {
- err = -ENOMEM;
- goto error;
- }
-
- m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
- m->rpos = 0;
- }
-
- clear_bit(Rpending, &m->wsched);
- err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
- if (err == -EAGAIN) {
- clear_bit(Rworksched, &m->wsched);
- return;
- }
-
- if (err <= 0)
- goto error;
-
- m->rpos += err;
- while (m->rpos > 4) {
- n = le32_to_cpu(*(__le32 *) m->rbuf);
- if (n >= m->msize) {
- P9_DPRINTK(P9_DEBUG_ERROR,
- "requested packet size too big: %d\n", n);
- err = -EIO;
- goto error;
- }
-
- if (m->rpos < n)
- break;
-
- err =
- p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
- if (err < 0) {
- goto error;
- }
-
-#ifdef CONFIG_NET_9P_DEBUG
- if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
- char buf[150];
-
- p9_printfcall(buf, sizeof(buf), m->rcall,
- *m->extended);
- printk(KERN_NOTICE ">>> %p %s\n", m, buf);
- }
-#endif
-
- rcall = m->rcall;
- rbuf = m->rbuf;
- if (m->rpos > n) {
- m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
- GFP_KERNEL);
- if (!m->rcall) {
- err = -ENOMEM;
- goto error;
- }
-
- m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
- memmove(m->rbuf, rbuf + n, m->rpos - n);
- m->rpos -= n;
- } else {
- m->rcall = NULL;
- m->rbuf = NULL;
- m->rpos = 0;
- }
-
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
- rcall->id, rcall->tag);
-
- req = NULL;
- spin_lock(&m->lock);
- list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
- if (rreq->tag == rcall->tag) {
- req = rreq;
- if (req->flush != Flushing)
- list_del(&req->req_list);
- break;
- }
- }
- spin_unlock(&m->lock);
-
- if (req) {
- req->rcall = rcall;
- process_request(m, req);
-
- if (req->flush != Flushing) {
- if (req->cb)
- (*req->cb) (req, req->cba);
- else
- kfree(req->rcall);
-
- wake_up(&m->equeue);
- }
- } else {
- if (err >= 0 && rcall->id != P9_RFLUSH)
- P9_DPRINTK(P9_DEBUG_ERROR,
- "unexpected response mux %p id %d tag %d\n",
- m, rcall->id, rcall->tag);
- kfree(rcall);
- }
- }
-
- if (!list_empty(&m->req_list)) {
- if (test_and_clear_bit(Rpending, &m->wsched))
- n = POLLIN;
- else
- n = m->trans->poll(m->trans, NULL);
-
- if (n & POLLIN) {
- P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
- queue_work(p9_mux_wq, &m->rq);
- } else
- clear_bit(Rworksched, &m->wsched);
- } else
- clear_bit(Rworksched, &m->wsched);
-
- return;
-
-error:
- p9_conn_cancel(m, err);
- clear_bit(Rworksched, &m->wsched);
-}
-
-/**
- * p9_send_request - send 9P request
- * The function can sleep until the request is scheduled for sending.
- * The function can be interrupted. Return from the function is not
- * a guarantee that the request is sent successfully. Can return errors
- * that can be retrieved by PTR_ERR macros.
- *
- * @m: mux data
- * @tc: request to be sent
- * @cb: callback function to call when response is received
- * @cba: parameter to pass to the callback function
- */
-static struct p9_req *p9_send_request(struct p9_conn *m,
- struct p9_fcall *tc,
- p9_conn_req_callback cb, void *cba)
-{
- int n;
- struct p9_req *req;
-
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
- tc, tc->id);
- if (m->err < 0)
- return ERR_PTR(m->err);
-
- req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
- if (!req)
- return ERR_PTR(-ENOMEM);
-
- if (tc->id == P9_TVERSION)
- n = P9_NOTAG;
- else
- n = p9_mux_get_tag(m);
-
- if (n < 0)
- return ERR_PTR(-ENOMEM);
-
- p9_set_tag(tc, n);
-
-#ifdef CONFIG_NET_9P_DEBUG
- if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
- char buf[150];
-
- p9_printfcall(buf, sizeof(buf), tc, *m->extended);
- printk(KERN_NOTICE "<<< %p %s\n", m, buf);
- }
-#endif
-
- spin_lock_init(&req->lock);
- req->tag = n;
- req->tcall = tc;
- req->rcall = NULL;
- req->err = 0;
- req->cb = cb;
- req->cba = cba;
- req->flush = None;
-
- spin_lock(&m->lock);
- list_add_tail(&req->req_list, &m->unsent_req_list);
- spin_unlock(&m->lock);
-
- if (test_and_clear_bit(Wpending, &m->wsched))
- n = POLLOUT;
- else
- n = m->trans->poll(m->trans, NULL);
-
- if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
- queue_work(p9_mux_wq, &m->wq);
-
- return req;
-}
-
-static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
-{
- p9_mux_put_tag(m, req->tag);
- kfree(req);
-}
-
-static void p9_mux_flush_cb(struct p9_req *freq, void *a)
-{
- p9_conn_req_callback cb;
- int tag;
- struct p9_conn *m;
- struct p9_req *req, *rreq, *rptr;
-
- m = a;
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
- freq->tcall, freq->rcall, freq->err,
- freq->tcall->params.tflush.oldtag);
-
- spin_lock(&m->lock);
- cb = NULL;
- tag = freq->tcall->params.tflush.oldtag;
- req = NULL;
- list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
- if (rreq->tag == tag) {
- req = rreq;
- list_del(&req->req_list);
- break;
- }
- }
- spin_unlock(&m->lock);
-
- if (req) {
- spin_lock(&req->lock);
- req->flush = Flushed;
- spin_unlock(&req->lock);
-
- if (req->cb)
- (*req->cb) (req, req->cba);
- else
- kfree(req->rcall);
-
- wake_up(&m->equeue);
- }
-
- kfree(freq->tcall);
- kfree(freq->rcall);
- p9_mux_free_request(m, freq);
-}
-
-static int
-p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
-{
- struct p9_fcall *fc;
- struct p9_req *rreq, *rptr;
-
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
-
- /* if a response was received for a request, do nothing */
- spin_lock(&req->lock);
- if (req->rcall || req->err) {
- spin_unlock(&req->lock);
- P9_DPRINTK(P9_DEBUG_MUX,
- "mux %p req %p response already received\n", m, req);
- return 0;
- }
-
- req->flush = Flushing;
- spin_unlock(&req->lock);
-
- spin_lock(&m->lock);
- /* if the request is not sent yet, just remove it from the list */
- list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
- if (rreq->tag == req->tag) {
- P9_DPRINTK(P9_DEBUG_MUX,
- "mux %p req %p request is not sent yet\n", m, req);
- list_del(&rreq->req_list);
- req->flush = Flushed;
- spin_unlock(&m->lock);
- if (req->cb)
- (*req->cb) (req, req->cba);
- return 0;
- }
- }
- spin_unlock(&m->lock);
-
- clear_thread_flag(TIF_SIGPENDING);
- fc = p9_create_tflush(req->tag);
- p9_send_request(m, fc, p9_mux_flush_cb, m);
- return 1;
-}
-
-static void
-p9_conn_rpc_cb(struct p9_req *req, void *a)
-{
- struct p9_mux_rpc *r;
-
- P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
- r = a;
- r->rcall = req->rcall;
- r->err = req->err;
-
- if (req->flush != None && !req->err)
- r->err = -ERESTARTSYS;
-
- wake_up(&r->wqueue);
-}
-
-/**
- * p9_mux_rpc - sends 9P request and waits until a response is available.
- * The function can be interrupted.
- * @m: mux data
- * @tc: request to be sent
- * @rc: pointer where a pointer to the response is stored
- */
-int
-p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc,
- struct p9_fcall **rc)
-{
- int err, sigpending;
- unsigned long flags;
- struct p9_req *req;
- struct p9_mux_rpc r;
-
- r.err = 0;
- r.tcall = tc;
- r.rcall = NULL;
- r.m = m;
- init_waitqueue_head(&r.wqueue);
-
- if (rc)
- *rc = NULL;
-
- sigpending = 0;
- if (signal_pending(current)) {
- sigpending = 1;
- clear_thread_flag(TIF_SIGPENDING);
- }
-
- req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
- if (IS_ERR(req)) {
- err = PTR_ERR(req);
- P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
- return err;
- }
-
- err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
- if (r.err < 0)
- err = r.err;
-
- if (err == -ERESTARTSYS && m->trans->status == Connected
- && m->err == 0) {
- if (p9_mux_flush_request(m, req)) {
- /* wait until we get response of the flush message */
- do {
- clear_thread_flag(TIF_SIGPENDING);
- err = wait_event_interruptible(r.wqueue,
- r.rcall || r.err);
- } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
- m->trans->status == Connected && !m->err);
-
- err = -ERESTARTSYS;
- }
- sigpending = 1;
- }
-
- if (sigpending) {
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
- }
-
- if (rc)
- *rc = r.rcall;
- else
- kfree(r.rcall);
-
- p9_mux_free_request(m, req);
- if (err > 0)
- err = -EIO;
-
- return err;
-}
-EXPORT_SYMBOL(p9_conn_rpc);
-
-#ifdef P9_NONBLOCK
-/**
- * p9_conn_rpcnb - sends 9P request without waiting for response.
- * @m: mux data
- * @tc: request to be sent
- * @cb: callback function to be called when response arrives
- * @cba: value to pass to the callback function
- */
-int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
- p9_conn_req_callback cb, void *a)
-{
- int err;
- struct p9_req *req;
-
- req = p9_send_request(m, tc, cb, a);
- if (IS_ERR(req)) {
- err = PTR_ERR(req);
- P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
- return PTR_ERR(req);
- }
-
- P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
- return 0;
-}
-EXPORT_SYMBOL(p9_conn_rpcnb);
-#endif /* P9_NONBLOCK */
-
-/**
- * p9_conn_cancel - cancel all pending requests with error
- * @m: mux data
- * @err: error code
- */
-void p9_conn_cancel(struct p9_conn *m, int err)
-{
- struct p9_req *req, *rtmp;
- LIST_HEAD(cancel_list);
-
- P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
- m->err = err;
- spin_lock(&m->lock);
- list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
- list_move(&req->req_list, &cancel_list);
- }
- list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
- list_move(&req->req_list, &cancel_list);
- }
- spin_unlock(&m->lock);
-
- list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
- list_del(&req->req_list);
- if (!req->err)
- req->err = err;
-
- if (req->cb)
- (*req->cb) (req, req->cba);
- else
- kfree(req->rcall);
- }
-
- wake_up(&m->equeue);
-}
-EXPORT_SYMBOL(p9_conn_cancel);
-
-static u16 p9_mux_get_tag(struct p9_conn *m)
-{
- int tag;
-
- tag = p9_idpool_get(m->tagpool);
- if (tag < 0)
- return P9_NOTAG;
- else
- return (u16) tag;
-}
-
-static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
-{
- if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
- p9_idpool_put(tag, m->tagpool);
-}
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 62332ed..1aa9d51 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -5,7 +5,7 @@
*
* Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
* Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/net.h>
#include <linux/ipv6.h>
+#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/un.h>
@@ -42,7 +43,9 @@
#define P9_PORT 564
#define MAX_SOCK_BUF (64*1024)
-
+#define ERREQFLUSH 1
+#define SCHED_TIMEOUT 10
+#define MAXPOLLWADDR 2
struct p9_fd_opts {
int rfd;
@@ -53,6 +56,7 @@
struct p9_trans_fd {
struct file *rd;
struct file *wr;
+ struct p9_conn *conn;
};
/*
@@ -72,6 +76,1028 @@
{Opt_err, NULL},
};
+enum {
+ Rworksched = 1, /* read work scheduled or running */
+ Rpending = 2, /* can read */
+ Wworksched = 4, /* write work scheduled or running */
+ Wpending = 8, /* can write */
+};
+
+enum {
+ None,
+ Flushing,
+ Flushed,
+};
+
+struct p9_req;
+
+typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
+struct p9_req {
+ spinlock_t lock; /* protect request structure */
+ int tag;
+ struct p9_fcall *tcall;
+ struct p9_fcall *rcall;
+ int err;
+ p9_conn_req_callback cb;
+ void *cba;
+ int flush;
+ struct list_head req_list;
+};
+
+struct p9_mux_poll_task;
+
+struct p9_conn {
+ spinlock_t lock; /* protect lock structure */
+ struct list_head mux_list;
+ struct p9_mux_poll_task *poll_task;
+ int msize;
+ unsigned char extended;
+ struct p9_trans *trans;
+ struct p9_idpool *tagpool;
+ int err;
+ wait_queue_head_t equeue;
+ struct list_head req_list;
+ struct list_head unsent_req_list;
+ struct p9_fcall *rcall;
+ int rpos;
+ char *rbuf;
+ int wpos;
+ int wsize;
+ char *wbuf;
+ wait_queue_t poll_wait[MAXPOLLWADDR];
+ wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
+ poll_table pt;
+ struct work_struct rq;
+ struct work_struct wq;
+ unsigned long wsched;
+};
+
+struct p9_mux_poll_task {
+ struct task_struct *task;
+ struct list_head mux_list;
+ int muxnum;
+};
+
+struct p9_mux_rpc {
+ struct p9_conn *m;
+ int err;
+ struct p9_fcall *tcall;
+ struct p9_fcall *rcall;
+ wait_queue_head_t wqueue;
+};
+
+static int p9_poll_proc(void *);
+static void p9_read_work(struct work_struct *work);
+static void p9_write_work(struct work_struct *work);
+static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table *p);
+static int p9_fd_write(struct p9_trans *trans, void *v, int len);
+static int p9_fd_read(struct p9_trans *trans, void *v, int len);
+
+static DEFINE_MUTEX(p9_mux_task_lock);
+static struct workqueue_struct *p9_mux_wq;
+
+static int p9_mux_num;
+static int p9_mux_poll_task_num;
+static struct p9_mux_poll_task p9_mux_poll_tasks[100];
+
+static void p9_conn_destroy(struct p9_conn *);
+static unsigned int p9_fd_poll(struct p9_trans *trans,
+ struct poll_table_struct *pt);
+
+#ifdef P9_NONBLOCK
+static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *a);
+#endif /* P9_NONBLOCK */
+
+static void p9_conn_cancel(struct p9_conn *m, int err);
+
+static int p9_mux_global_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
+ p9_mux_poll_tasks[i].task = NULL;
+
+ p9_mux_wq = create_workqueue("v9fs");
+ if (!p9_mux_wq) {
+ printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static u16 p9_mux_get_tag(struct p9_conn *m)
+{
+ int tag;
+
+ tag = p9_idpool_get(m->tagpool);
+ if (tag < 0)
+ return P9_NOTAG;
+ else
+ return (u16) tag;
+}
+
+static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
+{
+ if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
+ p9_idpool_put(tag, m->tagpool);
+}
+
+/**
+ * p9_mux_calc_poll_procs - calculates the number of polling procs
+ * based on the number of mounted v9fs filesystems.
+ *
+ * The current implementation returns sqrt of the number of mounts.
+ */
+static int p9_mux_calc_poll_procs(int muxnum)
+{
+ int n;
+
+ if (p9_mux_poll_task_num)
+ n = muxnum / p9_mux_poll_task_num +
+ (muxnum % p9_mux_poll_task_num ? 1 : 0);
+ else
+ n = 1;
+
+ if (n > ARRAY_SIZE(p9_mux_poll_tasks))
+ n = ARRAY_SIZE(p9_mux_poll_tasks);
+
+ return n;
+}
+
+static int p9_mux_poll_start(struct p9_conn *m)
+{
+ int i, n;
+ struct p9_mux_poll_task *vpt, *vptlast;
+ struct task_struct *pproc;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
+ p9_mux_poll_task_num);
+ mutex_lock(&p9_mux_task_lock);
+
+ n = p9_mux_calc_poll_procs(p9_mux_num + 1);
+ if (n > p9_mux_poll_task_num) {
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+ if (p9_mux_poll_tasks[i].task == NULL) {
+ vpt = &p9_mux_poll_tasks[i];
+ P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
+ vpt);
+ pproc = kthread_create(p9_poll_proc, vpt,
+ "v9fs-poll");
+
+ if (!IS_ERR(pproc)) {
+ vpt->task = pproc;
+ INIT_LIST_HEAD(&vpt->mux_list);
+ vpt->muxnum = 0;
+ p9_mux_poll_task_num++;
+ wake_up_process(vpt->task);
+ }
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "warning: no free poll slots\n");
+ }
+
+ n = (p9_mux_num + 1) / p9_mux_poll_task_num +
+ ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
+
+ vptlast = NULL;
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+ vpt = &p9_mux_poll_tasks[i];
+ if (vpt->task != NULL) {
+ vptlast = vpt;
+ if (vpt->muxnum < n) {
+ P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
+ list_add(&m->mux_list, &vpt->mux_list);
+ vpt->muxnum++;
+ m->poll_task = vpt;
+ memset(&m->poll_waddr, 0,
+ sizeof(m->poll_waddr));
+ init_poll_funcptr(&m->pt, p9_pollwait);
+ break;
+ }
+ }
+ }
+
+ if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
+ if (vptlast == NULL) {
+ mutex_unlock(&p9_mux_task_lock);
+ return -ENOMEM;
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
+ list_add(&m->mux_list, &vptlast->mux_list);
+ vptlast->muxnum++;
+ m->poll_task = vptlast;
+ memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+ init_poll_funcptr(&m->pt, p9_pollwait);
+ }
+
+ p9_mux_num++;
+ mutex_unlock(&p9_mux_task_lock);
+
+ return 0;
+}
+
+static void p9_mux_poll_stop(struct p9_conn *m)
+{
+ int i;
+ struct p9_mux_poll_task *vpt;
+
+ mutex_lock(&p9_mux_task_lock);
+ vpt = m->poll_task;
+ list_del(&m->mux_list);
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+ if (m->poll_waddr[i] != NULL) {
+ remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
+ m->poll_waddr[i] = NULL;
+ }
+ }
+ vpt->muxnum--;
+ if (!vpt->muxnum) {
+ P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
+ kthread_stop(vpt->task);
+ vpt->task = NULL;
+ p9_mux_poll_task_num--;
+ }
+ p9_mux_num--;
+ mutex_unlock(&p9_mux_task_lock);
+}
+
+/**
+ * p9_conn_create - allocate and initialize the per-session mux data
+ * Creates the polling task if this is the first session.
+ *
+ * @trans - transport structure
+ * @msize - maximum message size
+ * @extended - extended flag
+ */
+static struct p9_conn *p9_conn_create(struct p9_trans *trans)
+{
+ int i, n;
+ struct p9_conn *m, *mtmp;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans,
+ trans->msize);
+ m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
+ if (!m)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&m->lock);
+ INIT_LIST_HEAD(&m->mux_list);
+ m->msize = trans->msize;
+ m->extended = trans->extended;
+ m->trans = trans;
+ m->tagpool = p9_idpool_create();
+ if (IS_ERR(m->tagpool)) {
+ mtmp = ERR_PTR(-ENOMEM);
+ kfree(m);
+ return mtmp;
+ }
+
+ m->err = 0;
+ init_waitqueue_head(&m->equeue);
+ INIT_LIST_HEAD(&m->req_list);
+ INIT_LIST_HEAD(&m->unsent_req_list);
+ m->rcall = NULL;
+ m->rpos = 0;
+ m->rbuf = NULL;
+ m->wpos = m->wsize = 0;
+ m->wbuf = NULL;
+ INIT_WORK(&m->rq, p9_read_work);
+ INIT_WORK(&m->wq, p9_write_work);
+ m->wsched = 0;
+ memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+ m->poll_task = NULL;
+ n = p9_mux_poll_start(m);
+ if (n) {
+ kfree(m);
+ return ERR_PTR(n);
+ }
+
+ n = p9_fd_poll(trans, &m->pt);
+ if (n & POLLIN) {
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
+ set_bit(Rpending, &m->wsched);
+ }
+
+ if (n & POLLOUT) {
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
+ set_bit(Wpending, &m->wsched);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+ if (IS_ERR(m->poll_waddr[i])) {
+ p9_mux_poll_stop(m);
+ mtmp = (void *)m->poll_waddr; /* the error code */
+ kfree(m);
+ m = mtmp;
+ break;
+ }
+ }
+
+ return m;
+}
+
+/**
+ * p9_mux_destroy - cancels all pending requests and frees mux resources
+ */
+static void p9_conn_destroy(struct p9_conn *m)
+{
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
+ m->mux_list.prev, m->mux_list.next);
+ p9_conn_cancel(m, -ECONNRESET);
+
+ if (!list_empty(&m->req_list)) {
+ /* wait until all processes waiting on this session exit */
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p waiting for empty request queue\n", m);
+ wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
+ list_empty(&m->req_list));
+ }
+
+ p9_mux_poll_stop(m);
+ m->trans = NULL;
+ p9_idpool_destroy(m->tagpool);
+ kfree(m);
+}
+
+/**
+ * p9_pollwait - called by files poll operation to add v9fs-poll task
+ * to files wait queue
+ */
+static void
+p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
+{
+ int i;
+ struct p9_conn *m;
+
+ m = container_of(p, struct p9_conn, pt);
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
+ if (m->poll_waddr[i] == NULL)
+ break;
+
+ if (i >= ARRAY_SIZE(m->poll_waddr)) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
+ return;
+ }
+
+ m->poll_waddr[i] = wait_address;
+
+ if (!wait_address) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
+ m->poll_waddr[i] = ERR_PTR(-EIO);
+ return;
+ }
+
+ init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
+ add_wait_queue(wait_address, &m->poll_wait[i]);
+}
+
+/**
+ * p9_poll_mux - polls a mux and schedules read or write works if necessary
+ */
+static void p9_poll_mux(struct p9_conn *m)
+{
+ int n;
+
+ if (m->err < 0)
+ return;
+
+ n = p9_fd_poll(m->trans, NULL);
+ if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
+ if (n >= 0)
+ n = -ECONNRESET;
+ p9_conn_cancel(m, n);
+ }
+
+ if (n & POLLIN) {
+ set_bit(Rpending, &m->wsched);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
+ if (!test_and_set_bit(Rworksched, &m->wsched)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+ queue_work(p9_mux_wq, &m->rq);
+ }
+ }
+
+ if (n & POLLOUT) {
+ set_bit(Wpending, &m->wsched);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
+ if ((m->wsize || !list_empty(&m->unsent_req_list))
+ && !test_and_set_bit(Wworksched, &m->wsched)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+ queue_work(p9_mux_wq, &m->wq);
+ }
+ }
+}
+
+/**
+ * p9_poll_proc - polls all v9fs transports for new events and queues
+ * the appropriate work to the work queue
+ */
+static int p9_poll_proc(void *a)
+{
+ struct p9_conn *m, *mtmp;
+ struct p9_mux_poll_task *vpt;
+
+ vpt = a;
+ P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
+ p9_poll_mux(m);
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
+ schedule_timeout(SCHED_TIMEOUT * HZ);
+ }
+
+ __set_current_state(TASK_RUNNING);
+ P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
+ return 0;
+}
+
+/**
+ * p9_write_work - called when a transport can send some data
+ */
+static void p9_write_work(struct work_struct *work)
+{
+ int n, err;
+ struct p9_conn *m;
+ struct p9_req *req;
+
+ m = container_of(work, struct p9_conn, wq);
+
+ if (m->err < 0) {
+ clear_bit(Wworksched, &m->wsched);
+ return;
+ }
+
+ if (!m->wsize) {
+ if (list_empty(&m->unsent_req_list)) {
+ clear_bit(Wworksched, &m->wsched);
+ return;
+ }
+
+ spin_lock(&m->lock);
+again:
+ req = list_entry(m->unsent_req_list.next, struct p9_req,
+ req_list);
+ list_move_tail(&req->req_list, &m->req_list);
+ if (req->err == ERREQFLUSH)
+ goto again;
+
+ m->wbuf = req->tcall->sdata;
+ m->wsize = req->tcall->size;
+ m->wpos = 0;
+ spin_unlock(&m->lock);
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
+ m->wsize);
+ clear_bit(Wpending, &m->wsched);
+ err = p9_fd_write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
+ if (err == -EAGAIN) {
+ clear_bit(Wworksched, &m->wsched);
+ return;
+ }
+
+ if (err < 0)
+ goto error;
+ else if (err == 0) {
+ err = -EREMOTEIO;
+ goto error;
+ }
+
+ m->wpos += err;
+ if (m->wpos == m->wsize)
+ m->wpos = m->wsize = 0;
+
+ if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
+ if (test_and_clear_bit(Wpending, &m->wsched))
+ n = POLLOUT;
+ else
+ n = p9_fd_poll(m->trans, NULL);
+
+ if (n & POLLOUT) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+ queue_work(p9_mux_wq, &m->wq);
+ } else
+ clear_bit(Wworksched, &m->wsched);
+ } else
+ clear_bit(Wworksched, &m->wsched);
+
+ return;
+
+error:
+ p9_conn_cancel(m, err);
+ clear_bit(Wworksched, &m->wsched);
+}
+
+static void process_request(struct p9_conn *m, struct p9_req *req)
+{
+ int ecode;
+ struct p9_str *ename;
+
+ if (!req->err && req->rcall->id == P9_RERROR) {
+ ecode = req->rcall->params.rerror.errno;
+ ename = &req->rcall->params.rerror.error;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
+ ename->str);
+
+ if (m->extended)
+ req->err = -ecode;
+
+ if (!req->err) {
+ req->err = p9_errstr2errno(ename->str, ename->len);
+
+ /* string match failed */
+ if (!req->err) {
+ PRINT_FCALL_ERROR("unknown error", req->rcall);
+ req->err = -ESERVERFAULT;
+ }
+ }
+ } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "fcall mismatch: expected %d, got %d\n",
+ req->tcall->id + 1, req->rcall->id);
+ if (!req->err)
+ req->err = -EIO;
+ }
+}
+
+/**
+ * p9_read_work - called when there is some data to be read from a transport
+ */
+static void p9_read_work(struct work_struct *work)
+{
+ int n, err;
+ struct p9_conn *m;
+ struct p9_req *req, *rptr, *rreq;
+ struct p9_fcall *rcall;
+ char *rbuf;
+
+ m = container_of(work, struct p9_conn, rq);
+
+ if (m->err < 0)
+ return;
+
+ rcall = NULL;
+ P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
+
+ if (!m->rcall) {
+ m->rcall =
+ kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
+ if (!m->rcall) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
+ m->rpos = 0;
+ }
+
+ clear_bit(Rpending, &m->wsched);
+ err = p9_fd_read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
+ if (err == -EAGAIN) {
+ clear_bit(Rworksched, &m->wsched);
+ return;
+ }
+
+ if (err <= 0)
+ goto error;
+
+ m->rpos += err;
+ while (m->rpos > 4) {
+ n = le32_to_cpu(*(__le32 *) m->rbuf);
+ if (n >= m->msize) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "requested packet size too big: %d\n", n);
+ err = -EIO;
+ goto error;
+ }
+
+ if (m->rpos < n)
+ break;
+
+ err =
+ p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended);
+ if (err < 0)
+ goto error;
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+ char buf[150];
+
+ p9_printfcall(buf, sizeof(buf), m->rcall,
+ m->extended);
+ printk(KERN_NOTICE ">>> %p %s\n", m, buf);
+ }
+#endif
+
+ rcall = m->rcall;
+ rbuf = m->rbuf;
+ if (m->rpos > n) {
+ m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
+ GFP_KERNEL);
+ if (!m->rcall) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
+ memmove(m->rbuf, rbuf + n, m->rpos - n);
+ m->rpos -= n;
+ } else {
+ m->rcall = NULL;
+ m->rbuf = NULL;
+ m->rpos = 0;
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
+ rcall->id, rcall->tag);
+
+ req = NULL;
+ spin_lock(&m->lock);
+ list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+ if (rreq->tag == rcall->tag) {
+ req = rreq;
+ if (req->flush != Flushing)
+ list_del(&req->req_list);
+ break;
+ }
+ }
+ spin_unlock(&m->lock);
+
+ if (req) {
+ req->rcall = rcall;
+ process_request(m, req);
+
+ if (req->flush != Flushing) {
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ else
+ kfree(req->rcall);
+
+ wake_up(&m->equeue);
+ }
+ } else {
+ if (err >= 0 && rcall->id != P9_RFLUSH)
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "unexpected response mux %p id %d tag %d\n",
+ m, rcall->id, rcall->tag);
+ kfree(rcall);
+ }
+ }
+
+ if (!list_empty(&m->req_list)) {
+ if (test_and_clear_bit(Rpending, &m->wsched))
+ n = POLLIN;
+ else
+ n = p9_fd_poll(m->trans, NULL);
+
+ if (n & POLLIN) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+ queue_work(p9_mux_wq, &m->rq);
+ } else
+ clear_bit(Rworksched, &m->wsched);
+ } else
+ clear_bit(Rworksched, &m->wsched);
+
+ return;
+
+error:
+ p9_conn_cancel(m, err);
+ clear_bit(Rworksched, &m->wsched);
+}
+
+/**
+ * p9_send_request - send 9P request
+ * The function can sleep until the request is scheduled for sending.
+ * The function can be interrupted. Return from the function is not
+ * a guarantee that the request is sent successfully. Can return errors
+ * that can be retrieved by PTR_ERR macros.
+ *
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to call when response is received
+ * @cba: parameter to pass to the callback function
+ */
+static struct p9_req *p9_send_request(struct p9_conn *m,
+ struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *cba)
+{
+ int n;
+ struct p9_req *req;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
+ tc, tc->id);
+ if (m->err < 0)
+ return ERR_PTR(m->err);
+
+ req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ if (tc->id == P9_TVERSION)
+ n = P9_NOTAG;
+ else
+ n = p9_mux_get_tag(m);
+
+ if (n < 0)
+ return ERR_PTR(-ENOMEM);
+
+ p9_set_tag(tc, n);
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+ char buf[150];
+
+ p9_printfcall(buf, sizeof(buf), tc, m->extended);
+ printk(KERN_NOTICE "<<< %p %s\n", m, buf);
+ }
+#endif
+
+ spin_lock_init(&req->lock);
+ req->tag = n;
+ req->tcall = tc;
+ req->rcall = NULL;
+ req->err = 0;
+ req->cb = cb;
+ req->cba = cba;
+ req->flush = None;
+
+ spin_lock(&m->lock);
+ list_add_tail(&req->req_list, &m->unsent_req_list);
+ spin_unlock(&m->lock);
+
+ if (test_and_clear_bit(Wpending, &m->wsched))
+ n = POLLOUT;
+ else
+ n = p9_fd_poll(m->trans, NULL);
+
+ if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
+ queue_work(p9_mux_wq, &m->wq);
+
+ return req;
+}
+
+static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
+{
+ p9_mux_put_tag(m, req->tag);
+ kfree(req);
+}
+
+static void p9_mux_flush_cb(struct p9_req *freq, void *a)
+{
+ p9_conn_req_callback cb;
+ int tag;
+ struct p9_conn *m;
+ struct p9_req *req, *rreq, *rptr;
+
+ m = a;
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
+ freq->tcall, freq->rcall, freq->err,
+ freq->tcall->params.tflush.oldtag);
+
+ spin_lock(&m->lock);
+ cb = NULL;
+ tag = freq->tcall->params.tflush.oldtag;
+ req = NULL;
+ list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+ if (rreq->tag == tag) {
+ req = rreq;
+ list_del(&req->req_list);
+ break;
+ }
+ }
+ spin_unlock(&m->lock);
+
+ if (req) {
+ spin_lock(&req->lock);
+ req->flush = Flushed;
+ spin_unlock(&req->lock);
+
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ else
+ kfree(req->rcall);
+
+ wake_up(&m->equeue);
+ }
+
+ kfree(freq->tcall);
+ kfree(freq->rcall);
+ p9_mux_free_request(m, freq);
+}
+
+static int
+p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
+{
+ struct p9_fcall *fc;
+ struct p9_req *rreq, *rptr;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
+
+ /* if a response was received for a request, do nothing */
+ spin_lock(&req->lock);
+ if (req->rcall || req->err) {
+ spin_unlock(&req->lock);
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p req %p response already received\n", m, req);
+ return 0;
+ }
+
+ req->flush = Flushing;
+ spin_unlock(&req->lock);
+
+ spin_lock(&m->lock);
+ /* if the request is not sent yet, just remove it from the list */
+ list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
+ if (rreq->tag == req->tag) {
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p req %p request is not sent yet\n", m, req);
+ list_del(&rreq->req_list);
+ req->flush = Flushed;
+ spin_unlock(&m->lock);
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ return 0;
+ }
+ }
+ spin_unlock(&m->lock);
+
+ clear_thread_flag(TIF_SIGPENDING);
+ fc = p9_create_tflush(req->tag);
+ p9_send_request(m, fc, p9_mux_flush_cb, m);
+ return 1;
+}
+
+static void
+p9_conn_rpc_cb(struct p9_req *req, void *a)
+{
+ struct p9_mux_rpc *r;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
+ r = a;
+ r->rcall = req->rcall;
+ r->err = req->err;
+
+ if (req->flush != None && !req->err)
+ r->err = -ERESTARTSYS;
+
+ wake_up(&r->wqueue);
+}
+
+/**
+ * p9_fd_rpc- sends 9P request and waits until a response is available.
+ * The function can be interrupted.
+ * @m: mux data
+ * @tc: request to be sent
+ * @rc: pointer where a pointer to the response is stored
+ */
+int
+p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
+{
+ struct p9_trans_fd *p = t->priv;
+ struct p9_conn *m = p->conn;
+ int err, sigpending;
+ unsigned long flags;
+ struct p9_req *req;
+ struct p9_mux_rpc r;
+
+ r.err = 0;
+ r.tcall = tc;
+ r.rcall = NULL;
+ r.m = m;
+ init_waitqueue_head(&r.wqueue);
+
+ if (rc)
+ *rc = NULL;
+
+ sigpending = 0;
+ if (signal_pending(current)) {
+ sigpending = 1;
+ clear_thread_flag(TIF_SIGPENDING);
+ }
+
+ req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
+ return err;
+ }
+
+ err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
+ if (r.err < 0)
+ err = r.err;
+
+ if (err == -ERESTARTSYS && m->trans->status == Connected
+ && m->err == 0) {
+ if (p9_mux_flush_request(m, req)) {
+ /* wait until we get response of the flush message */
+ do {
+ clear_thread_flag(TIF_SIGPENDING);
+ err = wait_event_interruptible(r.wqueue,
+ r.rcall || r.err);
+ } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
+ m->trans->status == Connected && !m->err);
+
+ err = -ERESTARTSYS;
+ }
+ sigpending = 1;
+ }
+
+ if (sigpending) {
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+ }
+
+ if (rc)
+ *rc = r.rcall;
+ else
+ kfree(r.rcall);
+
+ p9_mux_free_request(m, req);
+ if (err > 0)
+ err = -EIO;
+
+ return err;
+}
+
+#ifdef P9_NONBLOCK
+/**
+ * p9_conn_rpcnb - sends 9P request without waiting for response.
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to be called when response arrives
+ * @cba: value to pass to the callback function
+ */
+int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *a)
+{
+ int err;
+ struct p9_req *req;
+
+ req = p9_send_request(m, tc, cb, a);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
+ return PTR_ERR(req);
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
+ return 0;
+}
+#endif /* P9_NONBLOCK */
+
+/**
+ * p9_conn_cancel - cancel all pending requests with error
+ * @m: mux data
+ * @err: error code
+ */
+void p9_conn_cancel(struct p9_conn *m, int err)
+{
+ struct p9_req *req, *rtmp;
+ LIST_HEAD(cancel_list);
+
+ P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
+ m->err = err;
+ spin_lock(&m->lock);
+ list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
+ list_move(&req->req_list, &cancel_list);
+ }
+ list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
+ list_move(&req->req_list, &cancel_list);
+ }
+ spin_unlock(&m->lock);
+
+ list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
+ list_del(&req->req_list);
+ if (!req->err)
+ req->err = err;
+
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ else
+ kfree(req->rcall);
+ }
+
+ wake_up(&m->equeue);
+}
+
/**
* v9fs_parse_options - parse mount options into session structure
* @options: options string passed from mount
@@ -268,7 +1294,7 @@
}
/**
- * p9_sock_close - shutdown socket
+ * p9_fd_close - shutdown socket
* @trans: private socket structure
*
*/
@@ -284,6 +1310,8 @@
if (!ts)
return;
+ p9_conn_destroy(ts->conn);
+
trans->status = Disconnected;
if (ts->rd)
fput(ts->rd);
@@ -292,13 +1320,15 @@
kfree(ts);
}
-static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
+static struct p9_trans *
+p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
{
int err;
struct p9_trans *trans;
struct socket *csocket;
struct sockaddr_in sin_server;
struct p9_fd_opts opts;
+ struct p9_trans_fd *p;
parse_opts(args, &opts);
@@ -306,11 +1336,10 @@
trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
if (!trans)
return ERR_PTR(-ENOMEM);
-
- trans->write = p9_fd_write;
- trans->read = p9_fd_read;
+ trans->msize = msize;
+ trans->extended = dotu;
+ trans->rpc = p9_fd_rpc;
trans->close = p9_fd_close;
- trans->poll = p9_fd_poll;
sin_server.sin_family = AF_INET;
sin_server.sin_addr.s_addr = in_aton(addr);
@@ -337,6 +1366,14 @@
if (err < 0)
goto error;
+ p = (struct p9_trans_fd *) trans->priv;
+ p->conn = p9_conn_create(trans);
+ if (IS_ERR(p->conn)) {
+ err = PTR_ERR(p->conn);
+ p->conn = NULL;
+ goto error;
+ }
+
return trans;
error:
@@ -347,22 +1384,23 @@
return ERR_PTR(err);
}
-static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
+static struct p9_trans *
+p9_trans_create_unix(const char *addr, char *args, int msize,
+ unsigned char dotu)
{
int err;
struct socket *csocket;
struct sockaddr_un sun_server;
struct p9_trans *trans;
+ struct p9_trans_fd *p;
csocket = NULL;
trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
if (!trans)
return ERR_PTR(-ENOMEM);
- trans->write = p9_fd_write;
- trans->read = p9_fd_read;
+ trans->rpc = p9_fd_rpc;
trans->close = p9_fd_close;
- trans->poll = p9_fd_poll;
if (strlen(addr) > UNIX_PATH_MAX) {
P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
@@ -387,6 +1425,16 @@
if (err < 0)
goto error;
+ trans->msize = msize;
+ trans->extended = dotu;
+ p = (struct p9_trans_fd *) trans->priv;
+ p->conn = p9_conn_create(trans);
+ if (IS_ERR(p->conn)) {
+ err = PTR_ERR(p->conn);
+ p->conn = NULL;
+ goto error;
+ }
+
return trans;
error:
@@ -397,11 +1445,14 @@
return ERR_PTR(err);
}
-static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
+static struct p9_trans *
+p9_trans_create_fd(const char *name, char *args, int msize,
+ unsigned char extended)
{
int err;
struct p9_trans *trans;
struct p9_fd_opts opts;
+ struct p9_trans_fd *p;
parse_opts(args, &opts);
@@ -414,15 +1465,23 @@
if (!trans)
return ERR_PTR(-ENOMEM);
- trans->write = p9_fd_write;
- trans->read = p9_fd_read;
+ trans->rpc = p9_fd_rpc;
trans->close = p9_fd_close;
- trans->poll = p9_fd_poll;
err = p9_fd_open(trans, opts.rfd, opts.wfd);
if (err < 0)
goto error;
+ trans->msize = msize;
+ trans->extended = extended;
+ p = (struct p9_trans_fd *) trans->priv;
+ p->conn = p9_conn_create(trans);
+ if (IS_ERR(p->conn)) {
+ err = PTR_ERR(p->conn);
+ p->conn = NULL;
+ goto error;
+ }
+
return trans;
error:
@@ -453,6 +1512,12 @@
static int __init p9_trans_fd_init(void)
{
+ int ret = p9_mux_global_init();
+ if (ret) {
+ printk(KERN_WARNING "9p: starting mux failed\n");
+ return ret;
+ }
+
v9fs_register_trans(&p9_tcp_trans);
v9fs_register_trans(&p9_unix_trans);
v9fs_register_trans(&p9_fd_trans);
@@ -460,13 +1525,7 @@
return 1;
}
-static void __exit p9_trans_fd_exit(void) {
- printk(KERN_ERR "Removal of 9p transports not implemented\n");
- BUG();
-}
-
module_init(p9_trans_fd_init);
-module_exit(p9_trans_fd_exit);
MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 40b71a2..0117b9f 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -1,17 +1,8 @@
/*
* The Guest 9p transport driver
*
- * This is a trivial pipe-based transport driver based on the lguest console
- * code: we use lguest's DMA mechanism to send bytes out, and register a
- * DMA buffer to receive bytes in. It is assumed to be present and available
- * from the very beginning of boot.
- *
- * This may be have been done by just instaniating another HVC console,
- * but HVC's blocksize of 16 bytes is annoying and painful to performance.
- *
- * A more efficient transport could be built based on the virtio block driver
- * but it requires some changes in the 9p transport model (which are in
- * progress)
+ * This is a block based transport driver based on the lguest block driver
+ * code.
*
*/
/*
@@ -55,11 +46,25 @@
#include <linux/virtio.h>
#include <linux/virtio_9p.h>
+#define VIRTQUEUE_NUM 128
+
/* a single mutex to manage channel initialization and attachment */
static DECLARE_MUTEX(virtio_9p_lock);
/* global which tracks highest initialized channel */
static int chan_index;
+#define P9_INIT_MAXTAG 16
+
+#define REQ_STATUS_IDLE 0
+#define REQ_STATUS_SENT 1
+#define REQ_STATUS_RCVD 2
+#define REQ_STATUS_FLSH 3
+
+struct p9_req_t {
+ int status;
+ wait_queue_head_t *wq;
+};
+
/* We keep all per-channel information in a structure.
* This structure is allocated within the devices dev->mem space.
* A pointer to the structure will get put in the transport private.
@@ -68,129 +73,76 @@
bool initialized; /* channel is initialized */
bool inuse; /* channel is in use */
- struct virtqueue *in_vq, *out_vq;
+ spinlock_t lock;
+
struct virtio_device *vdev;
+ struct virtqueue *vq;
- /* This is our input buffer, and how much data is left in it. */
- unsigned int in_len;
- char *in, *inbuf;
+ struct p9_idpool *tagpool;
+ struct p9_req_t *reqs;
+ int max_tag;
- wait_queue_head_t wq; /* waitq for buffer */
+ /* Scatterlist: can be too big for stack. */
+ struct scatterlist sg[VIRTQUEUE_NUM];
} channels[MAX_9P_CHAN];
+/* Lookup requests by tag */
+static struct p9_req_t *p9_lookup_tag(struct virtio_chan *c, u16 tag)
+{
+ /* This looks up the original request by tag so we know which
+ * buffer to read the data into */
+ tag++;
+
+ while (tag >= c->max_tag) {
+ int old_max = c->max_tag;
+ int count;
+
+ if (c->max_tag)
+ c->max_tag *= 2;
+ else
+ c->max_tag = P9_INIT_MAXTAG;
+
+ c->reqs = krealloc(c->reqs, sizeof(struct p9_req_t)*c->max_tag,
+ GFP_ATOMIC);
+ if (!c->reqs) {
+ printk(KERN_ERR "Couldn't grow tag array\n");
+ BUG();
+ }
+ for (count = old_max; count < c->max_tag; count++) {
+ c->reqs[count].status = REQ_STATUS_IDLE;
+ c->reqs[count].wq = kmalloc(sizeof(wait_queue_t),
+ GFP_ATOMIC);
+ if (!c->reqs[count].wq) {
+ printk(KERN_ERR "Couldn't grow tag array\n");
+ BUG();
+ }
+ init_waitqueue_head(c->reqs[count].wq);
+ }
+ }
+
+ return &c->reqs[tag];
+}
+
+
/* How many bytes left in this page. */
static unsigned int rest_of_page(void *data)
{
return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
}
-static int p9_virtio_write(struct p9_trans *trans, void *buf, int count)
-{
- struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
- struct virtqueue *out_vq = chan->out_vq;
- struct scatterlist sg[1];
- unsigned int len;
-
- P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio write (%d)\n", count);
-
- /* keep it simple - make sure we don't overflow a page */
- if (rest_of_page(buf) < count)
- count = rest_of_page(buf);
-
- sg_init_one(sg, buf, count);
-
- /* add_buf wants a token to identify this buffer: we hand it any
- * non-NULL pointer, since there's only ever one buffer. */
- if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
- /* Tell Host to go! */
- out_vq->vq_ops->kick(out_vq);
- /* Chill out until it's done with the buffer. */
- while (!out_vq->vq_ops->get_buf(out_vq, &len))
- cpu_relax();
- }
-
- P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio wrote (%d)\n", count);
-
- /* We're expected to return the amount of data we wrote: all of it. */
- return count;
-}
-
-/* Create a scatter-gather list representing our input buffer and put it in the
- * queue. */
-static void add_inbuf(struct virtio_chan *chan)
-{
- struct scatterlist sg[1];
-
- sg_init_one(sg, chan->inbuf, PAGE_SIZE);
-
- /* We should always be able to add one buffer to an empty queue. */
- if (chan->in_vq->vq_ops->add_buf(chan->in_vq, sg, 0, 1, chan->inbuf))
- BUG();
- chan->in_vq->vq_ops->kick(chan->in_vq);
-}
-
-static int p9_virtio_read(struct p9_trans *trans, void *buf, int count)
-{
- struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
- struct virtqueue *in_vq = chan->in_vq;
-
- P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio read (%d)\n", count);
-
- /* If we don't have an input queue yet, we can't get input. */
- BUG_ON(!in_vq);
-
- /* No buffer? Try to get one. */
- if (!chan->in_len) {
- chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
- if (!chan->in)
- return 0;
- }
-
- /* You want more than we have to give? Well, try wanting less! */
- if (chan->in_len < count)
- count = chan->in_len;
-
- /* Copy across to their buffer and increment offset. */
- memcpy(buf, chan->in, count);
- chan->in += count;
- chan->in_len -= count;
-
- /* Finished? Re-register buffer so Host will use it again. */
- if (chan->in_len == 0)
- add_inbuf(chan);
-
- P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio finished read (%d)\n",
- count);
-
- return count;
-}
-
-/* The poll function is used by 9p transports to determine if there
- * is there is activity available on a particular channel. In our case
- * we use it to wait for a callback from the input routines.
- */
-static unsigned int
-p9_virtio_poll(struct p9_trans *trans, struct poll_table_struct *pt)
-{
- struct virtio_chan *chan = (struct virtio_chan *)trans->priv;
- struct virtqueue *in_vq = chan->in_vq;
- int ret = POLLOUT; /* we can always handle more output */
-
- poll_wait(NULL, &chan->wq, pt);
-
- /* No buffer? Try to get one. */
- if (!chan->in_len)
- chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
-
- if (chan->in_len)
- ret |= POLLIN;
-
- return ret;
-}
-
static void p9_virtio_close(struct p9_trans *trans)
{
struct virtio_chan *chan = trans->priv;
+ int count;
+ unsigned int flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ p9_idpool_destroy(chan->tagpool);
+ for (count = 0; count < chan->max_tag; count++)
+ kfree(chan->reqs[count].wq);
+ kfree(chan->reqs);
+ chan->max_tag = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
down(&virtio_9p_lock);
chan->inuse = false;
@@ -199,17 +151,120 @@
kfree(trans);
}
-static bool p9_virtio_intr(struct virtqueue *q)
+static void req_done(struct virtqueue *vq)
{
- struct virtio_chan *chan = q->vdev->priv;
+ struct virtio_chan *chan = vq->vdev->priv;
+ struct p9_fcall *rc;
+ unsigned int len;
+ unsigned long flags;
+ struct p9_req_t *req;
- P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq);
- wake_up_interruptible(&chan->wq);
-
- return true;
+ spin_lock_irqsave(&chan->lock, flags);
+ while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) {
+ req = p9_lookup_tag(chan, rc->tag);
+ req->status = REQ_STATUS_RCVD;
+ wake_up(req->wq);
+ }
+ /* In case queue is stopped waiting for more buffers. */
+ spin_unlock_irqrestore(&chan->lock, flags);
}
-static int p9_virtio_probe(struct virtio_device *dev)
+static int
+pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
+ int count)
+{
+ int s;
+ int index = start;
+
+ while (count) {
+ s = rest_of_page(data);
+ if (s > count)
+ s = count;
+ sg_set_buf(&sg[index++], data, s);
+ count -= s;
+ data += s;
+ if (index > limit)
+ BUG();
+ }
+
+ return index-start;
+}
+
+static int
+p9_virtio_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
+{
+ int in, out;
+ int n, err, size;
+ struct virtio_chan *chan = t->priv;
+ char *rdata;
+ struct p9_req_t *req;
+ unsigned long flags;
+
+ if (*rc == NULL) {
+ *rc = kmalloc(sizeof(struct p9_fcall) + t->msize, GFP_KERNEL);
+ if (!*rc)
+ return -ENOMEM;
+ }
+
+ rdata = (char *)*rc+sizeof(struct p9_fcall);
+
+ n = P9_NOTAG;
+ if (tc->id != P9_TVERSION) {
+ n = p9_idpool_get(chan->tagpool);
+ if (n < 0)
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&chan->lock, flags);
+ req = p9_lookup_tag(chan, n);
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ p9_set_tag(tc, n);
+
+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n);
+
+ out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size);
+ in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, t->msize);
+
+ req->status = REQ_STATUS_SENT;
+
+ if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) {
+ P9_DPRINTK(P9_DEBUG_TRANS,
+ "9p debug: virtio rpc add_buf returned failure");
+ return -EIO;
+ }
+
+ chan->vq->vq_ops->kick(chan->vq);
+
+ wait_event(*req->wq, req->status == REQ_STATUS_RCVD);
+
+ size = le32_to_cpu(*(__le32 *) rdata);
+
+ err = p9_deserialize_fcall(rdata, size, *rc, t->extended);
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_TRANS,
+ "9p debug: virtio rpc deserialize returned %d\n", err);
+ return err;
+ }
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+ char buf[150];
+
+ p9_printfcall(buf, sizeof(buf), *rc, t->extended);
+ printk(KERN_NOTICE ">>> %p %s\n", t, buf);
+ }
+#endif
+
+ if (n != P9_NOTAG && p9_idpool_check(n, chan->tagpool))
+ p9_idpool_put(n, chan->tagpool);
+
+ req->status = REQ_STATUS_IDLE;
+
+ return 0;
+}
+
+static int p9_virtio_probe(struct virtio_device *vdev)
{
int err;
struct virtio_chan *chan;
@@ -223,44 +278,29 @@
if (chan_index > MAX_9P_CHAN) {
printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
BUG();
- }
-
- chan->vdev = dev;
-
- /* This is the scratch page we use to receive console input */
- chan->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!chan->inbuf) {
err = -ENOMEM;
goto fail;
}
- /* Find the input queue. */
- dev->priv = chan;
- chan->in_vq = dev->config->find_vq(dev, p9_virtio_intr);
- if (IS_ERR(chan->in_vq)) {
- err = PTR_ERR(chan->in_vq);
- goto free;
+ chan->vdev = vdev;
+
+ /* We expect one virtqueue, for requests. */
+ chan->vq = vdev->config->find_vq(vdev, 0, req_done);
+ if (IS_ERR(chan->vq)) {
+ err = PTR_ERR(chan->vq);
+ goto out_free_vq;
}
+ chan->vq->vdev->priv = chan;
+ spin_lock_init(&chan->lock);
- chan->out_vq = dev->config->find_vq(dev, NULL);
- if (IS_ERR(chan->out_vq)) {
- err = PTR_ERR(chan->out_vq);
- goto free_in_vq;
- }
+ sg_init_table(chan->sg, VIRTQUEUE_NUM);
- init_waitqueue_head(&chan->wq);
-
- /* Register the input buffer the first time. */
- add_inbuf(chan);
chan->inuse = false;
chan->initialized = true;
-
return 0;
-free_in_vq:
- dev->config->del_vq(chan->in_vq);
-free:
- kfree(chan->inbuf);
+out_free_vq:
+ vdev->config->del_vq(chan->vq);
fail:
down(&virtio_9p_lock);
chan_index--;
@@ -273,11 +313,13 @@
* alternate channels by matching devname versus a virtio_config entry.
* We use a simple reference count mechanism to ensure that only a single
* mount has a channel open at a time. */
-static struct p9_trans *p9_virtio_create(const char *devname, char *args)
+static struct p9_trans *
+p9_virtio_create(const char *devname, char *args, int msize,
+ unsigned char extended)
{
struct p9_trans *trans;
- int index = 0;
struct virtio_chan *chan = channels;
+ int index = 0;
down(&virtio_9p_lock);
while (index < MAX_9P_CHAN) {
@@ -292,25 +334,45 @@
up(&virtio_9p_lock);
if (index >= MAX_9P_CHAN) {
- printk(KERN_ERR "9p: virtio: couldn't find a free channel\n");
- return NULL;
+ printk(KERN_ERR "9p: no channels available\n");
+ return ERR_PTR(-ENODEV);
}
+ chan->tagpool = p9_idpool_create();
+ if (IS_ERR(chan->tagpool)) {
+ printk(KERN_ERR "9p: couldn't allocate tagpool\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ p9_idpool_get(chan->tagpool); /* reserve tag 0 */
+ chan->max_tag = 0;
+ chan->reqs = NULL;
+
trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
if (!trans) {
printk(KERN_ERR "9p: couldn't allocate transport\n");
return ERR_PTR(-ENOMEM);
}
-
- trans->write = p9_virtio_write;
- trans->read = p9_virtio_read;
+ trans->extended = extended;
+ trans->msize = msize;
trans->close = p9_virtio_close;
- trans->poll = p9_virtio_poll;
+ trans->rpc = p9_virtio_rpc;
trans->priv = chan;
return trans;
}
+static void p9_virtio_remove(struct virtio_device *vdev)
+{
+ struct virtio_chan *chan = vdev->priv;
+
+ BUG_ON(chan->inuse);
+
+ if (chan->initialized) {
+ vdev->config->del_vq(chan->vq);
+ chan->initialized = false;
+ }
+}
+
#define VIRTIO_ID_9P 9
static struct virtio_device_id id_table[] = {
@@ -324,12 +386,13 @@
.driver.owner = THIS_MODULE,
.id_table = id_table,
.probe = p9_virtio_probe,
+ .remove = p9_virtio_remove,
};
static struct p9_trans_module p9_virtio_trans = {
.name = "virtio",
.create = p9_virtio_create,
- .maxsize = PAGE_SIZE,
+ .maxsize = PAGE_SIZE*16,
.def = 0,
};
@@ -345,7 +408,13 @@
return register_virtio_driver(&p9_virtio_drv);
}
+static void __exit p9_virtio_cleanup(void)
+{
+ unregister_virtio_driver(&p9_virtio_drv);
+}
+
module_init(p9_virtio_init);
+module_exit(p9_virtio_cleanup);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
diff --git a/net/9p/util.c b/net/9p/util.c
index 22077b7..ef72155 100644
--- a/net/9p/util.c
+++ b/net/9p/util.c
@@ -33,7 +33,7 @@
#include <net/9p/9p.h>
struct p9_idpool {
- struct semaphore lock;
+ spinlock_t lock;
struct idr pool;
};
@@ -45,7 +45,7 @@
if (!p)
return ERR_PTR(-ENOMEM);
- init_MUTEX(&p->lock);
+ spin_lock_init(&p->lock);
idr_init(&p->pool);
return p;
@@ -71,19 +71,17 @@
{
int i = 0;
int error;
+ unsigned int flags;
retry:
if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
return 0;
- if (down_interruptible(&p->lock) == -EINTR) {
- P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
- return -1;
- }
+ spin_lock_irqsave(&p->lock, flags);
/* no need to store exactly p, we just need something non-null */
error = idr_get_new(&p->pool, p, &i);
- up(&p->lock);
+ spin_unlock_irqrestore(&p->lock, flags);
if (error == -EAGAIN)
goto retry;
@@ -104,12 +102,10 @@
void p9_idpool_put(int id, struct p9_idpool *p)
{
- if (down_interruptible(&p->lock) == -EINTR) {
- P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
- return;
- }
+ unsigned int flags;
+ spin_lock_irqsave(&p->lock, flags);
idr_remove(&p->pool, id);
- up(&p->lock);
+ spin_unlock_irqrestore(&p->lock, flags);
}
EXPORT_SYMBOL(p9_idpool_put);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 782a2260..519cdb9 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -135,8 +135,8 @@
}
}
-static inline int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
+static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
{
unsigned char newleds;
struct sk_buff *skb;
@@ -243,7 +243,8 @@
input_sync(dev);
}
-static inline int hidp_queue_report(struct hidp_session *session, unsigned char *data, int size)
+static int hidp_queue_report(struct hidp_session *session,
+ unsigned char *data, int size)
{
struct sk_buff *skb;
@@ -287,7 +288,7 @@
hidp_schedule(session);
}
-static inline void hidp_set_timer(struct hidp_session *session)
+static void hidp_set_timer(struct hidp_session *session)
{
if (session->idle_to > 0)
mod_timer(&session->timer, jiffies + HZ * session->idle_to);
@@ -332,7 +333,8 @@
return err;
}
-static inline void hidp_process_handshake(struct hidp_session *session, unsigned char param)
+static void hidp_process_handshake(struct hidp_session *session,
+ unsigned char param)
{
BT_DBG("session %p param 0x%02x", session, param);
@@ -365,38 +367,23 @@
}
}
-static inline void hidp_process_hid_control(struct hidp_session *session, unsigned char param)
+static void hidp_process_hid_control(struct hidp_session *session,
+ unsigned char param)
{
BT_DBG("session %p param 0x%02x", session, param);
- switch (param) {
- case HIDP_CTRL_NOP:
- break;
-
- case HIDP_CTRL_VIRTUAL_CABLE_UNPLUG:
+ if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
/* Flush the transmit queues */
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
/* Kill session thread */
atomic_inc(&session->terminate);
- break;
-
- case HIDP_CTRL_HARD_RESET:
- case HIDP_CTRL_SOFT_RESET:
- case HIDP_CTRL_SUSPEND:
- case HIDP_CTRL_EXIT_SUSPEND:
- /* FIXME: We have to parse these and return no error */
- break;
-
- default:
- __hidp_send_ctrl_message(session,
- HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
- break;
}
}
-static inline void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, unsigned char param)
+static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
+ unsigned char param)
{
BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
@@ -423,7 +410,8 @@
}
}
-static inline void hidp_recv_ctrl_frame(struct hidp_session *session, struct sk_buff *skb)
+static void hidp_recv_ctrl_frame(struct hidp_session *session,
+ struct sk_buff *skb)
{
unsigned char hdr, type, param;
@@ -457,7 +445,8 @@
kfree_skb(skb);
}
-static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_buff *skb)
+static void hidp_recv_intr_frame(struct hidp_session *session,
+ struct sk_buff *skb)
{
unsigned char hdr;
@@ -625,7 +614,8 @@
return conn ? &conn->dev : NULL;
}
-static inline int hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
+static int hidp_setup_input(struct hidp_session *session,
+ struct hidp_connadd_req *req)
{
struct input_dev *input = session->input;
int i;
@@ -702,7 +692,8 @@
hid->quirks = hidp_blacklist[n].quirks;
}
-static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_connadd_req *req)
+static void hidp_setup_hid(struct hidp_session *session,
+ struct hidp_connadd_req *req)
{
struct hid_device *hid = session->hid;
struct hid_report *report;
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 788c703..e4c779b 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -429,7 +429,8 @@
if (dev->tty)
tty_vhangup(dev->tty);
- rfcomm_dev_del(dev);
+ if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+ rfcomm_dev_del(dev);
rfcomm_dev_put(dev);
return 0;
}
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 26e941d..7b66083 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -287,7 +287,7 @@
* @ops: pernet operations structure to manipulate
*
* Remove the pernet operations structure from the list to be
- * used when network namespaces are created or destoryed. In
+ * used when network namespaces are created or destroyed. In
* addition run the exit method for all existing network
* namespaces.
*/
@@ -335,7 +335,7 @@
* @ops: pernet operations structure to manipulate
*
* Remove the pernet operations structure from the list to be
- * used when network namespaces are created or destoryed. In
+ * used when network namespaces are created or destroyed. In
* addition run the exit method for all existing network
* namespaces.
*/
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index ddbdde8..61ac8d0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -82,32 +82,6 @@
return mutex_trylock(&rtnl_mutex);
}
-int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
-{
- memset(tb, 0, sizeof(struct rtattr*)*maxattr);
-
- while (RTA_OK(rta, len)) {
- unsigned flavor = rta->rta_type;
- if (flavor && flavor <= maxattr)
- tb[flavor-1] = rta;
- rta = RTA_NEXT(rta, len);
- }
- return 0;
-}
-
-int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
- struct rtattr *rta, int len)
-{
- if (RTA_PAYLOAD(rta) < len)
- return -1;
- if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
- rta = RTA_DATA(rta) + RTA_ALIGN(len);
- return rtattr_parse_nested(tb, maxattr, rta);
- }
- memset(tb, 0, sizeof(struct rtattr *) * maxattr);
- return 0;
-}
-
static struct rtnl_link *rtnl_msg_handlers[NPROTO];
static inline int rtm_msgindex(int msgtype)
@@ -442,21 +416,6 @@
memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
}
-size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
-{
- size_t ret = RTA_PAYLOAD(rta);
- char *src = RTA_DATA(rta);
-
- if (ret > 0 && src[ret - 1] == '\0')
- ret--;
- if (size > 0) {
- size_t len = (ret >= size) ? size - 1 : ret;
- memset(dest, 0, size);
- memcpy(dest, src, len);
- }
- return ret;
-}
-
int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
{
struct sock *rtnl = net->rtnl;
@@ -1411,9 +1370,6 @@
}
EXPORT_SYMBOL(__rta_fill);
-EXPORT_SYMBOL(rtattr_strlcpy);
-EXPORT_SYMBOL(rtattr_parse);
-EXPORT_SYMBOL(__rtattr_parse_nested_compat);
EXPORT_SYMBOL(rtnetlink_put_metrics);
EXPORT_SYMBOL(rtnl_lock);
EXPORT_SYMBOL(rtnl_trylock);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 98420f9..4e35422 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2461,6 +2461,34 @@
return elt;
}
+/**
+ * skb_partial_csum_set - set up and verify partial csum values for packet
+ * @skb: the skb to set
+ * @start: the number of bytes after skb->data to start checksumming.
+ * @off: the offset from start to place the checksum.
+ *
+ * For untrusted partially-checksummed packets, we need to make sure the values
+ * for skb->csum_start and skb->csum_offset are valid so we don't oops.
+ *
+ * This function checks and sets those values and skb->ip_summed: if this
+ * returns false you should drop the packet.
+ */
+bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
+{
+ if (unlikely(start > skb->len - 2) ||
+ unlikely((int)start + off > skb->len - 2)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "bad partial csum: csum=%u/%u len=%u\n",
+ start, off, skb->len);
+ return false;
+ }
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_headroom(skb) + start;
+ skb->csum_offset = off;
+ return true;
+}
+
EXPORT_SYMBOL(___pskb_trim);
EXPORT_SYMBOL(__kfree_skb);
EXPORT_SYMBOL(kfree_skb);
@@ -2497,3 +2525,4 @@
EXPORT_SYMBOL_GPL(skb_to_sgvec);
EXPORT_SYMBOL_GPL(skb_cow_data);
+EXPORT_SYMBOL_GPL(skb_partial_csum_set);
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index ebe59d9..287a62b 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -271,8 +271,6 @@
extern int dccp_connect(struct sock *sk);
extern int dccp_disconnect(struct sock *sk, int flags);
-extern void dccp_hash(struct sock *sk);
-extern void dccp_unhash(struct sock *sk);
extern int dccp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
extern int dccp_setsockopt(struct sock *sk, int level, int optname,
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index c982ad8..474075a 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -38,12 +38,6 @@
*/
static struct socket *dccp_v4_ctl_socket;
-static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
-{
- return inet_csk_get_port(&dccp_hashinfo, sk, snum,
- inet_csk_bind_conflict);
-}
-
int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct inet_sock *inet = inet_sk(sk);
@@ -408,8 +402,8 @@
dccp_sync_mss(newsk, dst_mtu(dst));
- __inet_hash_nolisten(&dccp_hashinfo, newsk);
- __inet_inherit_port(&dccp_hashinfo, sk, newsk);
+ __inet_hash_nolisten(newsk);
+ __inet_inherit_port(sk, newsk);
return newsk;
@@ -898,6 +892,7 @@
.getsockopt = ip_getsockopt,
.addr2sockaddr = inet_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in),
+ .bind_conflict = inet_csk_bind_conflict,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt,
@@ -937,10 +932,10 @@
.sendmsg = dccp_sendmsg,
.recvmsg = dccp_recvmsg,
.backlog_rcv = dccp_v4_do_rcv,
- .hash = dccp_hash,
- .unhash = dccp_unhash,
+ .hash = inet_hash,
+ .unhash = inet_unhash,
.accept = inet_csk_accept,
- .get_port = dccp_v4_get_port,
+ .get_port = inet_csk_get_port,
.shutdown = dccp_shutdown,
.destroy = dccp_destroy_sock,
.orphan_count = &dccp_orphan_count,
@@ -948,6 +943,7 @@
.obj_size = sizeof(struct dccp_sock),
.rsk_prot = &dccp_request_sock_ops,
.twsk_prot = &dccp_timewait_sock_ops,
+ .hashinfo = &dccp_hashinfo,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_dccp_setsockopt,
.compat_getsockopt = compat_dccp_getsockopt,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index ed0a005..490333d 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -39,21 +39,15 @@
static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
-static int dccp_v6_get_port(struct sock *sk, unsigned short snum)
-{
- return inet_csk_get_port(&dccp_hashinfo, sk, snum,
- inet6_csk_bind_conflict);
-}
-
static void dccp_v6_hash(struct sock *sk)
{
if (sk->sk_state != DCCP_CLOSED) {
if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
- dccp_hash(sk);
+ inet_hash(sk);
return;
}
local_bh_disable();
- __inet6_hash(&dccp_hashinfo, sk);
+ __inet6_hash(sk);
local_bh_enable();
}
}
@@ -630,8 +624,8 @@
newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
- __inet6_hash(&dccp_hashinfo, newsk);
- inet_inherit_port(&dccp_hashinfo, sk, newsk);
+ __inet6_hash(newsk);
+ inet_inherit_port(sk, newsk);
return newsk;
@@ -1054,6 +1048,7 @@
.getsockopt = ipv6_getsockopt,
.addr2sockaddr = inet6_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in6),
+ .bind_conflict = inet6_csk_bind_conflict,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ipv6_setsockopt,
.compat_getsockopt = compat_ipv6_getsockopt,
@@ -1123,9 +1118,9 @@
.recvmsg = dccp_recvmsg,
.backlog_rcv = dccp_v6_do_rcv,
.hash = dccp_v6_hash,
- .unhash = dccp_unhash,
+ .unhash = inet_unhash,
.accept = inet_csk_accept,
- .get_port = dccp_v6_get_port,
+ .get_port = inet_csk_get_port,
.shutdown = dccp_shutdown,
.destroy = dccp_v6_destroy_sock,
.orphan_count = &dccp_orphan_count,
@@ -1133,6 +1128,7 @@
.obj_size = sizeof(struct dccp6_sock),
.rsk_prot = &dccp6_request_sock_ops,
.twsk_prot = &dccp6_timewait_sock_ops,
+ .hashinfo = &dccp_hashinfo,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_dccp_setsockopt,
.compat_getsockopt = compat_dccp_getsockopt,
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 0bed4a6..e3f5d37 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -78,7 +78,7 @@
sk->sk_prot->unhash(sk);
if (inet_csk(sk)->icsk_bind_hash != NULL &&
!(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
- inet_put_port(&dccp_hashinfo, sk);
+ inet_put_port(sk);
/* fall through */
default:
if (oldstate == DCCP_OPEN)
@@ -173,20 +173,6 @@
EXPORT_SYMBOL_GPL(dccp_state_name);
-void dccp_hash(struct sock *sk)
-{
- inet_hash(&dccp_hashinfo, sk);
-}
-
-EXPORT_SYMBOL_GPL(dccp_hash);
-
-void dccp_unhash(struct sock *sk)
-{
- inet_unhash(&dccp_hashinfo, sk);
-}
-
-EXPORT_SYMBOL_GPL(dccp_unhash);
-
int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -268,7 +254,7 @@
/* Clean up a referenced DCCP bind bucket. */
if (inet_csk(sk)->icsk_bind_hash != NULL)
- inet_put_port(&dccp_hashinfo, sk);
+ inet_put_port(sk);
kfree(dp->dccps_service_list);
dp->dccps_service_list = NULL;
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index a224106..8cd357f 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -547,8 +547,8 @@
rcu_read_lock();
list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
if (dom_iter->valid)
- netlbl_domhsh_remove(dom_iter->domain,
- audit_info);
+ netlbl_cfg_map_del(dom_iter->domain,
+ audit_info);
rcu_read_unlock();
cipso_v4_cache_invalidate();
call_rcu(&doi_def->rcu, callback);
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 35851c9..f5fba3f 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2431,8 +2431,7 @@
rtn_type(buf2, sizeof(buf2),
fa->fa_type));
if (fa->fa_tos)
- seq_printf(seq, "tos =%d\n",
- fa->fa_tos);
+ seq_printf(seq, " tos=%d", fa->fa_tos);
seq_putc(seq, '\n');
}
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index a7321a8..a13c074 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1015,7 +1015,8 @@
goto error;
}
- __skb_pull(skb, sizeof(*icmph));
+ if (!pskb_pull(skb, sizeof(*icmph)))
+ goto error;
icmph = icmp_hdr(skb);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index de5a41d..b189278 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -78,11 +78,9 @@
/* Obtain a reference to a local port for the given sock,
* if snum is zero it means select any available local port.
*/
-int inet_csk_get_port(struct inet_hashinfo *hashinfo,
- struct sock *sk, unsigned short snum,
- int (*bind_conflict)(const struct sock *sk,
- const struct inet_bind_bucket *tb))
+int inet_csk_get_port(struct sock *sk, unsigned short snum)
{
+ struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
struct inet_bind_hashbucket *head;
struct hlist_node *node;
struct inet_bind_bucket *tb;
@@ -142,7 +140,7 @@
goto success;
} else {
ret = 1;
- if (bind_conflict(sk, tb))
+ if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb))
goto fail_unlock;
}
}
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 48d4500..9cac6c0 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -66,8 +66,9 @@
/*
* Get rid of any references to a local port held by the given sock.
*/
-static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
+static void __inet_put_port(struct sock *sk)
{
+ struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size);
struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
struct inet_bind_bucket *tb;
@@ -81,10 +82,10 @@
spin_unlock(&head->lock);
}
-void inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
+void inet_put_port(struct sock *sk)
{
local_bh_disable();
- __inet_put_port(hashinfo, sk);
+ __inet_put_port(sk);
local_bh_enable();
}
@@ -317,8 +318,9 @@
inet->dport);
}
-void __inet_hash_nolisten(struct inet_hashinfo *hashinfo, struct sock *sk)
+void __inet_hash_nolisten(struct sock *sk)
{
+ struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
struct hlist_head *list;
rwlock_t *lock;
struct inet_ehash_bucket *head;
@@ -337,13 +339,14 @@
}
EXPORT_SYMBOL_GPL(__inet_hash_nolisten);
-void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
+static void __inet_hash(struct sock *sk)
{
+ struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
struct hlist_head *list;
rwlock_t *lock;
if (sk->sk_state != TCP_LISTEN) {
- __inet_hash_nolisten(hashinfo, sk);
+ __inet_hash_nolisten(sk);
return;
}
@@ -357,13 +360,48 @@
write_unlock(lock);
wake_up(&hashinfo->lhash_wait);
}
-EXPORT_SYMBOL_GPL(__inet_hash);
+
+void inet_hash(struct sock *sk)
+{
+ if (sk->sk_state != TCP_CLOSE) {
+ local_bh_disable();
+ __inet_hash(sk);
+ local_bh_enable();
+ }
+}
+EXPORT_SYMBOL_GPL(inet_hash);
+
+void inet_unhash(struct sock *sk)
+{
+ rwlock_t *lock;
+ struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+
+ if (sk_unhashed(sk))
+ goto out;
+
+ if (sk->sk_state == TCP_LISTEN) {
+ local_bh_disable();
+ inet_listen_wlock(hashinfo);
+ lock = &hashinfo->lhash_lock;
+ } else {
+ lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
+ write_lock_bh(lock);
+ }
+
+ if (__sk_del_node_init(sk))
+ sock_prot_inuse_add(sk->sk_prot, -1);
+ write_unlock_bh(lock);
+out:
+ if (sk->sk_state == TCP_LISTEN)
+ wake_up(&hashinfo->lhash_wait);
+}
+EXPORT_SYMBOL_GPL(inet_unhash);
int __inet_hash_connect(struct inet_timewait_death_row *death_row,
- struct sock *sk,
+ struct sock *sk, u32 port_offset,
int (*check_established)(struct inet_timewait_death_row *,
struct sock *, __u16, struct inet_timewait_sock **),
- void (*hash)(struct inet_hashinfo *, struct sock *))
+ void (*hash)(struct sock *sk))
{
struct inet_hashinfo *hinfo = death_row->hashinfo;
const unsigned short snum = inet_sk(sk)->num;
@@ -375,7 +413,7 @@
if (!snum) {
int i, remaining, low, high, port;
static u32 hint;
- u32 offset = hint + inet_sk_port_offset(sk);
+ u32 offset = hint + port_offset;
struct hlist_node *node;
struct inet_timewait_sock *tw = NULL;
@@ -427,7 +465,7 @@
inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) {
inet_sk(sk)->sport = htons(port);
- hash(hinfo, sk);
+ hash(sk);
}
spin_unlock(&head->lock);
@@ -444,7 +482,7 @@
tb = inet_csk(sk)->icsk_bind_hash;
spin_lock_bh(&head->lock);
if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
- hash(hinfo, sk);
+ hash(sk);
spin_unlock_bh(&head->lock);
return 0;
} else {
@@ -464,7 +502,7 @@
int inet_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk)
{
- return __inet_hash_connect(death_row, sk,
+ return __inet_hash_connect(death_row, sk, inet_sk_port_offset(sk),
__inet_check_established, __inet_hash_nolisten);
}
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 749fa04..85c680a 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/net.h>
#include <net/ip_vs.h>
@@ -169,7 +170,7 @@
*/
if (mark->cw == 0) {
mark->cl = &svc->destinations;
- IP_VS_INFO("ip_vs_wrr_schedule(): "
+ IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
"no available servers\n");
dest = NULL;
goto out;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index a0d373b..071e83a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1669,7 +1669,7 @@
sk->sk_prot->unhash(sk);
if (inet_csk(sk)->icsk_bind_hash &&
!(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
- inet_put_port(&tcp_hashinfo, sk);
+ inet_put_port(sk);
/* fall through */
default:
if (oldstate==TCP_ESTABLISHED)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 77c1939..63414ea42 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -108,22 +108,6 @@
.lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
};
-static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
-{
- return inet_csk_get_port(&tcp_hashinfo, sk, snum,
- inet_csk_bind_conflict);
-}
-
-static void tcp_v4_hash(struct sock *sk)
-{
- inet_hash(&tcp_hashinfo, sk);
-}
-
-void tcp_unhash(struct sock *sk)
-{
- inet_unhash(&tcp_hashinfo, sk);
-}
-
static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
{
return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
@@ -1478,8 +1462,8 @@
}
#endif
- __inet_hash_nolisten(&tcp_hashinfo, newsk);
- __inet_inherit_port(&tcp_hashinfo, sk, newsk);
+ __inet_hash_nolisten(newsk);
+ __inet_inherit_port(sk, newsk);
return newsk;
@@ -1827,6 +1811,7 @@
.getsockopt = ip_getsockopt,
.addr2sockaddr = inet_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in),
+ .bind_conflict = inet_csk_bind_conflict,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt,
@@ -1926,7 +1911,7 @@
/* Clean up a referenced TCP bind bucket. */
if (inet_csk(sk)->icsk_bind_hash)
- inet_put_port(&tcp_hashinfo, sk);
+ inet_put_port(sk);
/*
* If sendmsg cached page exists, toss it.
@@ -2435,9 +2420,9 @@
.getsockopt = tcp_getsockopt,
.recvmsg = tcp_recvmsg,
.backlog_rcv = tcp_v4_do_rcv,
- .hash = tcp_v4_hash,
- .unhash = tcp_unhash,
- .get_port = tcp_v4_get_port,
+ .hash = inet_hash,
+ .unhash = inet_unhash,
+ .get_port = inet_csk_get_port,
.enter_memory_pressure = tcp_enter_memory_pressure,
.sockets_allocated = &tcp_sockets_allocated,
.orphan_count = &tcp_orphan_count,
@@ -2450,6 +2435,7 @@
.obj_size = sizeof(struct tcp_sock),
.twsk_prot = &tcp_timewait_sock_ops,
.rsk_prot = &tcp_request_sock_ops,
+ .hashinfo = &tcp_hashinfo,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
@@ -2467,7 +2453,6 @@
EXPORT_SYMBOL(ipv4_specific);
EXPORT_SYMBOL(tcp_hashinfo);
EXPORT_SYMBOL(tcp_prot);
-EXPORT_SYMBOL(tcp_unhash);
EXPORT_SYMBOL(tcp_v4_conn_request);
EXPORT_SYMBOL(tcp_v4_connect);
EXPORT_SYMBOL(tcp_v4_do_rcv);
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index e093a7b..b47030b 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -102,7 +102,7 @@
XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
- if (!pskb_may_pull(skb, phlen));
+ if (!pskb_may_pull(skb, phlen))
goto out;
__skb_pull(skb, phlen);
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index cbb5b9c..121d517 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -683,7 +683,8 @@
}
}
- __skb_pull(skb, sizeof(*hdr));
+ if (!pskb_pull(skb, sizeof(*hdr)))
+ goto discard_it;
hdr = icmp6_hdr(skb);
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index d325a99..99fd25f 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -22,9 +22,9 @@
#include <net/inet6_hashtables.h>
#include <net/ip.h>
-void __inet6_hash(struct inet_hashinfo *hashinfo,
- struct sock *sk)
+void __inet6_hash(struct sock *sk)
{
+ struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
struct hlist_head *list;
rwlock_t *lock;
@@ -236,7 +236,7 @@
int inet6_hash_connect(struct inet_timewait_death_row *death_row,
struct sock *sk)
{
- return __inet_hash_connect(death_row, sk,
+ return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk),
__inet6_check_established, __inet6_hash);
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 59d0029..12750f2 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -86,12 +86,6 @@
static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
#endif
-static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
-{
- return inet_csk_get_port(&tcp_hashinfo, sk, snum,
- inet6_csk_bind_conflict);
-}
-
static void tcp_v6_hash(struct sock *sk)
{
if (sk->sk_state != TCP_CLOSE) {
@@ -100,7 +94,7 @@
return;
}
local_bh_disable();
- __inet6_hash(&tcp_hashinfo, sk);
+ __inet6_hash(sk);
local_bh_enable();
}
}
@@ -1504,8 +1498,8 @@
}
#endif
- __inet6_hash(&tcp_hashinfo, newsk);
- inet_inherit_port(&tcp_hashinfo, sk, newsk);
+ __inet6_hash(newsk);
+ inet_inherit_port(sk, newsk);
return newsk;
@@ -1833,6 +1827,7 @@
.getsockopt = ipv6_getsockopt,
.addr2sockaddr = inet6_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in6),
+ .bind_conflict = inet6_csk_bind_conflict,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ipv6_setsockopt,
.compat_getsockopt = compat_ipv6_getsockopt,
@@ -1864,6 +1859,7 @@
.getsockopt = ipv6_getsockopt,
.addr2sockaddr = inet6_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in6),
+ .bind_conflict = inet6_csk_bind_conflict,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ipv6_setsockopt,
.compat_getsockopt = compat_ipv6_getsockopt,
@@ -2127,8 +2123,8 @@
.recvmsg = tcp_recvmsg,
.backlog_rcv = tcp_v6_do_rcv,
.hash = tcp_v6_hash,
- .unhash = tcp_unhash,
- .get_port = tcp_v6_get_port,
+ .unhash = inet_unhash,
+ .get_port = inet_csk_get_port,
.enter_memory_pressure = tcp_enter_memory_pressure,
.sockets_allocated = &tcp_sockets_allocated,
.memory_allocated = &tcp_memory_allocated,
@@ -2141,6 +2137,7 @@
.obj_size = sizeof(struct tcp6_sock),
.twsk_prot = &tcp6_timewait_sock_ops,
.rsk_prot = &tcp6_request_sock_ops,
+ .hashinfo = &tcp_hashinfo,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 09c25500..45c7c0c 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -1,6 +1,5 @@
config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
- depends on EXPERIMENTAL
select CRYPTO
select CRYPTO_ECB
select CRYPTO_ARC4
@@ -98,6 +97,18 @@
Say N unless you know you need this.
+config MAC80211_DEBUG_PACKET_ALIGNMENT
+ bool "Enable packet alignment debugging"
+ depends on MAC80211
+ help
+ This option is recommended for driver authors and strongly
+ discouraged for everybody else, it will trigger a warning
+ when a driver hands mac80211 a buffer that is aligned in
+ a way that will cause problems with the IP stack on some
+ architectures.
+
+ Say N unless you're writing a mac80211 based driver.
+
config MAC80211_DEBUG
bool "Enable debugging output"
depends on MAC80211
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 5dcc2d6..67b7c75c 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -1344,17 +1344,17 @@
ret = rc80211_simple_init();
if (ret)
- goto fail;
+ goto out;
ret = rc80211_pid_init();
if (ret)
- goto fail_simple;
+ goto out_cleanup_simple;
ret = ieee80211_wme_register();
if (ret) {
printk(KERN_DEBUG "ieee80211_init: failed to "
"initialize WME (err=%d)\n", ret);
- goto fail_pid;
+ goto out_cleanup_pid;
}
ieee80211_debugfs_netdev_init();
@@ -1362,11 +1362,11 @@
return 0;
- fail_pid:
- rc80211_simple_exit();
- fail_simple:
+ out_cleanup_pid:
rc80211_pid_exit();
- fail:
+ out_cleanup_simple:
+ rc80211_simple_exit();
+ out:
return ret;
}
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 554c4ba..c339571 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -538,7 +538,7 @@
return ieee80211_rate_control_register(&mac80211_rcpid);
}
-void __exit rc80211_pid_exit(void)
+void rc80211_pid_exit(void)
{
ieee80211_rate_control_unregister(&mac80211_rcpid);
}
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
index 934676d..9a78b11 100644
--- a/net/mac80211/rc80211_simple.c
+++ b/net/mac80211/rc80211_simple.c
@@ -389,7 +389,7 @@
return ieee80211_rate_control_register(&mac80211_rcsimple);
}
-void __exit rc80211_simple_exit(void)
+void rc80211_simple_exit(void)
{
ieee80211_rate_control_unregister(&mac80211_rcsimple);
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d44c872..535407d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -340,11 +340,15 @@
return load;
}
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
static ieee80211_txrx_result
ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx)
{
int hdrlen;
+ if (!WLAN_FC_DATA_PRESENT(rx->fc))
+ return TXRX_CONTINUE;
+
/*
* Drivers are required to align the payload data in a way that
* guarantees that the contained IP header is aligned to a four-
@@ -371,11 +375,14 @@
return TXRX_CONTINUE;
}
+#endif
ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
{
ieee80211_rx_h_parse_qos,
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
ieee80211_rx_h_verify_ip_alignment,
+#endif
NULL
};
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index becf91a..c7ad64d 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -90,7 +90,7 @@
* safely.
*
*/
-static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
+void netlbl_cipsov4_doi_free(struct rcu_head *entry)
{
struct cipso_v4_doi *ptr;
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h
index f03cf9b..220cb9d 100644
--- a/net/netlabel/netlabel_cipso_v4.h
+++ b/net/netlabel/netlabel_cipso_v4.h
@@ -163,4 +163,7 @@
/* NetLabel protocol functions */
int netlbl_cipsov4_genl_init(void);
+/* Free the memory associated with a CIPSOv4 DOI definition */
+void netlbl_cipsov4_doi_free(struct rcu_head *entry);
+
#endif
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index 3689956..8220990 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -61,6 +61,7 @@
struct netlbl_audit *audit_info);
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
int netlbl_domhsh_walk(u32 *skip_bkt,
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index c69e3e1..39793a1 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/audit.h>
#include <net/ip.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
@@ -38,10 +39,186 @@
#include "netlabel_domainhash.h"
#include "netlabel_unlabeled.h"
+#include "netlabel_cipso_v4.h"
#include "netlabel_user.h"
#include "netlabel_mgmt.h"
/*
+ * Configuration Functions
+ */
+
+/**
+ * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
+ * @domain: the domain mapping to remove
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes a NetLabel/LSM domain mapping. A @domain value of NULL causes the
+ * default domain mapping to be removed. Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
+{
+ return netlbl_domhsh_remove(domain, audit_info);
+}
+
+/**
+ * netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping
+ * @domain: the domain mapping to add
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Adds a new unlabeled NetLabel/LSM domain mapping. A @domain value of NULL
+ * causes a new default domain mapping to be added. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int netlbl_cfg_unlbl_add_map(const char *domain,
+ struct netlbl_audit *audit_info)
+{
+ int ret_val = -ENOMEM;
+ struct netlbl_dom_map *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry == NULL)
+ goto cfg_unlbl_add_map_failure;
+ if (domain != NULL) {
+ entry->domain = kstrdup(domain, GFP_ATOMIC);
+ if (entry->domain == NULL)
+ goto cfg_unlbl_add_map_failure;
+ }
+ entry->type = NETLBL_NLTYPE_UNLABELED;
+
+ ret_val = netlbl_domhsh_add(entry, audit_info);
+ if (ret_val != 0)
+ goto cfg_unlbl_add_map_failure;
+
+ return 0;
+
+cfg_unlbl_add_map_failure:
+ if (entry != NULL)
+ kfree(entry->domain);
+ kfree(entry);
+ return ret_val;
+}
+
+/**
+ * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
+ * @doi_def: the DOI definition
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Add a new CIPSOv4 DOI definition to the NetLabel subsystem. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+ struct netlbl_audit *audit_info)
+{
+ int ret_val;
+ const char *type_str;
+ struct audit_buffer *audit_buf;
+
+ ret_val = cipso_v4_doi_add(doi_def);
+
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+ audit_info);
+ if (audit_buf != NULL) {
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_STD:
+ type_str = "std";
+ break;
+ case CIPSO_V4_MAP_PASS:
+ type_str = "pass";
+ break;
+ default:
+ type_str = "(unknown)";
+ }
+ audit_log_format(audit_buf,
+ " cipso_doi=%u cipso_type=%s res=%u",
+ doi_def->doi,
+ type_str,
+ ret_val == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
+ }
+
+ return ret_val;
+}
+
+/**
+ * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
+ * @doi_def: the DOI definition
+ * @domain: the domain mapping to add
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this
+ * new DOI definition to the NetLabel subsystem. A @domain value of NULL adds
+ * a new default domain mapping. Returns zero on success, negative values on
+ * failure.
+ *
+ */
+int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+ const char *domain,
+ struct netlbl_audit *audit_info)
+{
+ int ret_val = -ENOMEM;
+ struct netlbl_dom_map *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry == NULL)
+ goto cfg_cipsov4_add_map_failure;
+ if (domain != NULL) {
+ entry->domain = kstrdup(domain, GFP_ATOMIC);
+ if (entry->domain == NULL)
+ goto cfg_cipsov4_add_map_failure;
+ }
+ entry->type = NETLBL_NLTYPE_CIPSOV4;
+ entry->type_def.cipsov4 = doi_def;
+
+ /* Grab a RCU read lock here so nothing happens to the doi_def variable
+ * between adding it to the CIPSOv4 protocol engine and adding a
+ * domain mapping for it. */
+
+ rcu_read_lock();
+ ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
+ if (ret_val != 0)
+ goto cfg_cipsov4_add_map_failure_unlock;
+ ret_val = netlbl_domhsh_add(entry, audit_info);
+ if (ret_val != 0)
+ goto cfg_cipsov4_add_map_failure_remove_doi;
+ rcu_read_unlock();
+
+ return 0;
+
+cfg_cipsov4_add_map_failure_remove_doi:
+ cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
+cfg_cipsov4_add_map_failure_unlock:
+ rcu_read_unlock();
+cfg_cipsov4_add_map_failure:
+ if (entry != NULL)
+ kfree(entry->domain);
+ kfree(entry);
+ return ret_val;
+}
+
+/**
+ * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
+ * @doi: the CIPSO DOI value
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
+{
+ return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
+}
+
+/*
* Security Attribute Functions
*/
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 6562f86..1a47f5d 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -340,7 +340,7 @@
* rfkill_free - Mark rfkill structure for deletion
* @rfkill: rfkill structure to be destroyed
*
- * Decrements reference count of rfkill structure so it is destoryed.
+ * Decrements reference count of rfkill structure so it is destroyed.
* Note that rfkill_free() should _not_ be called after rfkill_unregister().
*/
void rfkill_free(struct rfkill *rfkill)
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 5a7f6a3..971b867 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -19,6 +19,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
+#include <linux/if_vlan.h>
#include <net/pkt_cls.h>
#include <net/ip.h>
@@ -270,6 +271,15 @@
return 0;
}
+static u32 flow_get_vlan_tag(const struct sk_buff *skb)
+{
+ u16 uninitialized_var(tag);
+
+ if (vlan_get_tag(skb, &tag) < 0)
+ return 0;
+ return tag & VLAN_VID_MASK;
+}
+
static u32 flow_key_get(const struct sk_buff *skb, int key)
{
switch (key) {
@@ -305,6 +315,8 @@
return flow_get_skuid(skb);
case FLOW_KEY_SKGID:
return flow_get_skgid(skb);
+ case FLOW_KEY_VLAN_TAG:
+ return flow_get_vlan_tag(skb);
default:
WARN_ON(1);
return 0;
@@ -402,12 +414,13 @@
if (tb[TCA_FLOW_KEYS]) {
keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);
- if (fls(keymask) - 1 > FLOW_KEY_MAX)
- return -EOPNOTSUPP;
nkeys = hweight32(keymask);
if (nkeys == 0)
return -EINVAL;
+
+ if (fls(keymask) - 1 > FLOW_KEY_MAX)
+ return -EOPNOTSUPP;
}
err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
@@ -594,11 +607,11 @@
if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
goto nla_put_failure;
-
+#ifdef CONFIG_NET_EMATCH
if (f->ematches.hdr.nmatches &&
tcf_em_tree_dump(skb, &f->ematches, TCA_FLOW_EMATCHES) < 0)
goto nla_put_failure;
-
+#endif
nla_nest_end(skb, nest);
if (tcf_exts_dump_stats(skb, &f->exts, &flow_ext_map) < 0)
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index a1e5619..2a7e648 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -65,6 +65,7 @@
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/random.h>
+#include <linux/if_vlan.h>
#include <linux/tc_ematch/tc_em_meta.h>
#include <net/dst.h>
#include <net/route.h>
@@ -170,6 +171,21 @@
}
/**************************************************************************
+ * vlan tag
+ **************************************************************************/
+
+META_COLLECTOR(int_vlan_tag)
+{
+ unsigned short uninitialized_var(tag);
+ if (vlan_get_tag(skb, &tag) < 0)
+ *err = -1;
+ else
+ dst->value = tag;
+}
+
+
+
+/**************************************************************************
* skb attributes
**************************************************************************/
@@ -520,6 +536,7 @@
[META_ID(SK_SNDTIMEO)] = META_FUNC(int_sk_sndtimeo),
[META_ID(SK_SENDMSG_OFF)] = META_FUNC(int_sk_sendmsg_off),
[META_ID(SK_WRITE_PENDING)] = META_FUNC(int_sk_write_pend),
+ [META_ID(VLAN_TAG)] = META_FUNC(int_vlan_tag),
}
};
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 97e6ebd..ae367c8 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -420,15 +420,15 @@
const struct sctp_association *asoc,
__u16 key_id)
{
- struct sctp_shared_key *key = NULL;
+ struct sctp_shared_key *key;
/* First search associations set of endpoint pair shared keys */
key_for_each(key, &asoc->endpoint_shared_keys) {
if (key->key_id == key_id)
- break;
+ return key;
}
- return key;
+ return NULL;
}
/*
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 61cbd5a..f986587 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -537,7 +537,7 @@
*
* This means that if we only want to abort associations
* in an authenticated way (i.e AUTH+ABORT), then we
- * can't destory this association just becuase the packet
+ * can't destroy this association just becuase the packet
* was malformed.
*/
if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
@@ -3865,6 +3865,10 @@
struct sctp_chunk *err_chunk;
sctp_ierror_t error;
+ /* Make sure that the peer has AUTH capable */
+ if (!asoc->peer.auth_capable)
+ return sctp_sf_unk_chunk(ep, asoc, type, arg, commands);
+
if (!sctp_vtag_verify(chunk, asoc)) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
SCTP_NULL());
@@ -4130,7 +4134,7 @@
*
* This means that if we only want to abort associations
* in an authenticated way (i.e AUTH+ABORT), then we
- * can't destory this association just becuase the packet
+ * can't destroy this association just becuase the packet
* was malformed.
*/
if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index 5c69a72..92e1dbe 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -11,6 +11,7 @@
auth.o auth_null.o auth_unix.o \
svc.o svcsock.o svcauth.o svcauth_unix.o \
rpcb_clnt.o timer.o xdr.o \
- sunrpc_syms.o cache.o rpc_pipe.o
+ sunrpc_syms.o cache.o rpc_pipe.o \
+ svc_xprt.o
sunrpc-$(CONFIG_PROC_FS) += stats.o
sunrpc-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 73940df..481f984 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -224,38 +224,34 @@
/* major/minor */
len = qword_get(&mesg, buf, mlen);
+ if (len <= 0)
+ goto out;
+ rsii.major_status = simple_strtoul(buf, &ep, 10);
+ if (*ep)
+ goto out;
+ len = qword_get(&mesg, buf, mlen);
+ if (len <= 0)
+ goto out;
+ rsii.minor_status = simple_strtoul(buf, &ep, 10);
+ if (*ep)
+ goto out;
+
+ /* out_handle */
+ len = qword_get(&mesg, buf, mlen);
if (len < 0)
goto out;
- if (len == 0) {
+ status = -ENOMEM;
+ if (dup_to_netobj(&rsii.out_handle, buf, len))
goto out;
- } else {
- rsii.major_status = simple_strtoul(buf, &ep, 10);
- if (*ep)
- goto out;
- len = qword_get(&mesg, buf, mlen);
- if (len <= 0)
- goto out;
- rsii.minor_status = simple_strtoul(buf, &ep, 10);
- if (*ep)
- goto out;
- /* out_handle */
- len = qword_get(&mesg, buf, mlen);
- if (len < 0)
- goto out;
- status = -ENOMEM;
- if (dup_to_netobj(&rsii.out_handle, buf, len))
- goto out;
-
- /* out_token */
- len = qword_get(&mesg, buf, mlen);
- status = -EINVAL;
- if (len < 0)
- goto out;
- status = -ENOMEM;
- if (dup_to_netobj(&rsii.out_token, buf, len))
- goto out;
- }
+ /* out_token */
+ len = qword_get(&mesg, buf, mlen);
+ status = -EINVAL;
+ if (len < 0)
+ goto out;
+ status = -ENOMEM;
+ if (dup_to_netobj(&rsii.out_token, buf, len))
+ goto out;
rsii.h.expiry_time = expiry;
rsip = rsi_update(&rsii, rsip);
status = 0;
@@ -975,6 +971,7 @@
struct kvec *resv = &rqstp->rq_res.head[0];
struct xdr_netobj tmpobj;
struct rsi *rsip, rsikey;
+ int ret;
/* Read the verifier; should be NULL: */
*authp = rpc_autherr_badverf;
@@ -1014,23 +1011,27 @@
/* No upcall result: */
return SVC_DROP;
case 0:
+ ret = SVC_DROP;
/* Got an answer to the upcall; use it: */
if (gss_write_init_verf(rqstp, rsip))
- return SVC_DROP;
+ goto out;
if (resv->iov_len + 4 > PAGE_SIZE)
- return SVC_DROP;
+ goto out;
svc_putnl(resv, RPC_SUCCESS);
if (svc_safe_putnetobj(resv, &rsip->out_handle))
- return SVC_DROP;
+ goto out;
if (resv->iov_len + 3 * 4 > PAGE_SIZE)
- return SVC_DROP;
+ goto out;
svc_putnl(resv, rsip->major_status);
svc_putnl(resv, rsip->minor_status);
svc_putnl(resv, GSS_SEQ_WIN);
if (svc_safe_putnetobj(resv, &rsip->out_token))
- return SVC_DROP;
+ goto out;
}
- return SVC_COMPLETE;
+ ret = SVC_COMPLETE;
+out:
+ cache_put(&rsip->h, &rsi_cache);
+ return ret;
}
/*
@@ -1125,6 +1126,7 @@
case RPC_GSS_PROC_DESTROY:
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err;
+ rsci->h.expiry_time = get_seconds();
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
@@ -1386,19 +1388,26 @@
gss_svc_init(void)
{
int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
- if (rv == 0) {
- cache_register(&rsc_cache);
- cache_register(&rsi_cache);
- }
+ if (rv)
+ return rv;
+ rv = cache_register(&rsc_cache);
+ if (rv)
+ goto out1;
+ rv = cache_register(&rsi_cache);
+ if (rv)
+ goto out2;
+ return 0;
+out2:
+ cache_unregister(&rsc_cache);
+out1:
+ svc_auth_unregister(RPC_AUTH_GSS);
return rv;
}
void
gss_svc_shutdown(void)
{
- if (cache_unregister(&rsc_cache))
- printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");
- if (cache_unregister(&rsi_cache))
- printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");
+ cache_unregister(&rsc_cache);
+ cache_unregister(&rsi_cache);
svc_auth_unregister(RPC_AUTH_GSS);
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 73f053d..636c8e0 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -245,6 +245,7 @@
cache_put(h, detail);
return rv;
}
+EXPORT_SYMBOL(cache_check);
/*
* caches need to be periodically cleaned.
@@ -290,44 +291,78 @@
static void do_cache_clean(struct work_struct *work);
static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
-void cache_register(struct cache_detail *cd)
+static void remove_cache_proc_entries(struct cache_detail *cd)
{
+ if (cd->proc_ent == NULL)
+ return;
+ if (cd->flush_ent)
+ remove_proc_entry("flush", cd->proc_ent);
+ if (cd->channel_ent)
+ remove_proc_entry("channel", cd->proc_ent);
+ if (cd->content_ent)
+ remove_proc_entry("content", cd->proc_ent);
+ cd->proc_ent = NULL;
+ remove_proc_entry(cd->name, proc_net_rpc);
+}
+
+#ifdef CONFIG_PROC_FS
+static int create_cache_proc_entries(struct cache_detail *cd)
+{
+ struct proc_dir_entry *p;
+
cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
- if (cd->proc_ent) {
- struct proc_dir_entry *p;
- cd->proc_ent->owner = cd->owner;
- cd->channel_ent = cd->content_ent = NULL;
+ if (cd->proc_ent == NULL)
+ goto out_nomem;
+ cd->proc_ent->owner = cd->owner;
+ cd->channel_ent = cd->content_ent = NULL;
- p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
+ p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR, cd->proc_ent);
+ cd->flush_ent = p;
+ if (p == NULL)
+ goto out_nomem;
+ p->proc_fops = &cache_flush_operations;
+ p->owner = cd->owner;
+ p->data = cd;
+
+ if (cd->cache_request || cd->cache_parse) {
+ p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
cd->proc_ent);
- cd->flush_ent = p;
- if (p) {
- p->proc_fops = &cache_flush_operations;
- p->owner = cd->owner;
- p->data = cd;
- }
-
- if (cd->cache_request || cd->cache_parse) {
- p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
- cd->proc_ent);
- cd->channel_ent = p;
- if (p) {
- p->proc_fops = &cache_file_operations;
- p->owner = cd->owner;
- p->data = cd;
- }
- }
- if (cd->cache_show) {
- p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
- cd->proc_ent);
- cd->content_ent = p;
- if (p) {
- p->proc_fops = &content_file_operations;
- p->owner = cd->owner;
- p->data = cd;
- }
- }
+ cd->channel_ent = p;
+ if (p == NULL)
+ goto out_nomem;
+ p->proc_fops = &cache_file_operations;
+ p->owner = cd->owner;
+ p->data = cd;
}
+ if (cd->cache_show) {
+ p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
+ cd->proc_ent);
+ cd->content_ent = p;
+ if (p == NULL)
+ goto out_nomem;
+ p->proc_fops = &content_file_operations;
+ p->owner = cd->owner;
+ p->data = cd;
+ }
+ return 0;
+out_nomem:
+ remove_cache_proc_entries(cd);
+ return -ENOMEM;
+}
+#else /* CONFIG_PROC_FS */
+static int create_cache_proc_entries(struct cache_detail *cd)
+{
+ return 0;
+}
+#endif
+
+int cache_register(struct cache_detail *cd)
+{
+ int ret;
+
+ ret = create_cache_proc_entries(cd);
+ if (ret)
+ return ret;
rwlock_init(&cd->hash_lock);
INIT_LIST_HEAD(&cd->queue);
spin_lock(&cache_list_lock);
@@ -341,9 +376,11 @@
/* start the cleaning process */
schedule_delayed_work(&cache_cleaner, 0);
+ return 0;
}
+EXPORT_SYMBOL(cache_register);
-int cache_unregister(struct cache_detail *cd)
+void cache_unregister(struct cache_detail *cd)
{
cache_purge(cd);
spin_lock(&cache_list_lock);
@@ -351,30 +388,23 @@
if (cd->entries || atomic_read(&cd->inuse)) {
write_unlock(&cd->hash_lock);
spin_unlock(&cache_list_lock);
- return -EBUSY;
+ goto out;
}
if (current_detail == cd)
current_detail = NULL;
list_del_init(&cd->others);
write_unlock(&cd->hash_lock);
spin_unlock(&cache_list_lock);
- if (cd->proc_ent) {
- if (cd->flush_ent)
- remove_proc_entry("flush", cd->proc_ent);
- if (cd->channel_ent)
- remove_proc_entry("channel", cd->proc_ent);
- if (cd->content_ent)
- remove_proc_entry("content", cd->proc_ent);
-
- cd->proc_ent = NULL;
- remove_proc_entry(cd->name, proc_net_rpc);
- }
+ remove_cache_proc_entries(cd);
if (list_empty(&cache_list)) {
/* module must be being unloaded so its safe to kill the worker */
cancel_delayed_work_sync(&cache_cleaner);
}
- return 0;
+ return;
+out:
+ printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
}
+EXPORT_SYMBOL(cache_unregister);
/* clean cache tries to find something to clean
* and cleans it.
@@ -489,6 +519,7 @@
while (cache_clean() != -1)
cond_resched();
}
+EXPORT_SYMBOL(cache_flush);
void cache_purge(struct cache_detail *detail)
{
@@ -497,7 +528,7 @@
cache_flush();
detail->flush_time = 1;
}
-
+EXPORT_SYMBOL(cache_purge);
/*
@@ -634,13 +665,13 @@
/*
* communicate with user-space
*
- * We have a magic /proc file - /proc/sunrpc/cache
- * On read, you get a full request, or block
- * On write, an update request is processed
- * Poll works if anything to read, and always allows write
+ * We have a magic /proc file - /proc/sunrpc/<cachename>/channel.
+ * On read, you get a full request, or block.
+ * On write, an update request is processed.
+ * Poll works if anything to read, and always allows write.
*
* Implemented by linked list of requests. Each open file has
- * a ->private that also exists in this list. New request are added
+ * a ->private that also exists in this list. New requests are added
* to the end and may wakeup and preceding readers.
* New readers are added to the head. If, on read, an item is found with
* CACHE_UPCALLING clear, we free it from the list.
@@ -963,6 +994,7 @@
*bpp = bp;
*lp = len;
}
+EXPORT_SYMBOL(qword_add);
void qword_addhex(char **bpp, int *lp, char *buf, int blen)
{
@@ -991,6 +1023,7 @@
*bpp = bp;
*lp = len;
}
+EXPORT_SYMBOL(qword_addhex);
static void warn_no_listener(struct cache_detail *detail)
{
@@ -1113,6 +1146,7 @@
*dest = '\0';
return len;
}
+EXPORT_SYMBOL(qword_get);
/*
@@ -1244,18 +1278,18 @@
struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
char tbuf[20];
unsigned long p = *ppos;
- int len;
+ size_t len;
sprintf(tbuf, "%lu\n", cd->flush_time);
len = strlen(tbuf);
if (p >= len)
return 0;
len -= p;
- if (len > count) len = count;
+ if (len > count)
+ len = count;
if (copy_to_user(buf, (void*)(tbuf+p), len))
- len = -EFAULT;
- else
- *ppos += len;
+ return -EFAULT;
+ *ppos += len;
return len;
}
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 74df2d3..5a16875 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -33,7 +33,7 @@
static int rpc_proc_show(struct seq_file *seq, void *v) {
const struct rpc_stat *statp = seq->private;
const struct rpc_program *prog = statp->program;
- int i, j;
+ unsigned int i, j;
seq_printf(seq,
"net %u %u %u %u\n",
@@ -81,7 +81,7 @@
const struct svc_program *prog = statp->program;
const struct svc_procedure *proc;
const struct svc_version *vers;
- int i, j;
+ unsigned int i, j;
seq_printf(seq,
"net %u %u %u %u\n",
@@ -106,6 +106,7 @@
seq_putc(seq, '\n');
}
}
+EXPORT_SYMBOL(svc_seq_show);
/**
* rpc_alloc_iostats - allocate an rpc_iostats structure
@@ -255,12 +256,14 @@
{
return do_register(statp->program->pg_name, statp, fops);
}
+EXPORT_SYMBOL(svc_proc_register);
void
svc_proc_unregister(const char *name)
{
remove_proc_entry(name, proc_net_rpc);
}
+EXPORT_SYMBOL(svc_proc_unregister);
void
rpc_proc_init(void)
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 1a7e309..843629f 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -22,48 +22,6 @@
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/xprtsock.h>
-/* RPC server stuff */
-EXPORT_SYMBOL(svc_create);
-EXPORT_SYMBOL(svc_create_thread);
-EXPORT_SYMBOL(svc_create_pooled);
-EXPORT_SYMBOL(svc_set_num_threads);
-EXPORT_SYMBOL(svc_exit_thread);
-EXPORT_SYMBOL(svc_destroy);
-EXPORT_SYMBOL(svc_drop);
-EXPORT_SYMBOL(svc_process);
-EXPORT_SYMBOL(svc_recv);
-EXPORT_SYMBOL(svc_wake_up);
-EXPORT_SYMBOL(svc_makesock);
-EXPORT_SYMBOL(svc_reserve);
-EXPORT_SYMBOL(svc_auth_register);
-EXPORT_SYMBOL(auth_domain_lookup);
-EXPORT_SYMBOL(svc_authenticate);
-EXPORT_SYMBOL(svc_set_client);
-
-/* RPC statistics */
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(svc_proc_register);
-EXPORT_SYMBOL(svc_proc_unregister);
-EXPORT_SYMBOL(svc_seq_show);
-#endif
-
-/* caching... */
-EXPORT_SYMBOL(auth_domain_find);
-EXPORT_SYMBOL(auth_domain_put);
-EXPORT_SYMBOL(auth_unix_add_addr);
-EXPORT_SYMBOL(auth_unix_forget_old);
-EXPORT_SYMBOL(auth_unix_lookup);
-EXPORT_SYMBOL(cache_check);
-EXPORT_SYMBOL(cache_flush);
-EXPORT_SYMBOL(cache_purge);
-EXPORT_SYMBOL(cache_register);
-EXPORT_SYMBOL(cache_unregister);
-EXPORT_SYMBOL(qword_add);
-EXPORT_SYMBOL(qword_addhex);
-EXPORT_SYMBOL(qword_get);
-EXPORT_SYMBOL(svcauth_unix_purge);
-EXPORT_SYMBOL(unix_domain_find);
-
extern struct cache_detail ip_map_cache, unix_gid_cache;
static int __init
@@ -85,7 +43,8 @@
#endif
cache_register(&ip_map_cache);
cache_register(&unix_gid_cache);
- init_socket_xprt();
+ svc_init_xprt_sock(); /* svc sock transport */
+ init_socket_xprt(); /* clnt sock transport */
rpcauth_init_module();
out:
return err;
@@ -96,12 +55,11 @@
{
rpcauth_remove_module();
cleanup_socket_xprt();
+ svc_cleanup_xprt_sock();
unregister_rpc_pipefs();
rpc_destroy_mempool();
- if (cache_unregister(&ip_map_cache))
- printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
- if (cache_unregister(&unix_gid_cache))
- printk(KERN_ERR "sunrpc: failed to unregister unix_gid cache\n");
+ cache_unregister(&ip_map_cache);
+ cache_unregister(&unix_gid_cache);
#ifdef RPC_DEBUG
rpc_unregister_sysctl();
#endif
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 4ad5fbb..a290e15 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -364,7 +364,7 @@
void (*shutdown)(struct svc_serv *serv))
{
struct svc_serv *serv;
- int vers;
+ unsigned int vers;
unsigned int xdrsize;
unsigned int i;
@@ -433,6 +433,7 @@
{
return __svc_create(prog, bufsize, /*npools*/1, shutdown);
}
+EXPORT_SYMBOL(svc_create);
struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
@@ -452,6 +453,7 @@
return serv;
}
+EXPORT_SYMBOL(svc_create_pooled);
/*
* Destroy an RPC service. Should be called with the BKL held
@@ -459,9 +461,6 @@
void
svc_destroy(struct svc_serv *serv)
{
- struct svc_sock *svsk;
- struct svc_sock *tmp;
-
dprintk("svc: svc_destroy(%s, %d)\n",
serv->sv_program->pg_name,
serv->sv_nrthreads);
@@ -476,14 +475,12 @@
del_timer_sync(&serv->sv_temptimer);
- list_for_each_entry_safe(svsk, tmp, &serv->sv_tempsocks, sk_list)
- svc_force_close_socket(svsk);
+ svc_close_all(&serv->sv_tempsocks);
if (serv->sv_shutdown)
serv->sv_shutdown(serv);
- list_for_each_entry_safe(svsk, tmp, &serv->sv_permsocks, sk_list)
- svc_force_close_socket(svsk);
+ svc_close_all(&serv->sv_permsocks);
BUG_ON(!list_empty(&serv->sv_permsocks));
BUG_ON(!list_empty(&serv->sv_tempsocks));
@@ -498,6 +495,7 @@
kfree(serv->sv_pools);
kfree(serv);
}
+EXPORT_SYMBOL(svc_destroy);
/*
* Allocate an RPC server's buffer space.
@@ -536,6 +534,44 @@
put_page(rqstp->rq_pages[i]);
}
+struct svc_rqst *
+svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
+{
+ struct svc_rqst *rqstp;
+
+ rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
+ if (!rqstp)
+ goto out_enomem;
+
+ init_waitqueue_head(&rqstp->rq_wait);
+
+ serv->sv_nrthreads++;
+ spin_lock_bh(&pool->sp_lock);
+ pool->sp_nrthreads++;
+ list_add(&rqstp->rq_all, &pool->sp_all_threads);
+ spin_unlock_bh(&pool->sp_lock);
+ rqstp->rq_server = serv;
+ rqstp->rq_pool = pool;
+
+ rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
+ if (!rqstp->rq_argp)
+ goto out_thread;
+
+ rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
+ if (!rqstp->rq_resp)
+ goto out_thread;
+
+ if (!svc_init_buffer(rqstp, serv->sv_max_mesg))
+ goto out_thread;
+
+ return rqstp;
+out_thread:
+ svc_exit_thread(rqstp);
+out_enomem:
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(svc_prepare_thread);
+
/*
* Create a thread in the given pool. Caller must hold BKL.
* On a NUMA or SMP machine, with a multi-pool serv, the thread
@@ -550,24 +586,11 @@
int have_oldmask = 0;
cpumask_t oldmask;
- rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
- if (!rqstp)
+ rqstp = svc_prepare_thread(serv, pool);
+ if (IS_ERR(rqstp)) {
+ error = PTR_ERR(rqstp);
goto out;
-
- init_waitqueue_head(&rqstp->rq_wait);
-
- if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
- || !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
- || !svc_init_buffer(rqstp, serv->sv_max_mesg))
- goto out_thread;
-
- serv->sv_nrthreads++;
- spin_lock_bh(&pool->sp_lock);
- pool->sp_nrthreads++;
- list_add(&rqstp->rq_all, &pool->sp_all_threads);
- spin_unlock_bh(&pool->sp_lock);
- rqstp->rq_server = serv;
- rqstp->rq_pool = pool;
+ }
if (serv->sv_nrpools > 1)
have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask);
@@ -597,6 +620,7 @@
{
return __svc_create_thread(func, serv, &serv->sv_pools[0]);
}
+EXPORT_SYMBOL(svc_create_thread);
/*
* Choose a pool in which to create a new thread, for svc_set_num_threads
@@ -700,6 +724,7 @@
return error;
}
+EXPORT_SYMBOL(svc_set_num_threads);
/*
* Called from a server thread as it's exiting. Caller must hold BKL.
@@ -726,6 +751,7 @@
if (serv)
svc_destroy(serv);
}
+EXPORT_SYMBOL(svc_exit_thread);
/*
* Register an RPC service with the local portmapper.
@@ -737,7 +763,8 @@
{
struct svc_program *progp;
unsigned long flags;
- int i, error = 0, dummy;
+ unsigned int i;
+ int error = 0, dummy;
if (!port)
clear_thread_flag(TIF_SIGPENDING);
@@ -840,9 +867,9 @@
rqstp->rq_res.tail[0].iov_len = 0;
/* Will be turned off only in gss privacy case: */
rqstp->rq_splice_ok = 1;
- /* tcp needs a space for the record length... */
- if (rqstp->rq_prot == IPPROTO_TCP)
- svc_putnl(resv, 0);
+
+ /* Setup reply header */
+ rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
rqstp->rq_xid = svc_getu32(argv);
svc_putu32(resv, rqstp->rq_xid);
@@ -1049,16 +1076,15 @@
svc_putnl(resv, ntohl(rpc_stat));
goto sendit;
}
+EXPORT_SYMBOL(svc_process);
/*
* Return (transport-specific) limit on the rpc payload.
*/
u32 svc_max_payload(const struct svc_rqst *rqstp)
{
- int max = RPCSVC_MAXPAYLOAD_TCP;
+ u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload;
- if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
- max = RPCSVC_MAXPAYLOAD_UDP;
if (rqstp->rq_server->sv_max_payload < max)
max = rqstp->rq_server->sv_max_payload;
return max;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
new file mode 100644
index 0000000..ea377e0
--- /dev/null
+++ b/net/sunrpc/svc_xprt.c
@@ -0,0 +1,1055 @@
+/*
+ * linux/net/sunrpc/svc_xprt.c
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/file.h>
+#include <linux/freezer.h>
+#include <net/sock.h>
+#include <net/checksum.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/tcp_states.h>
+#include <linux/uaccess.h>
+#include <asm/ioctls.h>
+
+#include <linux/sunrpc/types.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/svc_xprt.h>
+
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
+
+static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
+static int svc_deferred_recv(struct svc_rqst *rqstp);
+static struct cache_deferred_req *svc_defer(struct cache_req *req);
+static void svc_age_temp_xprts(unsigned long closure);
+
+/* apparently the "standard" is that clients close
+ * idle connections after 5 minutes, servers after
+ * 6 minutes
+ * http://www.connectathon.org/talks96/nfstcp.pdf
+ */
+static int svc_conn_age_period = 6*60;
+
+/* List of registered transport classes */
+static DEFINE_SPINLOCK(svc_xprt_class_lock);
+static LIST_HEAD(svc_xprt_class_list);
+
+/* SMP locking strategy:
+ *
+ * svc_pool->sp_lock protects most of the fields of that pool.
+ * svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
+ * when both need to be taken (rare), svc_serv->sv_lock is first.
+ * BKL protects svc_serv->sv_nrthread.
+ * svc_sock->sk_lock protects the svc_sock->sk_deferred list
+ * and the ->sk_info_authunix cache.
+ *
+ * The XPT_BUSY bit in xprt->xpt_flags prevents a transport being
+ * enqueued multiply. During normal transport processing this bit
+ * is set by svc_xprt_enqueue and cleared by svc_xprt_received.
+ * Providers should not manipulate this bit directly.
+ *
+ * Some flags can be set to certain values at any time
+ * providing that certain rules are followed:
+ *
+ * XPT_CONN, XPT_DATA:
+ * - Can be set or cleared at any time.
+ * - After a set, svc_xprt_enqueue must be called to enqueue
+ * the transport for processing.
+ * - After a clear, the transport must be read/accepted.
+ * If this succeeds, it must be set again.
+ * XPT_CLOSE:
+ * - Can set at any time. It is never cleared.
+ * XPT_DEAD:
+ * - Can only be set while XPT_BUSY is held which ensures
+ * that no other thread will be using the transport or will
+ * try to set XPT_DEAD.
+ */
+
+int svc_reg_xprt_class(struct svc_xprt_class *xcl)
+{
+ struct svc_xprt_class *cl;
+ int res = -EEXIST;
+
+ dprintk("svc: Adding svc transport class '%s'\n", xcl->xcl_name);
+
+ INIT_LIST_HEAD(&xcl->xcl_list);
+ spin_lock(&svc_xprt_class_lock);
+ /* Make sure there isn't already a class with the same name */
+ list_for_each_entry(cl, &svc_xprt_class_list, xcl_list) {
+ if (strcmp(xcl->xcl_name, cl->xcl_name) == 0)
+ goto out;
+ }
+ list_add_tail(&xcl->xcl_list, &svc_xprt_class_list);
+ res = 0;
+out:
+ spin_unlock(&svc_xprt_class_lock);
+ return res;
+}
+EXPORT_SYMBOL_GPL(svc_reg_xprt_class);
+
+void svc_unreg_xprt_class(struct svc_xprt_class *xcl)
+{
+ dprintk("svc: Removing svc transport class '%s'\n", xcl->xcl_name);
+ spin_lock(&svc_xprt_class_lock);
+ list_del_init(&xcl->xcl_list);
+ spin_unlock(&svc_xprt_class_lock);
+}
+EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
+
+/*
+ * Format the transport list for printing
+ */
+int svc_print_xprts(char *buf, int maxlen)
+{
+ struct list_head *le;
+ char tmpstr[80];
+ int len = 0;
+ buf[0] = '\0';
+
+ spin_lock(&svc_xprt_class_lock);
+ list_for_each(le, &svc_xprt_class_list) {
+ int slen;
+ struct svc_xprt_class *xcl =
+ list_entry(le, struct svc_xprt_class, xcl_list);
+
+ sprintf(tmpstr, "%s %d\n", xcl->xcl_name, xcl->xcl_max_payload);
+ slen = strlen(tmpstr);
+ if (len + slen > maxlen)
+ break;
+ len += slen;
+ strcat(buf, tmpstr);
+ }
+ spin_unlock(&svc_xprt_class_lock);
+
+ return len;
+}
+
+static void svc_xprt_free(struct kref *kref)
+{
+ struct svc_xprt *xprt =
+ container_of(kref, struct svc_xprt, xpt_ref);
+ struct module *owner = xprt->xpt_class->xcl_owner;
+ if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)
+ && xprt->xpt_auth_cache != NULL)
+ svcauth_unix_info_release(xprt->xpt_auth_cache);
+ xprt->xpt_ops->xpo_free(xprt);
+ module_put(owner);
+}
+
+void svc_xprt_put(struct svc_xprt *xprt)
+{
+ kref_put(&xprt->xpt_ref, svc_xprt_free);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_put);
+
+/*
+ * Called by transport drivers to initialize the transport independent
+ * portion of the transport instance.
+ */
+void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
+ struct svc_serv *serv)
+{
+ memset(xprt, 0, sizeof(*xprt));
+ xprt->xpt_class = xcl;
+ xprt->xpt_ops = xcl->xcl_ops;
+ kref_init(&xprt->xpt_ref);
+ xprt->xpt_server = serv;
+ INIT_LIST_HEAD(&xprt->xpt_list);
+ INIT_LIST_HEAD(&xprt->xpt_ready);
+ INIT_LIST_HEAD(&xprt->xpt_deferred);
+ mutex_init(&xprt->xpt_mutex);
+ spin_lock_init(&xprt->xpt_lock);
+ set_bit(XPT_BUSY, &xprt->xpt_flags);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_init);
+
+int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+ int flags)
+{
+ struct svc_xprt_class *xcl;
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = INADDR_ANY,
+ .sin_port = htons(port),
+ };
+ dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
+ spin_lock(&svc_xprt_class_lock);
+ list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
+ struct svc_xprt *newxprt;
+
+ if (strcmp(xprt_name, xcl->xcl_name))
+ continue;
+
+ if (!try_module_get(xcl->xcl_owner))
+ goto err;
+
+ spin_unlock(&svc_xprt_class_lock);
+ newxprt = xcl->xcl_ops->
+ xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
+ flags);
+ if (IS_ERR(newxprt)) {
+ module_put(xcl->xcl_owner);
+ return PTR_ERR(newxprt);
+ }
+
+ clear_bit(XPT_TEMP, &newxprt->xpt_flags);
+ spin_lock_bh(&serv->sv_lock);
+ list_add(&newxprt->xpt_list, &serv->sv_permsocks);
+ spin_unlock_bh(&serv->sv_lock);
+ clear_bit(XPT_BUSY, &newxprt->xpt_flags);
+ return svc_xprt_local_port(newxprt);
+ }
+ err:
+ spin_unlock(&svc_xprt_class_lock);
+ dprintk("svc: transport %s not found\n", xprt_name);
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(svc_create_xprt);
+
+/*
+ * Copy the local and remote xprt addresses to the rqstp structure
+ */
+void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
+{
+ struct sockaddr *sin;
+
+ memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
+ rqstp->rq_addrlen = xprt->xpt_remotelen;
+
+ /*
+ * Destination address in request is needed for binding the
+ * source address in RPC replies/callbacks later.
+ */
+ sin = (struct sockaddr *)&xprt->xpt_local;
+ switch (sin->sa_family) {
+ case AF_INET:
+ rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
+ break;
+ case AF_INET6:
+ rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
+
+/**
+ * svc_print_addr - Format rq_addr field for printing
+ * @rqstp: svc_rqst struct containing address to print
+ * @buf: target buffer for formatted address
+ * @len: length of target buffer
+ *
+ */
+char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
+{
+ return __svc_print_addr(svc_addr(rqstp), buf, len);
+}
+EXPORT_SYMBOL_GPL(svc_print_addr);
+
+/*
+ * Queue up an idle server thread. Must have pool->sp_lock held.
+ * Note: this is really a stack rather than a queue, so that we only
+ * use as many different threads as we need, and the rest don't pollute
+ * the cache.
+ */
+static void svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
+{
+ list_add(&rqstp->rq_list, &pool->sp_threads);
+}
+
+/*
+ * Dequeue an nfsd thread. Must have pool->sp_lock held.
+ */
+static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
+{
+ list_del(&rqstp->rq_list);
+}
+
+/*
+ * Queue up a transport with data pending. If there are idle nfsd
+ * processes, wake 'em up.
+ *
+ */
+void svc_xprt_enqueue(struct svc_xprt *xprt)
+{
+ struct svc_serv *serv = xprt->xpt_server;
+ struct svc_pool *pool;
+ struct svc_rqst *rqstp;
+ int cpu;
+
+ if (!(xprt->xpt_flags &
+ ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
+ return;
+ if (test_bit(XPT_DEAD, &xprt->xpt_flags))
+ return;
+
+ cpu = get_cpu();
+ pool = svc_pool_for_cpu(xprt->xpt_server, cpu);
+ put_cpu();
+
+ spin_lock_bh(&pool->sp_lock);
+
+ if (!list_empty(&pool->sp_threads) &&
+ !list_empty(&pool->sp_sockets))
+ printk(KERN_ERR
+ "svc_xprt_enqueue: "
+ "threads and transports both waiting??\n");
+
+ if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
+ /* Don't enqueue dead transports */
+ dprintk("svc: transport %p is dead, not enqueued\n", xprt);
+ goto out_unlock;
+ }
+
+ /* Mark transport as busy. It will remain in this state until
+ * the provider calls svc_xprt_received. We update XPT_BUSY
+ * atomically because it also guards against trying to enqueue
+ * the transport twice.
+ */
+ if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) {
+ /* Don't enqueue transport while already enqueued */
+ dprintk("svc: transport %p busy, not enqueued\n", xprt);
+ goto out_unlock;
+ }
+ BUG_ON(xprt->xpt_pool != NULL);
+ xprt->xpt_pool = pool;
+
+ /* Handle pending connection */
+ if (test_bit(XPT_CONN, &xprt->xpt_flags))
+ goto process;
+
+ /* Handle close in-progress */
+ if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
+ goto process;
+
+ /* Check if we have space to reply to a request */
+ if (!xprt->xpt_ops->xpo_has_wspace(xprt)) {
+ /* Don't enqueue while not enough space for reply */
+ dprintk("svc: no write space, transport %p not enqueued\n",
+ xprt);
+ xprt->xpt_pool = NULL;
+ clear_bit(XPT_BUSY, &xprt->xpt_flags);
+ goto out_unlock;
+ }
+
+ process:
+ if (!list_empty(&pool->sp_threads)) {
+ rqstp = list_entry(pool->sp_threads.next,
+ struct svc_rqst,
+ rq_list);
+ dprintk("svc: transport %p served by daemon %p\n",
+ xprt, rqstp);
+ svc_thread_dequeue(pool, rqstp);
+ if (rqstp->rq_xprt)
+ printk(KERN_ERR
+ "svc_xprt_enqueue: server %p, rq_xprt=%p!\n",
+ rqstp, rqstp->rq_xprt);
+ rqstp->rq_xprt = xprt;
+ svc_xprt_get(xprt);
+ rqstp->rq_reserved = serv->sv_max_mesg;
+ atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
+ BUG_ON(xprt->xpt_pool != pool);
+ wake_up(&rqstp->rq_wait);
+ } else {
+ dprintk("svc: transport %p put into queue\n", xprt);
+ list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
+ BUG_ON(xprt->xpt_pool != pool);
+ }
+
+out_unlock:
+ spin_unlock_bh(&pool->sp_lock);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_enqueue);
+
+/*
+ * Dequeue the first transport. Must be called with the pool->sp_lock held.
+ */
+static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
+{
+ struct svc_xprt *xprt;
+
+ if (list_empty(&pool->sp_sockets))
+ return NULL;
+
+ xprt = list_entry(pool->sp_sockets.next,
+ struct svc_xprt, xpt_ready);
+ list_del_init(&xprt->xpt_ready);
+
+ dprintk("svc: transport %p dequeued, inuse=%d\n",
+ xprt, atomic_read(&xprt->xpt_ref.refcount));
+
+ return xprt;
+}
+
+/*
+ * svc_xprt_received conditionally queues the transport for processing
+ * by another thread. The caller must hold the XPT_BUSY bit and must
+ * not thereafter touch transport data.
+ *
+ * Note: XPT_DATA only gets cleared when a read-attempt finds no (or
+ * insufficient) data.
+ */
+void svc_xprt_received(struct svc_xprt *xprt)
+{
+ BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
+ xprt->xpt_pool = NULL;
+ clear_bit(XPT_BUSY, &xprt->xpt_flags);
+ svc_xprt_enqueue(xprt);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_received);
+
+/**
+ * svc_reserve - change the space reserved for the reply to a request.
+ * @rqstp: The request in question
+ * @space: new max space to reserve
+ *
+ * Each request reserves some space on the output queue of the transport
+ * to make sure the reply fits. This function reduces that reserved
+ * space to be the amount of space used already, plus @space.
+ *
+ */
+void svc_reserve(struct svc_rqst *rqstp, int space)
+{
+ space += rqstp->rq_res.head[0].iov_len;
+
+ if (space < rqstp->rq_reserved) {
+ struct svc_xprt *xprt = rqstp->rq_xprt;
+ atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
+ rqstp->rq_reserved = space;
+
+ svc_xprt_enqueue(xprt);
+ }
+}
+EXPORT_SYMBOL(svc_reserve);
+
+static void svc_xprt_release(struct svc_rqst *rqstp)
+{
+ struct svc_xprt *xprt = rqstp->rq_xprt;
+
+ rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
+
+ svc_free_res_pages(rqstp);
+ rqstp->rq_res.page_len = 0;
+ rqstp->rq_res.page_base = 0;
+
+ /* Reset response buffer and release
+ * the reservation.
+ * But first, check that enough space was reserved
+ * for the reply, otherwise we have a bug!
+ */
+ if ((rqstp->rq_res.len) > rqstp->rq_reserved)
+ printk(KERN_ERR "RPC request reserved %d but used %d\n",
+ rqstp->rq_reserved,
+ rqstp->rq_res.len);
+
+ rqstp->rq_res.head[0].iov_len = 0;
+ svc_reserve(rqstp, 0);
+ rqstp->rq_xprt = NULL;
+
+ svc_xprt_put(xprt);
+}
+
+/*
+ * External function to wake up a server waiting for data
+ * This really only makes sense for services like lockd
+ * which have exactly one thread anyway.
+ */
+void svc_wake_up(struct svc_serv *serv)
+{
+ struct svc_rqst *rqstp;
+ unsigned int i;
+ struct svc_pool *pool;
+
+ for (i = 0; i < serv->sv_nrpools; i++) {
+ pool = &serv->sv_pools[i];
+
+ spin_lock_bh(&pool->sp_lock);
+ if (!list_empty(&pool->sp_threads)) {
+ rqstp = list_entry(pool->sp_threads.next,
+ struct svc_rqst,
+ rq_list);
+ dprintk("svc: daemon %p woken up.\n", rqstp);
+ /*
+ svc_thread_dequeue(pool, rqstp);
+ rqstp->rq_xprt = NULL;
+ */
+ wake_up(&rqstp->rq_wait);
+ }
+ spin_unlock_bh(&pool->sp_lock);
+ }
+}
+EXPORT_SYMBOL(svc_wake_up);
+
+int svc_port_is_privileged(struct sockaddr *sin)
+{
+ switch (sin->sa_family) {
+ case AF_INET:
+ return ntohs(((struct sockaddr_in *)sin)->sin_port)
+ < PROT_SOCK;
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
+ < PROT_SOCK;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Make sure that we don't have too many active connections. If we
+ * have, something must be dropped.
+ *
+ * There's no point in trying to do random drop here for DoS
+ * prevention. The NFS clients does 1 reconnect in 15 seconds. An
+ * attacker can easily beat that.
+ *
+ * The only somewhat efficient mechanism would be if drop old
+ * connections from the same IP first. But right now we don't even
+ * record the client IP in svc_sock.
+ */
+static void svc_check_conn_limits(struct svc_serv *serv)
+{
+ if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
+ struct svc_xprt *xprt = NULL;
+ spin_lock_bh(&serv->sv_lock);
+ if (!list_empty(&serv->sv_tempsocks)) {
+ if (net_ratelimit()) {
+ /* Try to help the admin */
+ printk(KERN_NOTICE "%s: too many open "
+ "connections, consider increasing the "
+ "number of nfsd threads\n",
+ serv->sv_name);
+ }
+ /*
+ * Always select the oldest connection. It's not fair,
+ * but so is life
+ */
+ xprt = list_entry(serv->sv_tempsocks.prev,
+ struct svc_xprt,
+ xpt_list);
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ svc_xprt_get(xprt);
+ }
+ spin_unlock_bh(&serv->sv_lock);
+
+ if (xprt) {
+ svc_xprt_enqueue(xprt);
+ svc_xprt_put(xprt);
+ }
+ }
+}
+
+/*
+ * Receive the next request on any transport. This code is carefully
+ * organised not to touch any cachelines in the shared svc_serv
+ * structure, only cachelines in the local svc_pool.
+ */
+int svc_recv(struct svc_rqst *rqstp, long timeout)
+{
+ struct svc_xprt *xprt = NULL;
+ struct svc_serv *serv = rqstp->rq_server;
+ struct svc_pool *pool = rqstp->rq_pool;
+ int len, i;
+ int pages;
+ struct xdr_buf *arg;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dprintk("svc: server %p waiting for data (to = %ld)\n",
+ rqstp, timeout);
+
+ if (rqstp->rq_xprt)
+ printk(KERN_ERR
+ "svc_recv: service %p, transport not NULL!\n",
+ rqstp);
+ if (waitqueue_active(&rqstp->rq_wait))
+ printk(KERN_ERR
+ "svc_recv: service %p, wait queue active!\n",
+ rqstp);
+
+ /* now allocate needed pages. If we get a failure, sleep briefly */
+ pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
+ for (i = 0; i < pages ; i++)
+ while (rqstp->rq_pages[i] == NULL) {
+ struct page *p = alloc_page(GFP_KERNEL);
+ if (!p) {
+ int j = msecs_to_jiffies(500);
+ schedule_timeout_uninterruptible(j);
+ }
+ rqstp->rq_pages[i] = p;
+ }
+ rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
+ BUG_ON(pages >= RPCSVC_MAXPAGES);
+
+ /* Make arg->head point to first page and arg->pages point to rest */
+ arg = &rqstp->rq_arg;
+ arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
+ arg->head[0].iov_len = PAGE_SIZE;
+ arg->pages = rqstp->rq_pages + 1;
+ arg->page_base = 0;
+ /* save at least one page for response */
+ arg->page_len = (pages-2)*PAGE_SIZE;
+ arg->len = (pages-1)*PAGE_SIZE;
+ arg->tail[0].iov_len = 0;
+
+ try_to_freeze();
+ cond_resched();
+ if (signalled())
+ return -EINTR;
+
+ spin_lock_bh(&pool->sp_lock);
+ xprt = svc_xprt_dequeue(pool);
+ if (xprt) {
+ rqstp->rq_xprt = xprt;
+ svc_xprt_get(xprt);
+ rqstp->rq_reserved = serv->sv_max_mesg;
+ atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
+ } else {
+ /* No data pending. Go to sleep */
+ svc_thread_enqueue(pool, rqstp);
+
+ /*
+ * We have to be able to interrupt this wait
+ * to bring down the daemons ...
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&rqstp->rq_wait, &wait);
+ spin_unlock_bh(&pool->sp_lock);
+
+ schedule_timeout(timeout);
+
+ try_to_freeze();
+
+ spin_lock_bh(&pool->sp_lock);
+ remove_wait_queue(&rqstp->rq_wait, &wait);
+
+ xprt = rqstp->rq_xprt;
+ if (!xprt) {
+ svc_thread_dequeue(pool, rqstp);
+ spin_unlock_bh(&pool->sp_lock);
+ dprintk("svc: server %p, no data yet\n", rqstp);
+ return signalled()? -EINTR : -EAGAIN;
+ }
+ }
+ spin_unlock_bh(&pool->sp_lock);
+
+ len = 0;
+ if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
+ dprintk("svc_recv: found XPT_CLOSE\n");
+ svc_delete_xprt(xprt);
+ } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
+ struct svc_xprt *newxpt;
+ newxpt = xprt->xpt_ops->xpo_accept(xprt);
+ if (newxpt) {
+ /*
+ * We know this module_get will succeed because the
+ * listener holds a reference too
+ */
+ __module_get(newxpt->xpt_class->xcl_owner);
+ svc_check_conn_limits(xprt->xpt_server);
+ spin_lock_bh(&serv->sv_lock);
+ set_bit(XPT_TEMP, &newxpt->xpt_flags);
+ list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
+ serv->sv_tmpcnt++;
+ if (serv->sv_temptimer.function == NULL) {
+ /* setup timer to age temp transports */
+ setup_timer(&serv->sv_temptimer,
+ svc_age_temp_xprts,
+ (unsigned long)serv);
+ mod_timer(&serv->sv_temptimer,
+ jiffies + svc_conn_age_period * HZ);
+ }
+ spin_unlock_bh(&serv->sv_lock);
+ svc_xprt_received(newxpt);
+ }
+ svc_xprt_received(xprt);
+ } else {
+ dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
+ rqstp, pool->sp_id, xprt,
+ atomic_read(&xprt->xpt_ref.refcount));
+ rqstp->rq_deferred = svc_deferred_dequeue(xprt);
+ if (rqstp->rq_deferred) {
+ svc_xprt_received(xprt);
+ len = svc_deferred_recv(rqstp);
+ } else
+ len = xprt->xpt_ops->xpo_recvfrom(rqstp);
+ dprintk("svc: got len=%d\n", len);
+ }
+
+ /* No data, incomplete (TCP) read, or accept() */
+ if (len == 0 || len == -EAGAIN) {
+ rqstp->rq_res.len = 0;
+ svc_xprt_release(rqstp);
+ return -EAGAIN;
+ }
+ clear_bit(XPT_OLD, &xprt->xpt_flags);
+
+ rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
+ rqstp->rq_chandle.defer = svc_defer;
+
+ if (serv->sv_stats)
+ serv->sv_stats->netcnt++;
+ return len;
+}
+EXPORT_SYMBOL(svc_recv);
+
+/*
+ * Drop request
+ */
+void svc_drop(struct svc_rqst *rqstp)
+{
+ dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
+ svc_xprt_release(rqstp);
+}
+EXPORT_SYMBOL(svc_drop);
+
+/*
+ * Return reply to client.
+ */
+int svc_send(struct svc_rqst *rqstp)
+{
+ struct svc_xprt *xprt;
+ int len;
+ struct xdr_buf *xb;
+
+ xprt = rqstp->rq_xprt;
+ if (!xprt)
+ return -EFAULT;
+
+ /* release the receive skb before sending the reply */
+ rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
+
+ /* calculate over-all length */
+ xb = &rqstp->rq_res;
+ xb->len = xb->head[0].iov_len +
+ xb->page_len +
+ xb->tail[0].iov_len;
+
+ /* Grab mutex to serialize outgoing data. */
+ mutex_lock(&xprt->xpt_mutex);
+ if (test_bit(XPT_DEAD, &xprt->xpt_flags))
+ len = -ENOTCONN;
+ else
+ len = xprt->xpt_ops->xpo_sendto(rqstp);
+ mutex_unlock(&xprt->xpt_mutex);
+ svc_xprt_release(rqstp);
+
+ if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
+ return 0;
+ return len;
+}
+
+/*
+ * Timer function to close old temporary transports, using
+ * a mark-and-sweep algorithm.
+ */
+static void svc_age_temp_xprts(unsigned long closure)
+{
+ struct svc_serv *serv = (struct svc_serv *)closure;
+ struct svc_xprt *xprt;
+ struct list_head *le, *next;
+ LIST_HEAD(to_be_aged);
+
+ dprintk("svc_age_temp_xprts\n");
+
+ if (!spin_trylock_bh(&serv->sv_lock)) {
+ /* busy, try again 1 sec later */
+ dprintk("svc_age_temp_xprts: busy\n");
+ mod_timer(&serv->sv_temptimer, jiffies + HZ);
+ return;
+ }
+
+ list_for_each_safe(le, next, &serv->sv_tempsocks) {
+ xprt = list_entry(le, struct svc_xprt, xpt_list);
+
+ /* First time through, just mark it OLD. Second time
+ * through, close it. */
+ if (!test_and_set_bit(XPT_OLD, &xprt->xpt_flags))
+ continue;
+ if (atomic_read(&xprt->xpt_ref.refcount) > 1
+ || test_bit(XPT_BUSY, &xprt->xpt_flags))
+ continue;
+ svc_xprt_get(xprt);
+ list_move(le, &to_be_aged);
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ set_bit(XPT_DETACHED, &xprt->xpt_flags);
+ }
+ spin_unlock_bh(&serv->sv_lock);
+
+ while (!list_empty(&to_be_aged)) {
+ le = to_be_aged.next;
+ /* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */
+ list_del_init(le);
+ xprt = list_entry(le, struct svc_xprt, xpt_list);
+
+ dprintk("queuing xprt %p for closing\n", xprt);
+
+ /* a thread will dequeue and close it soon */
+ svc_xprt_enqueue(xprt);
+ svc_xprt_put(xprt);
+ }
+
+ mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
+}
+
+/*
+ * Remove a dead transport
+ */
+void svc_delete_xprt(struct svc_xprt *xprt)
+{
+ struct svc_serv *serv = xprt->xpt_server;
+
+ dprintk("svc: svc_delete_xprt(%p)\n", xprt);
+ xprt->xpt_ops->xpo_detach(xprt);
+
+ spin_lock_bh(&serv->sv_lock);
+ if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
+ list_del_init(&xprt->xpt_list);
+ /*
+ * We used to delete the transport from whichever list
+ * it's sk_xprt.xpt_ready node was on, but we don't actually
+ * need to. This is because the only time we're called
+ * while still attached to a queue, the queue itself
+ * is about to be destroyed (in svc_destroy).
+ */
+ if (!test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) {
+ BUG_ON(atomic_read(&xprt->xpt_ref.refcount) < 2);
+ if (test_bit(XPT_TEMP, &xprt->xpt_flags))
+ serv->sv_tmpcnt--;
+ svc_xprt_put(xprt);
+ }
+ spin_unlock_bh(&serv->sv_lock);
+}
+
+void svc_close_xprt(struct svc_xprt *xprt)
+{
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
+ /* someone else will have to effect the close */
+ return;
+
+ svc_xprt_get(xprt);
+ svc_delete_xprt(xprt);
+ clear_bit(XPT_BUSY, &xprt->xpt_flags);
+ svc_xprt_put(xprt);
+}
+EXPORT_SYMBOL_GPL(svc_close_xprt);
+
+void svc_close_all(struct list_head *xprt_list)
+{
+ struct svc_xprt *xprt;
+ struct svc_xprt *tmp;
+
+ list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ if (test_bit(XPT_BUSY, &xprt->xpt_flags)) {
+ /* Waiting to be processed, but no threads left,
+ * So just remove it from the waiting list
+ */
+ list_del_init(&xprt->xpt_ready);
+ clear_bit(XPT_BUSY, &xprt->xpt_flags);
+ }
+ svc_close_xprt(xprt);
+ }
+}
+
+/*
+ * Handle defer and revisit of requests
+ */
+
+static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
+{
+ struct svc_deferred_req *dr =
+ container_of(dreq, struct svc_deferred_req, handle);
+ struct svc_xprt *xprt = dr->xprt;
+
+ if (too_many) {
+ svc_xprt_put(xprt);
+ kfree(dr);
+ return;
+ }
+ dprintk("revisit queued\n");
+ dr->xprt = NULL;
+ spin_lock(&xprt->xpt_lock);
+ list_add(&dr->handle.recent, &xprt->xpt_deferred);
+ spin_unlock(&xprt->xpt_lock);
+ set_bit(XPT_DEFERRED, &xprt->xpt_flags);
+ svc_xprt_enqueue(xprt);
+ svc_xprt_put(xprt);
+}
+
+/*
+ * Save the request off for later processing. The request buffer looks
+ * like this:
+ *
+ * <xprt-header><rpc-header><rpc-pagelist><rpc-tail>
+ *
+ * This code can only handle requests that consist of an xprt-header
+ * and rpc-header.
+ */
+static struct cache_deferred_req *svc_defer(struct cache_req *req)
+{
+ struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
+ struct svc_deferred_req *dr;
+
+ if (rqstp->rq_arg.page_len)
+ return NULL; /* if more than a page, give up FIXME */
+ if (rqstp->rq_deferred) {
+ dr = rqstp->rq_deferred;
+ rqstp->rq_deferred = NULL;
+ } else {
+ size_t skip;
+ size_t size;
+ /* FIXME maybe discard if size too large */
+ size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len;
+ dr = kmalloc(size, GFP_KERNEL);
+ if (dr == NULL)
+ return NULL;
+
+ dr->handle.owner = rqstp->rq_server;
+ dr->prot = rqstp->rq_prot;
+ memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
+ dr->addrlen = rqstp->rq_addrlen;
+ dr->daddr = rqstp->rq_daddr;
+ dr->argslen = rqstp->rq_arg.len >> 2;
+ dr->xprt_hlen = rqstp->rq_xprt_hlen;
+
+ /* back up head to the start of the buffer and copy */
+ skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
+ memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip,
+ dr->argslen << 2);
+ }
+ svc_xprt_get(rqstp->rq_xprt);
+ dr->xprt = rqstp->rq_xprt;
+
+ dr->handle.revisit = svc_revisit;
+ return &dr->handle;
+}
+
+/*
+ * recv data from a deferred request into an active one
+ */
+static int svc_deferred_recv(struct svc_rqst *rqstp)
+{
+ struct svc_deferred_req *dr = rqstp->rq_deferred;
+
+ /* setup iov_base past transport header */
+ rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2);
+ /* The iov_len does not include the transport header bytes */
+ rqstp->rq_arg.head[0].iov_len = (dr->argslen<<2) - dr->xprt_hlen;
+ rqstp->rq_arg.page_len = 0;
+ /* The rq_arg.len includes the transport header bytes */
+ rqstp->rq_arg.len = dr->argslen<<2;
+ rqstp->rq_prot = dr->prot;
+ memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
+ rqstp->rq_addrlen = dr->addrlen;
+ /* Save off transport header len in case we get deferred again */
+ rqstp->rq_xprt_hlen = dr->xprt_hlen;
+ rqstp->rq_daddr = dr->daddr;
+ rqstp->rq_respages = rqstp->rq_pages;
+ return (dr->argslen<<2) - dr->xprt_hlen;
+}
+
+
+static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
+{
+ struct svc_deferred_req *dr = NULL;
+
+ if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
+ return NULL;
+ spin_lock(&xprt->xpt_lock);
+ clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
+ if (!list_empty(&xprt->xpt_deferred)) {
+ dr = list_entry(xprt->xpt_deferred.next,
+ struct svc_deferred_req,
+ handle.recent);
+ list_del_init(&dr->handle.recent);
+ set_bit(XPT_DEFERRED, &xprt->xpt_flags);
+ }
+ spin_unlock(&xprt->xpt_lock);
+ return dr;
+}
+
+/*
+ * Return the transport instance pointer for the endpoint accepting
+ * connections/peer traffic from the specified transport class,
+ * address family and port.
+ *
+ * Specifying 0 for the address family or port is effectively a
+ * wild-card, and will result in matching the first transport in the
+ * service's list that has a matching class name.
+ */
+struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
+ int af, int port)
+{
+ struct svc_xprt *xprt;
+ struct svc_xprt *found = NULL;
+
+ /* Sanity check the args */
+ if (!serv || !xcl_name)
+ return found;
+
+ spin_lock_bh(&serv->sv_lock);
+ list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+ if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
+ continue;
+ if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
+ continue;
+ if (port && port != svc_xprt_local_port(xprt))
+ continue;
+ found = xprt;
+ svc_xprt_get(xprt);
+ break;
+ }
+ spin_unlock_bh(&serv->sv_lock);
+ return found;
+}
+EXPORT_SYMBOL_GPL(svc_find_xprt);
+
+/*
+ * Format a buffer with a list of the active transports. A zero for
+ * the buflen parameter disables target buffer overflow checking.
+ */
+int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen)
+{
+ struct svc_xprt *xprt;
+ char xprt_str[64];
+ int totlen = 0;
+ int len;
+
+ /* Sanity check args */
+ if (!serv)
+ return 0;
+
+ spin_lock_bh(&serv->sv_lock);
+ list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+ len = snprintf(xprt_str, sizeof(xprt_str),
+ "%s %d\n", xprt->xpt_class->xcl_name,
+ svc_xprt_local_port(xprt));
+ /* If the string was truncated, replace with error string */
+ if (len >= sizeof(xprt_str))
+ strcpy(xprt_str, "name-too-long\n");
+ /* Don't overflow buffer */
+ len = strlen(xprt_str);
+ if (buflen && (len + totlen >= buflen))
+ break;
+ strcpy(buf+totlen, xprt_str);
+ totlen += len;
+ }
+ spin_unlock_bh(&serv->sv_lock);
+ return totlen;
+}
+EXPORT_SYMBOL_GPL(svc_xprt_names);
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index af7c5f0..8a73cbb 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -57,11 +57,13 @@
rqstp->rq_authop = aops;
return aops->accept(rqstp, authp);
}
+EXPORT_SYMBOL(svc_authenticate);
int svc_set_client(struct svc_rqst *rqstp)
{
return rqstp->rq_authop->set_client(rqstp);
}
+EXPORT_SYMBOL(svc_set_client);
/* A request, which was authenticated, has now executed.
* Time to finalise the credentials and verifier
@@ -93,6 +95,7 @@
spin_unlock(&authtab_lock);
return rv;
}
+EXPORT_SYMBOL(svc_auth_register);
void
svc_auth_unregister(rpc_authflavor_t flavor)
@@ -129,6 +132,7 @@
spin_unlock(&auth_domain_lock);
}
}
+EXPORT_SYMBOL(auth_domain_put);
struct auth_domain *
auth_domain_lookup(char *name, struct auth_domain *new)
@@ -153,8 +157,10 @@
spin_unlock(&auth_domain_lock);
return new;
}
+EXPORT_SYMBOL(auth_domain_lookup);
struct auth_domain *auth_domain_find(char *name)
{
return auth_domain_lookup(name, NULL);
}
+EXPORT_SYMBOL(auth_domain_find);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 41147941..3c64051 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -63,6 +63,7 @@
rv = auth_domain_lookup(name, &new->h);
}
}
+EXPORT_SYMBOL(unix_domain_find);
static void svcauth_unix_domain_release(struct auth_domain *dom)
{
@@ -340,6 +341,7 @@
else
return -ENOMEM;
}
+EXPORT_SYMBOL(auth_unix_add_addr);
int auth_unix_forget_old(struct auth_domain *dom)
{
@@ -351,6 +353,7 @@
udom->addr_changes++;
return 0;
}
+EXPORT_SYMBOL(auth_unix_forget_old);
struct auth_domain *auth_unix_lookup(struct in_addr addr)
{
@@ -375,50 +378,56 @@
cache_put(&ipm->h, &ip_map_cache);
return rv;
}
+EXPORT_SYMBOL(auth_unix_lookup);
void svcauth_unix_purge(void)
{
cache_purge(&ip_map_cache);
}
+EXPORT_SYMBOL(svcauth_unix_purge);
static inline struct ip_map *
ip_map_cached_get(struct svc_rqst *rqstp)
{
- struct ip_map *ipm;
- struct svc_sock *svsk = rqstp->rq_sock;
- spin_lock(&svsk->sk_lock);
- ipm = svsk->sk_info_authunix;
- if (ipm != NULL) {
- if (!cache_valid(&ipm->h)) {
- /*
- * The entry has been invalidated since it was
- * remembered, e.g. by a second mount from the
- * same IP address.
- */
- svsk->sk_info_authunix = NULL;
- spin_unlock(&svsk->sk_lock);
- cache_put(&ipm->h, &ip_map_cache);
- return NULL;
+ struct ip_map *ipm = NULL;
+ struct svc_xprt *xprt = rqstp->rq_xprt;
+
+ if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
+ spin_lock(&xprt->xpt_lock);
+ ipm = xprt->xpt_auth_cache;
+ if (ipm != NULL) {
+ if (!cache_valid(&ipm->h)) {
+ /*
+ * The entry has been invalidated since it was
+ * remembered, e.g. by a second mount from the
+ * same IP address.
+ */
+ xprt->xpt_auth_cache = NULL;
+ spin_unlock(&xprt->xpt_lock);
+ cache_put(&ipm->h, &ip_map_cache);
+ return NULL;
+ }
+ cache_get(&ipm->h);
}
- cache_get(&ipm->h);
+ spin_unlock(&xprt->xpt_lock);
}
- spin_unlock(&svsk->sk_lock);
return ipm;
}
static inline void
ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
{
- struct svc_sock *svsk = rqstp->rq_sock;
+ struct svc_xprt *xprt = rqstp->rq_xprt;
- spin_lock(&svsk->sk_lock);
- if (svsk->sk_sock->type == SOCK_STREAM &&
- svsk->sk_info_authunix == NULL) {
- /* newly cached, keep the reference */
- svsk->sk_info_authunix = ipm;
- ipm = NULL;
+ if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
+ spin_lock(&xprt->xpt_lock);
+ if (xprt->xpt_auth_cache == NULL) {
+ /* newly cached, keep the reference */
+ xprt->xpt_auth_cache = ipm;
+ ipm = NULL;
+ }
+ spin_unlock(&xprt->xpt_lock);
}
- spin_unlock(&svsk->sk_lock);
if (ipm)
cache_put(&ipm->h, &ip_map_cache);
}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index c75bffe..1d3e5fc 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -5,7 +5,7 @@
*
* The server scheduling algorithm does not always distribute the load
* evenly when servicing a single client. May need to modify the
- * svc_sock_enqueue procedure...
+ * svc_xprt_enqueue procedure...
*
* TCP support is largely untested and may be a little slow. The problem
* is that we currently do two separate recvfrom's, one for the 4-byte
@@ -48,72 +48,40 @@
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/stats.h>
-/* SMP locking strategy:
- *
- * svc_pool->sp_lock protects most of the fields of that pool.
- * svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
- * when both need to be taken (rare), svc_serv->sv_lock is first.
- * BKL protects svc_serv->sv_nrthread.
- * svc_sock->sk_lock protects the svc_sock->sk_deferred list
- * and the ->sk_info_authunix cache.
- * svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
- *
- * Some flags can be set to certain values at any time
- * providing that certain rules are followed:
- *
- * SK_CONN, SK_DATA, can be set or cleared at any time.
- * after a set, svc_sock_enqueue must be called.
- * after a clear, the socket must be read/accepted
- * if this succeeds, it must be set again.
- * SK_CLOSE can set at any time. It is never cleared.
- * sk_inuse contains a bias of '1' until SK_DEAD is set.
- * so when sk_inuse hits zero, we know the socket is dead
- * and no-one is using it.
- * SK_DEAD can only be set while SK_BUSY is held which ensures
- * no other thread will be using the socket or will try to
- * set SK_DEAD.
- *
- */
-
-#define RPCDBG_FACILITY RPCDBG_SVCSOCK
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
int *errp, int flags);
-static void svc_delete_socket(struct svc_sock *svsk);
static void svc_udp_data_ready(struct sock *, int);
static int svc_udp_recvfrom(struct svc_rqst *);
static int svc_udp_sendto(struct svc_rqst *);
-static void svc_close_socket(struct svc_sock *svsk);
+static void svc_sock_detach(struct svc_xprt *);
+static void svc_sock_free(struct svc_xprt *);
-static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
-static int svc_deferred_recv(struct svc_rqst *rqstp);
-static struct cache_deferred_req *svc_defer(struct cache_req *req);
-
-/* apparently the "standard" is that clients close
- * idle connections after 5 minutes, servers after
- * 6 minutes
- * http://www.connectathon.org/talks96/nfstcp.pdf
- */
-static int svc_conn_age_period = 6*60;
-
+static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
+ struct sockaddr *, int, int);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key svc_key[2];
static struct lock_class_key svc_slock_key[2];
-static inline void svc_reclassify_socket(struct socket *sock)
+static void svc_reclassify_socket(struct socket *sock)
{
struct sock *sk = sock->sk;
BUG_ON(sock_owned_by_user(sk));
switch (sk->sk_family) {
case AF_INET:
sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
- &svc_slock_key[0], "sk_lock-AF_INET-NFSD", &svc_key[0]);
+ &svc_slock_key[0],
+ "sk_xprt.xpt_lock-AF_INET-NFSD",
+ &svc_key[0]);
break;
case AF_INET6:
sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD",
- &svc_slock_key[1], "sk_lock-AF_INET6-NFSD", &svc_key[1]);
+ &svc_slock_key[1],
+ "sk_xprt.xpt_lock-AF_INET6-NFSD",
+ &svc_key[1]);
break;
default:
@@ -121,81 +89,26 @@
}
}
#else
-static inline void svc_reclassify_socket(struct socket *sock)
+static void svc_reclassify_socket(struct socket *sock)
{
}
#endif
-static char *__svc_print_addr(struct sockaddr *addr, char *buf, size_t len)
-{
- switch (addr->sa_family) {
- case AF_INET:
- snprintf(buf, len, "%u.%u.%u.%u, port=%u",
- NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
- ntohs(((struct sockaddr_in *) addr)->sin_port));
- break;
-
- case AF_INET6:
- snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
- NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
- ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
- break;
-
- default:
- snprintf(buf, len, "unknown address type: %d", addr->sa_family);
- break;
- }
- return buf;
-}
-
-/**
- * svc_print_addr - Format rq_addr field for printing
- * @rqstp: svc_rqst struct containing address to print
- * @buf: target buffer for formatted address
- * @len: length of target buffer
- *
- */
-char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
-{
- return __svc_print_addr(svc_addr(rqstp), buf, len);
-}
-EXPORT_SYMBOL_GPL(svc_print_addr);
-
-/*
- * Queue up an idle server thread. Must have pool->sp_lock held.
- * Note: this is really a stack rather than a queue, so that we only
- * use as many different threads as we need, and the rest don't pollute
- * the cache.
- */
-static inline void
-svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
-{
- list_add(&rqstp->rq_list, &pool->sp_threads);
-}
-
-/*
- * Dequeue an nfsd thread. Must have pool->sp_lock held.
- */
-static inline void
-svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
-{
- list_del(&rqstp->rq_list);
-}
-
/*
* Release an skbuff after use
*/
-static inline void
-svc_release_skb(struct svc_rqst *rqstp)
+static void svc_release_skb(struct svc_rqst *rqstp)
{
- struct sk_buff *skb = rqstp->rq_skbuff;
+ struct sk_buff *skb = rqstp->rq_xprt_ctxt;
struct svc_deferred_req *dr = rqstp->rq_deferred;
if (skb) {
- rqstp->rq_skbuff = NULL;
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ rqstp->rq_xprt_ctxt = NULL;
dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
- skb_free_datagram(rqstp->rq_sock->sk_sk, skb);
+ skb_free_datagram(svsk->sk_sk, skb);
}
if (dr) {
rqstp->rq_deferred = NULL;
@@ -203,253 +116,6 @@
}
}
-/*
- * Any space to write?
- */
-static inline unsigned long
-svc_sock_wspace(struct svc_sock *svsk)
-{
- int wspace;
-
- if (svsk->sk_sock->type == SOCK_STREAM)
- wspace = sk_stream_wspace(svsk->sk_sk);
- else
- wspace = sock_wspace(svsk->sk_sk);
-
- return wspace;
-}
-
-/*
- * Queue up a socket with data pending. If there are idle nfsd
- * processes, wake 'em up.
- *
- */
-static void
-svc_sock_enqueue(struct svc_sock *svsk)
-{
- struct svc_serv *serv = svsk->sk_server;
- struct svc_pool *pool;
- struct svc_rqst *rqstp;
- int cpu;
-
- if (!(svsk->sk_flags &
- ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))
- return;
- if (test_bit(SK_DEAD, &svsk->sk_flags))
- return;
-
- cpu = get_cpu();
- pool = svc_pool_for_cpu(svsk->sk_server, cpu);
- put_cpu();
-
- spin_lock_bh(&pool->sp_lock);
-
- if (!list_empty(&pool->sp_threads) &&
- !list_empty(&pool->sp_sockets))
- printk(KERN_ERR
- "svc_sock_enqueue: threads and sockets both waiting??\n");
-
- if (test_bit(SK_DEAD, &svsk->sk_flags)) {
- /* Don't enqueue dead sockets */
- dprintk("svc: socket %p is dead, not enqueued\n", svsk->sk_sk);
- goto out_unlock;
- }
-
- /* Mark socket as busy. It will remain in this state until the
- * server has processed all pending data and put the socket back
- * on the idle list. We update SK_BUSY atomically because
- * it also guards against trying to enqueue the svc_sock twice.
- */
- if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) {
- /* Don't enqueue socket while already enqueued */
- dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
- goto out_unlock;
- }
- BUG_ON(svsk->sk_pool != NULL);
- svsk->sk_pool = pool;
-
- set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
- if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2
- > svc_sock_wspace(svsk))
- && !test_bit(SK_CLOSE, &svsk->sk_flags)
- && !test_bit(SK_CONN, &svsk->sk_flags)) {
- /* Don't enqueue while not enough space for reply */
- dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n",
- svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg,
- svc_sock_wspace(svsk));
- svsk->sk_pool = NULL;
- clear_bit(SK_BUSY, &svsk->sk_flags);
- goto out_unlock;
- }
- clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
-
-
- if (!list_empty(&pool->sp_threads)) {
- rqstp = list_entry(pool->sp_threads.next,
- struct svc_rqst,
- rq_list);
- dprintk("svc: socket %p served by daemon %p\n",
- svsk->sk_sk, rqstp);
- svc_thread_dequeue(pool, rqstp);
- if (rqstp->rq_sock)
- printk(KERN_ERR
- "svc_sock_enqueue: server %p, rq_sock=%p!\n",
- rqstp, rqstp->rq_sock);
- rqstp->rq_sock = svsk;
- atomic_inc(&svsk->sk_inuse);
- rqstp->rq_reserved = serv->sv_max_mesg;
- atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
- BUG_ON(svsk->sk_pool != pool);
- wake_up(&rqstp->rq_wait);
- } else {
- dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
- list_add_tail(&svsk->sk_ready, &pool->sp_sockets);
- BUG_ON(svsk->sk_pool != pool);
- }
-
-out_unlock:
- spin_unlock_bh(&pool->sp_lock);
-}
-
-/*
- * Dequeue the first socket. Must be called with the pool->sp_lock held.
- */
-static inline struct svc_sock *
-svc_sock_dequeue(struct svc_pool *pool)
-{
- struct svc_sock *svsk;
-
- if (list_empty(&pool->sp_sockets))
- return NULL;
-
- svsk = list_entry(pool->sp_sockets.next,
- struct svc_sock, sk_ready);
- list_del_init(&svsk->sk_ready);
-
- dprintk("svc: socket %p dequeued, inuse=%d\n",
- svsk->sk_sk, atomic_read(&svsk->sk_inuse));
-
- return svsk;
-}
-
-/*
- * Having read something from a socket, check whether it
- * needs to be re-enqueued.
- * Note: SK_DATA only gets cleared when a read-attempt finds
- * no (or insufficient) data.
- */
-static inline void
-svc_sock_received(struct svc_sock *svsk)
-{
- svsk->sk_pool = NULL;
- clear_bit(SK_BUSY, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
-}
-
-
-/**
- * svc_reserve - change the space reserved for the reply to a request.
- * @rqstp: The request in question
- * @space: new max space to reserve
- *
- * Each request reserves some space on the output queue of the socket
- * to make sure the reply fits. This function reduces that reserved
- * space to be the amount of space used already, plus @space.
- *
- */
-void svc_reserve(struct svc_rqst *rqstp, int space)
-{
- space += rqstp->rq_res.head[0].iov_len;
-
- if (space < rqstp->rq_reserved) {
- struct svc_sock *svsk = rqstp->rq_sock;
- atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved);
- rqstp->rq_reserved = space;
-
- svc_sock_enqueue(svsk);
- }
-}
-
-/*
- * Release a socket after use.
- */
-static inline void
-svc_sock_put(struct svc_sock *svsk)
-{
- if (atomic_dec_and_test(&svsk->sk_inuse)) {
- BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags));
-
- dprintk("svc: releasing dead socket\n");
- if (svsk->sk_sock->file)
- sockfd_put(svsk->sk_sock);
- else
- sock_release(svsk->sk_sock);
- if (svsk->sk_info_authunix != NULL)
- svcauth_unix_info_release(svsk->sk_info_authunix);
- kfree(svsk);
- }
-}
-
-static void
-svc_sock_release(struct svc_rqst *rqstp)
-{
- struct svc_sock *svsk = rqstp->rq_sock;
-
- svc_release_skb(rqstp);
-
- svc_free_res_pages(rqstp);
- rqstp->rq_res.page_len = 0;
- rqstp->rq_res.page_base = 0;
-
-
- /* Reset response buffer and release
- * the reservation.
- * But first, check that enough space was reserved
- * for the reply, otherwise we have a bug!
- */
- if ((rqstp->rq_res.len) > rqstp->rq_reserved)
- printk(KERN_ERR "RPC request reserved %d but used %d\n",
- rqstp->rq_reserved,
- rqstp->rq_res.len);
-
- rqstp->rq_res.head[0].iov_len = 0;
- svc_reserve(rqstp, 0);
- rqstp->rq_sock = NULL;
-
- svc_sock_put(svsk);
-}
-
-/*
- * External function to wake up a server waiting for data
- * This really only makes sense for services like lockd
- * which have exactly one thread anyway.
- */
-void
-svc_wake_up(struct svc_serv *serv)
-{
- struct svc_rqst *rqstp;
- unsigned int i;
- struct svc_pool *pool;
-
- for (i = 0; i < serv->sv_nrpools; i++) {
- pool = &serv->sv_pools[i];
-
- spin_lock_bh(&pool->sp_lock);
- if (!list_empty(&pool->sp_threads)) {
- rqstp = list_entry(pool->sp_threads.next,
- struct svc_rqst,
- rq_list);
- dprintk("svc: daemon %p woken up.\n", rqstp);
- /*
- svc_thread_dequeue(pool, rqstp);
- rqstp->rq_sock = NULL;
- */
- wake_up(&rqstp->rq_wait);
- }
- spin_unlock_bh(&pool->sp_lock);
- }
-}
-
union svc_pktinfo_u {
struct in_pktinfo pkti;
struct in6_pktinfo pkti6;
@@ -459,7 +125,9 @@
static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
{
- switch (rqstp->rq_sock->sk_sk->sk_family) {
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ switch (svsk->sk_sk->sk_family) {
case AF_INET: {
struct in_pktinfo *pki = CMSG_DATA(cmh);
@@ -489,10 +157,10 @@
/*
* Generic sendto routine
*/
-static int
-svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
+static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
{
- struct svc_sock *svsk = rqstp->rq_sock;
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
struct socket *sock = svsk->sk_sock;
int slen;
union {
@@ -565,7 +233,7 @@
}
out:
dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n",
- rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len,
+ svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
return len;
@@ -602,7 +270,7 @@
if (!serv)
return 0;
spin_lock_bh(&serv->sv_lock);
- list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
+ list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
int onelen = one_sock_name(buf+len, svsk);
if (toclose && strcmp(toclose, buf+len) == 0)
closesk = svsk;
@@ -614,7 +282,7 @@
/* Should unregister with portmap, but you cannot
* unregister just one protocol...
*/
- svc_close_socket(closesk);
+ svc_close_xprt(&closesk->sk_xprt);
else if (toclose)
return -ENOENT;
return len;
@@ -624,8 +292,7 @@
/*
* Check input queue length
*/
-static int
-svc_recv_available(struct svc_sock *svsk)
+static int svc_recv_available(struct svc_sock *svsk)
{
struct socket *sock = svsk->sk_sock;
int avail, err;
@@ -638,48 +305,31 @@
/*
* Generic recvfrom routine.
*/
-static int
-svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen)
+static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
+ int buflen)
{
- struct svc_sock *svsk = rqstp->rq_sock;
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
struct msghdr msg = {
.msg_flags = MSG_DONTWAIT,
};
- struct sockaddr *sin;
int len;
+ rqstp->rq_xprt_hlen = 0;
+
len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
msg.msg_flags);
- /* sock_recvmsg doesn't fill in the name/namelen, so we must..
- */
- memcpy(&rqstp->rq_addr, &svsk->sk_remote, svsk->sk_remotelen);
- rqstp->rq_addrlen = svsk->sk_remotelen;
-
- /* Destination address in request is needed for binding the
- * source address in RPC callbacks later.
- */
- sin = (struct sockaddr *)&svsk->sk_local;
- switch (sin->sa_family) {
- case AF_INET:
- rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
- break;
- case AF_INET6:
- rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
- break;
- }
-
dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
svsk, iov[0].iov_base, iov[0].iov_len, len);
-
return len;
}
/*
* Set socket snd and rcv buffer lengths
*/
-static inline void
-svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
+static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
+ unsigned int rcv)
{
#if 0
mm_segment_t oldfs;
@@ -704,16 +354,16 @@
/*
* INET callback when data has been received on the socket.
*/
-static void
-svc_udp_data_ready(struct sock *sk, int count)
+static void svc_udp_data_ready(struct sock *sk, int count)
{
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
if (svsk) {
dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
- svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
- set_bit(SK_DATA, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
+ svsk, sk, count,
+ test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ svc_xprt_enqueue(&svsk->sk_xprt);
}
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
wake_up_interruptible(sk->sk_sleep);
@@ -722,15 +372,14 @@
/*
* INET callback when space is newly available on the socket.
*/
-static void
-svc_write_space(struct sock *sk)
+static void svc_write_space(struct sock *sk)
{
struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
if (svsk) {
dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
- svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags));
- svc_sock_enqueue(svsk);
+ svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+ svc_xprt_enqueue(&svsk->sk_xprt);
}
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) {
@@ -740,10 +389,19 @@
}
}
-static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp,
- struct cmsghdr *cmh)
+/*
+ * Copy the UDP datagram's destination address to the rqstp structure.
+ * The 'destination' address in this case is the address to which the
+ * peer sent the datagram, i.e. our local address. For multihomed
+ * hosts, this can change from msg to msg. Note that only the IP
+ * address changes, the port number should remain the same.
+ */
+static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
+ struct cmsghdr *cmh)
{
- switch (rqstp->rq_sock->sk_sk->sk_family) {
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ switch (svsk->sk_sk->sk_family) {
case AF_INET: {
struct in_pktinfo *pki = CMSG_DATA(cmh);
rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
@@ -760,11 +418,11 @@
/*
* Receive a datagram from a UDP socket.
*/
-static int
-svc_udp_recvfrom(struct svc_rqst *rqstp)
+static int svc_udp_recvfrom(struct svc_rqst *rqstp)
{
- struct svc_sock *svsk = rqstp->rq_sock;
- struct svc_serv *serv = svsk->sk_server;
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ struct svc_serv *serv = svsk->sk_xprt.xpt_server;
struct sk_buff *skb;
union {
struct cmsghdr hdr;
@@ -779,7 +437,7 @@
.msg_flags = MSG_DONTWAIT,
};
- if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+ if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
/* udp sockets need large rcvbuf as all pending
* requests are still in that buffer. sndbuf must
* also be large enough that there is enough space
@@ -792,17 +450,7 @@
(serv->sv_nrthreads+3) * serv->sv_max_mesg,
(serv->sv_nrthreads+3) * serv->sv_max_mesg);
- if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
- svc_sock_received(svsk);
- return svc_deferred_recv(rqstp);
- }
-
- if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
- svc_delete_socket(svsk);
- return 0;
- }
-
- clear_bit(SK_DATA, &svsk->sk_flags);
+ clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
skb = NULL;
err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
0, 0, MSG_PEEK | MSG_DONTWAIT);
@@ -813,24 +461,27 @@
if (err != -EAGAIN) {
/* possibly an icmp error */
dprintk("svc: recvfrom returned error %d\n", -err);
- set_bit(SK_DATA, &svsk->sk_flags);
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
}
- svc_sock_received(svsk);
+ svc_xprt_received(&svsk->sk_xprt);
return -EAGAIN;
}
- rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
+ len = svc_addr_len(svc_addr(rqstp));
+ if (len < 0)
+ return len;
+ rqstp->rq_addrlen = len;
if (skb->tstamp.tv64 == 0) {
skb->tstamp = ktime_get_real();
/* Don't enable netstamp, sunrpc doesn't
need that much accuracy */
}
svsk->sk_sk->sk_stamp = skb->tstamp;
- set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */
/*
* Maybe more packets - kick another thread ASAP.
*/
- svc_sock_received(svsk);
+ svc_xprt_received(&svsk->sk_xprt);
len = skb->len - sizeof(struct udphdr);
rqstp->rq_arg.len = len;
@@ -861,13 +512,14 @@
skb_free_datagram(svsk->sk_sk, skb);
} else {
/* we can use it in-place */
- rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr);
+ rqstp->rq_arg.head[0].iov_base = skb->data +
+ sizeof(struct udphdr);
rqstp->rq_arg.head[0].iov_len = len;
if (skb_checksum_complete(skb)) {
skb_free_datagram(svsk->sk_sk, skb);
return 0;
}
- rqstp->rq_skbuff = skb;
+ rqstp->rq_xprt_ctxt = skb;
}
rqstp->rq_arg.page_base = 0;
@@ -900,27 +552,81 @@
return error;
}
-static void
-svc_udp_init(struct svc_sock *svsk)
+static void svc_udp_prep_reply_hdr(struct svc_rqst *rqstp)
+{
+}
+
+static int svc_udp_has_wspace(struct svc_xprt *xprt)
+{
+ struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+ struct svc_serv *serv = xprt->xpt_server;
+ unsigned long required;
+
+ /*
+ * Set the SOCK_NOSPACE flag before checking the available
+ * sock space.
+ */
+ set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+ required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
+ if (required*2 > sock_wspace(svsk->sk_sk))
+ return 0;
+ clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+ return 1;
+}
+
+static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
+{
+ BUG();
+ return NULL;
+}
+
+static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
+ struct sockaddr *sa, int salen,
+ int flags)
+{
+ return svc_create_socket(serv, IPPROTO_UDP, sa, salen, flags);
+}
+
+static struct svc_xprt_ops svc_udp_ops = {
+ .xpo_create = svc_udp_create,
+ .xpo_recvfrom = svc_udp_recvfrom,
+ .xpo_sendto = svc_udp_sendto,
+ .xpo_release_rqst = svc_release_skb,
+ .xpo_detach = svc_sock_detach,
+ .xpo_free = svc_sock_free,
+ .xpo_prep_reply_hdr = svc_udp_prep_reply_hdr,
+ .xpo_has_wspace = svc_udp_has_wspace,
+ .xpo_accept = svc_udp_accept,
+};
+
+static struct svc_xprt_class svc_udp_class = {
+ .xcl_name = "udp",
+ .xcl_owner = THIS_MODULE,
+ .xcl_ops = &svc_udp_ops,
+ .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,
+};
+
+static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
{
int one = 1;
mm_segment_t oldfs;
+ svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
+ clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
svsk->sk_sk->sk_write_space = svc_write_space;
- svsk->sk_recvfrom = svc_udp_recvfrom;
- svsk->sk_sendto = svc_udp_sendto;
/* initialise setting must have enough space to
* receive and respond to one request.
* svc_udp_recvfrom will re-adjust if necessary
*/
svc_sock_setbufsize(svsk->sk_sock,
- 3 * svsk->sk_server->sv_max_mesg,
- 3 * svsk->sk_server->sv_max_mesg);
+ 3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
+ 3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
- set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
- set_bit(SK_CHNGBUF, &svsk->sk_flags);
+ /* data might have come in before data_ready set up */
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
oldfs = get_fs();
set_fs(KERNEL_DS);
@@ -934,8 +640,7 @@
* A data_ready event on a listening socket means there's a connection
* pending. Do not use state_change as a substitute for it.
*/
-static void
-svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
+static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
{
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
@@ -954,8 +659,8 @@
*/
if (sk->sk_state == TCP_LISTEN) {
if (svsk) {
- set_bit(SK_CONN, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
+ set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
+ svc_xprt_enqueue(&svsk->sk_xprt);
} else
printk("svc: socket %p: no user data\n", sk);
}
@@ -967,8 +672,7 @@
/*
* A state change on a connected socket means it's dying or dead.
*/
-static void
-svc_tcp_state_change(struct sock *sk)
+static void svc_tcp_state_change(struct sock *sk)
{
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
@@ -978,51 +682,36 @@
if (!svsk)
printk("svc: socket %p: no user data\n", sk);
else {
- set_bit(SK_CLOSE, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
+ set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+ svc_xprt_enqueue(&svsk->sk_xprt);
}
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
wake_up_interruptible_all(sk->sk_sleep);
}
-static void
-svc_tcp_data_ready(struct sock *sk, int count)
+static void svc_tcp_data_ready(struct sock *sk, int count)
{
struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
dprintk("svc: socket %p TCP data ready (svsk %p)\n",
sk, sk->sk_user_data);
if (svsk) {
- set_bit(SK_DATA, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ svc_xprt_enqueue(&svsk->sk_xprt);
}
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
wake_up_interruptible(sk->sk_sleep);
}
-static inline int svc_port_is_privileged(struct sockaddr *sin)
-{
- switch (sin->sa_family) {
- case AF_INET:
- return ntohs(((struct sockaddr_in *)sin)->sin_port)
- < PROT_SOCK;
- case AF_INET6:
- return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
- < PROT_SOCK;
- default:
- return 0;
- }
-}
-
/*
* Accept a TCP connection
*/
-static void
-svc_tcp_accept(struct svc_sock *svsk)
+static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
{
+ struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
struct sockaddr_storage addr;
struct sockaddr *sin = (struct sockaddr *) &addr;
- struct svc_serv *serv = svsk->sk_server;
+ struct svc_serv *serv = svsk->sk_xprt.xpt_server;
struct socket *sock = svsk->sk_sock;
struct socket *newsock;
struct svc_sock *newsvsk;
@@ -1031,9 +720,9 @@
dprintk("svc: tcp_accept %p sock %p\n", svsk, sock);
if (!sock)
- return;
+ return NULL;
- clear_bit(SK_CONN, &svsk->sk_flags);
+ clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
err = kernel_accept(sock, &newsock, O_NONBLOCK);
if (err < 0) {
if (err == -ENOMEM)
@@ -1042,11 +731,9 @@
else if (err != -EAGAIN && net_ratelimit())
printk(KERN_WARNING "%s: accept failed (err %d)!\n",
serv->sv_name, -err);
- return;
+ return NULL;
}
-
- set_bit(SK_CONN, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
+ set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
err = kernel_getpeername(newsock, sin, &slen);
if (err < 0) {
@@ -1077,106 +764,42 @@
if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
(SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
goto failed;
- memcpy(&newsvsk->sk_remote, sin, slen);
- newsvsk->sk_remotelen = slen;
+ svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
err = kernel_getsockname(newsock, sin, &slen);
if (unlikely(err < 0)) {
dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err);
slen = offsetof(struct sockaddr, sa_data);
}
- memcpy(&newsvsk->sk_local, sin, slen);
-
- svc_sock_received(newsvsk);
-
- /* make sure that we don't have too many active connections.
- * If we have, something must be dropped.
- *
- * There's no point in trying to do random drop here for
- * DoS prevention. The NFS clients does 1 reconnect in 15
- * seconds. An attacker can easily beat that.
- *
- * The only somewhat efficient mechanism would be if drop
- * old connections from the same IP first. But right now
- * we don't even record the client IP in svc_sock.
- */
- if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
- struct svc_sock *svsk = NULL;
- spin_lock_bh(&serv->sv_lock);
- if (!list_empty(&serv->sv_tempsocks)) {
- if (net_ratelimit()) {
- /* Try to help the admin */
- printk(KERN_NOTICE "%s: too many open TCP "
- "sockets, consider increasing the "
- "number of nfsd threads\n",
- serv->sv_name);
- printk(KERN_NOTICE
- "%s: last TCP connect from %s\n",
- serv->sv_name, __svc_print_addr(sin,
- buf, sizeof(buf)));
- }
- /*
- * Always select the oldest socket. It's not fair,
- * but so is life
- */
- svsk = list_entry(serv->sv_tempsocks.prev,
- struct svc_sock,
- sk_list);
- set_bit(SK_CLOSE, &svsk->sk_flags);
- atomic_inc(&svsk->sk_inuse);
- }
- spin_unlock_bh(&serv->sv_lock);
-
- if (svsk) {
- svc_sock_enqueue(svsk);
- svc_sock_put(svsk);
- }
-
- }
+ svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
if (serv->sv_stats)
serv->sv_stats->nettcpconn++;
- return;
+ return &newsvsk->sk_xprt;
failed:
sock_release(newsock);
- return;
+ return NULL;
}
/*
* Receive data from a TCP socket.
*/
-static int
-svc_tcp_recvfrom(struct svc_rqst *rqstp)
+static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
{
- struct svc_sock *svsk = rqstp->rq_sock;
- struct svc_serv *serv = svsk->sk_server;
+ struct svc_sock *svsk =
+ container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ struct svc_serv *serv = svsk->sk_xprt.xpt_server;
int len;
struct kvec *vec;
int pnum, vlen;
dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
- svsk, test_bit(SK_DATA, &svsk->sk_flags),
- test_bit(SK_CONN, &svsk->sk_flags),
- test_bit(SK_CLOSE, &svsk->sk_flags));
+ svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags),
+ test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
+ test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
- if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
- svc_sock_received(svsk);
- return svc_deferred_recv(rqstp);
- }
-
- if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
- svc_delete_socket(svsk);
- return 0;
- }
-
- if (svsk->sk_sk->sk_state == TCP_LISTEN) {
- svc_tcp_accept(svsk);
- svc_sock_received(svsk);
- return 0;
- }
-
- if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+ if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
/* sndbuf needs to have room for one request
* per thread, otherwise we can stall even when the
* network isn't a bottleneck.
@@ -1193,7 +816,7 @@
(serv->sv_nrthreads+3) * serv->sv_max_mesg,
3 * serv->sv_max_mesg);
- clear_bit(SK_DATA, &svsk->sk_flags);
+ clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
/* Receive data. If we haven't got the record length yet, get
* the next four bytes. Otherwise try to gobble up as much as
@@ -1212,7 +835,7 @@
if (len < want) {
dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
len, want);
- svc_sock_received(svsk);
+ svc_xprt_received(&svsk->sk_xprt);
return -EAGAIN; /* record header not complete */
}
@@ -1248,11 +871,11 @@
if (len < svsk->sk_reclen) {
dprintk("svc: incomplete TCP record (%d of %d)\n",
len, svsk->sk_reclen);
- svc_sock_received(svsk);
+ svc_xprt_received(&svsk->sk_xprt);
return -EAGAIN; /* record not complete */
}
len = svsk->sk_reclen;
- set_bit(SK_DATA, &svsk->sk_flags);
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
vec = rqstp->rq_vec;
vec[0] = rqstp->rq_arg.head[0];
@@ -1281,30 +904,31 @@
rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
}
- rqstp->rq_skbuff = NULL;
+ rqstp->rq_xprt_ctxt = NULL;
rqstp->rq_prot = IPPROTO_TCP;
/* Reset TCP read info */
svsk->sk_reclen = 0;
svsk->sk_tcplen = 0;
- svc_sock_received(svsk);
+ svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
+ svc_xprt_received(&svsk->sk_xprt);
if (serv->sv_stats)
serv->sv_stats->nettcpcnt++;
return len;
err_delete:
- svc_delete_socket(svsk);
+ set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
return -EAGAIN;
error:
if (len == -EAGAIN) {
dprintk("RPC: TCP recvfrom got EAGAIN\n");
- svc_sock_received(svsk);
+ svc_xprt_received(&svsk->sk_xprt);
} else {
printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
- svsk->sk_server->sv_name, -len);
+ svsk->sk_xprt.xpt_server->sv_name, -len);
goto err_delete;
}
@@ -1314,8 +938,7 @@
/*
* Send out data on TCP socket.
*/
-static int
-svc_tcp_sendto(struct svc_rqst *rqstp)
+static int svc_tcp_sendto(struct svc_rqst *rqstp)
{
struct xdr_buf *xbufp = &rqstp->rq_res;
int sent;
@@ -1328,35 +951,109 @@
reclen = htonl(0x80000000|((xbufp->len ) - 4));
memcpy(xbufp->head[0].iov_base, &reclen, 4);
- if (test_bit(SK_DEAD, &rqstp->rq_sock->sk_flags))
+ if (test_bit(XPT_DEAD, &rqstp->rq_xprt->xpt_flags))
return -ENOTCONN;
sent = svc_sendto(rqstp, &rqstp->rq_res);
if (sent != xbufp->len) {
- printk(KERN_NOTICE "rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
- rqstp->rq_sock->sk_server->sv_name,
+ printk(KERN_NOTICE
+ "rpc-srv/tcp: %s: %s %d when sending %d bytes "
+ "- shutting down socket\n",
+ rqstp->rq_xprt->xpt_server->sv_name,
(sent<0)?"got error":"sent only",
sent, xbufp->len);
- set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags);
- svc_sock_enqueue(rqstp->rq_sock);
+ set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
+ svc_xprt_enqueue(rqstp->rq_xprt);
sent = -EAGAIN;
}
return sent;
}
-static void
-svc_tcp_init(struct svc_sock *svsk)
+/*
+ * Setup response header. TCP has a 4B record length field.
+ */
+static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
+{
+ struct kvec *resv = &rqstp->rq_res.head[0];
+
+ /* tcp needs a space for the record length... */
+ svc_putnl(resv, 0);
+}
+
+static int svc_tcp_has_wspace(struct svc_xprt *xprt)
+{
+ struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+ struct svc_serv *serv = svsk->sk_xprt.xpt_server;
+ int required;
+ int wspace;
+
+ /*
+ * Set the SOCK_NOSPACE flag before checking the available
+ * sock space.
+ */
+ set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+ required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
+ wspace = sk_stream_wspace(svsk->sk_sk);
+
+ if (wspace < sk_stream_min_wspace(svsk->sk_sk))
+ return 0;
+ if (required * 2 > wspace)
+ return 0;
+
+ clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+ return 1;
+}
+
+static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
+ struct sockaddr *sa, int salen,
+ int flags)
+{
+ return svc_create_socket(serv, IPPROTO_TCP, sa, salen, flags);
+}
+
+static struct svc_xprt_ops svc_tcp_ops = {
+ .xpo_create = svc_tcp_create,
+ .xpo_recvfrom = svc_tcp_recvfrom,
+ .xpo_sendto = svc_tcp_sendto,
+ .xpo_release_rqst = svc_release_skb,
+ .xpo_detach = svc_sock_detach,
+ .xpo_free = svc_sock_free,
+ .xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
+ .xpo_has_wspace = svc_tcp_has_wspace,
+ .xpo_accept = svc_tcp_accept,
+};
+
+static struct svc_xprt_class svc_tcp_class = {
+ .xcl_name = "tcp",
+ .xcl_owner = THIS_MODULE,
+ .xcl_ops = &svc_tcp_ops,
+ .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
+};
+
+void svc_init_xprt_sock(void)
+{
+ svc_reg_xprt_class(&svc_tcp_class);
+ svc_reg_xprt_class(&svc_udp_class);
+}
+
+void svc_cleanup_xprt_sock(void)
+{
+ svc_unreg_xprt_class(&svc_tcp_class);
+ svc_unreg_xprt_class(&svc_udp_class);
+}
+
+static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
{
struct sock *sk = svsk->sk_sk;
struct tcp_sock *tp = tcp_sk(sk);
- svsk->sk_recvfrom = svc_tcp_recvfrom;
- svsk->sk_sendto = svc_tcp_sendto;
-
+ svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
+ set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
if (sk->sk_state == TCP_LISTEN) {
dprintk("setting up TCP socket for listening\n");
+ set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
sk->sk_data_ready = svc_tcp_listen_data_ready;
- set_bit(SK_CONN, &svsk->sk_flags);
+ set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
} else {
dprintk("setting up TCP socket for reading\n");
sk->sk_state_change = svc_tcp_state_change;
@@ -1373,18 +1070,17 @@
* svc_tcp_recvfrom will re-adjust if necessary
*/
svc_sock_setbufsize(svsk->sk_sock,
- 3 * svsk->sk_server->sv_max_mesg,
- 3 * svsk->sk_server->sv_max_mesg);
+ 3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
+ 3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
- set_bit(SK_CHNGBUF, &svsk->sk_flags);
- set_bit(SK_DATA, &svsk->sk_flags);
+ set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
if (sk->sk_state != TCP_ESTABLISHED)
- set_bit(SK_CLOSE, &svsk->sk_flags);
+ set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
}
}
-void
-svc_sock_update_bufs(struct svc_serv *serv)
+void svc_sock_update_bufs(struct svc_serv *serv)
{
/*
* The number of server threads has changed. Update
@@ -1395,232 +1091,18 @@
spin_lock_bh(&serv->sv_lock);
list_for_each(le, &serv->sv_permsocks) {
struct svc_sock *svsk =
- list_entry(le, struct svc_sock, sk_list);
- set_bit(SK_CHNGBUF, &svsk->sk_flags);
+ list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+ set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
}
list_for_each(le, &serv->sv_tempsocks) {
struct svc_sock *svsk =
- list_entry(le, struct svc_sock, sk_list);
- set_bit(SK_CHNGBUF, &svsk->sk_flags);
+ list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+ set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
}
spin_unlock_bh(&serv->sv_lock);
}
/*
- * Receive the next request on any socket. This code is carefully
- * organised not to touch any cachelines in the shared svc_serv
- * structure, only cachelines in the local svc_pool.
- */
-int
-svc_recv(struct svc_rqst *rqstp, long timeout)
-{
- struct svc_sock *svsk = NULL;
- struct svc_serv *serv = rqstp->rq_server;
- struct svc_pool *pool = rqstp->rq_pool;
- int len, i;
- int pages;
- struct xdr_buf *arg;
- DECLARE_WAITQUEUE(wait, current);
-
- dprintk("svc: server %p waiting for data (to = %ld)\n",
- rqstp, timeout);
-
- if (rqstp->rq_sock)
- printk(KERN_ERR
- "svc_recv: service %p, socket not NULL!\n",
- rqstp);
- if (waitqueue_active(&rqstp->rq_wait))
- printk(KERN_ERR
- "svc_recv: service %p, wait queue active!\n",
- rqstp);
-
-
- /* now allocate needed pages. If we get a failure, sleep briefly */
- pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
- for (i=0; i < pages ; i++)
- while (rqstp->rq_pages[i] == NULL) {
- struct page *p = alloc_page(GFP_KERNEL);
- if (!p)
- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- rqstp->rq_pages[i] = p;
- }
- rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
- BUG_ON(pages >= RPCSVC_MAXPAGES);
-
- /* Make arg->head point to first page and arg->pages point to rest */
- arg = &rqstp->rq_arg;
- arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
- arg->head[0].iov_len = PAGE_SIZE;
- arg->pages = rqstp->rq_pages + 1;
- arg->page_base = 0;
- /* save at least one page for response */
- arg->page_len = (pages-2)*PAGE_SIZE;
- arg->len = (pages-1)*PAGE_SIZE;
- arg->tail[0].iov_len = 0;
-
- try_to_freeze();
- cond_resched();
- if (signalled())
- return -EINTR;
-
- spin_lock_bh(&pool->sp_lock);
- if ((svsk = svc_sock_dequeue(pool)) != NULL) {
- rqstp->rq_sock = svsk;
- atomic_inc(&svsk->sk_inuse);
- rqstp->rq_reserved = serv->sv_max_mesg;
- atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
- } else {
- /* No data pending. Go to sleep */
- svc_thread_enqueue(pool, rqstp);
-
- /*
- * We have to be able to interrupt this wait
- * to bring down the daemons ...
- */
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&rqstp->rq_wait, &wait);
- spin_unlock_bh(&pool->sp_lock);
-
- schedule_timeout(timeout);
-
- try_to_freeze();
-
- spin_lock_bh(&pool->sp_lock);
- remove_wait_queue(&rqstp->rq_wait, &wait);
-
- if (!(svsk = rqstp->rq_sock)) {
- svc_thread_dequeue(pool, rqstp);
- spin_unlock_bh(&pool->sp_lock);
- dprintk("svc: server %p, no data yet\n", rqstp);
- return signalled()? -EINTR : -EAGAIN;
- }
- }
- spin_unlock_bh(&pool->sp_lock);
-
- dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n",
- rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse));
- len = svsk->sk_recvfrom(rqstp);
- dprintk("svc: got len=%d\n", len);
-
- /* No data, incomplete (TCP) read, or accept() */
- if (len == 0 || len == -EAGAIN) {
- rqstp->rq_res.len = 0;
- svc_sock_release(rqstp);
- return -EAGAIN;
- }
- svsk->sk_lastrecv = get_seconds();
- clear_bit(SK_OLD, &svsk->sk_flags);
-
- rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
- rqstp->rq_chandle.defer = svc_defer;
-
- if (serv->sv_stats)
- serv->sv_stats->netcnt++;
- return len;
-}
-
-/*
- * Drop request
- */
-void
-svc_drop(struct svc_rqst *rqstp)
-{
- dprintk("svc: socket %p dropped request\n", rqstp->rq_sock);
- svc_sock_release(rqstp);
-}
-
-/*
- * Return reply to client.
- */
-int
-svc_send(struct svc_rqst *rqstp)
-{
- struct svc_sock *svsk;
- int len;
- struct xdr_buf *xb;
-
- if ((svsk = rqstp->rq_sock) == NULL) {
- printk(KERN_WARNING "NULL socket pointer in %s:%d\n",
- __FILE__, __LINE__);
- return -EFAULT;
- }
-
- /* release the receive skb before sending the reply */
- svc_release_skb(rqstp);
-
- /* calculate over-all length */
- xb = & rqstp->rq_res;
- xb->len = xb->head[0].iov_len +
- xb->page_len +
- xb->tail[0].iov_len;
-
- /* Grab svsk->sk_mutex to serialize outgoing data. */
- mutex_lock(&svsk->sk_mutex);
- if (test_bit(SK_DEAD, &svsk->sk_flags))
- len = -ENOTCONN;
- else
- len = svsk->sk_sendto(rqstp);
- mutex_unlock(&svsk->sk_mutex);
- svc_sock_release(rqstp);
-
- if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
- return 0;
- return len;
-}
-
-/*
- * Timer function to close old temporary sockets, using
- * a mark-and-sweep algorithm.
- */
-static void
-svc_age_temp_sockets(unsigned long closure)
-{
- struct svc_serv *serv = (struct svc_serv *)closure;
- struct svc_sock *svsk;
- struct list_head *le, *next;
- LIST_HEAD(to_be_aged);
-
- dprintk("svc_age_temp_sockets\n");
-
- if (!spin_trylock_bh(&serv->sv_lock)) {
- /* busy, try again 1 sec later */
- dprintk("svc_age_temp_sockets: busy\n");
- mod_timer(&serv->sv_temptimer, jiffies + HZ);
- return;
- }
-
- list_for_each_safe(le, next, &serv->sv_tempsocks) {
- svsk = list_entry(le, struct svc_sock, sk_list);
-
- if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
- continue;
- if (atomic_read(&svsk->sk_inuse) > 1 || test_bit(SK_BUSY, &svsk->sk_flags))
- continue;
- atomic_inc(&svsk->sk_inuse);
- list_move(le, &to_be_aged);
- set_bit(SK_CLOSE, &svsk->sk_flags);
- set_bit(SK_DETACHED, &svsk->sk_flags);
- }
- spin_unlock_bh(&serv->sv_lock);
-
- while (!list_empty(&to_be_aged)) {
- le = to_be_aged.next;
- /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */
- list_del_init(le);
- svsk = list_entry(le, struct svc_sock, sk_list);
-
- dprintk("queuing svsk %p for closing, %lu seconds old\n",
- svsk, get_seconds() - svsk->sk_lastrecv);
-
- /* a thread will dequeue and close it soon */
- svc_sock_enqueue(svsk);
- svc_sock_put(svsk);
- }
-
- mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
-}
-
-/*
* Initialize socket for RPC use and create svc_sock struct
* XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
*/
@@ -1631,7 +1113,6 @@
struct svc_sock *svsk;
struct sock *inet;
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
- int is_temporary = flags & SVC_SOCK_TEMPORARY;
dprintk("svc: svc_setup_socket %p\n", sock);
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1651,44 +1132,18 @@
return NULL;
}
- set_bit(SK_BUSY, &svsk->sk_flags);
inet->sk_user_data = svsk;
svsk->sk_sock = sock;
svsk->sk_sk = inet;
svsk->sk_ostate = inet->sk_state_change;
svsk->sk_odata = inet->sk_data_ready;
svsk->sk_owspace = inet->sk_write_space;
- svsk->sk_server = serv;
- atomic_set(&svsk->sk_inuse, 1);
- svsk->sk_lastrecv = get_seconds();
- spin_lock_init(&svsk->sk_lock);
- INIT_LIST_HEAD(&svsk->sk_deferred);
- INIT_LIST_HEAD(&svsk->sk_ready);
- mutex_init(&svsk->sk_mutex);
/* Initialize the socket */
if (sock->type == SOCK_DGRAM)
- svc_udp_init(svsk);
+ svc_udp_init(svsk, serv);
else
- svc_tcp_init(svsk);
-
- spin_lock_bh(&serv->sv_lock);
- if (is_temporary) {
- set_bit(SK_TEMP, &svsk->sk_flags);
- list_add(&svsk->sk_list, &serv->sv_tempsocks);
- serv->sv_tmpcnt++;
- if (serv->sv_temptimer.function == NULL) {
- /* setup timer to age temp sockets */
- setup_timer(&serv->sv_temptimer, svc_age_temp_sockets,
- (unsigned long)serv);
- mod_timer(&serv->sv_temptimer,
- jiffies + svc_conn_age_period * HZ);
- }
- } else {
- clear_bit(SK_TEMP, &svsk->sk_flags);
- list_add(&svsk->sk_list, &serv->sv_permsocks);
- }
- spin_unlock_bh(&serv->sv_lock);
+ svc_tcp_init(svsk, serv);
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
svsk, svsk->sk_sk);
@@ -1717,7 +1172,16 @@
else {
svsk = svc_setup_socket(serv, so, &err, SVC_SOCK_DEFAULTS);
if (svsk) {
- svc_sock_received(svsk);
+ struct sockaddr_storage addr;
+ struct sockaddr *sin = (struct sockaddr *)&addr;
+ int salen;
+ if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
+ svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
+ clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags);
+ spin_lock_bh(&serv->sv_lock);
+ list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks);
+ spin_unlock_bh(&serv->sv_lock);
+ svc_xprt_received(&svsk->sk_xprt);
err = 0;
}
}
@@ -1733,14 +1197,19 @@
/*
* Create socket for RPC service.
*/
-static int svc_create_socket(struct svc_serv *serv, int protocol,
- struct sockaddr *sin, int len, int flags)
+static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
+ int protocol,
+ struct sockaddr *sin, int len,
+ int flags)
{
struct svc_sock *svsk;
struct socket *sock;
int error;
int type;
char buf[RPC_MAX_ADDRBUFLEN];
+ struct sockaddr_storage addr;
+ struct sockaddr *newsin = (struct sockaddr *)&addr;
+ int newlen;
dprintk("svc: svc_create_socket(%s, %d, %s)\n",
serv->sv_program->pg_name, protocol,
@@ -1749,13 +1218,13 @@
if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
printk(KERN_WARNING "svc: only UDP and TCP "
"sockets supported\n");
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
error = sock_create_kern(sin->sa_family, type, protocol, &sock);
if (error < 0)
- return error;
+ return ERR_PTR(error);
svc_reclassify_socket(sock);
@@ -1765,203 +1234,55 @@
if (error < 0)
goto bummer;
+ newlen = len;
+ error = kernel_getsockname(sock, newsin, &newlen);
+ if (error < 0)
+ goto bummer;
+
if (protocol == IPPROTO_TCP) {
if ((error = kernel_listen(sock, 64)) < 0)
goto bummer;
}
if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
- svc_sock_received(svsk);
- return ntohs(inet_sk(svsk->sk_sk)->sport);
+ svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
+ return (struct svc_xprt *)svsk;
}
bummer:
dprintk("svc: svc_create_socket error = %d\n", -error);
sock_release(sock);
- return error;
+ return ERR_PTR(error);
}
/*
- * Remove a dead socket
+ * Detach the svc_sock from the socket so that no
+ * more callbacks occur.
*/
-static void
-svc_delete_socket(struct svc_sock *svsk)
+static void svc_sock_detach(struct svc_xprt *xprt)
{
- struct svc_serv *serv;
- struct sock *sk;
+ struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+ struct sock *sk = svsk->sk_sk;
- dprintk("svc: svc_delete_socket(%p)\n", svsk);
+ dprintk("svc: svc_sock_detach(%p)\n", svsk);
- serv = svsk->sk_server;
- sk = svsk->sk_sk;
-
+ /* put back the old socket callbacks */
sk->sk_state_change = svsk->sk_ostate;
sk->sk_data_ready = svsk->sk_odata;
sk->sk_write_space = svsk->sk_owspace;
-
- spin_lock_bh(&serv->sv_lock);
-
- if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags))
- list_del_init(&svsk->sk_list);
- /*
- * We used to delete the svc_sock from whichever list
- * it's sk_ready node was on, but we don't actually
- * need to. This is because the only time we're called
- * while still attached to a queue, the queue itself
- * is about to be destroyed (in svc_destroy).
- */
- if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) {
- BUG_ON(atomic_read(&svsk->sk_inuse)<2);
- atomic_dec(&svsk->sk_inuse);
- if (test_bit(SK_TEMP, &svsk->sk_flags))
- serv->sv_tmpcnt--;
- }
-
- spin_unlock_bh(&serv->sv_lock);
-}
-
-static void svc_close_socket(struct svc_sock *svsk)
-{
- set_bit(SK_CLOSE, &svsk->sk_flags);
- if (test_and_set_bit(SK_BUSY, &svsk->sk_flags))
- /* someone else will have to effect the close */
- return;
-
- atomic_inc(&svsk->sk_inuse);
- svc_delete_socket(svsk);
- clear_bit(SK_BUSY, &svsk->sk_flags);
- svc_sock_put(svsk);
-}
-
-void svc_force_close_socket(struct svc_sock *svsk)
-{
- set_bit(SK_CLOSE, &svsk->sk_flags);
- if (test_bit(SK_BUSY, &svsk->sk_flags)) {
- /* Waiting to be processed, but no threads left,
- * So just remove it from the waiting list
- */
- list_del_init(&svsk->sk_ready);
- clear_bit(SK_BUSY, &svsk->sk_flags);
- }
- svc_close_socket(svsk);
-}
-
-/**
- * svc_makesock - Make a socket for nfsd and lockd
- * @serv: RPC server structure
- * @protocol: transport protocol to use
- * @port: port to use
- * @flags: requested socket characteristics
- *
- */
-int svc_makesock(struct svc_serv *serv, int protocol, unsigned short port,
- int flags)
-{
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
- .sin_addr.s_addr = INADDR_ANY,
- .sin_port = htons(port),
- };
-
- dprintk("svc: creating socket proto = %d\n", protocol);
- return svc_create_socket(serv, protocol, (struct sockaddr *) &sin,
- sizeof(sin), flags);
}
/*
- * Handle defer and revisit of requests
+ * Free the svc_sock's socket resources and the svc_sock itself.
*/
-
-static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
+static void svc_sock_free(struct svc_xprt *xprt)
{
- struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle);
- struct svc_sock *svsk;
+ struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+ dprintk("svc: svc_sock_free(%p)\n", svsk);
- if (too_many) {
- svc_sock_put(dr->svsk);
- kfree(dr);
- return;
- }
- dprintk("revisit queued\n");
- svsk = dr->svsk;
- dr->svsk = NULL;
- spin_lock(&svsk->sk_lock);
- list_add(&dr->handle.recent, &svsk->sk_deferred);
- spin_unlock(&svsk->sk_lock);
- set_bit(SK_DEFERRED, &svsk->sk_flags);
- svc_sock_enqueue(svsk);
- svc_sock_put(svsk);
-}
-
-static struct cache_deferred_req *
-svc_defer(struct cache_req *req)
-{
- struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
- int size = sizeof(struct svc_deferred_req) + (rqstp->rq_arg.len);
- struct svc_deferred_req *dr;
-
- if (rqstp->rq_arg.page_len)
- return NULL; /* if more than a page, give up FIXME */
- if (rqstp->rq_deferred) {
- dr = rqstp->rq_deferred;
- rqstp->rq_deferred = NULL;
- } else {
- int skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
- /* FIXME maybe discard if size too large */
- dr = kmalloc(size, GFP_KERNEL);
- if (dr == NULL)
- return NULL;
-
- dr->handle.owner = rqstp->rq_server;
- dr->prot = rqstp->rq_prot;
- memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
- dr->addrlen = rqstp->rq_addrlen;
- dr->daddr = rqstp->rq_daddr;
- dr->argslen = rqstp->rq_arg.len >> 2;
- memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2);
- }
- atomic_inc(&rqstp->rq_sock->sk_inuse);
- dr->svsk = rqstp->rq_sock;
-
- dr->handle.revisit = svc_revisit;
- return &dr->handle;
-}
-
-/*
- * recv data from a deferred request into an active one
- */
-static int svc_deferred_recv(struct svc_rqst *rqstp)
-{
- struct svc_deferred_req *dr = rqstp->rq_deferred;
-
- rqstp->rq_arg.head[0].iov_base = dr->args;
- rqstp->rq_arg.head[0].iov_len = dr->argslen<<2;
- rqstp->rq_arg.page_len = 0;
- rqstp->rq_arg.len = dr->argslen<<2;
- rqstp->rq_prot = dr->prot;
- memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
- rqstp->rq_addrlen = dr->addrlen;
- rqstp->rq_daddr = dr->daddr;
- rqstp->rq_respages = rqstp->rq_pages;
- return dr->argslen<<2;
-}
-
-
-static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
-{
- struct svc_deferred_req *dr = NULL;
-
- if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
- return NULL;
- spin_lock(&svsk->sk_lock);
- clear_bit(SK_DEFERRED, &svsk->sk_flags);
- if (!list_empty(&svsk->sk_deferred)) {
- dr = list_entry(svsk->sk_deferred.next,
- struct svc_deferred_req,
- handle.recent);
- list_del_init(&dr->handle.recent);
- set_bit(SK_DEFERRED, &svsk->sk_flags);
- }
- spin_unlock(&svsk->sk_lock);
- return dr;
+ if (svsk->sk_sock->file)
+ sockfd_put(svsk->sk_sock);
+ else
+ sock_release(svsk->sk_sock);
+ kfree(svsk);
}
diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c
index bada7de..0f8c439 100644
--- a/net/sunrpc/sysctl.c
+++ b/net/sunrpc/sysctl.c
@@ -18,6 +18,7 @@
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/svc_xprt.h>
/*
* Declare the debug flags here
@@ -55,6 +56,30 @@
}
}
+static int proc_do_xprt(ctl_table *table, int write, struct file *file,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ char tmpbuf[256];
+ int len;
+ if ((*ppos && !write) || !*lenp) {
+ *lenp = 0;
+ return 0;
+ }
+ if (write)
+ return -EINVAL;
+ else {
+ len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
+ if (!access_ok(VERIFY_WRITE, buffer, len))
+ return -EFAULT;
+
+ if (__copy_to_user(buffer, tmpbuf, len))
+ return -EFAULT;
+ }
+ *lenp -= len;
+ *ppos += len;
+ return 0;
+}
+
static int
proc_dodebug(ctl_table *table, int write, struct file *file,
void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -147,6 +172,12 @@
.mode = 0644,
.proc_handler = &proc_dodebug
},
+ {
+ .procname = "transports",
+ .maxlen = 256,
+ .mode = 0444,
+ .proc_handler = &proc_do_xprt,
+ },
{ .ctl_name = 0 }
};
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 5426406..995c3fd 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -96,11 +96,13 @@
EXPORT_SYMBOL(xdr_encode_string);
__be32 *
-xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
+xdr_decode_string_inplace(__be32 *p, char **sp,
+ unsigned int *lenp, unsigned int maxlen)
{
- unsigned int len;
+ u32 len;
- if ((len = ntohl(*p++)) > maxlen)
+ len = ntohl(*p++);
+ if (len > maxlen)
return NULL;
*lenp = len;
*sp = (char *) p;
diff --git a/net/sunrpc/xprtrdma/Makefile b/net/sunrpc/xprtrdma/Makefile
index 264f0fe..5a8f268 100644
--- a/net/sunrpc/xprtrdma/Makefile
+++ b/net/sunrpc/xprtrdma/Makefile
@@ -1,3 +1,8 @@
obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
xprtrdma-y := transport.o rpc_rdma.o verbs.o
+
+obj-$(CONFIG_SUNRPC_XPRT_RDMA) += svcrdma.o
+
+svcrdma-y := svc_rdma.o svc_rdma_transport.o \
+ svc_rdma_marshal.o svc_rdma_sendto.o svc_rdma_recvfrom.o
diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
new file mode 100644
index 0000000..88c0ca2
--- /dev/null
+++ b/net/sunrpc/xprtrdma/svc_rdma.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
+
+/* RPC/RDMA parameters */
+unsigned int svcrdma_ord = RPCRDMA_ORD;
+static unsigned int min_ord = 1;
+static unsigned int max_ord = 4096;
+unsigned int svcrdma_max_requests = RPCRDMA_MAX_REQUESTS;
+static unsigned int min_max_requests = 4;
+static unsigned int max_max_requests = 16384;
+unsigned int svcrdma_max_req_size = RPCRDMA_MAX_REQ_SIZE;
+static unsigned int min_max_inline = 4096;
+static unsigned int max_max_inline = 65536;
+
+atomic_t rdma_stat_recv;
+atomic_t rdma_stat_read;
+atomic_t rdma_stat_write;
+atomic_t rdma_stat_sq_starve;
+atomic_t rdma_stat_rq_starve;
+atomic_t rdma_stat_rq_poll;
+atomic_t rdma_stat_rq_prod;
+atomic_t rdma_stat_sq_poll;
+atomic_t rdma_stat_sq_prod;
+
+/*
+ * This function implements reading and resetting an atomic_t stat
+ * variable through read/write to a proc file. Any write to the file
+ * resets the associated statistic to zero. Any read returns it's
+ * current value.
+ */
+static int read_reset_stat(ctl_table *table, int write,
+ struct file *filp, void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ atomic_t *stat = (atomic_t *)table->data;
+
+ if (!stat)
+ return -EINVAL;
+
+ if (write)
+ atomic_set(stat, 0);
+ else {
+ char str_buf[32];
+ char *data;
+ int len = snprintf(str_buf, 32, "%d\n", atomic_read(stat));
+ if (len >= 32)
+ return -EFAULT;
+ len = strlen(str_buf);
+ if (*ppos > len) {
+ *lenp = 0;
+ return 0;
+ }
+ data = &str_buf[*ppos];
+ len -= *ppos;
+ if (len > *lenp)
+ len = *lenp;
+ if (len && copy_to_user(buffer, str_buf, len))
+ return -EFAULT;
+ *lenp = len;
+ *ppos += len;
+ }
+ return 0;
+}
+
+static struct ctl_table_header *svcrdma_table_header;
+static ctl_table svcrdma_parm_table[] = {
+ {
+ .procname = "max_requests",
+ .data = &svcrdma_max_requests,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &min_max_requests,
+ .extra2 = &max_max_requests
+ },
+ {
+ .procname = "max_req_size",
+ .data = &svcrdma_max_req_size,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &min_max_inline,
+ .extra2 = &max_max_inline
+ },
+ {
+ .procname = "max_outbound_read_requests",
+ .data = &svcrdma_ord,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &min_ord,
+ .extra2 = &max_ord,
+ },
+
+ {
+ .procname = "rdma_stat_read",
+ .data = &rdma_stat_read,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_recv",
+ .data = &rdma_stat_recv,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_write",
+ .data = &rdma_stat_write,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_sq_starve",
+ .data = &rdma_stat_sq_starve,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_rq_starve",
+ .data = &rdma_stat_rq_starve,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_rq_poll",
+ .data = &rdma_stat_rq_poll,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_rq_prod",
+ .data = &rdma_stat_rq_prod,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_sq_poll",
+ .data = &rdma_stat_sq_poll,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .procname = "rdma_stat_sq_prod",
+ .data = &rdma_stat_sq_prod,
+ .maxlen = sizeof(atomic_t),
+ .mode = 0644,
+ .proc_handler = &read_reset_stat,
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+static ctl_table svcrdma_table[] = {
+ {
+ .procname = "svc_rdma",
+ .mode = 0555,
+ .child = svcrdma_parm_table
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+static ctl_table svcrdma_root_table[] = {
+ {
+ .ctl_name = CTL_SUNRPC,
+ .procname = "sunrpc",
+ .mode = 0555,
+ .child = svcrdma_table
+ },
+ {
+ .ctl_name = 0,
+ },
+};
+
+void svc_rdma_cleanup(void)
+{
+ dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
+ if (svcrdma_table_header) {
+ unregister_sysctl_table(svcrdma_table_header);
+ svcrdma_table_header = NULL;
+ }
+ svc_unreg_xprt_class(&svc_rdma_class);
+}
+
+int svc_rdma_init(void)
+{
+ dprintk("SVCRDMA Module Init, register RPC RDMA transport\n");
+ dprintk("\tsvcrdma_ord : %d\n", svcrdma_ord);
+ dprintk("\tmax_requests : %d\n", svcrdma_max_requests);
+ dprintk("\tsq_depth : %d\n",
+ svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT);
+ dprintk("\tmax_inline : %d\n", svcrdma_max_req_size);
+ if (!svcrdma_table_header)
+ svcrdma_table_header =
+ register_sysctl_table(svcrdma_root_table);
+
+ /* Register RDMA with the SVC transport switch */
+ svc_reg_xprt_class(&svc_rdma_class);
+ return 0;
+}
+MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
+MODULE_DESCRIPTION("SVC RDMA Transport");
+MODULE_LICENSE("Dual BSD/GPL");
+module_init(svc_rdma_init);
+module_exit(svc_rdma_cleanup);
diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
new file mode 100644
index 0000000..9530ef2
--- /dev/null
+++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/debug.h>
+#include <asm/unaligned.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
+
+/*
+ * Decodes a read chunk list. The expected format is as follows:
+ * descrim : xdr_one
+ * position : u32 offset into XDR stream
+ * handle : u32 RKEY
+ * . . .
+ * end-of-list: xdr_zero
+ */
+static u32 *decode_read_list(u32 *va, u32 *vaend)
+{
+ struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
+
+ while (ch->rc_discrim != xdr_zero) {
+ u64 ch_offset;
+
+ if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
+ (unsigned long)vaend) {
+ dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
+ return NULL;
+ }
+
+ ch->rc_discrim = ntohl(ch->rc_discrim);
+ ch->rc_position = ntohl(ch->rc_position);
+ ch->rc_target.rs_handle = ntohl(ch->rc_target.rs_handle);
+ ch->rc_target.rs_length = ntohl(ch->rc_target.rs_length);
+ va = (u32 *)&ch->rc_target.rs_offset;
+ xdr_decode_hyper(va, &ch_offset);
+ put_unaligned(ch_offset, (u64 *)va);
+ ch++;
+ }
+ return (u32 *)&ch->rc_position;
+}
+
+/*
+ * Determine number of chunks and total bytes in chunk list. The chunk
+ * list has already been verified to fit within the RPCRDMA header.
+ */
+void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
+ int *ch_count, int *byte_count)
+{
+ /* compute the number of bytes represented by read chunks */
+ *byte_count = 0;
+ *ch_count = 0;
+ for (; ch->rc_discrim != 0; ch++) {
+ *byte_count = *byte_count + ch->rc_target.rs_length;
+ *ch_count = *ch_count + 1;
+ }
+}
+
+/*
+ * Decodes a write chunk list. The expected format is as follows:
+ * descrim : xdr_one
+ * nchunks : <count>
+ * handle : u32 RKEY ---+
+ * length : u32 <len of segment> |
+ * offset : remove va + <count>
+ * . . . |
+ * ---+
+ */
+static u32 *decode_write_list(u32 *va, u32 *vaend)
+{
+ int ch_no;
+ struct rpcrdma_write_array *ary =
+ (struct rpcrdma_write_array *)va;
+
+ /* Check for not write-array */
+ if (ary->wc_discrim == xdr_zero)
+ return (u32 *)&ary->wc_nchunks;
+
+ if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
+ (unsigned long)vaend) {
+ dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
+ return NULL;
+ }
+ ary->wc_discrim = ntohl(ary->wc_discrim);
+ ary->wc_nchunks = ntohl(ary->wc_nchunks);
+ if (((unsigned long)&ary->wc_array[0] +
+ (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+ (unsigned long)vaend) {
+ dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
+ ary, ary->wc_nchunks, vaend);
+ return NULL;
+ }
+ for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
+ u64 ch_offset;
+
+ ary->wc_array[ch_no].wc_target.rs_handle =
+ ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
+ ary->wc_array[ch_no].wc_target.rs_length =
+ ntohl(ary->wc_array[ch_no].wc_target.rs_length);
+ va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
+ xdr_decode_hyper(va, &ch_offset);
+ put_unaligned(ch_offset, (u64 *)va);
+ }
+
+ /*
+ * rs_length is the 2nd 4B field in wc_target and taking its
+ * address skips the list terminator
+ */
+ return (u32 *)&ary->wc_array[ch_no].wc_target.rs_length;
+}
+
+static u32 *decode_reply_array(u32 *va, u32 *vaend)
+{
+ int ch_no;
+ struct rpcrdma_write_array *ary =
+ (struct rpcrdma_write_array *)va;
+
+ /* Check for no reply-array */
+ if (ary->wc_discrim == xdr_zero)
+ return (u32 *)&ary->wc_nchunks;
+
+ if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
+ (unsigned long)vaend) {
+ dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
+ return NULL;
+ }
+ ary->wc_discrim = ntohl(ary->wc_discrim);
+ ary->wc_nchunks = ntohl(ary->wc_nchunks);
+ if (((unsigned long)&ary->wc_array[0] +
+ (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+ (unsigned long)vaend) {
+ dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
+ ary, ary->wc_nchunks, vaend);
+ return NULL;
+ }
+ for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
+ u64 ch_offset;
+
+ ary->wc_array[ch_no].wc_target.rs_handle =
+ ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
+ ary->wc_array[ch_no].wc_target.rs_length =
+ ntohl(ary->wc_array[ch_no].wc_target.rs_length);
+ va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
+ xdr_decode_hyper(va, &ch_offset);
+ put_unaligned(ch_offset, (u64 *)va);
+ }
+
+ return (u32 *)&ary->wc_array[ch_no];
+}
+
+int svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req,
+ struct svc_rqst *rqstp)
+{
+ struct rpcrdma_msg *rmsgp = NULL;
+ u32 *va;
+ u32 *vaend;
+ u32 hdr_len;
+
+ rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
+
+ /* Verify that there's enough bytes for header + something */
+ if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_MIN) {
+ dprintk("svcrdma: header too short = %d\n",
+ rqstp->rq_arg.len);
+ return -EINVAL;
+ }
+
+ /* Decode the header */
+ rmsgp->rm_xid = ntohl(rmsgp->rm_xid);
+ rmsgp->rm_vers = ntohl(rmsgp->rm_vers);
+ rmsgp->rm_credit = ntohl(rmsgp->rm_credit);
+ rmsgp->rm_type = ntohl(rmsgp->rm_type);
+
+ if (rmsgp->rm_vers != RPCRDMA_VERSION)
+ return -ENOSYS;
+
+ /* Pull in the extra for the padded case and bump our pointer */
+ if (rmsgp->rm_type == RDMA_MSGP) {
+ int hdrlen;
+ rmsgp->rm_body.rm_padded.rm_align =
+ ntohl(rmsgp->rm_body.rm_padded.rm_align);
+ rmsgp->rm_body.rm_padded.rm_thresh =
+ ntohl(rmsgp->rm_body.rm_padded.rm_thresh);
+
+ va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
+ rqstp->rq_arg.head[0].iov_base = va;
+ hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
+ rqstp->rq_arg.head[0].iov_len -= hdrlen;
+ if (hdrlen > rqstp->rq_arg.len)
+ return -EINVAL;
+ return hdrlen;
+ }
+
+ /* The chunk list may contain either a read chunk list or a write
+ * chunk list and a reply chunk list.
+ */
+ va = &rmsgp->rm_body.rm_chunks[0];
+ vaend = (u32 *)((unsigned long)rmsgp + rqstp->rq_arg.len);
+ va = decode_read_list(va, vaend);
+ if (!va)
+ return -EINVAL;
+ va = decode_write_list(va, vaend);
+ if (!va)
+ return -EINVAL;
+ va = decode_reply_array(va, vaend);
+ if (!va)
+ return -EINVAL;
+
+ rqstp->rq_arg.head[0].iov_base = va;
+ hdr_len = (unsigned long)va - (unsigned long)rmsgp;
+ rqstp->rq_arg.head[0].iov_len -= hdr_len;
+
+ *rdma_req = rmsgp;
+ return hdr_len;
+}
+
+int svc_rdma_xdr_decode_deferred_req(struct svc_rqst *rqstp)
+{
+ struct rpcrdma_msg *rmsgp = NULL;
+ struct rpcrdma_read_chunk *ch;
+ struct rpcrdma_write_array *ary;
+ u32 *va;
+ u32 hdrlen;
+
+ dprintk("svcrdma: processing deferred RDMA header on rqstp=%p\n",
+ rqstp);
+ rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
+
+ /* Pull in the extra for the padded case and bump our pointer */
+ if (rmsgp->rm_type == RDMA_MSGP) {
+ va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
+ rqstp->rq_arg.head[0].iov_base = va;
+ hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
+ rqstp->rq_arg.head[0].iov_len -= hdrlen;
+ return hdrlen;
+ }
+
+ /*
+ * Skip all chunks to find RPC msg. These were previously processed
+ */
+ va = &rmsgp->rm_body.rm_chunks[0];
+
+ /* Skip read-list */
+ for (ch = (struct rpcrdma_read_chunk *)va;
+ ch->rc_discrim != xdr_zero; ch++);
+ va = (u32 *)&ch->rc_position;
+
+ /* Skip write-list */
+ ary = (struct rpcrdma_write_array *)va;
+ if (ary->wc_discrim == xdr_zero)
+ va = (u32 *)&ary->wc_nchunks;
+ else
+ /*
+ * rs_length is the 2nd 4B field in wc_target and taking its
+ * address skips the list terminator
+ */
+ va = (u32 *)&ary->wc_array[ary->wc_nchunks].wc_target.rs_length;
+
+ /* Skip reply-array */
+ ary = (struct rpcrdma_write_array *)va;
+ if (ary->wc_discrim == xdr_zero)
+ va = (u32 *)&ary->wc_nchunks;
+ else
+ va = (u32 *)&ary->wc_array[ary->wc_nchunks];
+
+ rqstp->rq_arg.head[0].iov_base = va;
+ hdrlen = (unsigned long)va - (unsigned long)rmsgp;
+ rqstp->rq_arg.head[0].iov_len -= hdrlen;
+
+ return hdrlen;
+}
+
+int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,
+ struct rpcrdma_msg *rmsgp,
+ enum rpcrdma_errcode err, u32 *va)
+{
+ u32 *startp = va;
+
+ *va++ = htonl(rmsgp->rm_xid);
+ *va++ = htonl(rmsgp->rm_vers);
+ *va++ = htonl(xprt->sc_max_requests);
+ *va++ = htonl(RDMA_ERROR);
+ *va++ = htonl(err);
+ if (err == ERR_VERS) {
+ *va++ = htonl(RPCRDMA_VERSION);
+ *va++ = htonl(RPCRDMA_VERSION);
+ }
+
+ return (int)((unsigned long)va - (unsigned long)startp);
+}
+
+int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *rmsgp)
+{
+ struct rpcrdma_write_array *wr_ary;
+
+ /* There is no read-list in a reply */
+
+ /* skip write list */
+ wr_ary = (struct rpcrdma_write_array *)
+ &rmsgp->rm_body.rm_chunks[1];
+ if (wr_ary->wc_discrim)
+ wr_ary = (struct rpcrdma_write_array *)
+ &wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)].
+ wc_target.rs_length;
+ else
+ wr_ary = (struct rpcrdma_write_array *)
+ &wr_ary->wc_nchunks;
+
+ /* skip reply array */
+ if (wr_ary->wc_discrim)
+ wr_ary = (struct rpcrdma_write_array *)
+ &wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)];
+ else
+ wr_ary = (struct rpcrdma_write_array *)
+ &wr_ary->wc_nchunks;
+
+ return (unsigned long) wr_ary - (unsigned long) rmsgp;
+}
+
+void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *rmsgp, int chunks)
+{
+ struct rpcrdma_write_array *ary;
+
+ /* no read-list */
+ rmsgp->rm_body.rm_chunks[0] = xdr_zero;
+
+ /* write-array discrim */
+ ary = (struct rpcrdma_write_array *)
+ &rmsgp->rm_body.rm_chunks[1];
+ ary->wc_discrim = xdr_one;
+ ary->wc_nchunks = htonl(chunks);
+
+ /* write-list terminator */
+ ary->wc_array[chunks].wc_target.rs_handle = xdr_zero;
+
+ /* reply-array discriminator */
+ ary->wc_array[chunks].wc_target.rs_length = xdr_zero;
+}
+
+void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary,
+ int chunks)
+{
+ ary->wc_discrim = xdr_one;
+ ary->wc_nchunks = htonl(chunks);
+}
+
+void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
+ int chunk_no,
+ u32 rs_handle, u64 rs_offset,
+ u32 write_len)
+{
+ struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
+ seg->rs_handle = htonl(rs_handle);
+ seg->rs_length = htonl(write_len);
+ xdr_encode_hyper((u32 *) &seg->rs_offset, rs_offset);
+}
+
+void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
+ struct rpcrdma_msg *rdma_argp,
+ struct rpcrdma_msg *rdma_resp,
+ enum rpcrdma_proc rdma_type)
+{
+ rdma_resp->rm_xid = htonl(rdma_argp->rm_xid);
+ rdma_resp->rm_vers = htonl(rdma_argp->rm_vers);
+ rdma_resp->rm_credit = htonl(xprt->sc_max_requests);
+ rdma_resp->rm_type = htonl(rdma_type);
+
+ /* Encode <nul> chunks lists */
+ rdma_resp->rm_body.rm_chunks[0] = xdr_zero;
+ rdma_resp->rm_body.rm_chunks[1] = xdr_zero;
+ rdma_resp->rm_body.rm_chunks[2] = xdr_zero;
+}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
new file mode 100644
index 0000000..ab54a73
--- /dev/null
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
+
+/*
+ * Replace the pages in the rq_argpages array with the pages from the SGE in
+ * the RDMA_RECV completion. The SGL should contain full pages up until the
+ * last one.
+ */
+static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
+ struct svc_rdma_op_ctxt *ctxt,
+ u32 byte_count)
+{
+ struct page *page;
+ u32 bc;
+ int sge_no;
+
+ /* Swap the page in the SGE with the page in argpages */
+ page = ctxt->pages[0];
+ put_page(rqstp->rq_pages[0]);
+ rqstp->rq_pages[0] = page;
+
+ /* Set up the XDR head */
+ rqstp->rq_arg.head[0].iov_base = page_address(page);
+ rqstp->rq_arg.head[0].iov_len = min(byte_count, ctxt->sge[0].length);
+ rqstp->rq_arg.len = byte_count;
+ rqstp->rq_arg.buflen = byte_count;
+
+ /* Compute bytes past head in the SGL */
+ bc = byte_count - rqstp->rq_arg.head[0].iov_len;
+
+ /* If data remains, store it in the pagelist */
+ rqstp->rq_arg.page_len = bc;
+ rqstp->rq_arg.page_base = 0;
+ rqstp->rq_arg.pages = &rqstp->rq_pages[1];
+ sge_no = 1;
+ while (bc && sge_no < ctxt->count) {
+ page = ctxt->pages[sge_no];
+ put_page(rqstp->rq_pages[sge_no]);
+ rqstp->rq_pages[sge_no] = page;
+ bc -= min(bc, ctxt->sge[sge_no].length);
+ rqstp->rq_arg.buflen += ctxt->sge[sge_no].length;
+ sge_no++;
+ }
+ rqstp->rq_respages = &rqstp->rq_pages[sge_no];
+
+ /* We should never run out of SGE because the limit is defined to
+ * support the max allowed RPC data length
+ */
+ BUG_ON(bc && (sge_no == ctxt->count));
+ BUG_ON((rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len)
+ != byte_count);
+ BUG_ON(rqstp->rq_arg.len != byte_count);
+
+ /* If not all pages were used from the SGL, free the remaining ones */
+ bc = sge_no;
+ while (sge_no < ctxt->count) {
+ page = ctxt->pages[sge_no++];
+ put_page(page);
+ }
+ ctxt->count = bc;
+
+ /* Set up tail */
+ rqstp->rq_arg.tail[0].iov_base = NULL;
+ rqstp->rq_arg.tail[0].iov_len = 0;
+}
+
+struct chunk_sge {
+ int start; /* sge no for this chunk */
+ int count; /* sge count for this chunk */
+};
+
+/* Encode a read-chunk-list as an array of IB SGE
+ *
+ * Assumptions:
+ * - chunk[0]->position points to pages[0] at an offset of 0
+ * - pages[] is not physically or virtually contigous and consists of
+ * PAGE_SIZE elements.
+ *
+ * Output:
+ * - sge array pointing into pages[] array.
+ * - chunk_sge array specifying sge index and count for each
+ * chunk in the read list
+ *
+ */
+static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
+ struct svc_rqst *rqstp,
+ struct svc_rdma_op_ctxt *head,
+ struct rpcrdma_msg *rmsgp,
+ struct ib_sge *sge,
+ struct chunk_sge *ch_sge_ary,
+ int ch_count,
+ int byte_count)
+{
+ int sge_no;
+ int sge_bytes;
+ int page_off;
+ int page_no;
+ int ch_bytes;
+ int ch_no;
+ struct rpcrdma_read_chunk *ch;
+
+ sge_no = 0;
+ page_no = 0;
+ page_off = 0;
+ ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+ ch_no = 0;
+ ch_bytes = ch->rc_target.rs_length;
+ head->arg.head[0] = rqstp->rq_arg.head[0];
+ head->arg.tail[0] = rqstp->rq_arg.tail[0];
+ head->arg.pages = &head->pages[head->count];
+ head->sge[0].length = head->count; /* save count of hdr pages */
+ head->arg.page_base = 0;
+ head->arg.page_len = ch_bytes;
+ head->arg.len = rqstp->rq_arg.len + ch_bytes;
+ head->arg.buflen = rqstp->rq_arg.buflen + ch_bytes;
+ head->count++;
+ ch_sge_ary[0].start = 0;
+ while (byte_count) {
+ sge_bytes = min_t(int, PAGE_SIZE-page_off, ch_bytes);
+ sge[sge_no].addr =
+ ib_dma_map_page(xprt->sc_cm_id->device,
+ rqstp->rq_arg.pages[page_no],
+ page_off, sge_bytes,
+ DMA_FROM_DEVICE);
+ sge[sge_no].length = sge_bytes;
+ sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ /*
+ * Don't bump head->count here because the same page
+ * may be used by multiple SGE.
+ */
+ head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
+ rqstp->rq_respages = &rqstp->rq_arg.pages[page_no+1];
+
+ byte_count -= sge_bytes;
+ ch_bytes -= sge_bytes;
+ sge_no++;
+ /*
+ * If all bytes for this chunk have been mapped to an
+ * SGE, move to the next SGE
+ */
+ if (ch_bytes == 0) {
+ ch_sge_ary[ch_no].count =
+ sge_no - ch_sge_ary[ch_no].start;
+ ch_no++;
+ ch++;
+ ch_sge_ary[ch_no].start = sge_no;
+ ch_bytes = ch->rc_target.rs_length;
+ /* If bytes remaining account for next chunk */
+ if (byte_count) {
+ head->arg.page_len += ch_bytes;
+ head->arg.len += ch_bytes;
+ head->arg.buflen += ch_bytes;
+ }
+ }
+ /*
+ * If this SGE consumed all of the page, move to the
+ * next page
+ */
+ if ((sge_bytes + page_off) == PAGE_SIZE) {
+ page_no++;
+ page_off = 0;
+ /*
+ * If there are still bytes left to map, bump
+ * the page count
+ */
+ if (byte_count)
+ head->count++;
+ } else
+ page_off += sge_bytes;
+ }
+ BUG_ON(byte_count != 0);
+ return sge_no;
+}
+
+static void rdma_set_ctxt_sge(struct svc_rdma_op_ctxt *ctxt,
+ struct ib_sge *sge,
+ u64 *sgl_offset,
+ int count)
+{
+ int i;
+
+ ctxt->count = count;
+ for (i = 0; i < count; i++) {
+ ctxt->sge[i].addr = sge[i].addr;
+ ctxt->sge[i].length = sge[i].length;
+ *sgl_offset = *sgl_offset + sge[i].length;
+ }
+}
+
+static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
+{
+#ifdef RDMA_TRANSPORT_IWARP
+ if ((RDMA_TRANSPORT_IWARP ==
+ rdma_node_get_transport(xprt->sc_cm_id->
+ device->node_type))
+ && sge_count > 1)
+ return 1;
+ else
+#endif
+ return min_t(int, sge_count, xprt->sc_max_sge);
+}
+
+/*
+ * Use RDMA_READ to read data from the advertised client buffer into the
+ * XDR stream starting at rq_arg.head[0].iov_base.
+ * Each chunk in the array
+ * contains the following fields:
+ * discrim - '1', This isn't used for data placement
+ * position - The xdr stream offset (the same for every chunk)
+ * handle - RMR for client memory region
+ * length - data transfer length
+ * offset - 64 bit tagged offset in remote memory region
+ *
+ * On our side, we need to read into a pagelist. The first page immediately
+ * follows the RPC header.
+ *
+ * This function returns 1 to indicate success. The data is not yet in
+ * the pagelist and therefore the RPC request must be deferred. The
+ * I/O completion will enqueue the transport again and
+ * svc_rdma_recvfrom will complete the request.
+ *
+ * NOTE: The ctxt must not be touched after the last WR has been posted
+ * because the I/O completion processing may occur on another
+ * processor and free / modify the context. Ne touche pas!
+ */
+static int rdma_read_xdr(struct svcxprt_rdma *xprt,
+ struct rpcrdma_msg *rmsgp,
+ struct svc_rqst *rqstp,
+ struct svc_rdma_op_ctxt *hdr_ctxt)
+{
+ struct ib_send_wr read_wr;
+ int err = 0;
+ int ch_no;
+ struct ib_sge *sge;
+ int ch_count;
+ int byte_count;
+ int sge_count;
+ u64 sgl_offset;
+ struct rpcrdma_read_chunk *ch;
+ struct svc_rdma_op_ctxt *ctxt = NULL;
+ struct svc_rdma_op_ctxt *head;
+ struct svc_rdma_op_ctxt *tmp_sge_ctxt;
+ struct svc_rdma_op_ctxt *tmp_ch_ctxt;
+ struct chunk_sge *ch_sge_ary;
+
+ /* If no read list is present, return 0 */
+ ch = svc_rdma_get_read_chunk(rmsgp);
+ if (!ch)
+ return 0;
+
+ /* Allocate temporary contexts to keep SGE */
+ BUG_ON(sizeof(struct ib_sge) < sizeof(struct chunk_sge));
+ tmp_sge_ctxt = svc_rdma_get_context(xprt);
+ sge = tmp_sge_ctxt->sge;
+ tmp_ch_ctxt = svc_rdma_get_context(xprt);
+ ch_sge_ary = (struct chunk_sge *)tmp_ch_ctxt->sge;
+
+ svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
+ sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
+ sge, ch_sge_ary,
+ ch_count, byte_count);
+ head = svc_rdma_get_context(xprt);
+ sgl_offset = 0;
+ ch_no = 0;
+
+ for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+ ch->rc_discrim != 0; ch++, ch_no++) {
+next_sge:
+ if (!ctxt)
+ ctxt = head;
+ else {
+ ctxt->next = svc_rdma_get_context(xprt);
+ ctxt = ctxt->next;
+ }
+ ctxt->next = NULL;
+ ctxt->direction = DMA_FROM_DEVICE;
+ clear_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
+ clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+ if ((ch+1)->rc_discrim == 0) {
+ /*
+ * Checked in sq_cq_reap to see if we need to
+ * be enqueued
+ */
+ set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+ ctxt->next = hdr_ctxt;
+ hdr_ctxt->next = head;
+ }
+
+ /* Prepare READ WR */
+ memset(&read_wr, 0, sizeof read_wr);
+ ctxt->wr_op = IB_WR_RDMA_READ;
+ read_wr.wr_id = (unsigned long)ctxt;
+ read_wr.opcode = IB_WR_RDMA_READ;
+ read_wr.send_flags = IB_SEND_SIGNALED;
+ read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
+ read_wr.wr.rdma.remote_addr =
+ get_unaligned(&(ch->rc_target.rs_offset)) +
+ sgl_offset;
+ read_wr.sg_list = &sge[ch_sge_ary[ch_no].start];
+ read_wr.num_sge =
+ rdma_read_max_sge(xprt, ch_sge_ary[ch_no].count);
+ rdma_set_ctxt_sge(ctxt, &sge[ch_sge_ary[ch_no].start],
+ &sgl_offset,
+ read_wr.num_sge);
+
+ /* Post the read */
+ err = svc_rdma_send(xprt, &read_wr);
+ if (err) {
+ printk(KERN_ERR "svcrdma: Error posting send = %d\n",
+ err);
+ /*
+ * Break the circular list so free knows when
+ * to stop if the error happened to occur on
+ * the last read
+ */
+ ctxt->next = NULL;
+ goto out;
+ }
+ atomic_inc(&rdma_stat_read);
+
+ if (read_wr.num_sge < ch_sge_ary[ch_no].count) {
+ ch_sge_ary[ch_no].count -= read_wr.num_sge;
+ ch_sge_ary[ch_no].start += read_wr.num_sge;
+ goto next_sge;
+ }
+ sgl_offset = 0;
+ err = 0;
+ }
+
+ out:
+ svc_rdma_put_context(tmp_sge_ctxt, 0);
+ svc_rdma_put_context(tmp_ch_ctxt, 0);
+
+ /* Detach arg pages. svc_recv will replenish them */
+ for (ch_no = 0; &rqstp->rq_pages[ch_no] < rqstp->rq_respages; ch_no++)
+ rqstp->rq_pages[ch_no] = NULL;
+
+ /*
+ * Detach res pages. svc_release must see a resused count of
+ * zero or it will attempt to put them.
+ */
+ while (rqstp->rq_resused)
+ rqstp->rq_respages[--rqstp->rq_resused] = NULL;
+
+ if (err) {
+ printk(KERN_ERR "svcrdma : RDMA_READ error = %d\n", err);
+ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+ /* Free the linked list of read contexts */
+ while (head != NULL) {
+ ctxt = head->next;
+ svc_rdma_put_context(head, 1);
+ head = ctxt;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+static int rdma_read_complete(struct svc_rqst *rqstp,
+ struct svc_rdma_op_ctxt *data)
+{
+ struct svc_rdma_op_ctxt *head = data->next;
+ int page_no;
+ int ret;
+
+ BUG_ON(!head);
+
+ /* Copy RPC pages */
+ for (page_no = 0; page_no < head->count; page_no++) {
+ put_page(rqstp->rq_pages[page_no]);
+ rqstp->rq_pages[page_no] = head->pages[page_no];
+ }
+ /* Point rq_arg.pages past header */
+ rqstp->rq_arg.pages = &rqstp->rq_pages[head->sge[0].length];
+ rqstp->rq_arg.page_len = head->arg.page_len;
+ rqstp->rq_arg.page_base = head->arg.page_base;
+
+ /* rq_respages starts after the last arg page */
+ rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
+ rqstp->rq_resused = 0;
+
+ /* Rebuild rq_arg head and tail. */
+ rqstp->rq_arg.head[0] = head->arg.head[0];
+ rqstp->rq_arg.tail[0] = head->arg.tail[0];
+ rqstp->rq_arg.len = head->arg.len;
+ rqstp->rq_arg.buflen = head->arg.buflen;
+
+ /* XXX: What should this be? */
+ rqstp->rq_prot = IPPROTO_MAX;
+
+ /*
+ * Free the contexts we used to build the RDMA_READ. We have
+ * to be careful here because the context list uses the same
+ * next pointer used to chain the contexts associated with the
+ * RDMA_READ
+ */
+ data->next = NULL; /* terminate circular list */
+ do {
+ data = head->next;
+ svc_rdma_put_context(head, 0);
+ head = data;
+ } while (head != NULL);
+
+ ret = rqstp->rq_arg.head[0].iov_len
+ + rqstp->rq_arg.page_len
+ + rqstp->rq_arg.tail[0].iov_len;
+ dprintk("svcrdma: deferred read ret=%d, rq_arg.len =%d, "
+ "rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len = %zd\n",
+ ret, rqstp->rq_arg.len, rqstp->rq_arg.head[0].iov_base,
+ rqstp->rq_arg.head[0].iov_len);
+
+ /* Indicate that we've consumed an RQ credit */
+ rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+ svc_xprt_received(rqstp->rq_xprt);
+ return ret;
+}
+
+/*
+ * Set up the rqstp thread context to point to the RQ buffer. If
+ * necessary, pull additional data from the client with an RDMA_READ
+ * request.
+ */
+int svc_rdma_recvfrom(struct svc_rqst *rqstp)
+{
+ struct svc_xprt *xprt = rqstp->rq_xprt;
+ struct svcxprt_rdma *rdma_xprt =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ struct svc_rdma_op_ctxt *ctxt = NULL;
+ struct rpcrdma_msg *rmsgp;
+ int ret = 0;
+ int len;
+
+ dprintk("svcrdma: rqstp=%p\n", rqstp);
+
+ /*
+ * The rq_xprt_ctxt indicates if we've consumed an RQ credit
+ * or not. It is used in the rdma xpo_release_rqst function to
+ * determine whether or not to return an RQ WQE to the RQ.
+ */
+ rqstp->rq_xprt_ctxt = NULL;
+
+ spin_lock_bh(&rdma_xprt->sc_read_complete_lock);
+ if (!list_empty(&rdma_xprt->sc_read_complete_q)) {
+ ctxt = list_entry(rdma_xprt->sc_read_complete_q.next,
+ struct svc_rdma_op_ctxt,
+ dto_q);
+ list_del_init(&ctxt->dto_q);
+ }
+ spin_unlock_bh(&rdma_xprt->sc_read_complete_lock);
+ if (ctxt)
+ return rdma_read_complete(rqstp, ctxt);
+
+ spin_lock_bh(&rdma_xprt->sc_rq_dto_lock);
+ if (!list_empty(&rdma_xprt->sc_rq_dto_q)) {
+ ctxt = list_entry(rdma_xprt->sc_rq_dto_q.next,
+ struct svc_rdma_op_ctxt,
+ dto_q);
+ list_del_init(&ctxt->dto_q);
+ } else {
+ atomic_inc(&rdma_stat_rq_starve);
+ clear_bit(XPT_DATA, &xprt->xpt_flags);
+ ctxt = NULL;
+ }
+ spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock);
+ if (!ctxt) {
+ /* This is the EAGAIN path. The svc_recv routine will
+ * return -EAGAIN, the nfsd thread will go to call into
+ * svc_recv again and we shouldn't be on the active
+ * transport list
+ */
+ if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
+ goto close_out;
+
+ BUG_ON(ret);
+ goto out;
+ }
+ dprintk("svcrdma: processing ctxt=%p on xprt=%p, rqstp=%p, status=%d\n",
+ ctxt, rdma_xprt, rqstp, ctxt->wc_status);
+ BUG_ON(ctxt->wc_status != IB_WC_SUCCESS);
+ atomic_inc(&rdma_stat_recv);
+
+ /* Build up the XDR from the receive buffers. */
+ rdma_build_arg_xdr(rqstp, ctxt, ctxt->byte_len);
+
+ /* Decode the RDMA header. */
+ len = svc_rdma_xdr_decode_req(&rmsgp, rqstp);
+ rqstp->rq_xprt_hlen = len;
+
+ /* If the request is invalid, reply with an error */
+ if (len < 0) {
+ if (len == -ENOSYS)
+ (void)svc_rdma_send_error(rdma_xprt, rmsgp, ERR_VERS);
+ goto close_out;
+ }
+
+ /* Read read-list data. If we would need to wait, defer
+ * it. Not that in this case, we don't return the RQ credit
+ * until after the read completes.
+ */
+ if (rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt)) {
+ svc_xprt_received(xprt);
+ return 0;
+ }
+
+ /* Indicate we've consumed an RQ credit */
+ rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+
+ ret = rqstp->rq_arg.head[0].iov_len
+ + rqstp->rq_arg.page_len
+ + rqstp->rq_arg.tail[0].iov_len;
+ svc_rdma_put_context(ctxt, 0);
+ out:
+ dprintk("svcrdma: ret = %d, rq_arg.len =%d, "
+ "rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len = %zd\n",
+ ret, rqstp->rq_arg.len,
+ rqstp->rq_arg.head[0].iov_base,
+ rqstp->rq_arg.head[0].iov_len);
+ rqstp->rq_prot = IPPROTO_MAX;
+ svc_xprt_copy_addrs(rqstp, xprt);
+ svc_xprt_received(xprt);
+ return ret;
+
+ close_out:
+ if (ctxt) {
+ svc_rdma_put_context(ctxt, 1);
+ /* Indicate we've consumed an RQ credit */
+ rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+ }
+ dprintk("svcrdma: transport %p is closing\n", xprt);
+ /*
+ * Set the close bit and enqueue it. svc_recv will see the
+ * close bit and call svc_xprt_delete
+ */
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ svc_xprt_received(xprt);
+ return 0;
+}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
new file mode 100644
index 0000000..3e32194
--- /dev/null
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
+
+/* Encode an XDR as an array of IB SGE
+ *
+ * Assumptions:
+ * - head[0] is physically contiguous.
+ * - tail[0] is physically contiguous.
+ * - pages[] is not physically or virtually contigous and consists of
+ * PAGE_SIZE elements.
+ *
+ * Output:
+ * SGE[0] reserved for RCPRDMA header
+ * SGE[1] data from xdr->head[]
+ * SGE[2..sge_count-2] data from xdr->pages[]
+ * SGE[sge_count-1] data from xdr->tail.
+ *
+ */
+static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
+ struct xdr_buf *xdr,
+ struct ib_sge *sge,
+ int *sge_count)
+{
+ /* Max we need is the length of the XDR / pagesize + one for
+ * head + one for tail + one for RPCRDMA header
+ */
+ int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
+ int sge_no;
+ u32 byte_count = xdr->len;
+ u32 sge_bytes;
+ u32 page_bytes;
+ int page_off;
+ int page_no;
+
+ /* Skip the first sge, this is for the RPCRDMA header */
+ sge_no = 1;
+
+ /* Head SGE */
+ sge[sge_no].addr = ib_dma_map_single(xprt->sc_cm_id->device,
+ xdr->head[0].iov_base,
+ xdr->head[0].iov_len,
+ DMA_TO_DEVICE);
+ sge_bytes = min_t(u32, byte_count, xdr->head[0].iov_len);
+ byte_count -= sge_bytes;
+ sge[sge_no].length = sge_bytes;
+ sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ sge_no++;
+
+ /* pages SGE */
+ page_no = 0;
+ page_bytes = xdr->page_len;
+ page_off = xdr->page_base;
+ while (byte_count && page_bytes) {
+ sge_bytes = min_t(u32, byte_count, (PAGE_SIZE-page_off));
+ sge[sge_no].addr =
+ ib_dma_map_page(xprt->sc_cm_id->device,
+ xdr->pages[page_no], page_off,
+ sge_bytes, DMA_TO_DEVICE);
+ sge_bytes = min(sge_bytes, page_bytes);
+ byte_count -= sge_bytes;
+ page_bytes -= sge_bytes;
+ sge[sge_no].length = sge_bytes;
+ sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+
+ sge_no++;
+ page_no++;
+ page_off = 0; /* reset for next time through loop */
+ }
+
+ /* Tail SGE */
+ if (byte_count && xdr->tail[0].iov_len) {
+ sge[sge_no].addr =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ xdr->tail[0].iov_base,
+ xdr->tail[0].iov_len,
+ DMA_TO_DEVICE);
+ sge_bytes = min_t(u32, byte_count, xdr->tail[0].iov_len);
+ byte_count -= sge_bytes;
+ sge[sge_no].length = sge_bytes;
+ sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ sge_no++;
+ }
+
+ BUG_ON(sge_no > sge_max);
+ BUG_ON(byte_count != 0);
+
+ *sge_count = sge_no;
+ return sge;
+}
+
+
+/* Assumptions:
+ * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
+ */
+static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
+ u32 rmr, u64 to,
+ u32 xdr_off, int write_len,
+ struct ib_sge *xdr_sge, int sge_count)
+{
+ struct svc_rdma_op_ctxt *tmp_sge_ctxt;
+ struct ib_send_wr write_wr;
+ struct ib_sge *sge;
+ int xdr_sge_no;
+ int sge_no;
+ int sge_bytes;
+ int sge_off;
+ int bc;
+ struct svc_rdma_op_ctxt *ctxt;
+ int ret = 0;
+
+ BUG_ON(sge_count >= 32);
+ dprintk("svcrdma: RDMA_WRITE rmr=%x, to=%llx, xdr_off=%d, "
+ "write_len=%d, xdr_sge=%p, sge_count=%d\n",
+ rmr, to, xdr_off, write_len, xdr_sge, sge_count);
+
+ ctxt = svc_rdma_get_context(xprt);
+ ctxt->count = 0;
+ tmp_sge_ctxt = svc_rdma_get_context(xprt);
+ sge = tmp_sge_ctxt->sge;
+
+ /* Find the SGE associated with xdr_off */
+ for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < sge_count;
+ xdr_sge_no++) {
+ if (xdr_sge[xdr_sge_no].length > bc)
+ break;
+ bc -= xdr_sge[xdr_sge_no].length;
+ }
+
+ sge_off = bc;
+ bc = write_len;
+ sge_no = 0;
+
+ /* Copy the remaining SGE */
+ while (bc != 0 && xdr_sge_no < sge_count) {
+ sge[sge_no].addr = xdr_sge[xdr_sge_no].addr + sge_off;
+ sge[sge_no].lkey = xdr_sge[xdr_sge_no].lkey;
+ sge_bytes = min((size_t)bc,
+ (size_t)(xdr_sge[xdr_sge_no].length-sge_off));
+ sge[sge_no].length = sge_bytes;
+
+ sge_off = 0;
+ sge_no++;
+ xdr_sge_no++;
+ bc -= sge_bytes;
+ }
+
+ BUG_ON(bc != 0);
+ BUG_ON(xdr_sge_no > sge_count);
+
+ /* Prepare WRITE WR */
+ memset(&write_wr, 0, sizeof write_wr);
+ ctxt->wr_op = IB_WR_RDMA_WRITE;
+ write_wr.wr_id = (unsigned long)ctxt;
+ write_wr.sg_list = &sge[0];
+ write_wr.num_sge = sge_no;
+ write_wr.opcode = IB_WR_RDMA_WRITE;
+ write_wr.send_flags = IB_SEND_SIGNALED;
+ write_wr.wr.rdma.rkey = rmr;
+ write_wr.wr.rdma.remote_addr = to;
+
+ /* Post It */
+ atomic_inc(&rdma_stat_write);
+ if (svc_rdma_send(xprt, &write_wr)) {
+ svc_rdma_put_context(ctxt, 1);
+ /* Fatal error, close transport */
+ ret = -EIO;
+ }
+ svc_rdma_put_context(tmp_sge_ctxt, 0);
+ return ret;
+}
+
+static int send_write_chunks(struct svcxprt_rdma *xprt,
+ struct rpcrdma_msg *rdma_argp,
+ struct rpcrdma_msg *rdma_resp,
+ struct svc_rqst *rqstp,
+ struct ib_sge *sge,
+ int sge_count)
+{
+ u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
+ int write_len;
+ int max_write;
+ u32 xdr_off;
+ int chunk_off;
+ int chunk_no;
+ struct rpcrdma_write_array *arg_ary;
+ struct rpcrdma_write_array *res_ary;
+ int ret;
+
+ arg_ary = svc_rdma_get_write_array(rdma_argp);
+ if (!arg_ary)
+ return 0;
+ res_ary = (struct rpcrdma_write_array *)
+ &rdma_resp->rm_body.rm_chunks[1];
+
+ max_write = xprt->sc_max_sge * PAGE_SIZE;
+
+ /* Write chunks start at the pagelist */
+ for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
+ xfer_len && chunk_no < arg_ary->wc_nchunks;
+ chunk_no++) {
+ struct rpcrdma_segment *arg_ch;
+ u64 rs_offset;
+
+ arg_ch = &arg_ary->wc_array[chunk_no].wc_target;
+ write_len = min(xfer_len, arg_ch->rs_length);
+
+ /* Prepare the response chunk given the length actually
+ * written */
+ rs_offset = get_unaligned(&(arg_ch->rs_offset));
+ svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
+ arg_ch->rs_handle,
+ rs_offset,
+ write_len);
+ chunk_off = 0;
+ while (write_len) {
+ int this_write;
+ this_write = min(write_len, max_write);
+ ret = send_write(xprt, rqstp,
+ arg_ch->rs_handle,
+ rs_offset + chunk_off,
+ xdr_off,
+ this_write,
+ sge,
+ sge_count);
+ if (ret) {
+ dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
+ ret);
+ return -EIO;
+ }
+ chunk_off += this_write;
+ xdr_off += this_write;
+ xfer_len -= this_write;
+ write_len -= this_write;
+ }
+ }
+ /* Update the req with the number of chunks actually used */
+ svc_rdma_xdr_encode_write_list(rdma_resp, chunk_no);
+
+ return rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
+}
+
+static int send_reply_chunks(struct svcxprt_rdma *xprt,
+ struct rpcrdma_msg *rdma_argp,
+ struct rpcrdma_msg *rdma_resp,
+ struct svc_rqst *rqstp,
+ struct ib_sge *sge,
+ int sge_count)
+{
+ u32 xfer_len = rqstp->rq_res.len;
+ int write_len;
+ int max_write;
+ u32 xdr_off;
+ int chunk_no;
+ int chunk_off;
+ struct rpcrdma_segment *ch;
+ struct rpcrdma_write_array *arg_ary;
+ struct rpcrdma_write_array *res_ary;
+ int ret;
+
+ arg_ary = svc_rdma_get_reply_array(rdma_argp);
+ if (!arg_ary)
+ return 0;
+ /* XXX: need to fix when reply lists occur with read-list and or
+ * write-list */
+ res_ary = (struct rpcrdma_write_array *)
+ &rdma_resp->rm_body.rm_chunks[2];
+
+ max_write = xprt->sc_max_sge * PAGE_SIZE;
+
+ /* xdr offset starts at RPC message */
+ for (xdr_off = 0, chunk_no = 0;
+ xfer_len && chunk_no < arg_ary->wc_nchunks;
+ chunk_no++) {
+ u64 rs_offset;
+ ch = &arg_ary->wc_array[chunk_no].wc_target;
+ write_len = min(xfer_len, ch->rs_length);
+
+
+ /* Prepare the reply chunk given the length actually
+ * written */
+ rs_offset = get_unaligned(&(ch->rs_offset));
+ svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
+ ch->rs_handle, rs_offset,
+ write_len);
+ chunk_off = 0;
+ while (write_len) {
+ int this_write;
+
+ this_write = min(write_len, max_write);
+ ret = send_write(xprt, rqstp,
+ ch->rs_handle,
+ rs_offset + chunk_off,
+ xdr_off,
+ this_write,
+ sge,
+ sge_count);
+ if (ret) {
+ dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
+ ret);
+ return -EIO;
+ }
+ chunk_off += this_write;
+ xdr_off += this_write;
+ xfer_len -= this_write;
+ write_len -= this_write;
+ }
+ }
+ /* Update the req with the number of chunks actually used */
+ svc_rdma_xdr_encode_reply_array(res_ary, chunk_no);
+
+ return rqstp->rq_res.len;
+}
+
+/* This function prepares the portion of the RPCRDMA message to be
+ * sent in the RDMA_SEND. This function is called after data sent via
+ * RDMA has already been transmitted. There are three cases:
+ * - The RPCRDMA header, RPC header, and payload are all sent in a
+ * single RDMA_SEND. This is the "inline" case.
+ * - The RPCRDMA header and some portion of the RPC header and data
+ * are sent via this RDMA_SEND and another portion of the data is
+ * sent via RDMA.
+ * - The RPCRDMA header [NOMSG] is sent in this RDMA_SEND and the RPC
+ * header and data are all transmitted via RDMA.
+ * In all three cases, this function prepares the RPCRDMA header in
+ * sge[0], the 'type' parameter indicates the type to place in the
+ * RPCRDMA header, and the 'byte_count' field indicates how much of
+ * the XDR to include in this RDMA_SEND.
+ */
+static int send_reply(struct svcxprt_rdma *rdma,
+ struct svc_rqst *rqstp,
+ struct page *page,
+ struct rpcrdma_msg *rdma_resp,
+ struct svc_rdma_op_ctxt *ctxt,
+ int sge_count,
+ int byte_count)
+{
+ struct ib_send_wr send_wr;
+ int sge_no;
+ int sge_bytes;
+ int page_no;
+ int ret;
+
+ /* Prepare the context */
+ ctxt->pages[0] = page;
+ ctxt->count = 1;
+
+ /* Prepare the SGE for the RPCRDMA Header */
+ ctxt->sge[0].addr =
+ ib_dma_map_page(rdma->sc_cm_id->device,
+ page, 0, PAGE_SIZE, DMA_TO_DEVICE);
+ ctxt->direction = DMA_TO_DEVICE;
+ ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
+ ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
+
+ /* Determine how many of our SGE are to be transmitted */
+ for (sge_no = 1; byte_count && sge_no < sge_count; sge_no++) {
+ sge_bytes = min((size_t)ctxt->sge[sge_no].length,
+ (size_t)byte_count);
+ byte_count -= sge_bytes;
+ }
+ BUG_ON(byte_count != 0);
+
+ /* Save all respages in the ctxt and remove them from the
+ * respages array. They are our pages until the I/O
+ * completes.
+ */
+ for (page_no = 0; page_no < rqstp->rq_resused; page_no++) {
+ ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
+ ctxt->count++;
+ rqstp->rq_respages[page_no] = NULL;
+ }
+
+ BUG_ON(sge_no > rdma->sc_max_sge);
+ memset(&send_wr, 0, sizeof send_wr);
+ ctxt->wr_op = IB_WR_SEND;
+ send_wr.wr_id = (unsigned long)ctxt;
+ send_wr.sg_list = ctxt->sge;
+ send_wr.num_sge = sge_no;
+ send_wr.opcode = IB_WR_SEND;
+ send_wr.send_flags = IB_SEND_SIGNALED;
+
+ ret = svc_rdma_send(rdma, &send_wr);
+ if (ret)
+ svc_rdma_put_context(ctxt, 1);
+
+ return ret;
+}
+
+void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
+{
+}
+
+/*
+ * Return the start of an xdr buffer.
+ */
+static void *xdr_start(struct xdr_buf *xdr)
+{
+ return xdr->head[0].iov_base -
+ (xdr->len -
+ xdr->page_len -
+ xdr->tail[0].iov_len -
+ xdr->head[0].iov_len);
+}
+
+int svc_rdma_sendto(struct svc_rqst *rqstp)
+{
+ struct svc_xprt *xprt = rqstp->rq_xprt;
+ struct svcxprt_rdma *rdma =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ struct rpcrdma_msg *rdma_argp;
+ struct rpcrdma_msg *rdma_resp;
+ struct rpcrdma_write_array *reply_ary;
+ enum rpcrdma_proc reply_type;
+ int ret;
+ int inline_bytes;
+ struct ib_sge *sge;
+ int sge_count = 0;
+ struct page *res_page;
+ struct svc_rdma_op_ctxt *ctxt;
+
+ dprintk("svcrdma: sending response for rqstp=%p\n", rqstp);
+
+ /* Get the RDMA request header. */
+ rdma_argp = xdr_start(&rqstp->rq_arg);
+
+ /* Build an SGE for the XDR */
+ ctxt = svc_rdma_get_context(rdma);
+ ctxt->direction = DMA_TO_DEVICE;
+ sge = xdr_to_sge(rdma, &rqstp->rq_res, ctxt->sge, &sge_count);
+
+ inline_bytes = rqstp->rq_res.len;
+
+ /* Create the RDMA response header */
+ res_page = svc_rdma_get_page();
+ rdma_resp = page_address(res_page);
+ reply_ary = svc_rdma_get_reply_array(rdma_argp);
+ if (reply_ary)
+ reply_type = RDMA_NOMSG;
+ else
+ reply_type = RDMA_MSG;
+ svc_rdma_xdr_encode_reply_header(rdma, rdma_argp,
+ rdma_resp, reply_type);
+
+ /* Send any write-chunk data and build resp write-list */
+ ret = send_write_chunks(rdma, rdma_argp, rdma_resp,
+ rqstp, sge, sge_count);
+ if (ret < 0) {
+ printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
+ ret);
+ goto error;
+ }
+ inline_bytes -= ret;
+
+ /* Send any reply-list data and update resp reply-list */
+ ret = send_reply_chunks(rdma, rdma_argp, rdma_resp,
+ rqstp, sge, sge_count);
+ if (ret < 0) {
+ printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
+ ret);
+ goto error;
+ }
+ inline_bytes -= ret;
+
+ ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, sge_count,
+ inline_bytes);
+ dprintk("svcrdma: send_reply returns %d\n", ret);
+ return ret;
+ error:
+ svc_rdma_put_context(ctxt, 0);
+ put_page(res_page);
+ return ret;
+}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
new file mode 100644
index 0000000..f09444c
--- /dev/null
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (c) 2005-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Neither the name of the Network Appliance, Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/svc_xprt.h>
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/spinlock.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY RPCDBG_SVCXPRT
+
+static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+ struct sockaddr *sa, int salen,
+ int flags);
+static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt);
+static void svc_rdma_release_rqst(struct svc_rqst *);
+static void rdma_destroy_xprt(struct svcxprt_rdma *xprt);
+static void dto_tasklet_func(unsigned long data);
+static void svc_rdma_detach(struct svc_xprt *xprt);
+static void svc_rdma_free(struct svc_xprt *xprt);
+static int svc_rdma_has_wspace(struct svc_xprt *xprt);
+static void rq_cq_reap(struct svcxprt_rdma *xprt);
+static void sq_cq_reap(struct svcxprt_rdma *xprt);
+
+DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL);
+static DEFINE_SPINLOCK(dto_lock);
+static LIST_HEAD(dto_xprt_q);
+
+static struct svc_xprt_ops svc_rdma_ops = {
+ .xpo_create = svc_rdma_create,
+ .xpo_recvfrom = svc_rdma_recvfrom,
+ .xpo_sendto = svc_rdma_sendto,
+ .xpo_release_rqst = svc_rdma_release_rqst,
+ .xpo_detach = svc_rdma_detach,
+ .xpo_free = svc_rdma_free,
+ .xpo_prep_reply_hdr = svc_rdma_prep_reply_hdr,
+ .xpo_has_wspace = svc_rdma_has_wspace,
+ .xpo_accept = svc_rdma_accept,
+};
+
+struct svc_xprt_class svc_rdma_class = {
+ .xcl_name = "rdma",
+ .xcl_owner = THIS_MODULE,
+ .xcl_ops = &svc_rdma_ops,
+ .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
+};
+
+static int rdma_bump_context_cache(struct svcxprt_rdma *xprt)
+{
+ int target;
+ int at_least_one = 0;
+ struct svc_rdma_op_ctxt *ctxt;
+
+ target = min(xprt->sc_ctxt_cnt + xprt->sc_ctxt_bump,
+ xprt->sc_ctxt_max);
+
+ spin_lock_bh(&xprt->sc_ctxt_lock);
+ while (xprt->sc_ctxt_cnt < target) {
+ xprt->sc_ctxt_cnt++;
+ spin_unlock_bh(&xprt->sc_ctxt_lock);
+
+ ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
+
+ spin_lock_bh(&xprt->sc_ctxt_lock);
+ if (ctxt) {
+ at_least_one = 1;
+ ctxt->next = xprt->sc_ctxt_head;
+ xprt->sc_ctxt_head = ctxt;
+ } else {
+ /* kmalloc failed...give up for now */
+ xprt->sc_ctxt_cnt--;
+ break;
+ }
+ }
+ spin_unlock_bh(&xprt->sc_ctxt_lock);
+ dprintk("svcrdma: sc_ctxt_max=%d, sc_ctxt_cnt=%d\n",
+ xprt->sc_ctxt_max, xprt->sc_ctxt_cnt);
+ return at_least_one;
+}
+
+struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
+{
+ struct svc_rdma_op_ctxt *ctxt;
+
+ while (1) {
+ spin_lock_bh(&xprt->sc_ctxt_lock);
+ if (unlikely(xprt->sc_ctxt_head == NULL)) {
+ /* Try to bump my cache. */
+ spin_unlock_bh(&xprt->sc_ctxt_lock);
+
+ if (rdma_bump_context_cache(xprt))
+ continue;
+
+ printk(KERN_INFO "svcrdma: sleeping waiting for "
+ "context memory on xprt=%p\n",
+ xprt);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+ continue;
+ }
+ ctxt = xprt->sc_ctxt_head;
+ xprt->sc_ctxt_head = ctxt->next;
+ spin_unlock_bh(&xprt->sc_ctxt_lock);
+ ctxt->xprt = xprt;
+ INIT_LIST_HEAD(&ctxt->dto_q);
+ ctxt->count = 0;
+ break;
+ }
+ return ctxt;
+}
+
+void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
+{
+ struct svcxprt_rdma *xprt;
+ int i;
+
+ BUG_ON(!ctxt);
+ xprt = ctxt->xprt;
+ if (free_pages)
+ for (i = 0; i < ctxt->count; i++)
+ put_page(ctxt->pages[i]);
+
+ for (i = 0; i < ctxt->count; i++)
+ dma_unmap_single(xprt->sc_cm_id->device->dma_device,
+ ctxt->sge[i].addr,
+ ctxt->sge[i].length,
+ ctxt->direction);
+ spin_lock_bh(&xprt->sc_ctxt_lock);
+ ctxt->next = xprt->sc_ctxt_head;
+ xprt->sc_ctxt_head = ctxt;
+ spin_unlock_bh(&xprt->sc_ctxt_lock);
+}
+
+/* ib_cq event handler */
+static void cq_event_handler(struct ib_event *event, void *context)
+{
+ struct svc_xprt *xprt = context;
+ dprintk("svcrdma: received CQ event id=%d, context=%p\n",
+ event->event, context);
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+}
+
+/* QP event handler */
+static void qp_event_handler(struct ib_event *event, void *context)
+{
+ struct svc_xprt *xprt = context;
+
+ switch (event->event) {
+ /* These are considered benign events */
+ case IB_EVENT_PATH_MIG:
+ case IB_EVENT_COMM_EST:
+ case IB_EVENT_SQ_DRAINED:
+ case IB_EVENT_QP_LAST_WQE_REACHED:
+ dprintk("svcrdma: QP event %d received for QP=%p\n",
+ event->event, event->element.qp);
+ break;
+ /* These are considered fatal events */
+ case IB_EVENT_PATH_MIG_ERR:
+ case IB_EVENT_QP_FATAL:
+ case IB_EVENT_QP_REQ_ERR:
+ case IB_EVENT_QP_ACCESS_ERR:
+ case IB_EVENT_DEVICE_FATAL:
+ default:
+ dprintk("svcrdma: QP ERROR event %d received for QP=%p, "
+ "closing transport\n",
+ event->event, event->element.qp);
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ break;
+ }
+}
+
+/*
+ * Data Transfer Operation Tasklet
+ *
+ * Walks a list of transports with I/O pending, removing entries as
+ * they are added to the server's I/O pending list. Two bits indicate
+ * if SQ, RQ, or both have I/O pending. The dto_lock is an irqsave
+ * spinlock that serializes access to the transport list with the RQ
+ * and SQ interrupt handlers.
+ */
+static void dto_tasklet_func(unsigned long data)
+{
+ struct svcxprt_rdma *xprt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dto_lock, flags);
+ while (!list_empty(&dto_xprt_q)) {
+ xprt = list_entry(dto_xprt_q.next,
+ struct svcxprt_rdma, sc_dto_q);
+ list_del_init(&xprt->sc_dto_q);
+ spin_unlock_irqrestore(&dto_lock, flags);
+
+ if (test_and_clear_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags)) {
+ ib_req_notify_cq(xprt->sc_rq_cq, IB_CQ_NEXT_COMP);
+ rq_cq_reap(xprt);
+ set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+ /*
+ * If data arrived before established event,
+ * don't enqueue. This defers RPC I/O until the
+ * RDMA connection is complete.
+ */
+ if (!test_bit(RDMAXPRT_CONN_PENDING, &xprt->sc_flags))
+ svc_xprt_enqueue(&xprt->sc_xprt);
+ }
+
+ if (test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags)) {
+ ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
+ sq_cq_reap(xprt);
+ }
+
+ spin_lock_irqsave(&dto_lock, flags);
+ }
+ spin_unlock_irqrestore(&dto_lock, flags);
+}
+
+/*
+ * Receive Queue Completion Handler
+ *
+ * Since an RQ completion handler is called on interrupt context, we
+ * need to defer the handling of the I/O to a tasklet
+ */
+static void rq_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+ struct svcxprt_rdma *xprt = cq_context;
+ unsigned long flags;
+
+ /*
+ * Set the bit regardless of whether or not it's on the list
+ * because it may be on the list already due to an SQ
+ * completion.
+ */
+ set_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags);
+
+ /*
+ * If this transport is not already on the DTO transport queue,
+ * add it
+ */
+ spin_lock_irqsave(&dto_lock, flags);
+ if (list_empty(&xprt->sc_dto_q))
+ list_add_tail(&xprt->sc_dto_q, &dto_xprt_q);
+ spin_unlock_irqrestore(&dto_lock, flags);
+
+ /* Tasklet does all the work to avoid irqsave locks. */
+ tasklet_schedule(&dto_tasklet);
+}
+
+/*
+ * rq_cq_reap - Process the RQ CQ.
+ *
+ * Take all completing WC off the CQE and enqueue the associated DTO
+ * context on the dto_q for the transport.
+ */
+static void rq_cq_reap(struct svcxprt_rdma *xprt)
+{
+ int ret;
+ struct ib_wc wc;
+ struct svc_rdma_op_ctxt *ctxt = NULL;
+
+ atomic_inc(&rdma_stat_rq_poll);
+
+ spin_lock_bh(&xprt->sc_rq_dto_lock);
+ while ((ret = ib_poll_cq(xprt->sc_rq_cq, 1, &wc)) > 0) {
+ ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+ ctxt->wc_status = wc.status;
+ ctxt->byte_len = wc.byte_len;
+ if (wc.status != IB_WC_SUCCESS) {
+ /* Close the transport */
+ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+ svc_rdma_put_context(ctxt, 1);
+ continue;
+ }
+ list_add_tail(&ctxt->dto_q, &xprt->sc_rq_dto_q);
+ }
+ spin_unlock_bh(&xprt->sc_rq_dto_lock);
+
+ if (ctxt)
+ atomic_inc(&rdma_stat_rq_prod);
+}
+
+/*
+ * Send Queue Completion Handler - potentially called on interrupt context.
+ */
+static void sq_cq_reap(struct svcxprt_rdma *xprt)
+{
+ struct svc_rdma_op_ctxt *ctxt = NULL;
+ struct ib_wc wc;
+ struct ib_cq *cq = xprt->sc_sq_cq;
+ int ret;
+
+ atomic_inc(&rdma_stat_sq_poll);
+ while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
+ ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+ xprt = ctxt->xprt;
+
+ if (wc.status != IB_WC_SUCCESS)
+ /* Close the transport */
+ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+
+ /* Decrement used SQ WR count */
+ atomic_dec(&xprt->sc_sq_count);
+ wake_up(&xprt->sc_send_wait);
+
+ switch (ctxt->wr_op) {
+ case IB_WR_SEND:
+ case IB_WR_RDMA_WRITE:
+ svc_rdma_put_context(ctxt, 1);
+ break;
+
+ case IB_WR_RDMA_READ:
+ if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
+ set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+ set_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
+ spin_lock_bh(&xprt->sc_read_complete_lock);
+ list_add_tail(&ctxt->dto_q,
+ &xprt->sc_read_complete_q);
+ spin_unlock_bh(&xprt->sc_read_complete_lock);
+ svc_xprt_enqueue(&xprt->sc_xprt);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "svcrdma: unexpected completion type, "
+ "opcode=%d, status=%d\n",
+ wc.opcode, wc.status);
+ break;
+ }
+ }
+
+ if (ctxt)
+ atomic_inc(&rdma_stat_sq_prod);
+}
+
+static void sq_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+ struct svcxprt_rdma *xprt = cq_context;
+ unsigned long flags;
+
+ /*
+ * Set the bit regardless of whether or not it's on the list
+ * because it may be on the list already due to an RQ
+ * completion.
+ */
+ set_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags);
+
+ /*
+ * If this transport is not already on the DTO transport queue,
+ * add it
+ */
+ spin_lock_irqsave(&dto_lock, flags);
+ if (list_empty(&xprt->sc_dto_q))
+ list_add_tail(&xprt->sc_dto_q, &dto_xprt_q);
+ spin_unlock_irqrestore(&dto_lock, flags);
+
+ /* Tasklet does all the work to avoid irqsave locks. */
+ tasklet_schedule(&dto_tasklet);
+}
+
+static void create_context_cache(struct svcxprt_rdma *xprt,
+ int ctxt_count, int ctxt_bump, int ctxt_max)
+{
+ struct svc_rdma_op_ctxt *ctxt;
+ int i;
+
+ xprt->sc_ctxt_max = ctxt_max;
+ xprt->sc_ctxt_bump = ctxt_bump;
+ xprt->sc_ctxt_cnt = 0;
+ xprt->sc_ctxt_head = NULL;
+ for (i = 0; i < ctxt_count; i++) {
+ ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
+ if (ctxt) {
+ ctxt->next = xprt->sc_ctxt_head;
+ xprt->sc_ctxt_head = ctxt;
+ xprt->sc_ctxt_cnt++;
+ }
+ }
+}
+
+static void destroy_context_cache(struct svc_rdma_op_ctxt *ctxt)
+{
+ struct svc_rdma_op_ctxt *next;
+ if (!ctxt)
+ return;
+
+ do {
+ next = ctxt->next;
+ kfree(ctxt);
+ ctxt = next;
+ } while (next);
+}
+
+static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
+ int listener)
+{
+ struct svcxprt_rdma *cma_xprt = kzalloc(sizeof *cma_xprt, GFP_KERNEL);
+
+ if (!cma_xprt)
+ return NULL;
+ svc_xprt_init(&svc_rdma_class, &cma_xprt->sc_xprt, serv);
+ INIT_LIST_HEAD(&cma_xprt->sc_accept_q);
+ INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
+ INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
+ INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
+ init_waitqueue_head(&cma_xprt->sc_send_wait);
+
+ spin_lock_init(&cma_xprt->sc_lock);
+ spin_lock_init(&cma_xprt->sc_read_complete_lock);
+ spin_lock_init(&cma_xprt->sc_ctxt_lock);
+ spin_lock_init(&cma_xprt->sc_rq_dto_lock);
+
+ cma_xprt->sc_ord = svcrdma_ord;
+
+ cma_xprt->sc_max_req_size = svcrdma_max_req_size;
+ cma_xprt->sc_max_requests = svcrdma_max_requests;
+ cma_xprt->sc_sq_depth = svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT;
+ atomic_set(&cma_xprt->sc_sq_count, 0);
+
+ if (!listener) {
+ int reqs = cma_xprt->sc_max_requests;
+ create_context_cache(cma_xprt,
+ reqs << 1, /* starting size */
+ reqs, /* bump amount */
+ reqs +
+ cma_xprt->sc_sq_depth +
+ RPCRDMA_MAX_THREADS + 1); /* max */
+ if (!cma_xprt->sc_ctxt_head) {
+ kfree(cma_xprt);
+ return NULL;
+ }
+ clear_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
+ } else
+ set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
+
+ return cma_xprt;
+}
+
+struct page *svc_rdma_get_page(void)
+{
+ struct page *page;
+
+ while ((page = alloc_page(GFP_KERNEL)) == NULL) {
+ /* If we can't get memory, wait a bit and try again */
+ printk(KERN_INFO "svcrdma: out of memory...retrying in 1000 "
+ "jiffies.\n");
+ schedule_timeout_uninterruptible(msecs_to_jiffies(1000));
+ }
+ return page;
+}
+
+int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
+{
+ struct ib_recv_wr recv_wr, *bad_recv_wr;
+ struct svc_rdma_op_ctxt *ctxt;
+ struct page *page;
+ unsigned long pa;
+ int sge_no;
+ int buflen;
+ int ret;
+
+ ctxt = svc_rdma_get_context(xprt);
+ buflen = 0;
+ ctxt->direction = DMA_FROM_DEVICE;
+ for (sge_no = 0; buflen < xprt->sc_max_req_size; sge_no++) {
+ BUG_ON(sge_no >= xprt->sc_max_sge);
+ page = svc_rdma_get_page();
+ ctxt->pages[sge_no] = page;
+ pa = ib_dma_map_page(xprt->sc_cm_id->device,
+ page, 0, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ ctxt->sge[sge_no].addr = pa;
+ ctxt->sge[sge_no].length = PAGE_SIZE;
+ ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ buflen += PAGE_SIZE;
+ }
+ ctxt->count = sge_no;
+ recv_wr.next = NULL;
+ recv_wr.sg_list = &ctxt->sge[0];
+ recv_wr.num_sge = ctxt->count;
+ recv_wr.wr_id = (u64)(unsigned long)ctxt;
+
+ ret = ib_post_recv(xprt->sc_qp, &recv_wr, &bad_recv_wr);
+ return ret;
+}
+
+/*
+ * This function handles the CONNECT_REQUEST event on a listening
+ * endpoint. It is passed the cma_id for the _new_ connection. The context in
+ * this cma_id is inherited from the listening cma_id and is the svc_xprt
+ * structure for the listening endpoint.
+ *
+ * This function creates a new xprt for the new connection and enqueues it on
+ * the accept queue for the listent xprt. When the listen thread is kicked, it
+ * will call the recvfrom method on the listen xprt which will accept the new
+ * connection.
+ */
+static void handle_connect_req(struct rdma_cm_id *new_cma_id)
+{
+ struct svcxprt_rdma *listen_xprt = new_cma_id->context;
+ struct svcxprt_rdma *newxprt;
+
+ /* Create a new transport */
+ newxprt = rdma_create_xprt(listen_xprt->sc_xprt.xpt_server, 0);
+ if (!newxprt) {
+ dprintk("svcrdma: failed to create new transport\n");
+ return;
+ }
+ newxprt->sc_cm_id = new_cma_id;
+ new_cma_id->context = newxprt;
+ dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n",
+ newxprt, newxprt->sc_cm_id, listen_xprt);
+
+ /*
+ * Enqueue the new transport on the accept queue of the listening
+ * transport
+ */
+ spin_lock_bh(&listen_xprt->sc_lock);
+ list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q);
+ spin_unlock_bh(&listen_xprt->sc_lock);
+
+ /*
+ * Can't use svc_xprt_received here because we are not on a
+ * rqstp thread
+ */
+ set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags);
+ svc_xprt_enqueue(&listen_xprt->sc_xprt);
+}
+
+/*
+ * Handles events generated on the listening endpoint. These events will be
+ * either be incoming connect requests or adapter removal events.
+ */
+static int rdma_listen_handler(struct rdma_cm_id *cma_id,
+ struct rdma_cm_event *event)
+{
+ struct svcxprt_rdma *xprt = cma_id->context;
+ int ret = 0;
+
+ switch (event->event) {
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
+ "event=%d\n", cma_id, cma_id->context, event->event);
+ handle_connect_req(cma_id);
+ break;
+
+ case RDMA_CM_EVENT_ESTABLISHED:
+ /* Accept complete */
+ dprintk("svcrdma: Connection completed on LISTEN xprt=%p, "
+ "cm_id=%p\n", xprt, cma_id);
+ break;
+
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ dprintk("svcrdma: Device removal xprt=%p, cm_id=%p\n",
+ xprt, cma_id);
+ if (xprt)
+ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+ break;
+
+ default:
+ dprintk("svcrdma: Unexpected event on listening endpoint %p, "
+ "event=%d\n", cma_id, event->event);
+ break;
+ }
+
+ return ret;
+}
+
+static int rdma_cma_handler(struct rdma_cm_id *cma_id,
+ struct rdma_cm_event *event)
+{
+ struct svc_xprt *xprt = cma_id->context;
+ struct svcxprt_rdma *rdma =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ switch (event->event) {
+ case RDMA_CM_EVENT_ESTABLISHED:
+ /* Accept complete */
+ dprintk("svcrdma: Connection completed on DTO xprt=%p, "
+ "cm_id=%p\n", xprt, cma_id);
+ clear_bit(RDMAXPRT_CONN_PENDING, &rdma->sc_flags);
+ svc_xprt_enqueue(xprt);
+ break;
+ case RDMA_CM_EVENT_DISCONNECTED:
+ dprintk("svcrdma: Disconnect on DTO xprt=%p, cm_id=%p\n",
+ xprt, cma_id);
+ if (xprt) {
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ svc_xprt_enqueue(xprt);
+ }
+ break;
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ dprintk("svcrdma: Device removal cma_id=%p, xprt = %p, "
+ "event=%d\n", cma_id, xprt, event->event);
+ if (xprt) {
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ svc_xprt_enqueue(xprt);
+ }
+ break;
+ default:
+ dprintk("svcrdma: Unexpected event on DTO endpoint %p, "
+ "event=%d\n", cma_id, event->event);
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Create a listening RDMA service endpoint.
+ */
+static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+ struct sockaddr *sa, int salen,
+ int flags)
+{
+ struct rdma_cm_id *listen_id;
+ struct svcxprt_rdma *cma_xprt;
+ struct svc_xprt *xprt;
+ int ret;
+
+ dprintk("svcrdma: Creating RDMA socket\n");
+
+ cma_xprt = rdma_create_xprt(serv, 1);
+ if (!cma_xprt)
+ return ERR_PTR(ENOMEM);
+ xprt = &cma_xprt->sc_xprt;
+
+ listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP);
+ if (IS_ERR(listen_id)) {
+ rdma_destroy_xprt(cma_xprt);
+ dprintk("svcrdma: rdma_create_id failed = %ld\n",
+ PTR_ERR(listen_id));
+ return (void *)listen_id;
+ }
+ ret = rdma_bind_addr(listen_id, sa);
+ if (ret) {
+ rdma_destroy_xprt(cma_xprt);
+ rdma_destroy_id(listen_id);
+ dprintk("svcrdma: rdma_bind_addr failed = %d\n", ret);
+ return ERR_PTR(ret);
+ }
+ cma_xprt->sc_cm_id = listen_id;
+
+ ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
+ if (ret) {
+ rdma_destroy_id(listen_id);
+ rdma_destroy_xprt(cma_xprt);
+ dprintk("svcrdma: rdma_listen failed = %d\n", ret);
+ }
+
+ /*
+ * We need to use the address from the cm_id in case the
+ * caller specified 0 for the port number.
+ */
+ sa = (struct sockaddr *)&cma_xprt->sc_cm_id->route.addr.src_addr;
+ svc_xprt_set_local(&cma_xprt->sc_xprt, sa, salen);
+
+ return &cma_xprt->sc_xprt;
+}
+
+/*
+ * This is the xpo_recvfrom function for listening endpoints. Its
+ * purpose is to accept incoming connections. The CMA callback handler
+ * has already created a new transport and attached it to the new CMA
+ * ID.
+ *
+ * There is a queue of pending connections hung on the listening
+ * transport. This queue contains the new svc_xprt structure. This
+ * function takes svc_xprt structures off the accept_q and completes
+ * the connection.
+ */
+static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
+{
+ struct svcxprt_rdma *listen_rdma;
+ struct svcxprt_rdma *newxprt = NULL;
+ struct rdma_conn_param conn_param;
+ struct ib_qp_init_attr qp_attr;
+ struct ib_device_attr devattr;
+ struct sockaddr *sa;
+ int ret;
+ int i;
+
+ listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ clear_bit(XPT_CONN, &xprt->xpt_flags);
+ /* Get the next entry off the accept list */
+ spin_lock_bh(&listen_rdma->sc_lock);
+ if (!list_empty(&listen_rdma->sc_accept_q)) {
+ newxprt = list_entry(listen_rdma->sc_accept_q.next,
+ struct svcxprt_rdma, sc_accept_q);
+ list_del_init(&newxprt->sc_accept_q);
+ }
+ if (!list_empty(&listen_rdma->sc_accept_q))
+ set_bit(XPT_CONN, &listen_rdma->sc_xprt.xpt_flags);
+ spin_unlock_bh(&listen_rdma->sc_lock);
+ if (!newxprt)
+ return NULL;
+
+ dprintk("svcrdma: newxprt from accept queue = %p, cm_id=%p\n",
+ newxprt, newxprt->sc_cm_id);
+
+ ret = ib_query_device(newxprt->sc_cm_id->device, &devattr);
+ if (ret) {
+ dprintk("svcrdma: could not query device attributes on "
+ "device %p, rc=%d\n", newxprt->sc_cm_id->device, ret);
+ goto errout;
+ }
+
+ /* Qualify the transport resource defaults with the
+ * capabilities of this particular device */
+ newxprt->sc_max_sge = min((size_t)devattr.max_sge,
+ (size_t)RPCSVC_MAXPAGES);
+ newxprt->sc_max_requests = min((size_t)devattr.max_qp_wr,
+ (size_t)svcrdma_max_requests);
+ newxprt->sc_sq_depth = RPCRDMA_SQ_DEPTH_MULT * newxprt->sc_max_requests;
+
+ newxprt->sc_ord = min((size_t)devattr.max_qp_rd_atom,
+ (size_t)svcrdma_ord);
+
+ newxprt->sc_pd = ib_alloc_pd(newxprt->sc_cm_id->device);
+ if (IS_ERR(newxprt->sc_pd)) {
+ dprintk("svcrdma: error creating PD for connect request\n");
+ goto errout;
+ }
+ newxprt->sc_sq_cq = ib_create_cq(newxprt->sc_cm_id->device,
+ sq_comp_handler,
+ cq_event_handler,
+ newxprt,
+ newxprt->sc_sq_depth,
+ 0);
+ if (IS_ERR(newxprt->sc_sq_cq)) {
+ dprintk("svcrdma: error creating SQ CQ for connect request\n");
+ goto errout;
+ }
+ newxprt->sc_rq_cq = ib_create_cq(newxprt->sc_cm_id->device,
+ rq_comp_handler,
+ cq_event_handler,
+ newxprt,
+ newxprt->sc_max_requests,
+ 0);
+ if (IS_ERR(newxprt->sc_rq_cq)) {
+ dprintk("svcrdma: error creating RQ CQ for connect request\n");
+ goto errout;
+ }
+
+ memset(&qp_attr, 0, sizeof qp_attr);
+ qp_attr.event_handler = qp_event_handler;
+ qp_attr.qp_context = &newxprt->sc_xprt;
+ qp_attr.cap.max_send_wr = newxprt->sc_sq_depth;
+ qp_attr.cap.max_recv_wr = newxprt->sc_max_requests;
+ qp_attr.cap.max_send_sge = newxprt->sc_max_sge;
+ qp_attr.cap.max_recv_sge = newxprt->sc_max_sge;
+ qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+ qp_attr.qp_type = IB_QPT_RC;
+ qp_attr.send_cq = newxprt->sc_sq_cq;
+ qp_attr.recv_cq = newxprt->sc_rq_cq;
+ dprintk("svcrdma: newxprt->sc_cm_id=%p, newxprt->sc_pd=%p\n"
+ " cm_id->device=%p, sc_pd->device=%p\n"
+ " cap.max_send_wr = %d\n"
+ " cap.max_recv_wr = %d\n"
+ " cap.max_send_sge = %d\n"
+ " cap.max_recv_sge = %d\n",
+ newxprt->sc_cm_id, newxprt->sc_pd,
+ newxprt->sc_cm_id->device, newxprt->sc_pd->device,
+ qp_attr.cap.max_send_wr,
+ qp_attr.cap.max_recv_wr,
+ qp_attr.cap.max_send_sge,
+ qp_attr.cap.max_recv_sge);
+
+ ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd, &qp_attr);
+ if (ret) {
+ /*
+ * XXX: This is a hack. We need a xx_request_qp interface
+ * that will adjust the qp_attr's with a best-effort
+ * number
+ */
+ qp_attr.cap.max_send_sge -= 2;
+ qp_attr.cap.max_recv_sge -= 2;
+ ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd,
+ &qp_attr);
+ if (ret) {
+ dprintk("svcrdma: failed to create QP, ret=%d\n", ret);
+ goto errout;
+ }
+ newxprt->sc_max_sge = qp_attr.cap.max_send_sge;
+ newxprt->sc_max_sge = qp_attr.cap.max_recv_sge;
+ newxprt->sc_sq_depth = qp_attr.cap.max_send_wr;
+ newxprt->sc_max_requests = qp_attr.cap.max_recv_wr;
+ }
+ newxprt->sc_qp = newxprt->sc_cm_id->qp;
+
+ /* Register all of physical memory */
+ newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
+ IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE);
+ if (IS_ERR(newxprt->sc_phys_mr)) {
+ dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
+ goto errout;
+ }
+
+ /* Post receive buffers */
+ for (i = 0; i < newxprt->sc_max_requests; i++) {
+ ret = svc_rdma_post_recv(newxprt);
+ if (ret) {
+ dprintk("svcrdma: failure posting receive buffers\n");
+ goto errout;
+ }
+ }
+
+ /* Swap out the handler */
+ newxprt->sc_cm_id->event_handler = rdma_cma_handler;
+
+ /* Accept Connection */
+ set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
+ memset(&conn_param, 0, sizeof conn_param);
+ conn_param.responder_resources = 0;
+ conn_param.initiator_depth = newxprt->sc_ord;
+ ret = rdma_accept(newxprt->sc_cm_id, &conn_param);
+ if (ret) {
+ dprintk("svcrdma: failed to accept new connection, ret=%d\n",
+ ret);
+ goto errout;
+ }
+
+ dprintk("svcrdma: new connection %p accepted with the following "
+ "attributes:\n"
+ " local_ip : %d.%d.%d.%d\n"
+ " local_port : %d\n"
+ " remote_ip : %d.%d.%d.%d\n"
+ " remote_port : %d\n"
+ " max_sge : %d\n"
+ " sq_depth : %d\n"
+ " max_requests : %d\n"
+ " ord : %d\n",
+ newxprt,
+ NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
+ route.addr.src_addr)->sin_addr.s_addr),
+ ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
+ route.addr.src_addr)->sin_port),
+ NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
+ route.addr.dst_addr)->sin_addr.s_addr),
+ ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
+ route.addr.dst_addr)->sin_port),
+ newxprt->sc_max_sge,
+ newxprt->sc_sq_depth,
+ newxprt->sc_max_requests,
+ newxprt->sc_ord);
+
+ /* Set the local and remote addresses in the transport */
+ sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
+ svc_xprt_set_remote(&newxprt->sc_xprt, sa, svc_addr_len(sa));
+ sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
+ svc_xprt_set_local(&newxprt->sc_xprt, sa, svc_addr_len(sa));
+
+ ib_req_notify_cq(newxprt->sc_sq_cq, IB_CQ_NEXT_COMP);
+ ib_req_notify_cq(newxprt->sc_rq_cq, IB_CQ_NEXT_COMP);
+ return &newxprt->sc_xprt;
+
+ errout:
+ dprintk("svcrdma: failure accepting new connection rc=%d.\n", ret);
+ rdma_destroy_id(newxprt->sc_cm_id);
+ rdma_destroy_xprt(newxprt);
+ return NULL;
+}
+
+/*
+ * Post an RQ WQE to the RQ when the rqst is being released. This
+ * effectively returns an RQ credit to the client. The rq_xprt_ctxt
+ * will be null if the request is deferred due to an RDMA_READ or the
+ * transport had no data ready (EAGAIN). Note that an RPC deferred in
+ * svc_process will still return the credit, this is because the data
+ * is copied and no longer consume a WQE/WC.
+ */
+static void svc_rdma_release_rqst(struct svc_rqst *rqstp)
+{
+ int err;
+ struct svcxprt_rdma *rdma =
+ container_of(rqstp->rq_xprt, struct svcxprt_rdma, sc_xprt);
+ if (rqstp->rq_xprt_ctxt) {
+ BUG_ON(rqstp->rq_xprt_ctxt != rdma);
+ err = svc_rdma_post_recv(rdma);
+ if (err)
+ dprintk("svcrdma: failed to post an RQ WQE error=%d\n",
+ err);
+ }
+ rqstp->rq_xprt_ctxt = NULL;
+}
+
+/* Disable data ready events for this connection */
+static void svc_rdma_detach(struct svc_xprt *xprt)
+{
+ struct svcxprt_rdma *rdma =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ unsigned long flags;
+
+ dprintk("svc: svc_rdma_detach(%p)\n", xprt);
+ /*
+ * Shutdown the connection. This will ensure we don't get any
+ * more events from the provider.
+ */
+ rdma_disconnect(rdma->sc_cm_id);
+ rdma_destroy_id(rdma->sc_cm_id);
+
+ /* We may already be on the DTO list */
+ spin_lock_irqsave(&dto_lock, flags);
+ if (!list_empty(&rdma->sc_dto_q))
+ list_del_init(&rdma->sc_dto_q);
+ spin_unlock_irqrestore(&dto_lock, flags);
+}
+
+static void svc_rdma_free(struct svc_xprt *xprt)
+{
+ struct svcxprt_rdma *rdma = (struct svcxprt_rdma *)xprt;
+ dprintk("svcrdma: svc_rdma_free(%p)\n", rdma);
+ rdma_destroy_xprt(rdma);
+ kfree(rdma);
+}
+
+static void rdma_destroy_xprt(struct svcxprt_rdma *xprt)
+{
+ if (xprt->sc_qp && !IS_ERR(xprt->sc_qp))
+ ib_destroy_qp(xprt->sc_qp);
+
+ if (xprt->sc_sq_cq && !IS_ERR(xprt->sc_sq_cq))
+ ib_destroy_cq(xprt->sc_sq_cq);
+
+ if (xprt->sc_rq_cq && !IS_ERR(xprt->sc_rq_cq))
+ ib_destroy_cq(xprt->sc_rq_cq);
+
+ if (xprt->sc_phys_mr && !IS_ERR(xprt->sc_phys_mr))
+ ib_dereg_mr(xprt->sc_phys_mr);
+
+ if (xprt->sc_pd && !IS_ERR(xprt->sc_pd))
+ ib_dealloc_pd(xprt->sc_pd);
+
+ destroy_context_cache(xprt->sc_ctxt_head);
+}
+
+static int svc_rdma_has_wspace(struct svc_xprt *xprt)
+{
+ struct svcxprt_rdma *rdma =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
+
+ /*
+ * If there are fewer SQ WR available than required to send a
+ * simple response, return false.
+ */
+ if ((rdma->sc_sq_depth - atomic_read(&rdma->sc_sq_count) < 3))
+ return 0;
+
+ /*
+ * ...or there are already waiters on the SQ,
+ * return false.
+ */
+ if (waitqueue_active(&rdma->sc_send_wait))
+ return 0;
+
+ /* Otherwise return true. */
+ return 1;
+}
+
+int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
+{
+ struct ib_send_wr *bad_wr;
+ int ret;
+
+ if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
+ return 0;
+
+ BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
+ BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
+ wr->opcode);
+ /* If the SQ is full, wait until an SQ entry is available */
+ while (1) {
+ spin_lock_bh(&xprt->sc_lock);
+ if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
+ spin_unlock_bh(&xprt->sc_lock);
+ atomic_inc(&rdma_stat_sq_starve);
+ /* See if we can reap some SQ WR */
+ sq_cq_reap(xprt);
+
+ /* Wait until SQ WR available if SQ still full */
+ wait_event(xprt->sc_send_wait,
+ atomic_read(&xprt->sc_sq_count) <
+ xprt->sc_sq_depth);
+ continue;
+ }
+ /* Bumped used SQ WR count and post */
+ ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
+ if (!ret)
+ atomic_inc(&xprt->sc_sq_count);
+ else
+ dprintk("svcrdma: failed to post SQ WR rc=%d, "
+ "sc_sq_count=%d, sc_sq_depth=%d\n",
+ ret, atomic_read(&xprt->sc_sq_count),
+ xprt->sc_sq_depth);
+ spin_unlock_bh(&xprt->sc_lock);
+ break;
+ }
+ return ret;
+}
+
+int svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ enum rpcrdma_errcode err)
+{
+ struct ib_send_wr err_wr;
+ struct ib_sge sge;
+ struct page *p;
+ struct svc_rdma_op_ctxt *ctxt;
+ u32 *va;
+ int length;
+ int ret;
+
+ p = svc_rdma_get_page();
+ va = page_address(p);
+
+ /* XDR encode error */
+ length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
+
+ /* Prepare SGE for local address */
+ sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
+ p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ sge.lkey = xprt->sc_phys_mr->lkey;
+ sge.length = length;
+
+ ctxt = svc_rdma_get_context(xprt);
+ ctxt->count = 1;
+ ctxt->pages[0] = p;
+
+ /* Prepare SEND WR */
+ memset(&err_wr, 0, sizeof err_wr);
+ ctxt->wr_op = IB_WR_SEND;
+ err_wr.wr_id = (unsigned long)ctxt;
+ err_wr.sg_list = &sge;
+ err_wr.num_sge = 1;
+ err_wr.opcode = IB_WR_SEND;
+ err_wr.send_flags = IB_SEND_SIGNALED;
+
+ /* Post It */
+ ret = svc_rdma_send(xprt, &err_wr);
+ if (ret) {
+ dprintk("svcrdma: Error posting send = %d\n", ret);
+ svc_rdma_put_context(ctxt, 1);
+ }
+
+ return ret;
+}
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index d716b76..340ad69 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -2,7 +2,7 @@
# Check the stack usage of functions
#
-# Copyright Joern Engel <joern@wh.fh-wedel.de>
+# Copyright Joern Engel <joern@lazybastard.org>
# Inspired by Linus Torvalds
# Original idea maybe from Keith Owens
# s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 1f11d84..c912137 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -31,17 +31,16 @@
#define KSYM_NAME_LEN 128
-
struct sym_entry {
unsigned long long addr;
unsigned int len;
+ unsigned int start_pos;
unsigned char *sym;
};
-
static struct sym_entry *table;
static unsigned int table_size, table_cnt;
-static unsigned long long _text, _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
+static unsigned long long _text, _stext, _etext, _sinittext, _einittext;
static int all_symbols = 0;
static char symbol_prefix_char = '\0';
@@ -99,10 +98,6 @@
_sinittext = s->addr;
else if (strcmp(sym, "_einittext") == 0)
_einittext = s->addr;
- else if (strcmp(sym, "_sextratext") == 0)
- _sextratext = s->addr;
- else if (strcmp(sym, "_eextratext") == 0)
- _eextratext = s->addr;
else if (toupper(stype) == 'A')
{
/* Keep these useful absolute symbols */
@@ -165,18 +160,18 @@
* and inittext sections are discarded */
if (!all_symbols) {
if ((s->addr < _stext || s->addr > _etext)
- && (s->addr < _sinittext || s->addr > _einittext)
- && (s->addr < _sextratext || s->addr > _eextratext))
+ && (s->addr < _sinittext || s->addr > _einittext))
return 0;
/* Corner case. Discard any symbols with the same value as
- * _etext _einittext or _eextratext; they can move between pass
- * 1 and 2 when the kallsyms data are added. If these symbols
- * move then they may get dropped in pass 2, which breaks the
- * kallsyms rules.
+ * _etext _einittext; they can move between pass 1 and 2 when
+ * the kallsyms data are added. If these symbols move then
+ * they may get dropped in pass 2, which breaks the kallsyms
+ * rules.
*/
- if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
- (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
- (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
+ if ((s->addr == _etext &&
+ strcmp((char *)s->sym + offset, "_etext")) ||
+ (s->addr == _einittext &&
+ strcmp((char *)s->sym + offset, "_einittext")))
return 0;
}
@@ -202,8 +197,10 @@
exit (1);
}
}
- if (read_symbol(in, &table[table_cnt]) == 0)
+ if (read_symbol(in, &table[table_cnt]) == 0) {
+ table[table_cnt].start_pos = table_cnt;
table_cnt++;
+ }
}
}
@@ -506,6 +503,35 @@
optimize_result();
}
+static int compare_symbols(const void *a, const void *b)
+{
+ const struct sym_entry *sa;
+ const struct sym_entry *sb;
+ int wa, wb;
+
+ sa = a;
+ sb = b;
+
+ /* sort by address first */
+ if (sa->addr > sb->addr)
+ return 1;
+ if (sa->addr < sb->addr)
+ return -1;
+
+ /* sort by "weakness" type */
+ wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
+ wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W');
+ if (wa != wb)
+ return wa - wb;
+
+ /* sort by initial order, so that other symbols are left undisturbed */
+ return sa->start_pos - sb->start_pos;
+}
+
+static void sort_symbols(void)
+{
+ qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
+}
int main(int argc, char **argv)
{
@@ -527,6 +553,7 @@
usage();
read_map(stdin);
+ sort_symbols();
optimize_token_table();
write_src();
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 50e61c4..734cf4f 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -821,6 +821,7 @@
return;
if (!conf_read(dialog_input_result)) {
set_config_filename(dialog_input_result);
+ sym_set_change_count(1);
return;
}
show_textbox(NULL, _("File does not exist!"), 5, 38);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index fdad173..606ceb9 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -203,12 +203,9 @@
prop_warn(prop,
"config symbol '%s' uses select, but is "
"not boolean or tristate", sym->name);
- else if (sym2->type == S_UNKNOWN)
- prop_warn(prop,
- "'select' used by config symbol '%s' "
- "refers to undefined symbol '%s'",
- sym->name, sym2->name);
- else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
+ else if (sym2->type != S_UNKNOWN &&
+ sym2->type != S_BOOLEAN &&
+ sym2->type != S_TRISTATE)
prop_warn(prop,
"'%s' has wrong type. 'select' only "
"accept arguments of boolean and "
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index d802b5a..9ddf944 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -155,7 +155,7 @@
* Some modules (visor) have empty slots as placeholder for
* run-time specification that results in catch-all alias
*/
- if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
+ if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass))
return;
/* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index f8efc93..5d54646 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -870,7 +870,7 @@
/* Do not export init/exit functions or data */
{
.fromsec = { "__ksymtab*", NULL },
- .tosec = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL },
+ .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
.mismatch = EXPORT_TO_INIT_EXIT
}
};
@@ -1125,15 +1125,15 @@
to = to_is_func ? "function" : "variable";
to_p = to_is_func ? "()" : "";
+ sec_mismatch_count++;
+ if (!sec_mismatch_verbose)
+ return;
+
fprintf(stderr, "WARNING: %s(%s+0x%llx): Section mismatch in"
" reference from the %s %s%s to the %s %s:%s%s\n",
modname, fromsec, fromaddr, from, fromsym, from_p,
to, tosec, tosym, to_p);
- sec_mismatch_count++;
- if (!sec_mismatch_verbose)
- return;
-
switch (mismatch) {
case TEXT_TO_INIT:
fprintf(stderr,
@@ -1939,10 +1939,9 @@
write_dump(dump_write);
if (sec_mismatch_count && !sec_mismatch_verbose)
fprintf(stderr, "modpost: Found %d section mismatch(es).\n"
- "To see additional details select \"Enable full "
- "Section mismatch analysis\"\n"
- "in the Kernel Hacking menu "
- "(CONFIG_SECTION_MISMATCH).\n", sec_mismatch_count);
+ "To see full details build your kernel with:\n"
+ "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n",
+ sec_mismatch_count);
return err;
}
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
old mode 100644
new mode 100755
index 52f032e..1c1bdaf
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -45,3 +45,19 @@
# All done with mercurial
exit
fi
+
+# Check for svn and a svn repo.
+if rev=`svn info 2>/dev/null | grep '^Revision'`; then
+ rev=`echo $rev | awk '{print $NF}'`
+ changes=`svn status 2>/dev/null | grep '^[AMD]' | wc -l`
+
+ # Are there uncommitted changes?
+ if [ $changes != 0 ]; then
+ printf -- '-svn%s%s%s' "$rev" -dirty "$changes"
+ else
+ printf -- '-svn%s' "$rev"
+ fi
+
+ # All done with svn
+ exit
+fi
diff --git a/security/Kconfig b/security/Kconfig
index 389e151..5dfc206 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -104,7 +104,26 @@
If you are unsure how to answer this question, answer N.
+config SECURITY_DEFAULT_MMAP_MIN_ADDR
+ int "Low address space to protect from user allocation"
+ depends on SECURITY
+ default 0
+ help
+ This is the portion of low virtual memory which should be protected
+ from userspace allocation. Keeping a user from writing to low pages
+ can help reduce the impact of kernel NULL pointer bugs.
+
+ For most users with lots of address space a value of 65536 is
+ reasonable and should cause no problems. Programs which use vm86
+ functionality would either need additional permissions from either
+ the LSM or the capabilities module or have this protection disabled.
+
+ This value can be changed after boot using the
+ /proc/sys/vm/mmap_min_addr tunable.
+
+
source security/selinux/Kconfig
+source security/smack/Kconfig
endmenu
diff --git a/security/Makefile b/security/Makefile
index ef87df2f..9e8b025 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
+subdir-$(CONFIG_SECURITY_SMACK) += smack
# if we don't select a security model, use the default capabilities
ifneq ($(CONFIG_SECURITY),y)
@@ -14,5 +15,6 @@
obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
+obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
diff --git a/security/commoncap.c b/security/commoncap.c
index ea61bc7..5aba826 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1,4 +1,4 @@
-/* Common capabilities, needed by capability.o and root_plug.o
+/* Common capabilities, needed by capability.o and root_plug.o
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,20 +25,6 @@
#include <linux/mount.h>
#include <linux/sched.h>
-#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
-/*
- * Because of the reduced scope of CAP_SETPCAP when filesystem
- * capabilities are in effect, it is safe to allow this capability to
- * be available in the default configuration.
- */
-# define CAP_INIT_BSET CAP_FULL_SET
-#else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */
-# define CAP_INIT_BSET CAP_INIT_EFF_SET
-#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
-
-kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */
-EXPORT_SYMBOL(cap_bset);
-
/* Global security state */
unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
@@ -93,9 +79,9 @@
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
/* Derived from kernel/capability.c:sys_capget. */
- *effective = cap_t (target->cap_effective);
- *inheritable = cap_t (target->cap_inheritable);
- *permitted = cap_t (target->cap_permitted);
+ *effective = target->cap_effective;
+ *inheritable = target->cap_inheritable;
+ *permitted = target->cap_permitted;
return 0;
}
@@ -140,6 +126,12 @@
/* incapable of using this inheritable set */
return -EPERM;
}
+ if (!cap_issubset(*inheritable,
+ cap_combine(target->cap_inheritable,
+ current->cap_bset))) {
+ /* no new pI capabilities outside bounding set */
+ return -EPERM;
+ }
/* verify restrictions on target's new Permitted set */
if (!cap_issubset (*permitted,
@@ -198,28 +190,50 @@
}
static inline int cap_from_disk(struct vfs_cap_data *caps,
- struct linux_binprm *bprm,
- int size)
+ struct linux_binprm *bprm, unsigned size)
{
__u32 magic_etc;
+ unsigned tocopy, i;
- if (size != XATTR_CAPS_SZ)
+ if (size < sizeof(magic_etc))
return -EINVAL;
magic_etc = le32_to_cpu(caps->magic_etc);
switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
- case VFS_CAP_REVISION:
- if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
- bprm->cap_effective = true;
- else
- bprm->cap_effective = false;
- bprm->cap_permitted = to_cap_t(le32_to_cpu(caps->permitted));
- bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps->inheritable));
- return 0;
+ case VFS_CAP_REVISION_1:
+ if (size != XATTR_CAPS_SZ_1)
+ return -EINVAL;
+ tocopy = VFS_CAP_U32_1;
+ break;
+ case VFS_CAP_REVISION_2:
+ if (size != XATTR_CAPS_SZ_2)
+ return -EINVAL;
+ tocopy = VFS_CAP_U32_2;
+ break;
default:
return -EINVAL;
}
+
+ if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
+ bprm->cap_effective = true;
+ } else {
+ bprm->cap_effective = false;
+ }
+
+ for (i = 0; i < tocopy; ++i) {
+ bprm->cap_permitted.cap[i] =
+ le32_to_cpu(caps->data[i].permitted);
+ bprm->cap_inheritable.cap[i] =
+ le32_to_cpu(caps->data[i].inheritable);
+ }
+ while (i < VFS_CAP_U32) {
+ bprm->cap_permitted.cap[i] = 0;
+ bprm->cap_inheritable.cap[i] = 0;
+ i++;
+ }
+
+ return 0;
}
/* Locate any VFS capabilities: */
@@ -227,7 +241,7 @@
{
struct dentry *dentry;
int rc = 0;
- struct vfs_cap_data incaps;
+ struct vfs_cap_data vcaps;
struct inode *inode;
if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
@@ -240,14 +254,8 @@
if (!inode->i_op || !inode->i_op->getxattr)
goto out;
- rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
- if (rc > 0) {
- if (rc == XATTR_CAPS_SZ)
- rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS,
- &incaps, XATTR_CAPS_SZ);
- else
- rc = -EINVAL;
- }
+ rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
+ XATTR_CAPS_SZ);
if (rc == -ENODATA || rc == -EOPNOTSUPP) {
/* no data, that's ok */
rc = 0;
@@ -256,7 +264,7 @@
if (rc < 0)
goto out;
- rc = cap_from_disk(&incaps, bprm, rc);
+ rc = cap_from_disk(&vcaps, bprm, rc);
if (rc)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
__FUNCTION__, rc, bprm->filename);
@@ -321,10 +329,11 @@
/* Derived from fs/exec.c:compute_creds. */
kernel_cap_t new_permitted, working;
- new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
- working = cap_intersect (bprm->cap_inheritable,
+ new_permitted = cap_intersect(bprm->cap_permitted,
+ current->cap_bset);
+ working = cap_intersect(bprm->cap_inheritable,
current->cap_inheritable);
- new_permitted = cap_combine (new_permitted, working);
+ new_permitted = cap_combine(new_permitted, working);
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset (new_permitted, current->cap_permitted)) {
@@ -351,8 +360,10 @@
* capability rules */
if (!is_global_init(current)) {
current->cap_permitted = new_permitted;
- current->cap_effective = bprm->cap_effective ?
- new_permitted : 0;
+ if (bprm->cap_effective)
+ current->cap_effective = new_permitted;
+ else
+ cap_clear(current->cap_effective);
}
/* AUD: Audit candidate if current->cap_effective is set */
@@ -474,13 +485,15 @@
if (!issecure (SECURE_NO_SETUID_FIXUP)) {
if (old_fsuid == 0 && current->fsuid != 0) {
- cap_t (current->cap_effective) &=
- ~CAP_FS_MASK;
+ current->cap_effective =
+ cap_drop_fs_set(
+ current->cap_effective);
}
if (old_fsuid != 0 && current->fsuid == 0) {
- cap_t (current->cap_effective) |=
- (cap_t (current->cap_permitted) &
- CAP_FS_MASK);
+ current->cap_effective =
+ cap_raise_fs_set(
+ current->cap_effective,
+ current->cap_permitted);
}
}
break;
@@ -561,6 +574,23 @@
return -EPERM;
}
+
+/*
+ * called from kernel/sys.c for prctl(PR_CABSET_DROP)
+ * done without task_capability_lock() because it introduces
+ * no new races - i.e. only another task doing capget() on
+ * this task could get inconsistent info. There can be no
+ * racing writer bc a task can only change its own caps.
+ */
+long cap_prctl_drop(unsigned long cap)
+{
+ if (!capable(CAP_SETPCAP))
+ return -EPERM;
+ if (!cap_valid(cap))
+ return -EINVAL;
+ cap_lower(current->cap_bset, cap);
+ return 0;
+}
#else
int cap_task_setscheduler (struct task_struct *p, int policy,
struct sched_param *lp)
@@ -584,9 +614,9 @@
void cap_task_reparent_to_init (struct task_struct *p)
{
- p->cap_effective = CAP_INIT_EFF_SET;
- p->cap_inheritable = CAP_INIT_INH_SET;
- p->cap_permitted = CAP_FULL_SET;
+ cap_set_init_eff(p->cap_effective);
+ cap_clear(p->cap_inheritable);
+ cap_set_full(p->cap_permitted);
p->keep_capabilities = 0;
return;
}
diff --git a/security/dummy.c b/security/dummy.c
index 48d4b0a..649326b 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -36,14 +36,19 @@
static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
kernel_cap_t * inheritable, kernel_cap_t * permitted)
{
- *effective = *inheritable = *permitted = 0;
if (target->euid == 0) {
- *permitted |= (~0 & ~CAP_FS_MASK);
- *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK);
+ cap_set_full(*permitted);
+ cap_set_init_eff(*effective);
+ } else {
+ cap_clear(*permitted);
+ cap_clear(*effective);
}
- if (target->fsuid == 0) {
- *permitted |= CAP_FS_MASK;
- *effective |= CAP_FS_MASK;
+
+ cap_clear(*inheritable);
+
+ if (target->fsuid != 0) {
+ *permitted = cap_drop_fs_set(*permitted);
+ *effective = cap_drop_fs_set(*effective);
}
return 0;
}
@@ -402,7 +407,7 @@
return 0;
}
-static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
diff --git a/security/security.c b/security/security.c
index ca475ca..d15e56c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -23,7 +23,9 @@
extern void security_fixup_ops(struct security_operations *ops);
struct security_operations *security_ops; /* Initialized to NULL */
-unsigned long mmap_min_addr; /* 0 means no protection */
+
+/* amount of vm to protect from userspace access */
+unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
static inline int verify(struct security_operations *ops)
{
@@ -493,11 +495,11 @@
return security_ops->inode_killpriv(dentry);
}
-int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
if (unlikely(IS_PRIVATE(inode)))
return 0;
- return security_ops->inode_getsecurity(inode, name, buffer, size, err);
+ return security_ops->inode_getsecurity(inode, name, buffer, alloc);
}
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index be6de0b..e5ed075 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -136,32 +136,6 @@
static struct kmem_cache *sel_inode_cache;
-/* Return security context for a given sid or just the context
- length if the buffer is null or length is 0 */
-static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
-{
- char *context;
- unsigned len;
- int rc;
-
- rc = security_sid_to_context(sid, &context, &len);
- if (rc)
- return rc;
-
- if (!buffer || !size)
- goto getsecurity_exit;
-
- if (size < len) {
- len = -ERANGE;
- goto getsecurity_exit;
- }
- memcpy(buffer, context, len);
-
-getsecurity_exit:
- kfree(context);
- return len;
-}
-
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
*
@@ -2675,14 +2649,27 @@
*
* Permission check is handled by selinux_inode_getxattr hook.
*/
-static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
+ u32 size;
+ int error;
+ char *context = NULL;
struct inode_security_struct *isec = inode->i_security;
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
- return selinux_getsecurity(isec->sid, buffer, size);
+ error = security_sid_to_context(isec->sid, &context, &size);
+ if (error)
+ return error;
+ error = size;
+ if (alloc) {
+ *buffer = context;
+ goto out_nofree;
+ }
+ kfree(context);
+out_nofree:
+ return error;
}
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 23137c1..837ce42 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -107,7 +107,6 @@
int security_get_permissions(char *class, char ***perms, int *nperms);
int security_get_reject_unknown(void);
int security_get_allow_unknown(void);
-int security_get_policycaps(int *len, int **values);
#define SECURITY_FS_USE_XATTR 1 /* use xattr */
#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index fced6bc..f374186 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2246,39 +2246,6 @@
}
/**
- * security_get_policycaps - Query the loaded policy for its capabilities
- * @len: the number of capability bits
- * @values: the capability bit array
- *
- * Description:
- * Get an array of the policy capabilities in @values where each entry in
- * @values is either true (1) or false (0) depending the policy's support of
- * that feature. The policy capabilities are defined by the
- * POLICYDB_CAPABILITY_* enums. The size of the array is stored in @len and it
- * is up to the caller to free the array in @values. Returns zero on success,
- * negative values on failure.
- *
- */
-int security_get_policycaps(int *len, int **values)
-{
- int rc = -ENOMEM;
- unsigned int iter;
-
- POLICY_RDLOCK;
-
- *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
- if (*values == NULL)
- goto out;
- for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
- (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
- *len = POLICYDB_CAPABILITY_MAX;
-
-out:
- POLICY_RDUNLOCK;
- return rc;
-}
-
-/**
* security_policycap_supported - Check for a specific policy capability
* @req_cap: capability
*
diff --git a/security/smack/Kconfig b/security/smack/Kconfig
new file mode 100644
index 0000000..603b087
--- /dev/null
+++ b/security/smack/Kconfig
@@ -0,0 +1,10 @@
+config SECURITY_SMACK
+ bool "Simplified Mandatory Access Control Kernel Support"
+ depends on NETLABEL && SECURITY_NETWORK
+ default n
+ help
+ This selects the Simplified Mandatory Access Control Kernel.
+ Smack is useful for sensitivity, integrity, and a variety
+ of other mandatory security schemes.
+ If you are unsure how to answer this question, answer N.
+
diff --git a/security/smack/Makefile b/security/smack/Makefile
new file mode 100644
index 0000000..67a63aa
--- /dev/null
+++ b/security/smack/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the SMACK LSM
+#
+
+obj-$(CONFIG_SECURITY_SMACK) := smack.o
+
+smack-y := smack_lsm.o smack_access.o smackfs.o
diff --git a/security/smack/smack.h b/security/smack/smack.h
new file mode 100644
index 0000000..a21a0e9
--- /dev/null
+++ b/security/smack/smack.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * Author:
+ * Casey Schaufler <casey@schaufler-ca.com>
+ *
+ */
+
+#ifndef _SECURITY_SMACK_H
+#define _SECURITY_SMACK_H
+
+#include <linux/capability.h>
+#include <linux/spinlock.h>
+#include <net/netlabel.h>
+
+/*
+ * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
+ * bigger than can be used, and 24 is the next lower multiple
+ * of 8, and there are too many issues if there isn't space set
+ * aside for the terminating null byte.
+ */
+#define SMK_MAXLEN 23
+#define SMK_LABELLEN (SMK_MAXLEN+1)
+
+/*
+ * How many kinds of access are there?
+ * Here's your answer.
+ */
+#define SMK_ACCESSDASH '-'
+#define SMK_ACCESSLOW "rwxa"
+#define SMK_ACCESSKINDS (sizeof(SMK_ACCESSLOW) - 1)
+
+struct superblock_smack {
+ char *smk_root;
+ char *smk_floor;
+ char *smk_hat;
+ char *smk_default;
+ int smk_initialized;
+ spinlock_t smk_sblock; /* for initialization */
+};
+
+struct socket_smack {
+ char *smk_out; /* outbound label */
+ char *smk_in; /* inbound label */
+ char smk_packet[SMK_LABELLEN]; /* TCP peer label */
+};
+
+/*
+ * Inode smack data
+ */
+struct inode_smack {
+ char *smk_inode; /* label of the fso */
+ struct mutex smk_lock; /* initialization lock */
+ int smk_flags; /* smack inode flags */
+};
+
+#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
+
+/*
+ * A label access rule.
+ */
+struct smack_rule {
+ char *smk_subject;
+ char *smk_object;
+ int smk_access;
+};
+
+/*
+ * An entry in the table of permitted label accesses.
+ */
+struct smk_list_entry {
+ struct smk_list_entry *smk_next;
+ struct smack_rule smk_rule;
+};
+
+/*
+ * An entry in the table mapping smack values to
+ * CIPSO level/category-set values.
+ */
+struct smack_cipso {
+ int smk_level;
+ char smk_catset[SMK_LABELLEN];
+};
+
+/*
+ * This is the repository for labels seen so that it is
+ * not necessary to keep allocating tiny chuncks of memory
+ * and so that they can be shared.
+ *
+ * Labels are never modified in place. Anytime a label
+ * is imported (e.g. xattrset on a file) the list is checked
+ * for it and it is added if it doesn't exist. The address
+ * is passed out in either case. Entries are added, but
+ * never deleted.
+ *
+ * Since labels are hanging around anyway it doesn't
+ * hurt to maintain a secid for those awkward situations
+ * where kernel components that ought to use LSM independent
+ * interfaces don't. The secid should go away when all of
+ * these components have been repaired.
+ *
+ * If there is a cipso value associated with the label it
+ * gets stored here, too. This will most likely be rare as
+ * the cipso direct mapping in used internally.
+ */
+struct smack_known {
+ struct smack_known *smk_next;
+ char smk_known[SMK_LABELLEN];
+ u32 smk_secid;
+ struct smack_cipso *smk_cipso;
+ spinlock_t smk_cipsolock; /* for changing cipso map */
+};
+
+/*
+ * Mount options
+ */
+#define SMK_FSDEFAULT "smackfsdef="
+#define SMK_FSFLOOR "smackfsfloor="
+#define SMK_FSHAT "smackfshat="
+#define SMK_FSROOT "smackfsroot="
+
+/*
+ * xattr names
+ */
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_SMACK_IPIN "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
+#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+
+/*
+ * smackfs macic number
+ */
+#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
+
+/*
+ * A limit on the number of entries in the lists
+ * makes some of the list administration easier.
+ */
+#define SMACK_LIST_MAX 10000
+
+/*
+ * CIPSO defaults.
+ */
+#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
+#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */
+#define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */
+#define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */
+#define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */
+
+/*
+ * Just to make the common cases easier to deal with
+ */
+#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+#define MAY_ANYREAD (MAY_READ | MAY_EXEC)
+#define MAY_ANYWRITE (MAY_WRITE | MAY_APPEND)
+#define MAY_READWRITE (MAY_READ | MAY_WRITE)
+#define MAY_NOT 0
+
+/*
+ * These functions are in smack_lsm.c
+ */
+struct inode_smack *new_inode_smack(char *);
+
+/*
+ * These functions are in smack_access.c
+ */
+int smk_access(char *, char *, int);
+int smk_curacc(char *, u32);
+int smack_to_cipso(const char *, struct smack_cipso *);
+void smack_from_cipso(u32, char *, char *);
+char *smack_from_secid(const u32);
+char *smk_import(const char *, int);
+struct smack_known *smk_import_entry(const char *, int);
+u32 smack_to_secid(const char *);
+
+/*
+ * Shared data.
+ */
+extern int smack_cipso_direct;
+extern int smack_net_nltype;
+extern char *smack_net_ambient;
+
+extern struct smack_known *smack_known;
+extern struct smack_known smack_known_floor;
+extern struct smack_known smack_known_hat;
+extern struct smack_known smack_known_huh;
+extern struct smack_known smack_known_invalid;
+extern struct smack_known smack_known_star;
+extern struct smack_known smack_known_unset;
+
+extern struct smk_list_entry *smack_list;
+
+/*
+ * Stricly for CIPSO level manipulation.
+ * Set the category bit number in a smack label sized buffer.
+ */
+static inline void smack_catset_bit(int cat, char *catsetp)
+{
+ if (cat > SMK_LABELLEN * 8)
+ return;
+
+ catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
+}
+
+/*
+ * Present a pointer to the smack label in an inode blob.
+ */
+static inline char *smk_of_inode(const struct inode *isp)
+{
+ struct inode_smack *sip = isp->i_security;
+ return sip->smk_inode;
+}
+
+#endif /* _SECURITY_SMACK_H */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
new file mode 100644
index 0000000..f6b5f6e
--- /dev/null
+++ b/security/smack/smack_access.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * Author:
+ * Casey Schaufler <casey@schaufler-ca.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include "smack.h"
+
+struct smack_known smack_known_unset = {
+ .smk_next = NULL,
+ .smk_known = "UNSET",
+ .smk_secid = 1,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_huh = {
+ .smk_next = &smack_known_unset,
+ .smk_known = "?",
+ .smk_secid = 2,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_hat = {
+ .smk_next = &smack_known_huh,
+ .smk_known = "^",
+ .smk_secid = 3,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_star = {
+ .smk_next = &smack_known_hat,
+ .smk_known = "*",
+ .smk_secid = 4,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_floor = {
+ .smk_next = &smack_known_star,
+ .smk_known = "_",
+ .smk_secid = 5,
+ .smk_cipso = NULL,
+};
+
+struct smack_known smack_known_invalid = {
+ .smk_next = &smack_known_floor,
+ .smk_known = "",
+ .smk_secid = 6,
+ .smk_cipso = NULL,
+};
+
+struct smack_known *smack_known = &smack_known_invalid;
+
+/*
+ * The initial value needs to be bigger than any of the
+ * known values above.
+ */
+static u32 smack_next_secid = 10;
+
+/**
+ * smk_access - determine if a subject has a specific access to an object
+ * @subject_label: a pointer to the subject's Smack label
+ * @object_label: a pointer to the object's Smack label
+ * @request: the access requested, in "MAY" format
+ *
+ * This function looks up the subject/object pair in the
+ * access rule list and returns 0 if the access is permitted,
+ * non zero otherwise.
+ *
+ * Even though Smack labels are usually shared on smack_list
+ * labels that come in off the network can't be imported
+ * and added to the list for locking reasons.
+ *
+ * Therefore, it is necessary to check the contents of the labels,
+ * not just the pointer values. Of course, in most cases the labels
+ * will be on the list, so checking the pointers may be a worthwhile
+ * optimization.
+ */
+int smk_access(char *subject_label, char *object_label, int request)
+{
+ u32 may = MAY_NOT;
+ struct smk_list_entry *sp;
+ struct smack_rule *srp;
+
+ /*
+ * Hardcoded comparisons.
+ *
+ * A star subject can't access any object.
+ */
+ if (subject_label == smack_known_star.smk_known ||
+ strcmp(subject_label, smack_known_star.smk_known) == 0)
+ return -EACCES;
+ /*
+ * A star object can be accessed by any subject.
+ */
+ if (object_label == smack_known_star.smk_known ||
+ strcmp(object_label, smack_known_star.smk_known) == 0)
+ return 0;
+ /*
+ * An object can be accessed in any way by a subject
+ * with the same label.
+ */
+ if (subject_label == object_label ||
+ strcmp(subject_label, object_label) == 0)
+ return 0;
+ /*
+ * A hat subject can read any object.
+ * A floor object can be read by any subject.
+ */
+ if ((request & MAY_ANYREAD) == request) {
+ if (object_label == smack_known_floor.smk_known ||
+ strcmp(object_label, smack_known_floor.smk_known) == 0)
+ return 0;
+ if (subject_label == smack_known_hat.smk_known ||
+ strcmp(subject_label, smack_known_hat.smk_known) == 0)
+ return 0;
+ }
+ /*
+ * Beyond here an explicit relationship is required.
+ * If the requested access is contained in the available
+ * access (e.g. read is included in readwrite) it's
+ * good.
+ */
+ for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
+ srp = &sp->smk_rule;
+
+ if (srp->smk_subject == subject_label ||
+ strcmp(srp->smk_subject, subject_label) == 0) {
+ if (srp->smk_object == object_label ||
+ strcmp(srp->smk_object, object_label) == 0) {
+ may = srp->smk_access;
+ break;
+ }
+ }
+ }
+ /*
+ * This is a bit map operation.
+ */
+ if ((request & may) == request)
+ return 0;
+
+ return -EACCES;
+}
+
+/**
+ * smk_curacc - determine if current has a specific access to an object
+ * @object_label: a pointer to the object's Smack label
+ * @request: the access requested, in "MAY" format
+ *
+ * This function checks the current subject label/object label pair
+ * in the access rule list and returns 0 if the access is permitted,
+ * non zero otherwise. It allows that current my have the capability
+ * to override the rules.
+ */
+int smk_curacc(char *obj_label, u32 mode)
+{
+ int rc;
+
+ rc = smk_access(current->security, obj_label, mode);
+ if (rc == 0)
+ return 0;
+
+ if (capable(CAP_MAC_OVERRIDE))
+ return 0;
+
+ return rc;
+}
+
+static DEFINE_MUTEX(smack_known_lock);
+
+/**
+ * smk_import_entry - import a label, return the list entry
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the entry in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+struct smack_known *smk_import_entry(const char *string, int len)
+{
+ struct smack_known *skp;
+ char smack[SMK_LABELLEN];
+ int found;
+ int i;
+
+ if (len <= 0 || len > SMK_MAXLEN)
+ len = SMK_MAXLEN;
+
+ for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
+ if (found)
+ smack[i] = '\0';
+ else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
+ string[i] == '/') {
+ smack[i] = '\0';
+ found = 1;
+ } else
+ smack[i] = string[i];
+ }
+
+ if (smack[0] == '\0')
+ return NULL;
+
+ mutex_lock(&smack_known_lock);
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+ if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
+ break;
+
+ if (skp == NULL) {
+ skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
+ if (skp != NULL) {
+ skp->smk_next = smack_known;
+ strncpy(skp->smk_known, smack, SMK_MAXLEN);
+ skp->smk_secid = smack_next_secid++;
+ skp->smk_cipso = NULL;
+ spin_lock_init(&skp->smk_cipsolock);
+ /*
+ * Make sure that the entry is actually
+ * filled before putting it on the list.
+ */
+ smp_mb();
+ smack_known = skp;
+ }
+ }
+
+ mutex_unlock(&smack_known_lock);
+
+ return skp;
+}
+
+/**
+ * smk_import - import a smack label
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the label in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+char *smk_import(const char *string, int len)
+{
+ struct smack_known *skp;
+
+ skp = smk_import_entry(string, len);
+ if (skp == NULL)
+ return NULL;
+ return skp->smk_known;
+}
+
+/**
+ * smack_from_secid - find the Smack label associated with a secid
+ * @secid: an integer that might be associated with a Smack label
+ *
+ * Returns a pointer to the appropraite Smack label if there is one,
+ * otherwise a pointer to the invalid Smack label.
+ */
+char *smack_from_secid(const u32 secid)
+{
+ struct smack_known *skp;
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+ if (skp->smk_secid == secid)
+ return skp->smk_known;
+
+ /*
+ * If we got this far someone asked for the translation
+ * of a secid that is not on the list.
+ */
+ return smack_known_invalid.smk_known;
+}
+
+/**
+ * smack_to_secid - find the secid associated with a Smack label
+ * @smack: the Smack label
+ *
+ * Returns the appropriate secid if there is one,
+ * otherwise 0
+ */
+u32 smack_to_secid(const char *smack)
+{
+ struct smack_known *skp;
+
+ for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+ if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
+ return skp->smk_secid;
+ return 0;
+}
+
+/**
+ * smack_from_cipso - find the Smack label associated with a CIPSO option
+ * @level: Bell & LaPadula level from the network
+ * @cp: Bell & LaPadula categories from the network
+ * @result: where to put the Smack value
+ *
+ * This is a simple lookup in the label table.
+ *
+ * This is an odd duck as far as smack handling goes in that
+ * it sends back a copy of the smack label rather than a pointer
+ * to the master list. This is done because it is possible for
+ * a foreign host to send a smack label that is new to this
+ * machine and hence not on the list. That would not be an
+ * issue except that adding an entry to the master list can't
+ * be done at that point.
+ */
+void smack_from_cipso(u32 level, char *cp, char *result)
+{
+ struct smack_known *kp;
+ char *final = NULL;
+
+ for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
+ if (kp->smk_cipso == NULL)
+ continue;
+
+ spin_lock_bh(&kp->smk_cipsolock);
+
+ if (kp->smk_cipso->smk_level == level &&
+ memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
+ final = kp->smk_known;
+
+ spin_unlock_bh(&kp->smk_cipsolock);
+ }
+ if (final == NULL)
+ final = smack_known_huh.smk_known;
+ strncpy(result, final, SMK_MAXLEN);
+ return;
+}
+
+/**
+ * smack_to_cipso - find the CIPSO option to go with a Smack label
+ * @smack: a pointer to the smack label in question
+ * @cp: where to put the result
+ *
+ * Returns zero if a value is available, non-zero otherwise.
+ */
+int smack_to_cipso(const char *smack, struct smack_cipso *cp)
+{
+ struct smack_known *kp;
+
+ for (kp = smack_known; kp != NULL; kp = kp->smk_next)
+ if (kp->smk_known == smack ||
+ strcmp(kp->smk_known, smack) == 0)
+ break;
+
+ if (kp == NULL || kp->smk_cipso == NULL)
+ return -ENOENT;
+
+ memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
+ return 0;
+}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
new file mode 100644
index 0000000..1c11e42
--- /dev/null
+++ b/security/smack/smack_lsm.c
@@ -0,0 +1,2518 @@
+/*
+ * Simplified MAC Kernel (smack) security module
+ *
+ * This file contains the smack hook function implementations.
+ *
+ * Author:
+ * Casey Schaufler <casey@schaufler-ca.com>
+ *
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/xattr.h>
+#include <linux/pagemap.h>
+#include <linux/mount.h>
+#include <linux/stat.h>
+#include <linux/ext2_fs.h>
+#include <linux/kd.h>
+#include <asm/ioctls.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/mutex.h>
+#include <linux/pipe_fs_i.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "smack.h"
+
+/*
+ * I hope these are the hokeyist lines of code in the module. Casey.
+ */
+#define DEVPTS_SUPER_MAGIC 0x1cd1
+#define SOCKFS_MAGIC 0x534F434B
+#define TMPFS_MAGIC 0x01021994
+
+/**
+ * smk_fetch - Fetch the smack label from a file.
+ * @ip: a pointer to the inode
+ * @dp: a pointer to the dentry
+ *
+ * Returns a pointer to the master list entry for the Smack label
+ * or NULL if there was no label to fetch.
+ */
+static char *smk_fetch(struct inode *ip, struct dentry *dp)
+{
+ int rc;
+ char in[SMK_LABELLEN];
+
+ if (ip->i_op->getxattr == NULL)
+ return NULL;
+
+ rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN);
+ if (rc < 0)
+ return NULL;
+
+ return smk_import(in, rc);
+}
+
+/**
+ * new_inode_smack - allocate an inode security blob
+ * @smack: a pointer to the Smack label to use in the blob
+ *
+ * Returns the new blob or NULL if there's no memory available
+ */
+struct inode_smack *new_inode_smack(char *smack)
+{
+ struct inode_smack *isp;
+
+ isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL);
+ if (isp == NULL)
+ return NULL;
+
+ isp->smk_inode = smack;
+ isp->smk_flags = 0;
+ mutex_init(&isp->smk_lock);
+
+ return isp;
+}
+
+/*
+ * LSM hooks.
+ * We he, that is fun!
+ */
+
+/**
+ * smack_ptrace - Smack approval on ptrace
+ * @ptp: parent task pointer
+ * @ctp: child task pointer
+ *
+ * Returns 0 if access is OK, an error code otherwise
+ *
+ * Do the capability checks, and require read and write.
+ */
+static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
+{
+ int rc;
+
+ rc = cap_ptrace(ptp, ctp);
+ if (rc != 0)
+ return rc;
+
+ rc = smk_access(ptp->security, ctp->security, MAY_READWRITE);
+ if (rc != 0 && __capable(ptp, CAP_MAC_OVERRIDE))
+ return 0;
+
+ return rc;
+}
+
+/**
+ * smack_syslog - Smack approval on syslog
+ * @type: message type
+ *
+ * Require that the task has the floor label
+ *
+ * Returns 0 on success, error code otherwise.
+ */
+static int smack_syslog(int type)
+{
+ int rc;
+ char *sp = current->security;
+
+ rc = cap_syslog(type);
+ if (rc != 0)
+ return rc;
+
+ if (capable(CAP_MAC_OVERRIDE))
+ return 0;
+
+ if (sp != smack_known_floor.smk_known)
+ rc = -EACCES;
+
+ return rc;
+}
+
+
+/*
+ * Superblock Hooks.
+ */
+
+/**
+ * smack_sb_alloc_security - allocate a superblock blob
+ * @sb: the superblock getting the blob
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_sb_alloc_security(struct super_block *sb)
+{
+ struct superblock_smack *sbsp;
+
+ sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
+
+ if (sbsp == NULL)
+ return -ENOMEM;
+
+ sbsp->smk_root = smack_known_floor.smk_known;
+ sbsp->smk_default = smack_known_floor.smk_known;
+ sbsp->smk_floor = smack_known_floor.smk_known;
+ sbsp->smk_hat = smack_known_hat.smk_known;
+ sbsp->smk_initialized = 0;
+ spin_lock_init(&sbsp->smk_sblock);
+
+ sb->s_security = sbsp;
+
+ return 0;
+}
+
+/**
+ * smack_sb_free_security - free a superblock blob
+ * @sb: the superblock getting the blob
+ *
+ */
+static void smack_sb_free_security(struct super_block *sb)
+{
+ kfree(sb->s_security);
+ sb->s_security = NULL;
+}
+
+/**
+ * smack_sb_copy_data - copy mount options data for processing
+ * @type: file system type
+ * @orig: where to start
+ * @smackopts
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ *
+ * Copy the Smack specific mount options out of the mount
+ * options list.
+ */
+static int smack_sb_copy_data(struct file_system_type *type, void *orig,
+ void *smackopts)
+{
+ char *cp, *commap, *otheropts, *dp;
+
+ /* Binary mount data: just copy */
+ if (type->fs_flags & FS_BINARY_MOUNTDATA) {
+ copy_page(smackopts, orig);
+ return 0;
+ }
+
+ otheropts = (char *)get_zeroed_page(GFP_KERNEL);
+ if (otheropts == NULL)
+ return -ENOMEM;
+
+ for (cp = orig, commap = orig; commap != NULL; cp = commap + 1) {
+ if (strstr(cp, SMK_FSDEFAULT) == cp)
+ dp = smackopts;
+ else if (strstr(cp, SMK_FSFLOOR) == cp)
+ dp = smackopts;
+ else if (strstr(cp, SMK_FSHAT) == cp)
+ dp = smackopts;
+ else if (strstr(cp, SMK_FSROOT) == cp)
+ dp = smackopts;
+ else
+ dp = otheropts;
+
+ commap = strchr(cp, ',');
+ if (commap != NULL)
+ *commap = '\0';
+
+ if (*dp != '\0')
+ strcat(dp, ",");
+ strcat(dp, cp);
+ }
+
+ strcpy(orig, otheropts);
+ free_page((unsigned long)otheropts);
+
+ return 0;
+}
+
+/**
+ * smack_sb_kern_mount - Smack specific mount processing
+ * @sb: the file system superblock
+ * @data: the smack mount options
+ *
+ * Returns 0 on success, an error code on failure
+ */
+static int smack_sb_kern_mount(struct super_block *sb, void *data)
+{
+ struct dentry *root = sb->s_root;
+ struct inode *inode = root->d_inode;
+ struct superblock_smack *sp = sb->s_security;
+ struct inode_smack *isp;
+ char *op;
+ char *commap;
+ char *nsp;
+
+ spin_lock(&sp->smk_sblock);
+ if (sp->smk_initialized != 0) {
+ spin_unlock(&sp->smk_sblock);
+ return 0;
+ }
+ sp->smk_initialized = 1;
+ spin_unlock(&sp->smk_sblock);
+
+ for (op = data; op != NULL; op = commap) {
+ commap = strchr(op, ',');
+ if (commap != NULL)
+ *commap++ = '\0';
+
+ if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
+ op += strlen(SMK_FSHAT);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_hat = nsp;
+ } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
+ op += strlen(SMK_FSFLOOR);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_floor = nsp;
+ } else if (strncmp(op, SMK_FSDEFAULT,
+ strlen(SMK_FSDEFAULT)) == 0) {
+ op += strlen(SMK_FSDEFAULT);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_default = nsp;
+ } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
+ op += strlen(SMK_FSROOT);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL)
+ sp->smk_root = nsp;
+ }
+ }
+
+ /*
+ * Initialize the root inode.
+ */
+ isp = inode->i_security;
+ if (isp == NULL)
+ inode->i_security = new_inode_smack(sp->smk_root);
+ else
+ isp->smk_inode = sp->smk_root;
+
+ return 0;
+}
+
+/**
+ * smack_sb_statfs - Smack check on statfs
+ * @dentry: identifies the file system in question
+ *
+ * Returns 0 if current can read the floor of the filesystem,
+ * and error code otherwise
+ */
+static int smack_sb_statfs(struct dentry *dentry)
+{
+ struct superblock_smack *sbp = dentry->d_sb->s_security;
+
+ return smk_curacc(sbp->smk_floor, MAY_READ);
+}
+
+/**
+ * smack_sb_mount - Smack check for mounting
+ * @dev_name: unused
+ * @nd: mount point
+ * @type: unused
+ * @flags: unused
+ * @data: unused
+ *
+ * Returns 0 if current can write the floor of the filesystem
+ * being mounted on, an error code otherwise.
+ */
+static int smack_sb_mount(char *dev_name, struct nameidata *nd,
+ char *type, unsigned long flags, void *data)
+{
+ struct superblock_smack *sbp = nd->mnt->mnt_sb->s_security;
+
+ return smk_curacc(sbp->smk_floor, MAY_WRITE);
+}
+
+/**
+ * smack_sb_umount - Smack check for unmounting
+ * @mnt: file system to unmount
+ * @flags: unused
+ *
+ * Returns 0 if current can write the floor of the filesystem
+ * being unmounted, an error code otherwise.
+ */
+static int smack_sb_umount(struct vfsmount *mnt, int flags)
+{
+ struct superblock_smack *sbp;
+
+ sbp = mnt->mnt_sb->s_security;
+
+ return smk_curacc(sbp->smk_floor, MAY_WRITE);
+}
+
+/*
+ * Inode hooks
+ */
+
+/**
+ * smack_inode_alloc_security - allocate an inode blob
+ * @inode - the inode in need of a blob
+ *
+ * Returns 0 if it gets a blob, -ENOMEM otherwise
+ */
+static int smack_inode_alloc_security(struct inode *inode)
+{
+ inode->i_security = new_inode_smack(current->security);
+ if (inode->i_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * smack_inode_free_security - free an inode blob
+ * @inode - the inode with a blob
+ *
+ * Clears the blob pointer in inode
+ */
+static void smack_inode_free_security(struct inode *inode)
+{
+ kfree(inode->i_security);
+ inode->i_security = NULL;
+}
+
+/**
+ * smack_inode_init_security - copy out the smack from an inode
+ * @inode: the inode
+ * @dir: unused
+ * @name: where to put the attribute name
+ * @value: where to put the attribute value
+ * @len: where to put the length of the attribute
+ *
+ * Returns 0 if it all works out, -ENOMEM if there's no memory
+ */
+static int smack_inode_init_security(struct inode *inode, struct inode *dir,
+ char **name, void **value, size_t *len)
+{
+ char *isp = smk_of_inode(inode);
+
+ if (name) {
+ *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
+ if (*name == NULL)
+ return -ENOMEM;
+ }
+
+ if (value) {
+ *value = kstrdup(isp, GFP_KERNEL);
+ if (*value == NULL)
+ return -ENOMEM;
+ }
+
+ if (len)
+ *len = strlen(isp) + 1;
+
+ return 0;
+}
+
+/**
+ * smack_inode_link - Smack check on link
+ * @old_dentry: the existing object
+ * @dir: unused
+ * @new_dentry: the new object
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry)
+{
+ int rc;
+ char *isp;
+
+ isp = smk_of_inode(old_dentry->d_inode);
+ rc = smk_curacc(isp, MAY_WRITE);
+
+ if (rc == 0 && new_dentry->d_inode != NULL) {
+ isp = smk_of_inode(new_dentry->d_inode);
+ rc = smk_curacc(isp, MAY_WRITE);
+ }
+
+ return rc;
+}
+
+/**
+ * smack_inode_unlink - Smack check on inode deletion
+ * @dir: containing directory object
+ * @dentry: file to unlink
+ *
+ * Returns 0 if current can write the containing directory
+ * and the object, error code otherwise
+ */
+static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *ip = dentry->d_inode;
+ int rc;
+
+ /*
+ * You need write access to the thing you're unlinking
+ */
+ rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
+ if (rc == 0)
+ /*
+ * You also need write access to the containing directory
+ */
+ rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+
+ return rc;
+}
+
+/**
+ * smack_inode_rmdir - Smack check on directory deletion
+ * @dir: containing directory object
+ * @dentry: directory to unlink
+ *
+ * Returns 0 if current can write the containing directory
+ * and the directory, error code otherwise
+ */
+static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ int rc;
+
+ /*
+ * You need write access to the thing you're removing
+ */
+ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+ if (rc == 0)
+ /*
+ * You also need write access to the containing directory
+ */
+ rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+
+ return rc;
+}
+
+/**
+ * smack_inode_rename - Smack check on rename
+ * @old_inode: the old directory
+ * @old_dentry: unused
+ * @new_inode: the new directory
+ * @new_dentry: unused
+ *
+ * Read and write access is required on both the old and
+ * new directories.
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_rename(struct inode *old_inode,
+ struct dentry *old_dentry,
+ struct inode *new_inode,
+ struct dentry *new_dentry)
+{
+ int rc;
+ char *isp;
+
+ isp = smk_of_inode(old_dentry->d_inode);
+ rc = smk_curacc(isp, MAY_READWRITE);
+
+ if (rc == 0 && new_dentry->d_inode != NULL) {
+ isp = smk_of_inode(new_dentry->d_inode);
+ rc = smk_curacc(isp, MAY_READWRITE);
+ }
+
+ return rc;
+}
+
+/**
+ * smack_inode_permission - Smack version of permission()
+ * @inode: the inode in question
+ * @mask: the access requested
+ * @nd: unused
+ *
+ * This is the important Smack hook.
+ *
+ * Returns 0 if access is permitted, -EACCES otherwise
+ */
+static int smack_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ /*
+ * No permission to check. Existence test. Yup, it's there.
+ */
+ if (mask == 0)
+ return 0;
+
+ return smk_curacc(smk_of_inode(inode), mask);
+}
+
+/**
+ * smack_inode_setattr - Smack check for setting attributes
+ * @dentry: the object
+ * @iattr: for the force flag
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+ /*
+ * Need to allow for clearing the setuid bit.
+ */
+ if (iattr->ia_valid & ATTR_FORCE)
+ return 0;
+
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_getattr - Smack check for getting attributes
+ * @mnt: unused
+ * @dentry: the object
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/**
+ * smack_inode_setxattr - Smack check for setting xattrs
+ * @dentry: the object
+ * @name: name of the attribute
+ * @value: unused
+ * @size: unused
+ * @flags: unused
+ *
+ * This protects the Smack attribute explicitly.
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_setxattr(struct dentry *dentry, char *name,
+ void *value, size_t size, int flags)
+{
+ if (!capable(CAP_MAC_ADMIN)) {
+ if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
+ strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
+ strcmp(name, XATTR_NAME_SMACKIPOUT) == 0)
+ return -EPERM;
+ }
+
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_post_setxattr - Apply the Smack update approved above
+ * @dentry: object
+ * @name: attribute name
+ * @value: attribute value
+ * @size: attribute size
+ * @flags: unused
+ *
+ * Set the pointer in the inode blob to the entry found
+ * in the master label list.
+ */
+static void smack_inode_post_setxattr(struct dentry *dentry, char *name,
+ void *value, size_t size, int flags)
+{
+ struct inode_smack *isp;
+ char *nsp;
+
+ /*
+ * Not SMACK
+ */
+ if (strcmp(name, XATTR_NAME_SMACK))
+ return;
+
+ if (size >= SMK_LABELLEN)
+ return;
+
+ isp = dentry->d_inode->i_security;
+
+ /*
+ * No locking is done here. This is a pointer
+ * assignment.
+ */
+ nsp = smk_import(value, size);
+ if (nsp != NULL)
+ isp->smk_inode = nsp;
+ else
+ isp->smk_inode = smack_known_invalid.smk_known;
+
+ return;
+}
+
+/*
+ * smack_inode_getxattr - Smack check on getxattr
+ * @dentry: the object
+ * @name: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_getxattr(struct dentry *dentry, char *name)
+{
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/*
+ * smack_inode_removexattr - Smack check on removexattr
+ * @dentry: the object
+ * @name: name of the attribute
+ *
+ * Removing the Smack attribute requires CAP_MAC_ADMIN
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_removexattr(struct dentry *dentry, char *name)
+{
+ if (strcmp(name, XATTR_NAME_SMACK) == 0 && !capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_getsecurity - get smack xattrs
+ * @inode: the object
+ * @name: attribute name
+ * @buffer: where to put the result
+ * @size: size of the buffer
+ * @err: unused
+ *
+ * Returns the size of the attribute or an error code
+ */
+static int smack_inode_getsecurity(const struct inode *inode,
+ const char *name, void **buffer,
+ bool alloc)
+{
+ struct socket_smack *ssp;
+ struct socket *sock;
+ struct super_block *sbp;
+ struct inode *ip = (struct inode *)inode;
+ char *isp;
+ int ilen;
+ int rc = 0;
+
+ if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+ isp = smk_of_inode(inode);
+ ilen = strlen(isp) + 1;
+ *buffer = isp;
+ return ilen;
+ }
+
+ /*
+ * The rest of the Smack xattrs are only on sockets.
+ */
+ sbp = ip->i_sb;
+ if (sbp->s_magic != SOCKFS_MAGIC)
+ return -EOPNOTSUPP;
+
+ sock = SOCKET_I(ip);
+ if (sock == NULL)
+ return -EOPNOTSUPP;
+
+ ssp = sock->sk->sk_security;
+
+ if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+ isp = ssp->smk_in;
+ else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
+ isp = ssp->smk_out;
+ else
+ return -EOPNOTSUPP;
+
+ ilen = strlen(isp) + 1;
+ if (rc == 0) {
+ *buffer = isp;
+ rc = ilen;
+ }
+
+ return rc;
+}
+
+
+/**
+ * smack_inode_listsecurity - list the Smack attributes
+ * @inode: the object
+ * @buffer: where they go
+ * @buffer_size: size of buffer
+ *
+ * Returns 0 on success, -EINVAL otherwise
+ */
+static int smack_inode_listsecurity(struct inode *inode, char *buffer,
+ size_t buffer_size)
+{
+ int len = strlen(XATTR_NAME_SMACK);
+
+ if (buffer != NULL && len <= buffer_size) {
+ memcpy(buffer, XATTR_NAME_SMACK, len);
+ return len;
+ }
+ return -EINVAL;
+}
+
+/*
+ * File Hooks
+ */
+
+/**
+ * smack_file_permission - Smack check on file operations
+ * @file: unused
+ * @mask: unused
+ *
+ * Returns 0
+ *
+ * Should access checks be done on each read or write?
+ * UNICOS and SELinux say yes.
+ * Trusted Solaris, Trusted Irix, and just about everyone else says no.
+ *
+ * I'll say no for now. Smack does not do the frequent
+ * label changing that SELinux does.
+ */
+static int smack_file_permission(struct file *file, int mask)
+{
+ return 0;
+}
+
+/**
+ * smack_file_alloc_security - assign a file security blob
+ * @file: the object
+ *
+ * The security blob for a file is a pointer to the master
+ * label list, so no allocation is done.
+ *
+ * Returns 0
+ */
+static int smack_file_alloc_security(struct file *file)
+{
+ file->f_security = current->security;
+ return 0;
+}
+
+/**
+ * smack_file_free_security - clear a file security blob
+ * @file: the object
+ *
+ * The security blob for a file is a pointer to the master
+ * label list, so no memory is freed.
+ */
+static void smack_file_free_security(struct file *file)
+{
+ file->f_security = NULL;
+}
+
+/**
+ * smack_file_ioctl - Smack check on ioctls
+ * @file: the object
+ * @cmd: what to do
+ * @arg: unused
+ *
+ * Relies heavily on the correct use of the ioctl command conventions.
+ *
+ * Returns 0 if allowed, error code otherwise
+ */
+static int smack_file_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ rc = smk_curacc(file->f_security, MAY_WRITE);
+
+ if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
+ rc = smk_curacc(file->f_security, MAY_READ);
+
+ return rc;
+}
+
+/**
+ * smack_file_lock - Smack check on file locking
+ * @file: the object
+ * @cmd unused
+ *
+ * Returns 0 if current has write access, error code otherwise
+ */
+static int smack_file_lock(struct file *file, unsigned int cmd)
+{
+ return smk_curacc(file->f_security, MAY_WRITE);
+}
+
+/**
+ * smack_file_fcntl - Smack check on fcntl
+ * @file: the object
+ * @cmd: what action to check
+ * @arg: unused
+ *
+ * Returns 0 if current has access, error code otherwise
+ */
+static int smack_file_fcntl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+
+ switch (cmd) {
+ case F_DUPFD:
+ case F_GETFD:
+ case F_GETFL:
+ case F_GETLK:
+ case F_GETOWN:
+ case F_GETSIG:
+ rc = smk_curacc(file->f_security, MAY_READ);
+ break;
+ case F_SETFD:
+ case F_SETFL:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_SETOWN:
+ case F_SETSIG:
+ rc = smk_curacc(file->f_security, MAY_WRITE);
+ break;
+ default:
+ rc = smk_curacc(file->f_security, MAY_READWRITE);
+ }
+
+ return rc;
+}
+
+/**
+ * smack_file_set_fowner - set the file security blob value
+ * @file: object in question
+ *
+ * Returns 0
+ * Further research may be required on this one.
+ */
+static int smack_file_set_fowner(struct file *file)
+{
+ file->f_security = current->security;
+ return 0;
+}
+
+/**
+ * smack_file_send_sigiotask - Smack on sigio
+ * @tsk: The target task
+ * @fown: the object the signal come from
+ * @signum: unused
+ *
+ * Allow a privileged task to get signals even if it shouldn't
+ *
+ * Returns 0 if a subject with the object's smack could
+ * write to the task, an error code otherwise.
+ */
+static int smack_file_send_sigiotask(struct task_struct *tsk,
+ struct fown_struct *fown, int signum)
+{
+ struct file *file;
+ int rc;
+
+ /*
+ * struct fown_struct is never outside the context of a struct file
+ */
+ file = container_of(fown, struct file, f_owner);
+ rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
+ if (rc != 0 && __capable(tsk, CAP_MAC_OVERRIDE))
+ return 0;
+ return rc;
+}
+
+/**
+ * smack_file_receive - Smack file receive check
+ * @file: the object
+ *
+ * Returns 0 if current has access, error code otherwise
+ */
+static int smack_file_receive(struct file *file)
+{
+ int may = 0;
+
+ /*
+ * This code relies on bitmasks.
+ */
+ if (file->f_mode & FMODE_READ)
+ may = MAY_READ;
+ if (file->f_mode & FMODE_WRITE)
+ may |= MAY_WRITE;
+
+ return smk_curacc(file->f_security, may);
+}
+
+/*
+ * Task hooks
+ */
+
+/**
+ * smack_task_alloc_security - "allocate" a task blob
+ * @tsk: the task in need of a blob
+ *
+ * Smack isn't using copies of blobs. Everyone
+ * points to an immutable list. No alloc required.
+ * No data copy required.
+ *
+ * Always returns 0
+ */
+static int smack_task_alloc_security(struct task_struct *tsk)
+{
+ tsk->security = current->security;
+
+ return 0;
+}
+
+/**
+ * smack_task_free_security - "free" a task blob
+ * @task: the task with the blob
+ *
+ * Smack isn't using copies of blobs. Everyone
+ * points to an immutable list. The blobs never go away.
+ * There is no leak here.
+ */
+static void smack_task_free_security(struct task_struct *task)
+{
+ task->security = NULL;
+}
+
+/**
+ * smack_task_setpgid - Smack check on setting pgid
+ * @p: the task object
+ * @pgid: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getpgid - Smack access check for getpgid
+ * @p: the object task
+ *
+ * Returns 0 if current can read the object task, error code otherwise
+ */
+static int smack_task_getpgid(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_getsid - Smack access check for getsid
+ * @p: the object task
+ *
+ * Returns 0 if current can read the object task, error code otherwise
+ */
+static int smack_task_getsid(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_getsecid - get the secid of the task
+ * @p: the object task
+ * @secid: where to put the result
+ *
+ * Sets the secid to contain a u32 version of the smack label.
+ */
+static void smack_task_getsecid(struct task_struct *p, u32 *secid)
+{
+ *secid = smack_to_secid(p->security);
+}
+
+/**
+ * smack_task_setnice - Smack check on setting nice
+ * @p: the task object
+ * @nice: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setnice(struct task_struct *p, int nice)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_setioprio - Smack check on setting ioprio
+ * @p: the task object
+ * @ioprio: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setioprio(struct task_struct *p, int ioprio)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getioprio - Smack check on reading ioprio
+ * @p: the task object
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_getioprio(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_setscheduler - Smack check on setting scheduler
+ * @p: the task object
+ * @policy: unused
+ * @lp: unused
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_setscheduler(struct task_struct *p, int policy,
+ struct sched_param *lp)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getscheduler - Smack check on reading scheduler
+ * @p: the task object
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_getscheduler(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_movememory - Smack check on moving memory
+ * @p: the task object
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_movememory(struct task_struct *p)
+{
+ return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_kill - Smack check on signal delivery
+ * @p: the task object
+ * @info: unused
+ * @sig: unused
+ * @secid: identifies the smack to use in lieu of current's
+ *
+ * Return 0 if write access is permitted
+ *
+ * The secid behavior is an artifact of an SELinux hack
+ * in the USB code. Someday it may go away.
+ */
+static int smack_task_kill(struct task_struct *p, struct siginfo *info,
+ int sig, u32 secid)
+{
+ /*
+ * Special cases where signals really ought to go through
+ * in spite of policy. Stephen Smalley suggests it may
+ * make sense to change the caller so that it doesn't
+ * bother with the LSM hook in these cases.
+ */
+ if (info != SEND_SIG_NOINFO &&
+ (is_si_special(info) || SI_FROMKERNEL(info)))
+ return 0;
+ /*
+ * Sending a signal requires that the sender
+ * can write the receiver.
+ */
+ if (secid == 0)
+ return smk_curacc(p->security, MAY_WRITE);
+ /*
+ * If the secid isn't 0 we're dealing with some USB IO
+ * specific behavior. This is not clean. For one thing
+ * we can't take privilege into account.
+ */
+ return smk_access(smack_from_secid(secid), p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_wait - Smack access check for waiting
+ * @p: task to wait for
+ *
+ * Returns 0 if current can wait for p, error code otherwise
+ */
+static int smack_task_wait(struct task_struct *p)
+{
+ int rc;
+
+ rc = smk_access(current->security, p->security, MAY_WRITE);
+ if (rc == 0)
+ return 0;
+
+ /*
+ * Allow the operation to succeed if either task
+ * has privilege to perform operations that might
+ * account for the smack labels having gotten to
+ * be different in the first place.
+ *
+ * This breaks the strict subjet/object access
+ * control ideal, taking the object's privilege
+ * state into account in the decision as well as
+ * the smack value.
+ */
+ if (capable(CAP_MAC_OVERRIDE) || __capable(p, CAP_MAC_OVERRIDE))
+ return 0;
+
+ return rc;
+}
+
+/**
+ * smack_task_to_inode - copy task smack into the inode blob
+ * @p: task to copy from
+ * inode: inode to copy to
+ *
+ * Sets the smack pointer in the inode security blob
+ */
+static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
+{
+ struct inode_smack *isp = inode->i_security;
+ isp->smk_inode = p->security;
+}
+
+/*
+ * Socket hooks.
+ */
+
+/**
+ * smack_sk_alloc_security - Allocate a socket blob
+ * @sk: the socket
+ * @family: unused
+ * @priority: memory allocation priority
+ *
+ * Assign Smack pointers to current
+ *
+ * Returns 0 on success, -ENOMEM is there's no memory
+ */
+static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+{
+ char *csp = current->security;
+ struct socket_smack *ssp;
+
+ ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
+ if (ssp == NULL)
+ return -ENOMEM;
+
+ ssp->smk_in = csp;
+ ssp->smk_out = csp;
+ ssp->smk_packet[0] = '\0';
+
+ sk->sk_security = ssp;
+
+ return 0;
+}
+
+/**
+ * smack_sk_free_security - Free a socket blob
+ * @sk: the socket
+ *
+ * Clears the blob pointer
+ */
+static void smack_sk_free_security(struct sock *sk)
+{
+ kfree(sk->sk_security);
+}
+
+/**
+ * smack_set_catset - convert a capset to netlabel mls categories
+ * @catset: the Smack categories
+ * @sap: where to put the netlabel categories
+ *
+ * Allocates and fills attr.mls.cat
+ */
+static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap)
+{
+ unsigned char *cp;
+ unsigned char m;
+ int cat;
+ int rc;
+ int byte;
+
+ if (catset == 0)
+ return;
+
+ sap->flags |= NETLBL_SECATTR_MLS_CAT;
+ sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ sap->attr.mls.cat->startbit = 0;
+
+ for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++)
+ for (m = 0x80; m != 0; m >>= 1, cat++) {
+ if ((m & *cp) == 0)
+ continue;
+ rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat,
+ cat, GFP_ATOMIC);
+ }
+}
+
+/**
+ * smack_to_secattr - fill a secattr from a smack value
+ * @smack: the smack value
+ * @nlsp: where the result goes
+ *
+ * Casey says that CIPSO is good enough for now.
+ * It can be used to effect.
+ * It can also be abused to effect when necessary.
+ * Appologies to the TSIG group in general and GW in particular.
+ */
+static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
+{
+ struct smack_cipso cipso;
+ int rc;
+
+ switch (smack_net_nltype) {
+ case NETLBL_NLTYPE_CIPSOV4:
+ nlsp->domain = NULL;
+ nlsp->flags = NETLBL_SECATTR_DOMAIN;
+ nlsp->flags |= NETLBL_SECATTR_MLS_LVL;
+
+ rc = smack_to_cipso(smack, &cipso);
+ if (rc == 0) {
+ nlsp->attr.mls.lvl = cipso.smk_level;
+ smack_set_catset(cipso.smk_catset, nlsp);
+ } else {
+ nlsp->attr.mls.lvl = smack_cipso_direct;
+ smack_set_catset(smack, nlsp);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * smack_netlabel - Set the secattr on a socket
+ * @sk: the socket
+ *
+ * Convert the outbound smack value (smk_out) to a
+ * secattr and attach it to the socket.
+ *
+ * Returns 0 on success or an error code
+ */
+static int smack_netlabel(struct sock *sk)
+{
+ struct socket_smack *ssp = sk->sk_security;
+ struct netlbl_lsm_secattr secattr;
+ int rc = 0;
+
+ netlbl_secattr_init(&secattr);
+ smack_to_secattr(ssp->smk_out, &secattr);
+ if (secattr.flags != NETLBL_SECATTR_NONE)
+ rc = netlbl_sock_setattr(sk, &secattr);
+
+ netlbl_secattr_destroy(&secattr);
+ return rc;
+}
+
+/**
+ * smack_inode_setsecurity - set smack xattrs
+ * @inode: the object
+ * @name: attribute name
+ * @value: attribute value
+ * @size: size of the attribute
+ * @flags: unused
+ *
+ * Sets the named attribute in the appropriate blob
+ *
+ * Returns 0 on success, or an error code
+ */
+static int smack_inode_setsecurity(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ char *sp;
+ struct inode_smack *nsp = inode->i_security;
+ struct socket_smack *ssp;
+ struct socket *sock;
+
+ if (value == NULL || size > SMK_LABELLEN)
+ return -EACCES;
+
+ sp = smk_import(value, size);
+ if (sp == NULL)
+ return -EINVAL;
+
+ if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+ nsp->smk_inode = sp;
+ return 0;
+ }
+ /*
+ * The rest of the Smack xattrs are only on sockets.
+ */
+ if (inode->i_sb->s_magic != SOCKFS_MAGIC)
+ return -EOPNOTSUPP;
+
+ sock = SOCKET_I(inode);
+ if (sock == NULL)
+ return -EOPNOTSUPP;
+
+ ssp = sock->sk->sk_security;
+
+ if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+ ssp->smk_in = sp;
+ else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
+ ssp->smk_out = sp;
+ return smack_netlabel(sock->sk);
+ } else
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+/**
+ * smack_socket_post_create - finish socket setup
+ * @sock: the socket
+ * @family: protocol family
+ * @type: unused
+ * @protocol: unused
+ * @kern: unused
+ *
+ * Sets the netlabel information on the socket
+ *
+ * Returns 0 on success, and error code otherwise
+ */
+static int smack_socket_post_create(struct socket *sock, int family,
+ int type, int protocol, int kern)
+{
+ if (family != PF_INET)
+ return 0;
+ /*
+ * Set the outbound netlbl.
+ */
+ return smack_netlabel(sock->sk);
+}
+
+/**
+ * smack_flags_to_may - convert S_ to MAY_ values
+ * @flags: the S_ value
+ *
+ * Returns the equivalent MAY_ value
+ */
+static int smack_flags_to_may(int flags)
+{
+ int may = 0;
+
+ if (flags & S_IRUGO)
+ may |= MAY_READ;
+ if (flags & S_IWUGO)
+ may |= MAY_WRITE;
+ if (flags & S_IXUGO)
+ may |= MAY_EXEC;
+
+ return may;
+}
+
+/**
+ * smack_msg_msg_alloc_security - Set the security blob for msg_msg
+ * @msg: the object
+ *
+ * Returns 0
+ */
+static int smack_msg_msg_alloc_security(struct msg_msg *msg)
+{
+ msg->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_msg_msg_free_security - Clear the security blob for msg_msg
+ * @msg: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_msg_msg_free_security(struct msg_msg *msg)
+{
+ msg->security = NULL;
+}
+
+/**
+ * smack_of_shm - the smack pointer for the shm
+ * @shp: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_shm(struct shmid_kernel *shp)
+{
+ return (char *)shp->shm_perm.security;
+}
+
+/**
+ * smack_shm_alloc_security - Set the security blob for shm
+ * @shp: the object
+ *
+ * Returns 0
+ */
+static int smack_shm_alloc_security(struct shmid_kernel *shp)
+{
+ struct kern_ipc_perm *isp = &shp->shm_perm;
+
+ isp->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_shm_free_security - Clear the security blob for shm
+ * @shp: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_shm_free_security(struct shmid_kernel *shp)
+{
+ struct kern_ipc_perm *isp = &shp->shm_perm;
+
+ isp->security = NULL;
+}
+
+/**
+ * smack_shm_associate - Smack access check for shm
+ * @shp: the object
+ * @shmflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
+{
+ char *ssp = smack_of_shm(shp);
+ int may;
+
+ may = smack_flags_to_may(shmflg);
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_shm_shmctl - Smack access check for shm
+ * @shp: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
+{
+ char *ssp = smack_of_shm(shp);
+ int may;
+
+ switch (cmd) {
+ case IPC_STAT:
+ case SHM_STAT:
+ may = MAY_READ;
+ break;
+ case IPC_SET:
+ case SHM_LOCK:
+ case SHM_UNLOCK:
+ case IPC_RMID:
+ may = MAY_READWRITE;
+ break;
+ case IPC_INFO:
+ case SHM_INFO:
+ /*
+ * System level information.
+ */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_shm_shmat - Smack access for shmat
+ * @shp: the object
+ * @shmaddr: unused
+ * @shmflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
+ int shmflg)
+{
+ char *ssp = smack_of_shm(shp);
+ int may;
+
+ may = smack_flags_to_may(shmflg);
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_of_sem - the smack pointer for the sem
+ * @sma: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_sem(struct sem_array *sma)
+{
+ return (char *)sma->sem_perm.security;
+}
+
+/**
+ * smack_sem_alloc_security - Set the security blob for sem
+ * @sma: the object
+ *
+ * Returns 0
+ */
+static int smack_sem_alloc_security(struct sem_array *sma)
+{
+ struct kern_ipc_perm *isp = &sma->sem_perm;
+
+ isp->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_sem_free_security - Clear the security blob for sem
+ * @sma: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_sem_free_security(struct sem_array *sma)
+{
+ struct kern_ipc_perm *isp = &sma->sem_perm;
+
+ isp->security = NULL;
+}
+
+/**
+ * smack_sem_associate - Smack access check for sem
+ * @sma: the object
+ * @semflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_sem_associate(struct sem_array *sma, int semflg)
+{
+ char *ssp = smack_of_sem(sma);
+ int may;
+
+ may = smack_flags_to_may(semflg);
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_sem_shmctl - Smack access check for sem
+ * @sma: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_sem_semctl(struct sem_array *sma, int cmd)
+{
+ char *ssp = smack_of_sem(sma);
+ int may;
+
+ switch (cmd) {
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETVAL:
+ case GETALL:
+ case IPC_STAT:
+ case SEM_STAT:
+ may = MAY_READ;
+ break;
+ case SETVAL:
+ case SETALL:
+ case IPC_RMID:
+ case IPC_SET:
+ may = MAY_READWRITE;
+ break;
+ case IPC_INFO:
+ case SEM_INFO:
+ /*
+ * System level information
+ */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_sem_semop - Smack checks of semaphore operations
+ * @sma: the object
+ * @sops: unused
+ * @nsops: unused
+ * @alter: unused
+ *
+ * Treated as read and write in all cases.
+ *
+ * Returns 0 if access is allowed, error code otherwise
+ */
+static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
+ unsigned nsops, int alter)
+{
+ char *ssp = smack_of_sem(sma);
+
+ return smk_curacc(ssp, MAY_READWRITE);
+}
+
+/**
+ * smack_msg_alloc_security - Set the security blob for msg
+ * @msq: the object
+ *
+ * Returns 0
+ */
+static int smack_msg_queue_alloc_security(struct msg_queue *msq)
+{
+ struct kern_ipc_perm *kisp = &msq->q_perm;
+
+ kisp->security = current->security;
+ return 0;
+}
+
+/**
+ * smack_msg_free_security - Clear the security blob for msg
+ * @msq: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_msg_queue_free_security(struct msg_queue *msq)
+{
+ struct kern_ipc_perm *kisp = &msq->q_perm;
+
+ kisp->security = NULL;
+}
+
+/**
+ * smack_of_msq - the smack pointer for the msq
+ * @msq: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_msq(struct msg_queue *msq)
+{
+ return (char *)msq->q_perm.security;
+}
+
+/**
+ * smack_msg_queue_associate - Smack access check for msg_queue
+ * @msq: the object
+ * @msqflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
+{
+ char *msp = smack_of_msq(msq);
+ int may;
+
+ may = smack_flags_to_may(msqflg);
+ return smk_curacc(msp, may);
+}
+
+/**
+ * smack_msg_queue_msgctl - Smack access check for msg_queue
+ * @msq: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+{
+ char *msp = smack_of_msq(msq);
+ int may;
+
+ switch (cmd) {
+ case IPC_STAT:
+ case MSG_STAT:
+ may = MAY_READ;
+ break;
+ case IPC_SET:
+ case IPC_RMID:
+ may = MAY_READWRITE;
+ break;
+ case IPC_INFO:
+ case MSG_INFO:
+ /*
+ * System level information
+ */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return smk_curacc(msp, may);
+}
+
+/**
+ * smack_msg_queue_msgsnd - Smack access check for msg_queue
+ * @msq: the object
+ * @msg: unused
+ * @msqflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
+ int msqflg)
+{
+ char *msp = smack_of_msq(msq);
+ int rc;
+
+ rc = smack_flags_to_may(msqflg);
+ return smk_curacc(msp, rc);
+}
+
+/**
+ * smack_msg_queue_msgsnd - Smack access check for msg_queue
+ * @msq: the object
+ * @msg: unused
+ * @target: unused
+ * @type: unused
+ * @mode: unused
+ *
+ * Returns 0 if current has read and write access, error code otherwise
+ */
+static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+ struct task_struct *target, long type, int mode)
+{
+ char *msp = smack_of_msq(msq);
+
+ return smk_curacc(msp, MAY_READWRITE);
+}
+
+/**
+ * smack_ipc_permission - Smack access for ipc_permission()
+ * @ipp: the object permissions
+ * @flag: access requested
+ *
+ * Returns 0 if current has read and write access, error code otherwise
+ */
+static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
+{
+ char *isp = ipp->security;
+ int may;
+
+ may = smack_flags_to_may(flag);
+ return smk_curacc(isp, may);
+}
+
+/**
+ * smack_d_instantiate - Make sure the blob is correct on an inode
+ * @opt_dentry: unused
+ * @inode: the object
+ *
+ * Set the inode's security blob if it hasn't been done already.
+ */
+static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
+{
+ struct super_block *sbp;
+ struct superblock_smack *sbsp;
+ struct inode_smack *isp;
+ char *csp = current->security;
+ char *fetched;
+ char *final;
+ struct dentry *dp;
+
+ if (inode == NULL)
+ return;
+
+ isp = inode->i_security;
+
+ mutex_lock(&isp->smk_lock);
+ /*
+ * If the inode is already instantiated
+ * take the quick way out
+ */
+ if (isp->smk_flags & SMK_INODE_INSTANT)
+ goto unlockandout;
+
+ sbp = inode->i_sb;
+ sbsp = sbp->s_security;
+ /*
+ * We're going to use the superblock default label
+ * if there's no label on the file.
+ */
+ final = sbsp->smk_default;
+
+ /*
+ * This is pretty hackish.
+ * Casey says that we shouldn't have to do
+ * file system specific code, but it does help
+ * with keeping it simple.
+ */
+ switch (sbp->s_magic) {
+ case SMACK_MAGIC:
+ /*
+ * Casey says that it's a little embarassing
+ * that the smack file system doesn't do
+ * extended attributes.
+ */
+ final = smack_known_star.smk_known;
+ break;
+ case PIPEFS_MAGIC:
+ /*
+ * Casey says pipes are easy (?)
+ */
+ final = smack_known_star.smk_known;
+ break;
+ case DEVPTS_SUPER_MAGIC:
+ /*
+ * devpts seems content with the label of the task.
+ * Programs that change smack have to treat the
+ * pty with respect.
+ */
+ final = csp;
+ break;
+ case SOCKFS_MAGIC:
+ /*
+ * Casey says sockets get the smack of the task.
+ */
+ final = csp;
+ break;
+ case PROC_SUPER_MAGIC:
+ /*
+ * Casey says procfs appears not to care.
+ * The superblock default suffices.
+ */
+ break;
+ case TMPFS_MAGIC:
+ /*
+ * Device labels should come from the filesystem,
+ * but watch out, because they're volitile,
+ * getting recreated on every reboot.
+ */
+ final = smack_known_star.smk_known;
+ /*
+ * No break.
+ *
+ * If a smack value has been set we want to use it,
+ * but since tmpfs isn't giving us the opportunity
+ * to set mount options simulate setting the
+ * superblock default.
+ */
+ default:
+ /*
+ * This isn't an understood special case.
+ * Get the value from the xattr.
+ *
+ * No xattr support means, alas, no SMACK label.
+ * Use the aforeapplied default.
+ * It would be curious if the label of the task
+ * does not match that assigned.
+ */
+ if (inode->i_op->getxattr == NULL)
+ break;
+ /*
+ * Get the dentry for xattr.
+ */
+ if (opt_dentry == NULL) {
+ dp = d_find_alias(inode);
+ if (dp == NULL)
+ break;
+ } else {
+ dp = dget(opt_dentry);
+ if (dp == NULL)
+ break;
+ }
+
+ fetched = smk_fetch(inode, dp);
+ if (fetched != NULL)
+ final = fetched;
+
+ dput(dp);
+ break;
+ }
+
+ if (final == NULL)
+ isp->smk_inode = csp;
+ else
+ isp->smk_inode = final;
+
+ isp->smk_flags |= SMK_INODE_INSTANT;
+
+unlockandout:
+ mutex_unlock(&isp->smk_lock);
+ return;
+}
+
+/**
+ * smack_getprocattr - Smack process attribute access
+ * @p: the object task
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: where to put the result
+ *
+ * Places a copy of the task Smack into value
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_getprocattr(struct task_struct *p, char *name, char **value)
+{
+ char *cp;
+ int slen;
+
+ if (strcmp(name, "current") != 0)
+ return -EINVAL;
+
+ cp = kstrdup(p->security, GFP_KERNEL);
+ if (cp == NULL)
+ return -ENOMEM;
+
+ slen = strlen(cp);
+ *value = cp;
+ return slen;
+}
+
+/**
+ * smack_setprocattr - Smack process attribute setting
+ * @p: the object task
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: the value to set
+ * @size: the size of the value
+ *
+ * Sets the Smack value of the task. Only setting self
+ * is permitted and only with privilege
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_setprocattr(struct task_struct *p, char *name,
+ void *value, size_t size)
+{
+ char *newsmack;
+
+ if (!__capable(p, CAP_MAC_ADMIN))
+ return -EPERM;
+
+ /*
+ * Changing another process' Smack value is too dangerous
+ * and supports no sane use case.
+ */
+ if (p != current)
+ return -EPERM;
+
+ if (value == NULL || size == 0 || size >= SMK_LABELLEN)
+ return -EINVAL;
+
+ if (strcmp(name, "current") != 0)
+ return -EINVAL;
+
+ newsmack = smk_import(value, size);
+ if (newsmack == NULL)
+ return -EINVAL;
+
+ p->security = newsmack;
+ return size;
+}
+
+/**
+ * smack_unix_stream_connect - Smack access on UDS
+ * @sock: one socket
+ * @other: the other socket
+ * @newsk: unused
+ *
+ * Return 0 if a subject with the smack of sock could access
+ * an object with the smack of other, otherwise an error code
+ */
+static int smack_unix_stream_connect(struct socket *sock,
+ struct socket *other, struct sock *newsk)
+{
+ struct inode *sp = SOCK_INODE(sock);
+ struct inode *op = SOCK_INODE(other);
+
+ return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE);
+}
+
+/**
+ * smack_unix_may_send - Smack access on UDS
+ * @sock: one socket
+ * @other: the other socket
+ *
+ * Return 0 if a subject with the smack of sock could access
+ * an object with the smack of other, otherwise an error code
+ */
+static int smack_unix_may_send(struct socket *sock, struct socket *other)
+{
+ struct inode *sp = SOCK_INODE(sock);
+ struct inode *op = SOCK_INODE(other);
+
+ return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
+}
+
+/**
+ * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
+ * pair to smack
+ * @sap: netlabel secattr
+ * @sip: where to put the result
+ *
+ * Copies a smack label into sip
+ */
+static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
+{
+ char smack[SMK_LABELLEN];
+ int pcat;
+
+ if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
+ /*
+ * If there are flags but no level netlabel isn't
+ * behaving the way we expect it to.
+ *
+ * Without guidance regarding the smack value
+ * for the packet fall back on the network
+ * ambient value.
+ */
+ strncpy(sip, smack_net_ambient, SMK_MAXLEN);
+ return;
+ }
+ /*
+ * Get the categories, if any
+ */
+ memset(smack, '\0', SMK_LABELLEN);
+ if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
+ for (pcat = -1;;) {
+ pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat,
+ pcat + 1);
+ if (pcat < 0)
+ break;
+ smack_catset_bit(pcat, smack);
+ }
+ /*
+ * If it is CIPSO using smack direct mapping
+ * we are already done. WeeHee.
+ */
+ if (sap->attr.mls.lvl == smack_cipso_direct) {
+ memcpy(sip, smack, SMK_MAXLEN);
+ return;
+ }
+ /*
+ * Look it up in the supplied table if it is not a direct mapping.
+ */
+ smack_from_cipso(sap->attr.mls.lvl, smack, sip);
+ return;
+}
+
+/**
+ * smack_socket_sock_rcv_skb - Smack packet delivery access check
+ * @sk: socket
+ * @skb: packet
+ *
+ * Returns 0 if the packet should be delivered, an error code otherwise
+ */
+static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct netlbl_lsm_secattr secattr;
+ struct socket_smack *ssp = sk->sk_security;
+ char smack[SMK_LABELLEN];
+ int rc;
+
+ if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+ return 0;
+
+ /*
+ * Translate what netlabel gave us.
+ */
+ memset(smack, '\0', SMK_LABELLEN);
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
+ if (rc == 0)
+ smack_from_secattr(&secattr, smack);
+ else
+ strncpy(smack, smack_net_ambient, SMK_MAXLEN);
+ netlbl_secattr_destroy(&secattr);
+ /*
+ * Receiving a packet requires that the other end
+ * be able to write here. Read access is not required.
+ * This is the simplist possible security model
+ * for networking.
+ */
+ return smk_access(smack, ssp->smk_in, MAY_WRITE);
+}
+
+/**
+ * smack_socket_getpeersec_stream - pull in packet label
+ * @sock: the socket
+ * @optval: user's destination
+ * @optlen: size thereof
+ * @len: max thereoe
+ *
+ * returns zero on success, an error code otherwise
+ */
+static int smack_socket_getpeersec_stream(struct socket *sock,
+ char __user *optval,
+ int __user *optlen, unsigned len)
+{
+ struct socket_smack *ssp;
+ int slen;
+ int rc = 0;
+
+ ssp = sock->sk->sk_security;
+ slen = strlen(ssp->smk_packet) + 1;
+
+ if (slen > len)
+ rc = -ERANGE;
+ else if (copy_to_user(optval, ssp->smk_packet, slen) != 0)
+ rc = -EFAULT;
+
+ if (put_user(slen, optlen) != 0)
+ rc = -EFAULT;
+
+ return rc;
+}
+
+
+/**
+ * smack_socket_getpeersec_dgram - pull in packet label
+ * @sock: the socket
+ * @skb: packet data
+ * @secid: pointer to where to put the secid of the packet
+ *
+ * Sets the netlabel socket state on sk from parent
+ */
+static int smack_socket_getpeersec_dgram(struct socket *sock,
+ struct sk_buff *skb, u32 *secid)
+
+{
+ struct netlbl_lsm_secattr secattr;
+ struct sock *sk;
+ char smack[SMK_LABELLEN];
+ int family = PF_INET;
+ u32 s;
+ int rc;
+
+ /*
+ * Only works for families with packets.
+ */
+ if (sock != NULL) {
+ sk = sock->sk;
+ if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+ return 0;
+ family = sk->sk_family;
+ }
+ /*
+ * Translate what netlabel gave us.
+ */
+ memset(smack, '\0', SMK_LABELLEN);
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_skbuff_getattr(skb, family, &secattr);
+ if (rc == 0)
+ smack_from_secattr(&secattr, smack);
+ netlbl_secattr_destroy(&secattr);
+
+ /*
+ * Give up if we couldn't get anything
+ */
+ if (rc != 0)
+ return rc;
+
+ s = smack_to_secid(smack);
+ if (s == 0)
+ return -EINVAL;
+
+ *secid = s;
+ return 0;
+}
+
+/**
+ * smack_sock_graft - graft access state between two sockets
+ * @sk: fresh sock
+ * @parent: donor socket
+ *
+ * Sets the netlabel socket state on sk from parent
+ */
+static void smack_sock_graft(struct sock *sk, struct socket *parent)
+{
+ struct socket_smack *ssp;
+ int rc;
+
+ if (sk == NULL)
+ return;
+
+ if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+ return;
+
+ ssp = sk->sk_security;
+ ssp->smk_in = current->security;
+ ssp->smk_out = current->security;
+ ssp->smk_packet[0] = '\0';
+
+ rc = smack_netlabel(sk);
+}
+
+/**
+ * smack_inet_conn_request - Smack access check on connect
+ * @sk: socket involved
+ * @skb: packet
+ * @req: unused
+ *
+ * Returns 0 if a task with the packet label could write to
+ * the socket, otherwise an error code
+ */
+static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req)
+{
+ struct netlbl_lsm_secattr skb_secattr;
+ struct socket_smack *ssp = sk->sk_security;
+ char smack[SMK_LABELLEN];
+ int rc;
+
+ if (skb == NULL)
+ return -EACCES;
+
+ memset(smack, '\0', SMK_LABELLEN);
+ netlbl_secattr_init(&skb_secattr);
+ rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
+ if (rc == 0)
+ smack_from_secattr(&skb_secattr, smack);
+ else
+ strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
+ netlbl_secattr_destroy(&skb_secattr);
+ /*
+ * Receiving a packet requires that the other end
+ * be able to write here. Read access is not required.
+ *
+ * If the request is successful save the peer's label
+ * so that SO_PEERCRED can report it.
+ */
+ rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+ if (rc == 0)
+ strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
+
+ return rc;
+}
+
+/*
+ * Key management security hooks
+ *
+ * Casey has not tested key support very heavily.
+ * The permission check is most likely too restrictive.
+ * If you care about keys please have a look.
+ */
+#ifdef CONFIG_KEYS
+
+/**
+ * smack_key_alloc - Set the key security blob
+ * @key: object
+ * @tsk: the task associated with the key
+ * @flags: unused
+ *
+ * No allocation required
+ *
+ * Returns 0
+ */
+static int smack_key_alloc(struct key *key, struct task_struct *tsk,
+ unsigned long flags)
+{
+ key->security = tsk->security;
+ return 0;
+}
+
+/**
+ * smack_key_free - Clear the key security blob
+ * @key: the object
+ *
+ * Clear the blob pointer
+ */
+static void smack_key_free(struct key *key)
+{
+ key->security = NULL;
+}
+
+/*
+ * smack_key_permission - Smack access on a key
+ * @key_ref: gets to the object
+ * @context: task involved
+ * @perm: unused
+ *
+ * Return 0 if the task has read and write to the object,
+ * an error code otherwise
+ */
+static int smack_key_permission(key_ref_t key_ref,
+ struct task_struct *context, key_perm_t perm)
+{
+ struct key *keyp;
+
+ keyp = key_ref_to_ptr(key_ref);
+ if (keyp == NULL)
+ return -EINVAL;
+ /*
+ * If the key hasn't been initialized give it access so that
+ * it may do so.
+ */
+ if (keyp->security == NULL)
+ return 0;
+ /*
+ * This should not occur
+ */
+ if (context->security == NULL)
+ return -EACCES;
+
+ return smk_access(context->security, keyp->security, MAY_READWRITE);
+}
+#endif /* CONFIG_KEYS */
+
+/*
+ * smack_secid_to_secctx - return the smack label for a secid
+ * @secid: incoming integer
+ * @secdata: destination
+ * @seclen: how long it is
+ *
+ * Exists for networking code.
+ */
+static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+{
+ char *sp = smack_from_secid(secid);
+
+ *secdata = sp;
+ *seclen = strlen(sp);
+ return 0;
+}
+
+/*
+ * smack_release_secctx - don't do anything.
+ * @key_ref: unused
+ * @context: unused
+ * @perm: unused
+ *
+ * Exists to make sure nothing gets done, and properly
+ */
+static void smack_release_secctx(char *secdata, u32 seclen)
+{
+}
+
+static struct security_operations smack_ops = {
+ .ptrace = smack_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .syslog = smack_syslog,
+ .settime = cap_settime,
+ .vm_enough_memory = cap_vm_enough_memory,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+
+ .sb_alloc_security = smack_sb_alloc_security,
+ .sb_free_security = smack_sb_free_security,
+ .sb_copy_data = smack_sb_copy_data,
+ .sb_kern_mount = smack_sb_kern_mount,
+ .sb_statfs = smack_sb_statfs,
+ .sb_mount = smack_sb_mount,
+ .sb_umount = smack_sb_umount,
+
+ .inode_alloc_security = smack_inode_alloc_security,
+ .inode_free_security = smack_inode_free_security,
+ .inode_init_security = smack_inode_init_security,
+ .inode_link = smack_inode_link,
+ .inode_unlink = smack_inode_unlink,
+ .inode_rmdir = smack_inode_rmdir,
+ .inode_rename = smack_inode_rename,
+ .inode_permission = smack_inode_permission,
+ .inode_setattr = smack_inode_setattr,
+ .inode_getattr = smack_inode_getattr,
+ .inode_setxattr = smack_inode_setxattr,
+ .inode_post_setxattr = smack_inode_post_setxattr,
+ .inode_getxattr = smack_inode_getxattr,
+ .inode_removexattr = smack_inode_removexattr,
+ .inode_getsecurity = smack_inode_getsecurity,
+ .inode_setsecurity = smack_inode_setsecurity,
+ .inode_listsecurity = smack_inode_listsecurity,
+
+ .file_permission = smack_file_permission,
+ .file_alloc_security = smack_file_alloc_security,
+ .file_free_security = smack_file_free_security,
+ .file_ioctl = smack_file_ioctl,
+ .file_lock = smack_file_lock,
+ .file_fcntl = smack_file_fcntl,
+ .file_set_fowner = smack_file_set_fowner,
+ .file_send_sigiotask = smack_file_send_sigiotask,
+ .file_receive = smack_file_receive,
+
+ .task_alloc_security = smack_task_alloc_security,
+ .task_free_security = smack_task_free_security,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_setpgid = smack_task_setpgid,
+ .task_getpgid = smack_task_getpgid,
+ .task_getsid = smack_task_getsid,
+ .task_getsecid = smack_task_getsecid,
+ .task_setnice = smack_task_setnice,
+ .task_setioprio = smack_task_setioprio,
+ .task_getioprio = smack_task_getioprio,
+ .task_setscheduler = smack_task_setscheduler,
+ .task_getscheduler = smack_task_getscheduler,
+ .task_movememory = smack_task_movememory,
+ .task_kill = smack_task_kill,
+ .task_wait = smack_task_wait,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .task_to_inode = smack_task_to_inode,
+
+ .ipc_permission = smack_ipc_permission,
+
+ .msg_msg_alloc_security = smack_msg_msg_alloc_security,
+ .msg_msg_free_security = smack_msg_msg_free_security,
+
+ .msg_queue_alloc_security = smack_msg_queue_alloc_security,
+ .msg_queue_free_security = smack_msg_queue_free_security,
+ .msg_queue_associate = smack_msg_queue_associate,
+ .msg_queue_msgctl = smack_msg_queue_msgctl,
+ .msg_queue_msgsnd = smack_msg_queue_msgsnd,
+ .msg_queue_msgrcv = smack_msg_queue_msgrcv,
+
+ .shm_alloc_security = smack_shm_alloc_security,
+ .shm_free_security = smack_shm_free_security,
+ .shm_associate = smack_shm_associate,
+ .shm_shmctl = smack_shm_shmctl,
+ .shm_shmat = smack_shm_shmat,
+
+ .sem_alloc_security = smack_sem_alloc_security,
+ .sem_free_security = smack_sem_free_security,
+ .sem_associate = smack_sem_associate,
+ .sem_semctl = smack_sem_semctl,
+ .sem_semop = smack_sem_semop,
+
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ .d_instantiate = smack_d_instantiate,
+
+ .getprocattr = smack_getprocattr,
+ .setprocattr = smack_setprocattr,
+
+ .unix_stream_connect = smack_unix_stream_connect,
+ .unix_may_send = smack_unix_may_send,
+
+ .socket_post_create = smack_socket_post_create,
+ .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
+ .socket_getpeersec_stream = smack_socket_getpeersec_stream,
+ .socket_getpeersec_dgram = smack_socket_getpeersec_dgram,
+ .sk_alloc_security = smack_sk_alloc_security,
+ .sk_free_security = smack_sk_free_security,
+ .sock_graft = smack_sock_graft,
+ .inet_conn_request = smack_inet_conn_request,
+ /* key management security hooks */
+#ifdef CONFIG_KEYS
+ .key_alloc = smack_key_alloc,
+ .key_free = smack_key_free,
+ .key_permission = smack_key_permission,
+#endif /* CONFIG_KEYS */
+ .secid_to_secctx = smack_secid_to_secctx,
+ .release_secctx = smack_release_secctx,
+};
+
+/**
+ * smack_init - initialize the smack system
+ *
+ * Returns 0
+ */
+static __init int smack_init(void)
+{
+ printk(KERN_INFO "Smack: Initializing.\n");
+
+ /*
+ * Set the security state for the initial task.
+ */
+ current->security = &smack_known_floor.smk_known;
+
+ /*
+ * Initialize locks
+ */
+ spin_lock_init(&smack_known_unset.smk_cipsolock);
+ spin_lock_init(&smack_known_huh.smk_cipsolock);
+ spin_lock_init(&smack_known_hat.smk_cipsolock);
+ spin_lock_init(&smack_known_star.smk_cipsolock);
+ spin_lock_init(&smack_known_floor.smk_cipsolock);
+ spin_lock_init(&smack_known_invalid.smk_cipsolock);
+
+ /*
+ * Register with LSM
+ */
+ if (register_security(&smack_ops))
+ panic("smack: Unable to register with kernel.\n");
+
+ return 0;
+}
+
+/*
+ * Smack requires early initialization in order to label
+ * all processes and objects when they are created.
+ */
+security_initcall(smack_init);
+
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
new file mode 100644
index 0000000..15aa37f
--- /dev/null
+++ b/security/smack/smackfs.c
@@ -0,0 +1,981 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * Authors:
+ * Casey Schaufler <casey@schaufler-ca.com>
+ * Ahmed S. Darwish <darwish.07@gmail.com>
+ *
+ * Special thanks to the authors of selinuxfs.
+ *
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * James Morris <jmorris@redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
+#include <linux/mutex.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <linux/seq_file.h>
+#include <linux/ctype.h>
+#include "smack.h"
+
+/*
+ * smackfs pseudo filesystem.
+ */
+
+enum smk_inos {
+ SMK_ROOT_INO = 2,
+ SMK_LOAD = 3, /* load policy */
+ SMK_CIPSO = 4, /* load label -> CIPSO mapping */
+ SMK_DOI = 5, /* CIPSO DOI */
+ SMK_DIRECT = 6, /* CIPSO level indicating direct label */
+ SMK_AMBIENT = 7, /* internet ambient label */
+ SMK_NLTYPE = 8, /* label scheme to use by default */
+};
+
+/*
+ * List locks
+ */
+static DEFINE_MUTEX(smack_list_lock);
+static DEFINE_MUTEX(smack_cipso_lock);
+
+/*
+ * This is the "ambient" label for network traffic.
+ * If it isn't somehow marked, use this.
+ * It can be reset via smackfs/ambient
+ */
+char *smack_net_ambient = smack_known_floor.smk_known;
+
+/*
+ * This is the default packet marking scheme for network traffic.
+ * It can be reset via smackfs/nltype
+ */
+int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
+
+/*
+ * This is the level in a CIPSO header that indicates a
+ * smack label is contained directly in the category set.
+ * It can be reset via smackfs/direct
+ */
+int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
+
+static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
+struct smk_list_entry *smack_list;
+
+#define SEQ_READ_FINISHED 1
+
+/*
+ * Disable concurrent writing open() operations
+ */
+static struct semaphore smack_write_sem;
+
+/*
+ * Values for parsing cipso rules
+ * SMK_DIGITLEN: Length of a digit field in a rule.
+ * SMK_CIPSOMEN: Minimum possible cipso rule length.
+ */
+#define SMK_DIGITLEN 4
+#define SMK_CIPSOMIN (SMK_MAXLEN + 2 * SMK_DIGITLEN)
+
+/*
+ * Seq_file read operations for /smack/load
+ */
+
+static void *load_seq_start(struct seq_file *s, loff_t *pos)
+{
+ if (*pos == SEQ_READ_FINISHED)
+ return NULL;
+
+ return smack_list;
+}
+
+static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
+
+ if (skp == NULL)
+ *pos = SEQ_READ_FINISHED;
+
+ return skp;
+}
+
+static int load_seq_show(struct seq_file *s, void *v)
+{
+ struct smk_list_entry *slp = (struct smk_list_entry *) v;
+ struct smack_rule *srp = &slp->smk_rule;
+
+ seq_printf(s, "%s %s", (char *)srp->smk_subject,
+ (char *)srp->smk_object);
+
+ seq_putc(s, ' ');
+
+ if (srp->smk_access & MAY_READ)
+ seq_putc(s, 'r');
+ if (srp->smk_access & MAY_WRITE)
+ seq_putc(s, 'w');
+ if (srp->smk_access & MAY_EXEC)
+ seq_putc(s, 'x');
+ if (srp->smk_access & MAY_APPEND)
+ seq_putc(s, 'a');
+ if (srp->smk_access == 0)
+ seq_putc(s, '-');
+
+ seq_putc(s, '\n');
+
+ return 0;
+}
+
+static void load_seq_stop(struct seq_file *s, void *v)
+{
+ /* No-op */
+}
+
+static struct seq_operations load_seq_ops = {
+ .start = load_seq_start,
+ .next = load_seq_next,
+ .show = load_seq_show,
+ .stop = load_seq_stop,
+};
+
+/**
+ * smk_open_load - open() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For reading, use load_seq_* seq_file reading operations.
+ */
+static int smk_open_load(struct inode *inode, struct file *file)
+{
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return seq_open(file, &load_seq_ops);
+
+ if (down_interruptible(&smack_write_sem))
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
+/**
+ * smk_release_load - release() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For a reading session, use the seq_file release
+ * implementation.
+ * Otherwise, we are at the end of a writing session so
+ * clean everything up.
+ */
+static int smk_release_load(struct inode *inode, struct file *file)
+{
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return seq_release(inode, file);
+
+ up(&smack_write_sem);
+ return 0;
+}
+
+/**
+ * smk_set_access - add a rule to the rule list
+ * @srp: the new rule to add
+ *
+ * Looks through the current subject/object/access list for
+ * the subject/object pair and replaces the access that was
+ * there. If the pair isn't found add it with the specified
+ * access.
+ */
+static void smk_set_access(struct smack_rule *srp)
+{
+ struct smk_list_entry *sp;
+ struct smk_list_entry *newp;
+
+ mutex_lock(&smack_list_lock);
+
+ for (sp = smack_list; sp != NULL; sp = sp->smk_next)
+ if (sp->smk_rule.smk_subject == srp->smk_subject &&
+ sp->smk_rule.smk_object == srp->smk_object) {
+ sp->smk_rule.smk_access = srp->smk_access;
+ break;
+ }
+
+ if (sp == NULL) {
+ newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
+ newp->smk_rule = *srp;
+ newp->smk_next = smack_list;
+ smack_list = newp;
+ }
+
+ mutex_unlock(&smack_list_lock);
+
+ return;
+}
+
+/**
+ * smk_write_load - write() for /smack/load
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ *
+ * Get one smack access rule from above.
+ * The format is exactly:
+ * char subject[SMK_LABELLEN]
+ * char object[SMK_LABELLEN]
+ * char access[SMK_ACCESSKINDS]
+ *
+ * Anything following is commentary and ignored.
+ *
+ * writes must be SMK_LABELLEN+SMK_LABELLEN+4 bytes.
+ */
+#define MINIMUM_LOAD (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSKINDS)
+
+static ssize_t smk_write_load(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_rule rule;
+ char *data;
+ int rc = -EINVAL;
+
+ /*
+ * Must have privilege.
+ * No partial writes.
+ * Enough data must be present.
+ */
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ if (*ppos != 0)
+ return -EINVAL;
+ if (count < MINIMUM_LOAD)
+ return -EINVAL;
+
+ data = kzalloc(count, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ rule.smk_subject = smk_import(data, 0);
+ if (rule.smk_subject == NULL)
+ goto out;
+
+ rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
+ if (rule.smk_object == NULL)
+ goto out;
+
+ rule.smk_access = 0;
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
+ case '-':
+ break;
+ case 'r':
+ case 'R':
+ rule.smk_access |= MAY_READ;
+ break;
+ default:
+ goto out;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
+ case '-':
+ break;
+ case 'w':
+ case 'W':
+ rule.smk_access |= MAY_WRITE;
+ break;
+ default:
+ goto out;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
+ case '-':
+ break;
+ case 'x':
+ case 'X':
+ rule.smk_access |= MAY_EXEC;
+ break;
+ default:
+ goto out;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
+ case '-':
+ break;
+ case 'a':
+ case 'A':
+ rule.smk_access |= MAY_READ;
+ break;
+ default:
+ goto out;
+ }
+
+ smk_set_access(&rule);
+ rc = count;
+
+out:
+ kfree(data);
+ return rc;
+}
+
+static const struct file_operations smk_load_ops = {
+ .open = smk_open_load,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = smk_write_load,
+ .release = smk_release_load,
+};
+
+/**
+ * smk_cipso_doi - initialize the CIPSO domain
+ */
+void smk_cipso_doi(void)
+{
+ int rc;
+ struct cipso_v4_doi *doip;
+ struct netlbl_audit audit_info;
+
+ rc = netlbl_cfg_map_del(NULL, &audit_info);
+ if (rc != 0)
+ printk(KERN_WARNING "%s:%d remove rc = %d\n",
+ __func__, __LINE__, rc);
+
+ doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
+ if (doip == NULL)
+ panic("smack: Failed to initialize cipso DOI.\n");
+ doip->map.std = NULL;
+ doip->doi = smk_cipso_doi_value;
+ doip->type = CIPSO_V4_MAP_PASS;
+ doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
+ for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
+ doip->tags[rc] = CIPSO_V4_TAG_INVALID;
+
+ rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
+ if (rc != 0)
+ printk(KERN_WARNING "%s:%d add rc = %d\n",
+ __func__, __LINE__, rc);
+}
+
+/*
+ * Seq_file read operations for /smack/cipso
+ */
+
+static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
+{
+ if (*pos == SEQ_READ_FINISHED)
+ return NULL;
+
+ return smack_known;
+}
+
+static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct smack_known *skp = ((struct smack_known *) v)->smk_next;
+
+ /*
+ * Omit labels with no associated cipso value
+ */
+ while (skp != NULL && !skp->smk_cipso)
+ skp = skp->smk_next;
+
+ if (skp == NULL)
+ *pos = SEQ_READ_FINISHED;
+
+ return skp;
+}
+
+/*
+ * Print cipso labels in format:
+ * label level[/cat[,cat]]
+ */
+static int cipso_seq_show(struct seq_file *s, void *v)
+{
+ struct smack_known *skp = (struct smack_known *) v;
+ struct smack_cipso *scp = skp->smk_cipso;
+ char *cbp;
+ char sep = '/';
+ int cat = 1;
+ int i;
+ unsigned char m;
+
+ if (scp == NULL)
+ return 0;
+
+ seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level);
+
+ cbp = scp->smk_catset;
+ for (i = 0; i < SMK_LABELLEN; i++)
+ for (m = 0x80; m != 0; m >>= 1) {
+ if (m & cbp[i]) {
+ seq_printf(s, "%c%d", sep, cat);
+ sep = ',';
+ }
+ cat++;
+ }
+
+ seq_putc(s, '\n');
+
+ return 0;
+}
+
+static void cipso_seq_stop(struct seq_file *s, void *v)
+{
+ /* No-op */
+}
+
+static struct seq_operations cipso_seq_ops = {
+ .start = cipso_seq_start,
+ .stop = cipso_seq_stop,
+ .next = cipso_seq_next,
+ .show = cipso_seq_show,
+};
+
+/**
+ * smk_open_cipso - open() for /smack/cipso
+ * @inode: inode structure representing file
+ * @file: "cipso" file pointer
+ *
+ * Connect our cipso_seq_* operations with /smack/cipso
+ * file_operations
+ */
+static int smk_open_cipso(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &cipso_seq_ops);
+}
+
+/**
+ * smk_write_cipso - write() for /smack/cipso
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Accepts only one cipso rule per write call.
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_known *skp;
+ struct smack_cipso *scp = NULL;
+ char mapcatset[SMK_LABELLEN];
+ int maplevel;
+ int cat;
+ int catlen;
+ ssize_t rc = -EINVAL;
+ char *data = NULL;
+ char *rule;
+ int ret;
+ int i;
+
+ /*
+ * Must have privilege.
+ * No partial writes.
+ * Enough data must be present.
+ */
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ if (*ppos != 0)
+ return -EINVAL;
+ if (count <= SMK_CIPSOMIN)
+ return -EINVAL;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ rc = -EFAULT;
+ goto unlockedout;
+ }
+
+ data[count] = '\0';
+ rule = data;
+ /*
+ * Only allow one writer at a time. Writes should be
+ * quite rare and small in any case.
+ */
+ mutex_lock(&smack_cipso_lock);
+
+ skp = smk_import_entry(rule, 0);
+ if (skp == NULL)
+ goto out;
+
+ rule += SMK_LABELLEN;;
+ ret = sscanf(rule, "%d", &maplevel);
+ if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL)
+ goto out;
+
+ rule += SMK_DIGITLEN;
+ ret = sscanf(rule, "%d", &catlen);
+ if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM)
+ goto out;
+
+ if (count <= (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
+ goto out;
+
+ memset(mapcatset, 0, sizeof(mapcatset));
+
+ for (i = 0; i < catlen; i++) {
+ rule += SMK_DIGITLEN;
+ ret = sscanf(rule, "%d", &cat);
+ if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL)
+ goto out;
+
+ smack_catset_bit(cat, mapcatset);
+ }
+
+ if (skp->smk_cipso == NULL) {
+ scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL);
+ if (scp == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
+
+ spin_lock_bh(&skp->smk_cipsolock);
+
+ if (scp == NULL)
+ scp = skp->smk_cipso;
+ else
+ skp->smk_cipso = scp;
+
+ scp->smk_level = maplevel;
+ memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset));
+
+ spin_unlock_bh(&skp->smk_cipsolock);
+
+ rc = count;
+out:
+ mutex_unlock(&smack_cipso_lock);
+unlockedout:
+ kfree(data);
+ return rc;
+}
+
+static const struct file_operations smk_cipso_ops = {
+ .open = smk_open_cipso,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = smk_write_cipso,
+ .release = seq_release,
+};
+
+/**
+ * smk_read_doi - read() for /smack/doi
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_doi(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ ssize_t rc;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(temp, "%d", smk_cipso_doi_value);
+ rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+ return rc;
+}
+
+/**
+ * smk_write_doi - write() for /smack/doi
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_doi(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ int i;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (count >= sizeof(temp) || count == 0)
+ return -EINVAL;
+
+ if (copy_from_user(temp, buf, count) != 0)
+ return -EFAULT;
+
+ temp[count] = '\0';
+
+ if (sscanf(temp, "%d", &i) != 1)
+ return -EINVAL;
+
+ smk_cipso_doi_value = i;
+
+ smk_cipso_doi();
+
+ return count;
+}
+
+static const struct file_operations smk_doi_ops = {
+ .read = smk_read_doi,
+ .write = smk_write_doi,
+};
+
+/**
+ * smk_read_direct - read() for /smack/direct
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_direct(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ ssize_t rc;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(temp, "%d", smack_cipso_direct);
+ rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+ return rc;
+}
+
+/**
+ * smk_write_direct - write() for /smack/direct
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_direct(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ int i;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (count >= sizeof(temp) || count == 0)
+ return -EINVAL;
+
+ if (copy_from_user(temp, buf, count) != 0)
+ return -EFAULT;
+
+ temp[count] = '\0';
+
+ if (sscanf(temp, "%d", &i) != 1)
+ return -EINVAL;
+
+ smack_cipso_direct = i;
+
+ return count;
+}
+
+static const struct file_operations smk_direct_ops = {
+ .read = smk_read_direct,
+ .write = smk_write_direct,
+};
+
+/**
+ * smk_read_ambient - read() for /smack/ambient
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
+ size_t cn, loff_t *ppos)
+{
+ ssize_t rc;
+ char out[SMK_LABELLEN];
+ int asize;
+
+ if (*ppos != 0)
+ return 0;
+ /*
+ * Being careful to avoid a problem in the case where
+ * smack_net_ambient gets changed in midstream.
+ * Since smack_net_ambient is always set with a value
+ * from the label list, including initially, and those
+ * never get freed, the worst case is that the pointer
+ * gets changed just after this strncpy, in which case
+ * the value passed up is incorrect. Locking around
+ * smack_net_ambient wouldn't be any better than this
+ * copy scheme as by the time the caller got to look
+ * at the ambient value it would have cleared the lock
+ * and been changed.
+ */
+ strncpy(out, smack_net_ambient, SMK_LABELLEN);
+ asize = strlen(out) + 1;
+
+ if (cn < asize)
+ return -EINVAL;
+
+ rc = simple_read_from_buffer(buf, cn, ppos, out, asize);
+
+ return rc;
+}
+
+/**
+ * smk_write_ambient - write() for /smack/ambient
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char in[SMK_LABELLEN];
+ char *smack;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (count >= SMK_LABELLEN)
+ return -EINVAL;
+
+ if (copy_from_user(in, buf, count) != 0)
+ return -EFAULT;
+
+ smack = smk_import(in, count);
+ if (smack == NULL)
+ return -EINVAL;
+
+ smack_net_ambient = smack;
+
+ return count;
+}
+
+static const struct file_operations smk_ambient_ops = {
+ .read = smk_read_ambient,
+ .write = smk_write_ambient,
+};
+
+struct option_names {
+ int o_number;
+ char *o_name;
+ char *o_alias;
+};
+
+static struct option_names netlbl_choices[] = {
+ { NETLBL_NLTYPE_RIPSO,
+ NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
+ { NETLBL_NLTYPE_CIPSOV4,
+ NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
+ { NETLBL_NLTYPE_CIPSOV4,
+ NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
+ { NETLBL_NLTYPE_CIPSOV6,
+ NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
+ { NETLBL_NLTYPE_UNLABELED,
+ NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
+};
+
+/**
+ * smk_read_nltype - read() for /smack/nltype
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char bound[40];
+ ssize_t rc;
+ int i;
+
+ if (count < SMK_LABELLEN)
+ return -EINVAL;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(bound, "unknown");
+
+ for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
+ if (smack_net_nltype == netlbl_choices[i].o_number) {
+ sprintf(bound, "%s", netlbl_choices[i].o_name);
+ break;
+ }
+
+ rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
+
+ return rc;
+}
+
+/**
+ * smk_write_nltype - write() for /smack/nltype
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_nltype(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char bound[40];
+ char *cp;
+ int i;
+
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (count >= 40)
+ return -EINVAL;
+
+ if (copy_from_user(bound, buf, count) != 0)
+ return -EFAULT;
+
+ bound[count] = '\0';
+ cp = strchr(bound, ' ');
+ if (cp != NULL)
+ *cp = '\0';
+ cp = strchr(bound, '\n');
+ if (cp != NULL)
+ *cp = '\0';
+
+ for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
+ if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
+ strcmp(bound, netlbl_choices[i].o_alias) == 0) {
+ smack_net_nltype = netlbl_choices[i].o_number;
+ return count;
+ }
+ /*
+ * Not a valid choice.
+ */
+ return -EINVAL;
+}
+
+static const struct file_operations smk_nltype_ops = {
+ .read = smk_read_nltype,
+ .write = smk_write_nltype,
+};
+
+/**
+ * smk_fill_super - fill the /smackfs superblock
+ * @sb: the empty superblock
+ * @data: unused
+ * @silent: unused
+ *
+ * Fill in the well known entries for /smack
+ *
+ * Returns 0 on success, an error code on failure
+ */
+static int smk_fill_super(struct super_block *sb, void *data, int silent)
+{
+ int rc;
+ struct inode *root_inode;
+
+ static struct tree_descr smack_files[] = {
+ [SMK_LOAD] =
+ {"load", &smk_load_ops, S_IRUGO|S_IWUSR},
+ [SMK_CIPSO] =
+ {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
+ [SMK_DOI] =
+ {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
+ [SMK_DIRECT] =
+ {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
+ [SMK_AMBIENT] =
+ {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
+ [SMK_NLTYPE] =
+ {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+ /* last one */ {""}
+ };
+
+ rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);
+ if (rc != 0) {
+ printk(KERN_ERR "%s failed %d while creating inodes\n",
+ __func__, rc);
+ return rc;
+ }
+
+ root_inode = sb->s_root->d_inode;
+ root_inode->i_security = new_inode_smack(smack_known_floor.smk_known);
+
+ return 0;
+}
+
+/**
+ * smk_get_sb - get the smackfs superblock
+ * @fs_type: passed along without comment
+ * @flags: passed along without comment
+ * @dev_name: passed along without comment
+ * @data: passed along without comment
+ * @mnt: passed along without comment
+ *
+ * Just passes everything along.
+ *
+ * Returns what the lower level code does.
+ */
+static int smk_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, smk_fill_super, mnt);
+}
+
+static struct file_system_type smk_fs_type = {
+ .name = "smackfs",
+ .get_sb = smk_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+static struct vfsmount *smackfs_mount;
+
+/**
+ * init_smk_fs - get the smackfs superblock
+ *
+ * register the smackfs
+ *
+ * Returns 0 unless the registration fails.
+ */
+static int __init init_smk_fs(void)
+{
+ int err;
+
+ err = register_filesystem(&smk_fs_type);
+ if (!err) {
+ smackfs_mount = kern_mount(&smk_fs_type);
+ if (IS_ERR(smackfs_mount)) {
+ printk(KERN_ERR "smackfs: could not mount!\n");
+ err = PTR_ERR(smackfs_mount);
+ smackfs_mount = NULL;
+ }
+ }
+
+ sema_init(&smack_write_sem, 1);
+ smk_cipso_doi();
+
+ return err;
+}
+
+__initcall(init_smk_fs);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 6244911..61f5d42 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -23,7 +23,7 @@
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
#include <linux/uio.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -443,9 +443,11 @@
snd_pcm_timer_resolution_change(substream);
runtime->status->state = SNDRV_PCM_STATE_SETUP;
- remove_acceptable_latency(substream->latency_id);
+ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
+ substream->latency_id);
if ((usecs = period_to_usecs(runtime)) >= 0)
- set_acceptable_latency(substream->latency_id, usecs);
+ pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY,
+ substream->latency_id, usecs);
return 0;
_error:
/* hardware might be unuseable from this time,
@@ -505,7 +507,8 @@
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
runtime->status->state = SNDRV_PCM_STATE_OPEN;
- remove_acceptable_latency(substream->latency_id);
+ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
+ substream->latency_id);
return result;
}
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index f883c4b..1f86299 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -6,7 +6,6 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_SOUND_OSS) += sound.o
-obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
# Please leave it as is, cause the link order is significant !
@@ -16,7 +15,6 @@
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
@@ -27,19 +25,12 @@
obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
-
-obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
-ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
- obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
-endif
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
-obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
-obj-$(CONFIG_SOUND_BT878) += btaudio.o
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index fef56ca..87a6726 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -189,42 +189,6 @@
{0x57454301, "Winbond 83971D", &null_ops},
};
-static const char *ac97_stereo_enhancements[] =
-{
- /* 0 */ "No 3D Stereo Enhancement",
- /* 1 */ "Analog Devices Phat Stereo",
- /* 2 */ "Creative Stereo Enhancement",
- /* 3 */ "National Semi 3D Stereo Enhancement",
- /* 4 */ "YAMAHA Ymersion",
- /* 5 */ "BBE 3D Stereo Enhancement",
- /* 6 */ "Crystal Semi 3D Stereo Enhancement",
- /* 7 */ "Qsound QXpander",
- /* 8 */ "Spatializer 3D Stereo Enhancement",
- /* 9 */ "SRS 3D Stereo Enhancement",
- /* 10 */ "Platform Tech 3D Stereo Enhancement",
- /* 11 */ "AKM 3D Audio",
- /* 12 */ "Aureal Stereo Enhancement",
- /* 13 */ "Aztech 3D Enhancement",
- /* 14 */ "Binaura 3D Audio Enhancement",
- /* 15 */ "ESS Technology Stereo Enhancement",
- /* 16 */ "Harman International VMAx",
- /* 17 */ "Nvidea 3D Stereo Enhancement",
- /* 18 */ "Philips Incredible Sound",
- /* 19 */ "Texas Instruments 3D Stereo Enhancement",
- /* 20 */ "VLSI Technology 3D Stereo Enhancement",
- /* 21 */ "TriTech 3D Stereo Enhancement",
- /* 22 */ "Realtek 3D Stereo Enhancement",
- /* 23 */ "Samsung 3D Stereo Enhancement",
- /* 24 */ "Wolfson Microelectronics 3D Enhancement",
- /* 25 */ "Delta Integration 3D Enhancement",
- /* 26 */ "SigmaTel 3D Enhancement",
- /* 27 */ "Winbond 3D Stereo Enhancement",
- /* 28 */ "Rockwell 3D Stereo Enhancement",
- /* 29 */ "Reserved 29",
- /* 30 */ "Reserved 30",
- /* 31 */ "Reserved 31"
-};
-
/* this table has default mixer values for all OSS mixers. */
static struct mixer_defaults {
int mixer;
@@ -614,83 +578,6 @@
return -EINVAL;
}
-/* entry point for /proc/driver/controller_vendor/ac97/%d */
-int ac97_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = 0, cap, extid, val, id1, id2;
- struct ac97_codec *codec;
- int is_ac97_20 = 0;
-
- if ((codec = data) == NULL)
- return -ENODEV;
-
- id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
- id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
- len += sprintf (page+len, "Vendor name : %s\n", codec->name);
- len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2);
-
- extid = codec->codec_read(codec, AC97_EXTENDED_ID);
- extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
- len += sprintf (page+len, "AC97 Version : %s\n",
- extid ? "2.0 or later" : "1.0");
- if (extid) is_ac97_20 = 1;
-
- cap = codec->codec_read(codec, AC97_RESET);
- len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n",
- cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
- cap & 0x0002 ? " -reserved1-" : "",
- cap & 0x0004 ? " -bass & treble-" : "",
- cap & 0x0008 ? " -simulated stereo-" : "",
- cap & 0x0010 ? " -headphone out-" : "",
- cap & 0x0020 ? " -loudness-" : "");
- val = cap & 0x00c0;
- len += sprintf (page+len, "DAC resolutions :%s%s%s\n",
- " -16-bit-",
- val & 0x0040 ? " -18-bit-" : "",
- val & 0x0080 ? " -20-bit-" : "");
- val = cap & 0x0300;
- len += sprintf (page+len, "ADC resolutions :%s%s%s\n",
- " -16-bit-",
- val & 0x0100 ? " -18-bit-" : "",
- val & 0x0200 ? " -20-bit-" : "");
- len += sprintf (page+len, "3D enhancement : %s\n",
- ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
-
- val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
- len += sprintf (page+len, "POP path : %s 3D\n"
- "Sim. stereo : %s\n"
- "3D enhancement : %s\n"
- "Loudness : %s\n"
- "Mono output : %s\n"
- "MIC select : %s\n"
- "ADC/DAC loopback : %s\n",
- val & 0x8000 ? "post" : "pre",
- val & 0x4000 ? "on" : "off",
- val & 0x2000 ? "on" : "off",
- val & 0x1000 ? "on" : "off",
- val & 0x0200 ? "MIC" : "MIX",
- val & 0x0100 ? "MIC2" : "MIC1",
- val & 0x0080 ? "on" : "off");
-
- extid = codec->codec_read(codec, AC97_EXTENDED_ID);
- cap = extid;
- len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
- cap & 0x0001 ? " -var rate PCM audio-" : "",
- cap & 0x0002 ? " -2x PCM audio out-" : "",
- cap & 0x0008 ? " -var rate MIC in-" : "",
- cap & 0x0040 ? " -PCM center DAC-" : "",
- cap & 0x0080 ? " -PCM surround DAC-" : "",
- cap & 0x0100 ? " -PCM LFE DAC-" : "",
- cap & 0x0200 ? " -slot/DAC mappings-" : "");
- if (is_ac97_20) {
- len += sprintf (page+len, "Front DAC rate : %d\n",
- codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE));
- }
-
- return len;
-}
-
/**
* codec_id - Turn id1/id2 into a PnP string
* @id1: Vendor ID1
@@ -1313,176 +1200,5 @@
#endif
-EXPORT_SYMBOL(ac97_read_proc);
EXPORT_SYMBOL(ac97_probe_codec);
-/*
- * AC97 library support routines
- */
-
-/**
- * ac97_set_dac_rate - set codec rate adaption
- * @codec: ac97 code
- * @rate: rate in hertz
- *
- * Set the DAC rate. Assumes the codec supports VRA. The caller is
- * expected to have checked this little detail.
- */
-
-unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate)
-{
- unsigned int new_rate = rate;
- u32 dacp;
- u32 mast_vol, phone_vol, mono_vol, pcm_vol;
- u32 mute_vol = 0x8000; /* The mute volume? */
-
- if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE))
- {
- /* Mute several registers */
- mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO);
- mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO);
- phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL);
- pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL);
- codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol);
- codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol);
- codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol);
- codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol);
-
- /* Power down the DAC */
- dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200);
- /* Load the rate and read the effective rate */
- codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate);
- new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE);
- /* Power it back up */
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
-
- /* Restore volumes */
- codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol);
- codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol);
- codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol);
- codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol);
- }
- return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_dac_rate);
-
-/**
- * ac97_set_adc_rate - set codec rate adaption
- * @codec: ac97 code
- * @rate: rate in hertz
- *
- * Set the ADC rate. Assumes the codec supports VRA. The caller is
- * expected to have checked this little detail.
- */
-
-unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate)
-{
- unsigned int new_rate = rate;
- u32 dacp;
-
- if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE))
- {
- /* Power down the ADC */
- dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100);
- /* Load the rate and read the effective rate */
- codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate);
- new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE);
- /* Power it back up */
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
- }
- return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_adc_rate);
-
-static int swap_headphone(int remove_master)
-{
- struct list_head *l;
- struct ac97_codec *c;
-
- if (remove_master) {
- mutex_lock(&codec_mutex);
- list_for_each(l, &codecs)
- {
- c = list_entry(l, struct ac97_codec, list);
- if (supported_mixer(c, SOUND_MIXER_PHONEOUT))
- c->supported_mixers &= ~SOUND_MASK_PHONEOUT;
- }
- mutex_unlock(&codec_mutex);
- } else
- ac97_hw[SOUND_MIXER_PHONEOUT].offset = AC97_MASTER_VOL_STEREO;
-
- /* Scale values already match */
- ac97_hw[SOUND_MIXER_VOLUME].offset = AC97_MASTER_VOL_MONO;
- return 0;
-}
-
-static int apply_quirk(int quirk)
-{
- switch (quirk) {
- case AC97_TUNE_NONE:
- return 0;
- case AC97_TUNE_HP_ONLY:
- return swap_headphone(1);
- case AC97_TUNE_SWAP_HP:
- return swap_headphone(0);
- case AC97_TUNE_SWAP_SURROUND:
- return -ENOSYS; /* not yet implemented */
- case AC97_TUNE_AD_SHARING:
- return -ENOSYS; /* not yet implemented */
- case AC97_TUNE_ALC_JACK:
- return -ENOSYS; /* not yet implemented */
- }
- return -EINVAL;
-}
-
-/**
- * ac97_tune_hardware - tune up the hardware
- * @pdev: pci_dev pointer
- * @quirk: quirk list
- * @override: explicit quirk value (overrides if not AC97_TUNE_DEFAULT)
- *
- * Do some workaround for each pci device, such as renaming of the
- * headphone (true line-out) control as "Master".
- * The quirk-list must be terminated with a zero-filled entry.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-
-int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override)
-{
- int result;
-
- if (!quirk)
- return -EINVAL;
-
- if (override != AC97_TUNE_DEFAULT) {
- result = apply_quirk(override);
- if (result < 0)
- printk(KERN_ERR "applying quirk type %d failed (%d)\n", override, result);
- return result;
- }
-
- for (; quirk->vendor; quirk++) {
- if (quirk->vendor != pdev->subsystem_vendor)
- continue;
- if ((! quirk->mask && quirk->device == pdev->subsystem_device) ||
- quirk->device == (quirk->mask & pdev->subsystem_device)) {
-#ifdef DEBUG
- printk("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, pdev->subsystem_device);
-#endif
- result = apply_quirk(quirk->type);
- if (result < 0)
- printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result);
- return result;
- }
- }
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_tune_hardware);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
deleted file mode 100644
index 4d5cf05..0000000
--- a/sound/oss/btaudio.c
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
- btaudio - bt878 audio dma driver for linux 2.4.x
-
- (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/slab.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-
-/* mmio access */
-#define btwrite(dat,adr) writel((dat), (bta->mmio+(adr)))
-#define btread(adr) readl(bta->mmio+(adr))
-
-#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-/* registers (shifted because bta->mmio is long) */
-#define REG_INT_STAT (0x100 >> 2)
-#define REG_INT_MASK (0x104 >> 2)
-#define REG_GPIO_DMA_CTL (0x10c >> 2)
-#define REG_PACKET_LEN (0x110 >> 2)
-#define REG_RISC_STRT_ADD (0x114 >> 2)
-#define REG_RISC_COUNT (0x120 >> 2)
-
-/* IRQ bits - REG_INT_(STAT|MASK) */
-#define IRQ_SCERR (1 << 19)
-#define IRQ_OCERR (1 << 18)
-#define IRQ_PABORT (1 << 17)
-#define IRQ_RIPERR (1 << 16)
-#define IRQ_PPERR (1 << 15)
-#define IRQ_FDSR (1 << 14)
-#define IRQ_FTRGT (1 << 13)
-#define IRQ_FBUS (1 << 12)
-#define IRQ_RISCI (1 << 11)
-#define IRQ_OFLOW (1 << 3)
-
-#define IRQ_BTAUDIO (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\
- IRQ_PPERR | IRQ_FDSR | IRQ_FTRGT | IRQ_FBUS |\
- IRQ_RISCI)
-
-/* REG_GPIO_DMA_CTL bits */
-#define DMA_CTL_A_PWRDN (1 << 26)
-#define DMA_CTL_DA_SBR (1 << 14)
-#define DMA_CTL_DA_ES2 (1 << 13)
-#define DMA_CTL_ACAP_EN (1 << 4)
-#define DMA_CTL_RISC_EN (1 << 1)
-#define DMA_CTL_FIFO_EN (1 << 0)
-
-/* RISC instructions */
-#define RISC_WRITE (0x01 << 28)
-#define RISC_JUMP (0x07 << 28)
-#define RISC_SYNC (0x08 << 28)
-
-/* RISC bits */
-#define RISC_WR_SOL (1 << 27)
-#define RISC_WR_EOL (1 << 26)
-#define RISC_IRQ (1 << 24)
-#define RISC_SYNC_RESYNC (1 << 15)
-#define RISC_SYNC_FM1 0x06
-#define RISC_SYNC_VRO 0x0c
-
-#define HWBASE_AD (448000)
-
-/* -------------------------------------------------------------- */
-
-struct btaudio {
- /* linked list */
- struct btaudio *next;
-
- /* device info */
- int dsp_digital;
- int dsp_analog;
- int mixer_dev;
- struct pci_dev *pci;
- unsigned int irq;
- unsigned long mem;
- unsigned long __iomem *mmio;
-
- /* locking */
- int users;
- struct mutex lock;
-
- /* risc instructions */
- unsigned int risc_size;
- unsigned long *risc_cpu;
- dma_addr_t risc_dma;
-
- /* audio data */
- unsigned int buf_size;
- unsigned char *buf_cpu;
- dma_addr_t buf_dma;
-
- /* buffer setup */
- int line_bytes;
- int line_count;
- int block_bytes;
- int block_count;
-
- /* read fifo management */
- int recording;
- int dma_block;
- int read_offset;
- int read_count;
- wait_queue_head_t readq;
-
- /* settings */
- int gain[3];
- int source;
- int bits;
- int decimation;
- int mixcount;
- int sampleshift;
- int channels;
- int analog;
- int rate;
-};
-
-struct cardinfo {
- char *name;
- int rate;
-};
-
-static struct btaudio *btaudios;
-static unsigned int debug;
-static unsigned int irq_debug;
-
-/* -------------------------------------------------------------- */
-
-#define BUF_DEFAULT 128*1024
-#define BUF_MIN 8192
-
-static int alloc_buffer(struct btaudio *bta)
-{
- if (NULL == bta->buf_cpu) {
- for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN;
- bta->buf_size = bta->buf_size >> 1) {
- bta->buf_cpu = pci_alloc_consistent
- (bta->pci, bta->buf_size, &bta->buf_dma);
- if (NULL != bta->buf_cpu)
- break;
- }
- if (NULL == bta->buf_cpu)
- return -ENOMEM;
- memset(bta->buf_cpu,0,bta->buf_size);
- }
- if (NULL == bta->risc_cpu) {
- bta->risc_size = PAGE_SIZE;
- bta->risc_cpu = pci_alloc_consistent
- (bta->pci, bta->risc_size, &bta->risc_dma);
- if (NULL == bta->risc_cpu) {
- pci_free_consistent(bta->pci, bta->buf_size, bta->buf_cpu, bta->buf_dma);
- bta->buf_cpu = NULL;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-static void free_buffer(struct btaudio *bta)
-{
- if (NULL != bta->buf_cpu) {
- pci_free_consistent(bta->pci, bta->buf_size,
- bta->buf_cpu, bta->buf_dma);
- bta->buf_cpu = NULL;
- }
- if (NULL != bta->risc_cpu) {
- pci_free_consistent(bta->pci, bta->risc_size,
- bta->risc_cpu, bta->risc_dma);
- bta->risc_cpu = NULL;
- }
-}
-
-static int make_risc(struct btaudio *bta)
-{
- int rp, bp, line, block;
- unsigned long risc;
-
- bta->block_bytes = bta->buf_size >> 4;
- bta->block_count = 1 << 4;
- bta->line_bytes = bta->block_bytes;
- bta->line_count = bta->block_count;
- while (bta->line_bytes > 4095) {
- bta->line_bytes >>= 1;
- bta->line_count <<= 1;
- }
- if (bta->line_count > 255)
- return -EINVAL;
- if (debug)
- printk(KERN_DEBUG
- "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",
- bta->buf_size,bta->block_bytes,bta->block_count,
- bta->line_bytes,bta->line_count);
- rp = 0; bp = 0;
- block = 0;
- bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_FM1);
- bta->risc_cpu[rp++] = cpu_to_le32(0);
- for (line = 0; line < bta->line_count; line++) {
- risc = RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL;
- risc |= bta->line_bytes;
- if (0 == (bp & (bta->block_bytes-1))) {
- risc |= RISC_IRQ;
- risc |= (block & 0x0f) << 16;
- risc |= (~block & 0x0f) << 20;
- block++;
- }
- bta->risc_cpu[rp++] = cpu_to_le32(risc);
- bta->risc_cpu[rp++] = cpu_to_le32(bta->buf_dma + bp);
- bp += bta->line_bytes;
- }
- bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_VRO);
- bta->risc_cpu[rp++] = cpu_to_le32(0);
- bta->risc_cpu[rp++] = cpu_to_le32(RISC_JUMP);
- bta->risc_cpu[rp++] = cpu_to_le32(bta->risc_dma);
- return 0;
-}
-
-static int start_recording(struct btaudio *bta)
-{
- int ret;
-
- if (0 != (ret = alloc_buffer(bta)))
- return ret;
- if (0 != (ret = make_risc(bta)))
- return ret;
-
- btwrite(bta->risc_dma, REG_RISC_STRT_ADD);
- btwrite((bta->line_count << 16) | bta->line_bytes,
- REG_PACKET_LEN);
- btwrite(IRQ_BTAUDIO, REG_INT_MASK);
- if (bta->analog) {
- btwrite(DMA_CTL_ACAP_EN |
- DMA_CTL_RISC_EN |
- DMA_CTL_FIFO_EN |
- DMA_CTL_DA_ES2 |
- ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
- (bta->gain[bta->source] << 28) |
- (bta->source << 24) |
- (bta->decimation << 8),
- REG_GPIO_DMA_CTL);
- } else {
- btwrite(DMA_CTL_ACAP_EN |
- DMA_CTL_RISC_EN |
- DMA_CTL_FIFO_EN |
- DMA_CTL_DA_ES2 |
- DMA_CTL_A_PWRDN |
- (1 << 6) |
- ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
- (bta->gain[bta->source] << 28) |
- (bta->source << 24) |
- (bta->decimation << 8),
- REG_GPIO_DMA_CTL);
- }
- bta->dma_block = 0;
- bta->read_offset = 0;
- bta->read_count = 0;
- bta->recording = 1;
- if (debug)
- printk(KERN_DEBUG "btaudio: recording started\n");
- return 0;
-}
-
-static void stop_recording(struct btaudio *bta)
-{
- btand(~15, REG_GPIO_DMA_CTL);
- bta->recording = 0;
- if (debug)
- printk(KERN_DEBUG "btaudio: recording stopped\n");
-}
-
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_mixer_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct btaudio *bta;
-
- for (bta = btaudios; bta != NULL; bta = bta->next)
- if (bta->mixer_dev == minor)
- break;
- if (NULL == bta)
- return -ENODEV;
-
- if (debug)
- printk("btaudio: open mixer [%d]\n",minor);
- file->private_data = bta;
- return 0;
-}
-
-static int btaudio_mixer_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct btaudio *bta = file->private_data;
- int ret,val=0,i=0;
- void __user *argp = (void __user *)arg;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info,0,sizeof(info));
- strlcpy(info.id,"bt878",sizeof(info.id));
- strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
- info.modify_counter = bta->mixcount;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- memset(&info,0,sizeof(info));
- strlcpy(info.id, "bt878", sizeof(info.id));
- strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int __user *)argp);
-
- /* read */
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
-
- switch (cmd) {
- case MIXER_READ(SOUND_MIXER_CAPS):
- ret = SOUND_CAP_EXCL_INPUT;
- break;
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- ret = 0;
- break;
- case MIXER_READ(SOUND_MIXER_RECMASK):
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- ret = SOUND_MASK_LINE1|SOUND_MASK_LINE2|SOUND_MASK_LINE3;
- break;
-
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- if (val & SOUND_MASK_LINE1 && bta->source != 0)
- bta->source = 0;
- else if (val & SOUND_MASK_LINE2 && bta->source != 1)
- bta->source = 1;
- else if (val & SOUND_MASK_LINE3 && bta->source != 2)
- bta->source = 2;
- btaor((bta->gain[bta->source] << 28) |
- (bta->source << 24),
- 0x0cffffff, REG_GPIO_DMA_CTL);
- case MIXER_READ(SOUND_MIXER_RECSRC):
- switch (bta->source) {
- case 0: ret = SOUND_MASK_LINE1; break;
- case 1: ret = SOUND_MASK_LINE2; break;
- case 2: ret = SOUND_MASK_LINE3; break;
- default: ret = 0;
- }
- break;
-
- case MIXER_WRITE(SOUND_MIXER_LINE1):
- case MIXER_WRITE(SOUND_MIXER_LINE2):
- case MIXER_WRITE(SOUND_MIXER_LINE3):
- if (MIXER_WRITE(SOUND_MIXER_LINE1) == cmd)
- i = 0;
- if (MIXER_WRITE(SOUND_MIXER_LINE2) == cmd)
- i = 1;
- if (MIXER_WRITE(SOUND_MIXER_LINE3) == cmd)
- i = 2;
- bta->gain[i] = (val & 0xff) * 15 / 100;
- if (bta->gain[i] > 15) bta->gain[i] = 15;
- if (bta->gain[i] < 0) bta->gain[i] = 0;
- if (i == bta->source)
- btaor((bta->gain[bta->source]<<28),
- 0x0fffffff, REG_GPIO_DMA_CTL);
- ret = bta->gain[i] * 100 / 15;
- ret |= ret << 8;
- break;
-
- case MIXER_READ(SOUND_MIXER_LINE1):
- case MIXER_READ(SOUND_MIXER_LINE2):
- case MIXER_READ(SOUND_MIXER_LINE3):
- if (MIXER_READ(SOUND_MIXER_LINE1) == cmd)
- i = 0;
- if (MIXER_READ(SOUND_MIXER_LINE2) == cmd)
- i = 1;
- if (MIXER_READ(SOUND_MIXER_LINE3) == cmd)
- i = 2;
- ret = bta->gain[i] * 100 / 15;
- ret |= ret << 8;
- break;
-
- default:
- return -EINVAL;
- }
- if (put_user(ret, (int __user *)argp))
- return -EFAULT;
- return 0;
-}
-
-static const struct file_operations btaudio_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = btaudio_mixer_open,
- .release = btaudio_mixer_release,
- .ioctl = btaudio_mixer_ioctl,
-};
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_dsp_open(struct inode *inode, struct file *file,
- struct btaudio *bta, int analog)
-{
- mutex_lock(&bta->lock);
- if (bta->users)
- goto busy;
- bta->users++;
- file->private_data = bta;
-
- bta->analog = analog;
- bta->dma_block = 0;
- bta->read_offset = 0;
- bta->read_count = 0;
- bta->sampleshift = 0;
-
- mutex_unlock(&bta->lock);
- return 0;
-
- busy:
- mutex_unlock(&bta->lock);
- return -EBUSY;
-}
-
-static int btaudio_dsp_open_digital(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct btaudio *bta;
-
- for (bta = btaudios; bta != NULL; bta = bta->next)
- if (bta->dsp_digital == minor)
- break;
- if (NULL == bta)
- return -ENODEV;
-
- if (debug)
- printk("btaudio: open digital dsp [%d]\n",minor);
- return btaudio_dsp_open(inode,file,bta,0);
-}
-
-static int btaudio_dsp_open_analog(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct btaudio *bta;
-
- for (bta = btaudios; bta != NULL; bta = bta->next)
- if (bta->dsp_analog == minor)
- break;
- if (NULL == bta)
- return -ENODEV;
-
- if (debug)
- printk("btaudio: open analog dsp [%d]\n",minor);
- return btaudio_dsp_open(inode,file,bta,1);
-}
-
-static int btaudio_dsp_release(struct inode *inode, struct file *file)
-{
- struct btaudio *bta = file->private_data;
-
- mutex_lock(&bta->lock);
- if (bta->recording)
- stop_recording(bta);
- bta->users--;
- mutex_unlock(&bta->lock);
- return 0;
-}
-
-static ssize_t btaudio_dsp_read(struct file *file, char __user *buffer,
- size_t swcount, loff_t *ppos)
-{
- struct btaudio *bta = file->private_data;
- int hwcount = swcount << bta->sampleshift;
- int nsrc, ndst, err, ret = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&bta->readq, &wait);
- mutex_lock(&bta->lock);
- while (swcount > 0) {
- if (0 == bta->read_count) {
- if (!bta->recording) {
- if (0 != (err = start_recording(bta))) {
- if (0 == ret)
- ret = err;
- break;
- }
- }
- if (file->f_flags & O_NONBLOCK) {
- if (0 == ret)
- ret = -EAGAIN;
- break;
- }
- mutex_unlock(&bta->lock);
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- mutex_lock(&bta->lock);
- if(signal_pending(current)) {
- if (0 == ret)
- ret = -EINTR;
- break;
- }
- }
- nsrc = (bta->read_count < hwcount) ? bta->read_count : hwcount;
- if (nsrc > bta->buf_size - bta->read_offset)
- nsrc = bta->buf_size - bta->read_offset;
- ndst = nsrc >> bta->sampleshift;
-
- if ((bta->analog && 0 == bta->sampleshift) ||
- (!bta->analog && 2 == bta->channels)) {
- /* just copy */
- if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
-
- } else if (!bta->analog) {
- /* stereo => mono (digital audio) */
- __s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset);
- __s16 __user *dst = (__s16 __user *)(buffer + ret);
- __s16 avg;
- int n = ndst>>1;
- if (!access_ok(VERIFY_WRITE, dst, ndst)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- for (; n; n--, dst++) {
- avg = (__s16)le16_to_cpu(*src) / 2; src++;
- avg += (__s16)le16_to_cpu(*src) / 2; src++;
- __put_user(cpu_to_le16(avg),dst);
- }
-
- } else if (8 == bta->bits) {
- /* copy + byte downsampling (audio A/D) */
- __u8 *src = bta->buf_cpu + bta->read_offset;
- __u8 __user *dst = buffer + ret;
- int n = ndst;
- if (!access_ok(VERIFY_WRITE, dst, ndst)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- for (; n; n--, src += (1 << bta->sampleshift), dst++)
- __put_user(*src, dst);
-
- } else {
- /* copy + word downsampling (audio A/D) */
- __u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);
- __u16 __user *dst = (__u16 __user *)(buffer + ret);
- int n = ndst>>1;
- if (!access_ok(VERIFY_WRITE,dst,ndst)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- for (; n; n--, src += (1 << bta->sampleshift), dst++)
- __put_user(*src, dst);
- }
-
- ret += ndst;
- swcount -= ndst;
- hwcount -= nsrc;
- bta->read_count -= nsrc;
- bta->read_offset += nsrc;
- if (bta->read_offset == bta->buf_size)
- bta->read_offset = 0;
- }
- mutex_unlock(&bta->lock);
- remove_wait_queue(&bta->readq, &wait);
- current->state = TASK_RUNNING;
- return ret;
-}
-
-static ssize_t btaudio_dsp_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct btaudio *bta = file->private_data;
- int s, i, ret, val = 0;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_GETCAPS:
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (bta->analog) {
- for (s = 0; s < 16; s++)
- if (val << s >= HWBASE_AD*4/15)
- break;
- for (i = 15; i >= 5; i--)
- if (val << s <= HWBASE_AD*4/i)
- break;
- bta->sampleshift = s;
- bta->decimation = i;
- if (debug)
- printk(KERN_DEBUG "btaudio: rate: req=%d "
- "dec=%d shift=%d hwrate=%d swrate=%d\n",
- val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s);
- } else {
- bta->sampleshift = (bta->channels == 2) ? 0 : 1;
- bta->decimation = 0;
- }
- if (bta->recording) {
- mutex_lock(&bta->lock);
- stop_recording(bta);
- start_recording(bta);
- mutex_unlock(&bta->lock);
- }
- /* fall through */
- case SOUND_PCM_READ_RATE:
- if (bta->analog) {
- return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, p);
- } else {
- return put_user(bta->rate, p);
- }
-
- case SNDCTL_DSP_STEREO:
- if (!bta->analog) {
- if (get_user(val, p))
- return -EFAULT;
- bta->channels = (val > 0) ? 2 : 1;
- bta->sampleshift = (bta->channels == 2) ? 0 : 1;
- if (debug)
- printk(KERN_INFO
- "btaudio: stereo=%d channels=%d\n",
- val,bta->channels);
- } else {
- if (val == 1)
- return -EFAULT;
- else {
- bta->channels = 1;
- if (debug)
- printk(KERN_INFO
- "btaudio: stereo=0 channels=1\n");
- }
- }
- return put_user((bta->channels)-1, p);
-
- case SNDCTL_DSP_CHANNELS:
- if (!bta->analog) {
- if (get_user(val, p))
- return -EFAULT;
- bta->channels = (val > 1) ? 2 : 1;
- bta->sampleshift = (bta->channels == 2) ? 0 : 1;
- if (debug)
- printk(KERN_DEBUG
- "btaudio: val=%d channels=%d\n",
- val,bta->channels);
- }
- /* fall through */
- case SOUND_PCM_READ_CHANNELS:
- return put_user(bta->channels, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- if (bta->analog)
- return put_user(AFMT_S16_LE|AFMT_S8, p);
- else
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (bta->analog)
- bta->bits = (val == AFMT_S8) ? 8 : 16;
- else
- bta->bits = 16;
- if (bta->recording) {
- mutex_lock(&bta->lock);
- stop_recording(bta);
- start_recording(bta);
- mutex_unlock(&bta->lock);
- }
- }
- if (debug)
- printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits);
- return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8,
- p);
- break;
- case SOUND_PCM_READ_BITS:
- return put_user(bta->bits, p);
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_RESET:
- if (bta->recording) {
- mutex_lock(&bta->lock);
- stop_recording(bta);
- mutex_unlock(&bta->lock);
- }
- return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- if (!bta->recording) {
- if (0 != (ret = alloc_buffer(bta)))
- return ret;
- if (0 != (ret = make_risc(bta)))
- return ret;
- }
- return put_user(bta->block_bytes>>bta->sampleshift,p);
-
- case SNDCTL_DSP_SYNC:
- /* NOP */
- return 0;
- case SNDCTL_DSP_GETISPACE:
- {
- audio_buf_info info;
- if (!bta->recording)
- return -EINVAL;
- info.fragsize = bta->block_bytes>>bta->sampleshift;
- info.fragstotal = bta->block_count;
- info.bytes = bta->read_count;
- info.fragments = info.bytes / info.fragsize;
- if (debug)
- printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE "
- "returns %d/%d/%d/%d\n",
- info.fragsize, info.fragstotal,
- info.bytes, info.fragments);
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
-#if 0 /* TODO */
- case SNDCTL_DSP_GETTRIGGER:
- case SNDCTL_DSP_SETTRIGGER:
- case SNDCTL_DSP_SETFRAGMENT:
-#endif
- default:
- return -EINVAL;
- }
-}
-
-static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct btaudio *bta = file->private_data;
- unsigned int mask = 0;
-
- poll_wait(file, &bta->readq, wait);
-
- if (0 != bta->read_count)
- mask |= (POLLIN | POLLRDNORM);
-
- return mask;
-}
-
-static const struct file_operations btaudio_digital_dsp_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = btaudio_dsp_open_digital,
- .release = btaudio_dsp_release,
- .read = btaudio_dsp_read,
- .write = btaudio_dsp_write,
- .ioctl = btaudio_dsp_ioctl,
- .poll = btaudio_dsp_poll,
-};
-
-static const struct file_operations btaudio_analog_dsp_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = btaudio_dsp_open_analog,
- .release = btaudio_dsp_release,
- .read = btaudio_dsp_read,
- .write = btaudio_dsp_write,
- .ioctl = btaudio_dsp_ioctl,
- .poll = btaudio_dsp_poll,
-};
-
-/* -------------------------------------------------------------- */
-
-static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "",
- "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
- "RIPERR", "PABORT", "OCERR", "SCERR" };
-
-static irqreturn_t btaudio_irq(int irq, void *dev_id)
-{
- int count = 0;
- u32 stat,astat;
- struct btaudio *bta = dev_id;
- int handled = 0;
-
- for (;;) {
- count++;
- stat = btread(REG_INT_STAT);
- astat = stat & btread(REG_INT_MASK);
- if (!astat)
- return IRQ_RETVAL(handled);
- handled = 1;
- btwrite(astat,REG_INT_STAT);
-
- if (irq_debug) {
- int i;
- printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:",
- count, stat>>28);
- for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
- if (stat & (1 << i))
- printk(" %s",irq_name[i]);
- if (astat & (1 << i))
- printk("*");
- }
- printk("\n");
- }
- if (stat & IRQ_RISCI) {
- int blocks;
- blocks = (stat >> 28) - bta->dma_block;
- if (blocks < 0)
- blocks += bta->block_count;
- bta->dma_block = stat >> 28;
- if (bta->read_count + 2*bta->block_bytes > bta->buf_size) {
- stop_recording(bta);
- printk(KERN_INFO "btaudio: buffer overrun\n");
- }
- if (blocks > 0) {
- bta->read_count += blocks * bta->block_bytes;
- wake_up_interruptible(&bta->readq);
- }
- }
- if (count > 10) {
- printk(KERN_WARNING
- "btaudio: Oops - irq mask cleared\n");
- btwrite(0, REG_INT_MASK);
- }
- }
- return IRQ_NONE;
-}
-
-/* -------------------------------------------------------------- */
-
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
-static int latency = -1;
-static int digital = 1;
-static int analog = 1;
-static int rate;
-
-#define BTA_OSPREY200 1
-
-static struct cardinfo cards[] = {
- [0] = {
- .name = "default",
- .rate = 32000,
- },
- [BTA_OSPREY200] = {
- .name = "Osprey 200",
- .rate = 44100,
- },
-};
-
-static int __devinit btaudio_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- struct btaudio *bta;
- struct cardinfo *card = &cards[pci_id->driver_data];
- unsigned char revision,lat;
- int rc = -EBUSY;
-
- if (pci_enable_device(pci_dev))
- return -EIO;
- if (!request_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0),
- "btaudio")) {
- return -EBUSY;
- }
-
- bta = kzalloc(sizeof(*bta),GFP_ATOMIC);
- if (!bta) {
- rc = -ENOMEM;
- goto fail0;
- }
-
- bta->pci = pci_dev;
- bta->irq = pci_dev->irq;
- bta->mem = pci_resource_start(pci_dev,0);
- bta->mmio = ioremap(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
-
- bta->source = 1;
- bta->bits = 8;
- bta->channels = 1;
- if (bta->analog) {
- bta->decimation = 15;
- } else {
- bta->decimation = 0;
- bta->sampleshift = 1;
- }
-
- /* sample rate */
- bta->rate = card->rate;
- if (rate)
- bta->rate = rate;
-
- mutex_init(&bta->lock);
- init_waitqueue_head(&bta->readq);
-
- if (-1 != latency) {
- printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",
- latency);
- pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
- }
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);
- printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
- pci_dev->device,revision,pci_dev->bus->number,
- PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
- printk("irq: %d, latency: %d, mmio: 0x%lx\n",
- bta->irq, lat, bta->mem);
- printk("btaudio: using card config \"%s\"\n", card->name);
-
- /* init hw */
- btwrite(0, REG_GPIO_DMA_CTL);
- btwrite(0, REG_INT_MASK);
- btwrite(~0U, REG_INT_STAT);
- pci_set_master(pci_dev);
-
- if ((rc = request_irq(bta->irq, btaudio_irq, IRQF_SHARED|IRQF_DISABLED,
- "btaudio",(void *)bta)) < 0) {
- printk(KERN_WARNING
- "btaudio: can't request irq (rc=%d)\n",rc);
- goto fail1;
- }
-
- /* register devices */
- if (digital) {
- rc = bta->dsp_digital =
- register_sound_dsp(&btaudio_digital_dsp_fops,dsp1);
- if (rc < 0) {
- printk(KERN_WARNING
- "btaudio: can't register digital dsp (rc=%d)\n",rc);
- goto fail2;
- }
- printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n",
- bta->dsp_digital >> 4);
- }
- if (analog) {
- rc = bta->dsp_analog =
- register_sound_dsp(&btaudio_analog_dsp_fops,dsp2);
- if (rc < 0) {
- printk(KERN_WARNING
- "btaudio: can't register analog dsp (rc=%d)\n",rc);
- goto fail3;
- }
- printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n",
- bta->dsp_analog >> 4);
- rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);
- if (rc < 0) {
- printk(KERN_WARNING
- "btaudio: can't register mixer (rc=%d)\n",rc);
- goto fail4;
- }
- printk(KERN_INFO "btaudio: registered device mixer%d\n",
- bta->mixer_dev >> 4);
- }
-
- /* hook into linked list */
- bta->next = btaudios;
- btaudios = bta;
-
- pci_set_drvdata(pci_dev,bta);
- return 0;
-
- fail4:
- unregister_sound_dsp(bta->dsp_analog);
- fail3:
- if (digital)
- unregister_sound_dsp(bta->dsp_digital);
- fail2:
- free_irq(bta->irq,bta);
- fail1:
- iounmap(bta->mmio);
- kfree(bta);
- fail0:
- release_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
- return rc;
-}
-
-static void __devexit btaudio_remove(struct pci_dev *pci_dev)
-{
- struct btaudio *bta = pci_get_drvdata(pci_dev);
- struct btaudio *walk;
-
- /* turn off all DMA / IRQs */
- btand(~15, REG_GPIO_DMA_CTL);
- btwrite(0, REG_INT_MASK);
- btwrite(~0U, REG_INT_STAT);
-
- /* unregister devices */
- if (digital) {
- unregister_sound_dsp(bta->dsp_digital);
- }
- if (analog) {
- unregister_sound_dsp(bta->dsp_analog);
- unregister_sound_mixer(bta->mixer_dev);
- }
-
- /* free resources */
- free_buffer(bta);
- free_irq(bta->irq,bta);
- release_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
- iounmap(bta->mmio);
-
- /* remove from linked list */
- if (bta == btaudios) {
- btaudios = NULL;
- } else {
- for (walk = btaudios; walk->next != bta; walk = walk->next)
- ; /* if (NULL == walk->next) BUG(); */
- walk->next = bta->next;
- }
-
- pci_set_drvdata(pci_dev, NULL);
- kfree(bta);
- return;
-}
-
-/* -------------------------------------------------------------- */
-
-static struct pci_device_id btaudio_pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_BROOKTREE,
- .device = 0x0878,
- .subvendor = 0x0070,
- .subdevice = 0xff01,
- .driver_data = BTA_OSPREY200,
- },{
- .vendor = PCI_VENDOR_ID_BROOKTREE,
- .device = 0x0878,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- .vendor = PCI_VENDOR_ID_BROOKTREE,
- .device = 0x0878,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- /* --- end of list --- */
- }
-};
-
-static struct pci_driver btaudio_pci_driver = {
- .name = "btaudio",
- .id_table = btaudio_pci_tbl,
- .probe = btaudio_probe,
- .remove = __devexit_p(btaudio_remove),
-};
-
-static int btaudio_init_module(void)
-{
- printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
- digital ? "digital" : "",
- analog && digital ? "+" : "",
- analog ? "analog" : "");
- return pci_register_driver(&btaudio_pci_driver);
-}
-
-static void btaudio_cleanup_module(void)
-{
- pci_unregister_driver(&btaudio_pci_driver);
- return;
-}
-
-module_init(btaudio_init_module);
-module_exit(btaudio_cleanup_module);
-
-module_param(dsp1, int, S_IRUGO);
-module_param(dsp2, int, S_IRUGO);
-module_param(mixer, int, S_IRUGO);
-module_param(debug, int, S_IRUGO | S_IWUSR);
-module_param(irq_debug, int, S_IRUGO | S_IWUSR);
-module_param(digital, int, S_IRUGO);
-module_param(analog, int, S_IRUGO);
-module_param(rate, int, S_IRUGO);
-module_param(latency, int, S_IRUGO);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
-MODULE_DESCRIPTION("bt878 audio dma driver");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c
deleted file mode 100644
index de40e21..0000000
--- a/sound/oss/cs4232.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * cs4232.c
- *
- * The low level driver for Crystal CS4232 based cards. The CS4232 is
- * a PnP compatible chip which contains a CS4231A codec, SB emulation,
- * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM
- * interfaces. This is just a temporary driver until full PnP support
- * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
- * supported. Other interfaces are left uninitialized.
- *
- * ifdef ...WAVEFRONT...
- *
- * Support is provided for initializing the WaveFront synth
- * interface as well, which is logical device #4. Note that if
- * you have a Tropez+ card, you probably don't need to setup
- * the CS4232-supported MIDI interface, since it corresponds to
- * the internal 26-pin header that's hard to access. Using this
- * requires an additional IRQ, a resource none too plentiful in
- * this environment. Just don't set module parameters mpuio and
- * mpuirq, and the MIDI port will be left uninitialized. You can
- * still use the ICS2115 hosted MIDI interface which corresponds
- * to the 9-pin D connector on the back of the card.
- *
- * endif ...WAVEFRONT...
- *
- * Supported chips are:
- * CS4232
- * CS4236
- * CS4236B
- *
- * Note: You will need a PnP config setup to initialise some CS4232 boards
- * anyway.
- *
- * Changes
- * John Rood Added Bose Sound System Support.
- * Toshio Spoor
- * Alan Cox Modularisation, Basic cleanups.
- * Paul Barton-Davis Separated MPU configuration, added
- * Tropez+ (WaveFront) support
- * Christoph Hellwig Adapted to module_init/module_exit,
- * simple cleanups
- * Arnaldo C. de Melo got rid of attach_uart401
- * Bartlomiej Zolnierkiewicz
- * Added some __init/__initdata/__exit
- * Marcus Meissner Added ISA PnP support.
- */
-
-#include <linux/pnp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#define KEY_PORT 0x279 /* Same as LPT1 status port */
-#define CSN_NUM 0x99 /* Just a random number */
-#define INDEX_ADDRESS 0x00 /* (R0) Index Address Register */
-#define INDEX_DATA 0x01 /* (R1) Indexed Data Register */
-#define PIN_CONTROL 0x0a /* (I10) Pin Control */
-#define ENABLE_PINS 0xc0 /* XCTRL0/XCTRL1 enable */
-
-static void CS_OUT(unsigned char a)
-{
- outb(a, KEY_PORT);
-}
-
-#define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);}
-#define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
-
-static int __initdata bss = 0;
-static int mpu_base, mpu_irq;
-static int synth_base, synth_irq;
-static int mpu_detected;
-
-static int probe_cs4232_mpu(struct address_info *hw_config)
-{
- /*
- * Just write down the config values.
- */
-
- mpu_base = hw_config->io_base;
- mpu_irq = hw_config->irq;
-
- return 1;
-}
-
-static unsigned char crystal_key[] = /* A 32 byte magic key sequence */
-{
- 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
- 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
- 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
- 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
-};
-
-static void sleep(unsigned howlong)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(howlong);
-}
-
-static void enable_xctrl(int baseio)
-{
- unsigned char regd;
-
- /*
- * Some IBM Aptiva's have the Bose Sound System. By default
- * the Bose Amplifier is disabled. The amplifier will be
- * activated, by setting the XCTRL0 and XCTRL1 bits.
- * Volume of the monitor bose speakers/woofer, can then
- * be set by changing the PCM volume.
- *
- */
-
- printk("cs4232: enabling Bose Sound System Amplifier.\n");
-
- /* Switch to Pin Control Address */
- regd = inb(baseio + INDEX_ADDRESS) & 0xe0;
- outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS );
-
- /* Activate the XCTRL0 and XCTRL1 Pins */
- regd = inb(baseio + INDEX_DATA);
- outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA );
-}
-
-static int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured)
-{
- int i, n;
- int base = hw_config->io_base, irq = hw_config->irq;
- int dma1 = hw_config->dma, dma2 = hw_config->dma2;
- struct resource *ports;
-
- if (base == -1 || irq == -1 || dma1 == -1) {
- printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
- return 0;
- }
-
- /*
- * Verify that the I/O port range is free.
- */
-
- ports = request_region(base, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);
- return 0;
- }
- if (ad1848_detect(ports, NULL, hw_config->osp)) {
- goto got_it; /* The card is already active */
- }
- if (isapnp_configured) {
- printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n");
- goto fail;
- }
-
- /*
- * This version of the driver doesn't use the PnP method when configuring
- * the card but a simplified method defined by Crystal. This means that
- * just one CS4232 compatible device can exist on the system. Also this
- * method conflicts with possible PnP support in the OS. For this reason
- * driver is just a temporary kludge.
- *
- * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)
- */
-
- /*
- * Repeat initialization few times since it doesn't always succeed in
- * first time.
- */
-
- for (n = 0; n < 4; n++)
- {
- /*
- * Wake up the card by sending a 32 byte Crystal key to the key port.
- */
-
- for (i = 0; i < 32; i++)
- CS_OUT(crystal_key[i]);
-
- sleep(HZ / 10);
-
- /*
- * Now set the CSN (Card Select Number).
- */
-
- CS_OUT2(0x06, CSN_NUM);
-
- /*
- * Then set some config bytes. First logical device 0
- */
-
- CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */
- CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */
-
- if (!request_region(0x388, 4, "FM")) /* Not free */
- CS_OUT3(0x48, 0x00, 0x00) /* FM base off */
- else {
- release_region(0x388, 4);
- CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */
- }
-
- CS_OUT3(0x42, 0x00, 0x00); /* SB base off */
- CS_OUT2(0x22, irq); /* SB+WSS IRQ */
- CS_OUT2(0x2a, dma1); /* SB+WSS DMA */
-
- if (dma2 != -1)
- CS_OUT2(0x25, dma2) /* WSS DMA2 */
- else
- CS_OUT2(0x25, 4); /* No WSS DMA2 */
-
- CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */
-
- sleep(HZ / 10);
-
- /*
- * Initialize logical device 3 (MPU)
- */
-
- if (mpu_base != 0 && mpu_irq != 0)
- {
- CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */
- CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */
- CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
- CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */
- }
-
- if(synth_base != 0)
- {
- CS_OUT2 (0x15, 0x04); /* logical device 4 (WaveFront) */
- CS_OUT3 (0x47, (synth_base >> 8) & 0xff,
- synth_base & 0xff); /* base */
- CS_OUT2 (0x22, synth_irq); /* IRQ */
- CS_OUT2 (0x33, 0x01); /* Activate logical dev 4 */
- }
-
- /*
- * Finally activate the chip
- */
-
- CS_OUT(0x79);
-
- sleep(HZ / 5);
-
- /*
- * Then try to detect the codec part of the chip
- */
-
- if (ad1848_detect(ports, NULL, hw_config->osp))
- goto got_it;
-
- sleep(HZ);
- }
-fail:
- release_region(base, 4);
- return 0;
-
-got_it:
- if (dma2 == -1)
- dma2 = dma1;
-
- hw_config->slots[0] = ad1848_init("Crystal audio controller", ports,
- irq,
- dma1, /* Playback DMA */
- dma2, /* Capture DMA */
- 0,
- hw_config->osp,
- THIS_MODULE);
-
- if (hw_config->slots[0] != -1 &&
- audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
- {
- /* Assume the mixer map is as suggested in the CS4232 databook */
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */
- }
- if (mpu_base != 0 && mpu_irq != 0)
- {
- static struct address_info hw_config2 = {
- 0
- }; /* Ensure it's initialized */
-
- hw_config2.io_base = mpu_base;
- hw_config2.irq = mpu_irq;
- hw_config2.dma = -1;
- hw_config2.dma2 = -1;
- hw_config2.always_detect = 0;
- hw_config2.name = NULL;
- hw_config2.driver_use_1 = 0;
- hw_config2.driver_use_2 = 0;
- hw_config2.card_subtype = 0;
-
- if (probe_uart401(&hw_config2, THIS_MODULE))
- {
- mpu_detected = 1;
- }
- else
- {
- mpu_base = mpu_irq = 0;
- }
- hw_config->slots[1] = hw_config2.slots[1];
- }
-
- if (bss)
- enable_xctrl(base);
-
- return 1;
-}
-
-static void __devexit unload_cs4232(struct address_info *hw_config)
-{
- int base = hw_config->io_base, irq = hw_config->irq;
- int dma1 = hw_config->dma, dma2 = hw_config->dma2;
-
- if (dma2 == -1)
- dma2 = dma1;
-
- ad1848_unload(base,
- irq,
- dma1, /* Playback DMA */
- dma2, /* Capture DMA */
- 0);
-
- sound_unload_audiodev(hw_config->slots[0]);
- if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
- {
- static struct address_info hw_config2 =
- {
- 0
- }; /* Ensure it's initialized */
-
- hw_config2.io_base = mpu_base;
- hw_config2.irq = mpu_irq;
- hw_config2.dma = -1;
- hw_config2.dma2 = -1;
- hw_config2.always_detect = 0;
- hw_config2.name = NULL;
- hw_config2.driver_use_1 = 0;
- hw_config2.driver_use_2 = 0;
- hw_config2.card_subtype = 0;
- hw_config2.slots[1] = hw_config->slots[1];
-
- unload_uart401(&hw_config2);
- }
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-static int __initdata mpuio = -1;
-static int __initdata mpuirq = -1;
-static int __initdata synthio = -1;
-static int __initdata synthirq = -1;
-static int __initdata isapnp = 1;
-
-static unsigned int cs4232_devices;
-
-MODULE_DESCRIPTION("CS4232 based soundcard driver");
-MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io,"base I/O port for AD1848");
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq,"IRQ for AD1848 chip");
-module_param(dma, int, 0);
-MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip");
-module_param(dma2, int, 0);
-MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip");
-module_param(mpuio, int, 0);
-MODULE_PARM_DESC(mpuio,"MPU 401 base address");
-module_param(mpuirq, int, 0);
-MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ");
-module_param(synthio, int, 0);
-MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port");
-module_param(synthirq, int, 0);
-MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)");
-module_param(bss, bool, 0);
-MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)");
-
-/*
- * Install a CS4232 based card. Need to have ad1848 and mpu401
- * loaded ready.
- */
-
-/* All cs4232 based cards have the main ad1848 card either as CSC0000 or
- * CSC0100. */
-static const struct pnp_device_id cs4232_pnp_table[] = {
- { .id = "CSC0100", .driver_data = 0 },
- { .id = "CSC0000", .driver_data = 0 },
- /* Guillemot Turtlebeach something appears to be cs4232 compatible
- * (untested) */
- { .id = "GIM0100", .driver_data = 0 },
- { .id = ""}
-};
-
-MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);
-
-static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
- struct address_info *isapnpcfg;
-
- isapnpcfg = kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
- if (!isapnpcfg)
- return -ENOMEM;
-
- isapnpcfg->irq = pnp_irq(dev, 0);
- isapnpcfg->dma = pnp_dma(dev, 0);
- isapnpcfg->dma2 = pnp_dma(dev, 1);
- isapnpcfg->io_base = pnp_port_start(dev, 0);
- if (probe_cs4232(isapnpcfg,TRUE) == 0) {
- printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
- kfree(isapnpcfg);
- return -ENODEV;
- }
- pnp_set_drvdata(dev,isapnpcfg);
- cs4232_devices++;
- return 0;
-}
-
-static void __devexit cs4232_pnp_remove(struct pnp_dev *dev)
-{
- struct address_info *cfg = pnp_get_drvdata(dev);
- if (cfg) {
- unload_cs4232(cfg);
- kfree(cfg);
- }
-}
-
-static struct pnp_driver cs4232_driver = {
- .name = "cs4232",
- .id_table = cs4232_pnp_table,
- .probe = cs4232_pnp_probe,
- .remove = __devexit_p(cs4232_pnp_remove),
-};
-
-static int __init init_cs4232(void)
-{
-#ifdef CONFIG_SOUND_WAVEFRONT_MODULE
- if(synthio == -1)
- printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
- else {
- synth_base = synthio;
- synth_irq = synthirq;
- }
-#else
- if(synthio != -1)
- printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");
-#endif
- cfg.irq = -1;
-
- if (isapnp) {
- pnp_register_driver(&cs4232_driver);
- if (cs4232_devices)
- return 0;
- }
-
- if(io==-1||irq==-1||dma==-1)
- {
- printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");
- return -ENODEV;
- }
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
-
- cfg_mpu.io_base = -1;
- cfg_mpu.irq = -1;
-
- if (mpuio != -1 && mpuirq != -1) {
- cfg_mpu.io_base = mpuio;
- cfg_mpu.irq = mpuirq;
- probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */
- }
-
- if (probe_cs4232(&cfg,FALSE) == 0)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit cleanup_cs4232(void)
-{
- pnp_unregister_driver(&cs4232_driver);
- if (cfg.irq != -1)
- unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */
-}
-
-module_init(init_cs4232);
-module_exit(cleanup_cs4232);
-
-#ifndef MODULE
-static int __init setup_cs4232(char *str)
-{
- /* io, irq, dma, dma2 mpuio, mpuirq*/
- int ints[7];
-
- /* If we have isapnp cards, no need for options */
- pnp_register_driver(&cs4232_driver);
- if (cs4232_devices)
- return 1;
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- mpuio = ints[5];
- mpuirq = ints[6];
-
- return 1;
-}
-
-__setup("cs4232=", setup_cs4232);
-#endif
diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig
index 71b3134..3eb7827 100644
--- a/sound/oss/dmasound/Kconfig
+++ b/sound/oss/dmasound/Kconfig
@@ -14,7 +14,7 @@
config DMASOUND_PAULA
tristate "Amiga DMA sound support"
- depends on (AMIGA || APUS) && SOUND
+ depends on AMIGA && SOUND
select DMASOUND
help
If you want to use the internal audio of your Amiga in Linux, answer
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
index 90fc058..202e810 100644
--- a/sound/oss/dmasound/dmasound_paula.c
+++ b/sound/oss/dmasound/dmasound_paula.c
@@ -91,10 +91,6 @@
* power LED are controlled by the same line.
*/
-#ifdef CONFIG_APUS
-#define mach_heartbeat ppc_md.heartbeat
-#endif
-
static void (*saved_heartbeat)(int) = NULL;
static inline void disable_heartbeat(void)
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
deleted file mode 100644
index f5e31f1..0000000
--- a/sound/oss/i810_audio.c
+++ /dev/null
@@ -1,3656 +0,0 @@
-/*
- * Intel i810 and friends ICH driver for Linux
- * Alan Cox <alan@redhat.com>
- *
- * Built from:
- * Low level code: Zach Brown (original nonworking i810 OSS driver)
- * Jaroslav Kysela <perex@suse.cz> (working ALSA driver)
- *
- * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Extended by: Zach Brown <zab@redhat.com>
- * and others..
- *
- * Hardware Provided By:
- * Analog Devices (A major AC97 codec maker)
- * Intel Corp (you've probably heard of them already)
- *
- * AC97 clues and assistance provided by
- * Analog Devices
- * Zach 'Fufu' Brown
- * Jeff Garzik
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * Intel 810 theory of operation
- *
- * The chipset provides three DMA channels that talk to an AC97
- * CODEC (AC97 is a digital/analog mixer standard). At its simplest
- * you get 48Khz audio with basic volume and mixer controls. At the
- * best you get rate adaption in the codec. We set the card up so
- * that we never take completion interrupts but instead keep the card
- * chasing its tail around a ring buffer. This is needed for mmap
- * mode audio and happens to work rather well for non-mmap modes too.
- *
- * The board has one output channel for PCM audio (supported) and
- * a stereo line in and mono microphone input. Again these are normally
- * locked to 48Khz only. Right now recording is not finished.
- *
- * There is no midi support, no synth support. Use timidity. To get
- * esd working you need to use esd -r 48000 as it won't probe 48KHz
- * by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- * Fix The Sound On Dell
- *
- * Not everyone uses 48KHz. We know of no way to detect this reliably
- * and certainly not to get the right data. If your i810 audio sounds
- * stupid you may need to investigate other speeds. According to Analog
- * they tend to use a 14.318MHz clock which gives you a base rate of
- * 41194Hz.
- *
- * This is available via the 'ftsodell=1' option.
- *
- * If you need to force a specific rate set the clocking= option
- *
- * This driver is cursed. (Ben LaHaise)
- *
- * ICH 3 caveats
- * Intel errata #7 for ICH3 IO. We need to disable SMI stuff
- * when codec probing. [Not Yet Done]
- *
- * ICH 4 caveats
- *
- * The ICH4 has the feature, that the codec ID doesn't have to be
- * congruent with the IO connection.
- *
- * Therefore, from driver version 0.23 on, there is a "codec ID" <->
- * "IO register base offset" mapping (card->ac97_id_map) field.
- *
- * Juergen "George" Sawinski (jsaw)
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#define DRIVER_VERSION "1.01"
-
-#define MODULOP2(a, b) ((a) & ((b) - 1))
-#define MASKP2(a, b) ((a) & ~((b) - 1))
-
-static int ftsodell;
-static int strict_clocking;
-static unsigned int clocking;
-static int spdif_locked;
-static int ac97_quirk = AC97_TUNE_DEFAULT;
-
-//#define DEBUG
-//#define DEBUG2
-//#define DEBUG_INTERRUPTS
-//#define DEBUG_MMAP
-//#define DEBUG_MMIO
-
-#define ADC_RUNNING 1
-#define DAC_RUNNING 2
-
-#define I810_FMT_16BIT 1
-#define I810_FMT_STEREO 2
-#define I810_FMT_MASK 3
-
-#define SPDIF_ON 0x0004
-#define SURR_ON 0x0010
-#define CENTER_LFE_ON 0x0020
-#define VOL_MUTED 0x8000
-
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK 0xFFFFFFFE
- u32 busaddr;
-#define CON_IOC 0x80000000 /* interrupt on completion */
-#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */
- u32 control;
-};
-
-/* an instance of the i810 channel */
-#define SG_LEN 32
-struct i810_channel
-{
- /* these sg guys should probably be allocated
- separately as nocache. Must be 8 byte aligned */
- struct sg_item sg[SG_LEN]; /* 32*8 */
- u32 offset; /* 4 */
- u32 port; /* 4 */
- u32 used;
- u32 num;
-};
-
-/*
- * we have 3 separate dma engines. pcm in, pcm out, and mic.
- * each dma engine has controlling registers. These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- *
- * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2,
- * mic in 2, s/pdif. Of special interest is the fact that
- * the upper 3 DMA engines on the ICH4 *must* be accessed
- * via mmio access instead of pio access.
- */
-
-#define ENUM_ENGINE(PRE,DIG) \
-enum { \
- PRE##_BASE = 0x##DIG##0, /* Base Address */ \
- PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \
- PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \
- PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \
- PRE##_SR = 0x##DIG##6, /* Status Register */ \
- PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \
- PRE##_PIV = 0x##DIG##a, /* Prefetched Index Value */ \
- PRE##_CR = 0x##DIG##b /* Control Register */ \
-}
-
-ENUM_ENGINE(OFF,0); /* Offsets */
-ENUM_ENGINE(PI,0); /* PCM In */
-ENUM_ENGINE(PO,1); /* PCM Out */
-ENUM_ENGINE(MC,2); /* Mic In */
-
-enum {
- GLOB_CNT = 0x2c, /* Global Control */
- GLOB_STA = 0x30, /* Global Status */
- CAS = 0x34 /* Codec Write Semaphore Register */
-};
-
-ENUM_ENGINE(MC2,4); /* Mic In 2 */
-ENUM_ENGINE(PI2,5); /* PCM In 2 */
-ENUM_ENGINE(SP,6); /* S/PDIF */
-
-enum {
- SDM = 0x80 /* SDATA_IN Map Register */
-};
-
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */
-#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */
-#define DMA_INT_LVI (1<<2) /* last valid done */
-#define DMA_INT_CELV (1<<1) /* last valid is current */
-#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */
-#define INT_SEC (1<<11)
-#define INT_PRI (1<<10)
-#define INT_MC (1<<7)
-#define INT_PO (1<<6)
-#define INT_PI (1<<5)
-#define INT_MO (1<<2)
-#define INT_NI (1<<1)
-#define INT_GPI (1<<0)
-#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
-
-/* magic numbers to protect our data structures */
-#define I810_CARD_MAGIC 0x5072696E /* "Prin" */
-#define I810_STATE_MAGIC 0x63657373 /* "cess" */
-#define I810_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH 3
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 4
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-enum {
- ICH82801AA = 0,
- ICH82901AB,
- INTEL440MX,
- INTELICH2,
- INTELICH3,
- INTELICH4,
- INTELICH5,
- SI7012,
- NVIDIA_NFORCE,
- AMD768,
- AMD8111
-};
-
-static char * card_names[] = {
- "Intel ICH 82801AA",
- "Intel ICH 82901AB",
- "Intel 440MX",
- "Intel ICH2",
- "Intel ICH3",
- "Intel ICH4",
- "Intel ICH5",
- "SiS 7012",
- "NVIDIA nForce Audio",
- "AMD 768",
- "AMD-8111 IOHub"
-};
-
-/* These are capabilities (and bugs) the chipsets _can_ have */
-static struct {
- int16_t nr_ac97;
-#define CAP_MMIO 0x0001
-#define CAP_20BIT_AUDIO_SUPPORT 0x0002
- u_int16_t flags;
-} card_cap[] = {
- { 1, 0x0000 }, /* ICH82801AA */
- { 1, 0x0000 }, /* ICH82901AB */
- { 1, 0x0000 }, /* INTEL440MX */
- { 1, 0x0000 }, /* INTELICH2 */
- { 2, 0x0000 }, /* INTELICH3 */
- { 3, 0x0003 }, /* INTELICH4 */
- { 3, 0x0003 }, /* INTELICH5 */
- /*@FIXME to be verified*/ { 2, 0x0000 }, /* SI7012 */
- /*@FIXME to be verified*/ { 2, 0x0000 }, /* NVIDIA_NFORCE */
- /*@FIXME to be verified*/ { 2, 0x0000 }, /* AMD768 */
- /*@FIXME to be verified*/ { 3, 0x0001 }, /* AMD8111 */
-};
-
-static struct pci_device_id i810_pci_tbl [] = {
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_4,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH5},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7445,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768},
- {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_18,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, i810_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct i810_state {
- unsigned int magic;
- struct i810_card *card; /* Card info */
-
- /* single open lock mechanism, only used for recording */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- /* file mode */
- mode_t open_mode;
-
- /* virtual channel number */
- int virt;
-
-#ifdef CONFIG_PM
- unsigned int pm_saved_dac_rate,pm_saved_adc_rate;
-#endif
- struct dmabuf {
- /* wave sample stuff */
- unsigned int rate;
- unsigned char fmt, enable, trigger;
-
- /* hardware channel */
- struct i810_channel *read_channel;
- struct i810_channel *write_channel;
-
- /* OSS buffer management stuff */
- void *rawbuf;
- dma_addr_t dma_handle;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started, updated by update_ptr */
- unsigned swptr; /* where driver last clear/filled, updated by read/write */
- int count; /* bytes to be consumed or been generated by dma machine */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- unsigned error; /* number of over/underruns */
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- /* what the hardware uses */
- unsigned dmasize;
- unsigned fragsize;
- unsigned fragsamples;
-
- /* what we tell the user to expect */
- unsigned userfrags;
- unsigned userfragsize;
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned update_flag;
- unsigned ossfragsize;
- unsigned ossmaxfrags;
- unsigned subdivision;
- } dmabuf;
-};
-
-
-struct i810_card {
- unsigned int magic;
-
- /* We keep i810 cards in a linked list */
- struct i810_card *next;
-
- /* The i810 has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
-
- /* Control AC97 access serialization */
- spinlock_t ac97_lock;
-
- /* PCI device stuff */
- struct pci_dev * pci_dev;
- u16 pci_id;
- u16 pci_id_internal; /* used to access card_cap[] */
-#ifdef CONFIG_PM
- u16 pm_suspended;
- int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
- /* soundcore stuff */
- int dev_audio;
-
- /* structures for abstraction of hardware facilities, codecs, banks and channels*/
- u16 ac97_id_map[NR_AC97];
- struct ac97_codec *ac97_codec[NR_AC97];
- struct i810_state *states[NR_HW_CH];
- struct i810_channel *channel; /* 1:1 to states[] but diff. lifetime */
- dma_addr_t chandma;
-
- u16 ac97_features;
- u16 ac97_status;
- u16 channels;
-
- /* hardware resources */
- unsigned long ac97base;
- unsigned long iobase;
- u32 irq;
-
- unsigned long ac97base_mmio_phys;
- unsigned long iobase_mmio_phys;
- u_int8_t __iomem *ac97base_mmio;
- u_int8_t __iomem *iobase_mmio;
-
- int use_mmio;
-
- /* Function support */
- struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
- struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
- struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
- void (*free_pcm_channel)(struct i810_card *, int chan);
-
- /* We have a *very* long init time possibly, so use this to block */
- /* attempts to open our devices before we are ready (stops oops'es) */
- int initializing;
-};
-
-/* extract register offset from codec struct */
-#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
-
-#define I810_IOREAD(size, type, card, off) \
-({ \
- type val; \
- if (card->use_mmio) \
- val=read##size(card->iobase_mmio+off); \
- else \
- val=in##size(card->iobase+off); \
- val; \
-})
-
-#define I810_IOREADL(card, off) I810_IOREAD(l, u32, card, off)
-#define I810_IOREADW(card, off) I810_IOREAD(w, u16, card, off)
-#define I810_IOREADB(card, off) I810_IOREAD(b, u8, card, off)
-
-#define I810_IOWRITE(size, val, card, off) \
-({ \
- if (card->use_mmio) \
- write##size(val, card->iobase_mmio+off); \
- else \
- out##size(val, card->iobase+off); \
-})
-
-#define I810_IOWRITEL(val, card, off) I810_IOWRITE(l, val, card, off)
-#define I810_IOWRITEW(val, card, off) I810_IOWRITE(w, val, card, off)
-#define I810_IOWRITEB(val, card, off) I810_IOWRITE(b, val, card, off)
-
-#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), SG_LEN)
-#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), SG_LEN)
-
-/* set LVI from CIV */
-#define CIV_TO_LVI(card, port, off) \
- I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI)
-
-static struct ac97_quirk ac97_quirks[] __devinitdata = {
- {
- .vendor = 0x0e11,
- .device = 0x00b8,
- .name = "Compaq Evo D510C",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x00d8,
- .name = "Dell Precision 530", /* AD1885 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x0126,
- .name = "Dell Optiplex GX260", /* AD1981A */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x012d,
- .name = "Dell Precision 450", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- { /* FIXME: which codec? */
- .vendor = 0x103c,
- .device = 0x00c3,
- .name = "Hewlett-Packard onboard",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x12f1,
- .name = "HP xw8200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x3008,
- .name = "HP xw4200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x10f1,
- .device = 0x2665,
- .name = "Fujitsu-Siemens Celsius", /* AD1981? */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x10f1,
- .device = 0x2885,
- .name = "AMD64 Mobo", /* ALC650 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x110a,
- .device = 0x0056,
- .name = "Fujitsu-Siemens Scenic", /* AD1981? */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x11d4,
- .device = 0x5375,
- .name = "ADI AD1985 (discrete)",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1462,
- .device = 0x5470,
- .name = "MSI P4 ATX 645 Ultra",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1734,
- .device = 0x0088,
- .name = "Fujitsu-Siemens D1522", /* AD1981 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x8086,
- .device = 0x4856,
- .name = "Intel D845WN (82801BA)",
- .type = AC97_TUNE_SWAP_HP
- },
- {
- .vendor = 0x8086,
- .device = 0x4d44,
- .name = "Intel D850EMV2", /* AD1885 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x8086,
- .device = 0x4d56,
- .name = "Intel ICH/AD1885",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x012d,
- .name = "Dell Precision 450", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x3008,
- .name = "HP xw4200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x12f1,
- .name = "HP xw8200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- { } /* terminator */
-};
-
-static struct i810_card *devs = NULL;
-
-static int i810_open_mixdev(struct inode *inode, struct file *file);
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
-{
- if(card->channel[1].used==1)
- return NULL;
- card->channel[1].used=1;
- return &card->channel[1];
-}
-
-static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card)
-{
- if(card->channel[0].used==1)
- return NULL;
- card->channel[0].used=1;
- return &card->channel[0];
-}
-
-static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card)
-{
- if(card->channel[2].used==1)
- return NULL;
- card->channel[2].used=1;
- return &card->channel[2];
-}
-
-static void i810_free_pcm_channel(struct i810_card *card, int channel)
-{
- card->channel[channel].used=0;
-}
-
-static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate )
-{
- unsigned long id = 0L;
-
- id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16);
- id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
-#ifdef DEBUG
- printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id);
-#endif
- switch ( id ) {
- case 0x41445361: /* AD1886 */
- if (rate == 48000) {
- return 1;
- }
- break;
- default: /* all other codecs, until we know otherwiae */
- if (rate == 48000 || rate == 44100 || rate == 32000) {
- return 1;
- }
- break;
- }
- return (0);
-}
-
-/* i810_set_spdif_output
- *
- * Configure the S/PDIF output transmitter. When we turn on
- * S/PDIF, we turn off the analog output. This may not be
- * the right thing to do.
- *
- * Assumptions:
- * The DSP sample rate must already be set to a supported
- * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static int i810_set_spdif_output(struct i810_state *state, int slots, int rate)
-{
- int vol;
- int aud_reg;
- int r = 0;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if(!codec->codec_ops->digital) {
- state->card->ac97_status &= ~SPDIF_ON;
- } else {
- if ( slots == -1 ) { /* Turn off S/PDIF */
- codec->codec_ops->digital(codec, 0, 0, 0);
- /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
- if ( !(state->card->ac97_status & VOL_MUTED) ) {
- aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
- }
- state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
- return 0;
- }
-
- vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- state->card->ac97_status = vol & VOL_MUTED;
-
- r = codec->codec_ops->digital(codec, slots, rate, 0);
-
- if(r)
- state->card->ac97_status |= SPDIF_ON;
- else
- state->card->ac97_status &= ~SPDIF_ON;
-
- /* Mute the analog output */
- /* Should this only mute the PCM volume??? */
- i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
- }
- return r;
-}
-
-/* i810_set_dac_channels
- *
- * Configure the codec's multi-channel DACs
- *
- * The logic is backwards. Setting the bit to 1 turns off the DAC.
- *
- * What about the ICH? We currently configure it using the
- * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC,
- * does that imply that we want the ICH set to support
- * these channels?
- *
- * TODO:
- * vailidate that the codec really supports these DACs
- * before turning them on.
- */
-static void i810_set_dac_channels(struct i810_state *state, int channel)
-{
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- /* No codec, no setup */
-
- if(codec == NULL)
- return;
-
- aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
- state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
- switch ( channel ) {
- case 2: /* always enabled */
- break;
- case 4:
- aud_reg &= ~AC97_EA_PRJ;
- state->card->ac97_status |= SURR_ON;
- break;
- case 6:
- aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
- state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
- break;
- default:
- break;
- }
- i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-
-/* set playback sample rate */
-static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec=state->card->ac97_codec[0];
-
- if(!(state->card->ac97_features&0x0001))
- {
- dmabuf->rate = clocking;
-#ifdef DEBUG
- printk("Asked for %d Hz, but ac97_features says we only do %dHz. Sorry!\n",
- rate,clocking);
-#endif
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
- rate = ( rate * clocking)/48000;
- if(strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000)/clocking;
- }
-
- new_rate=ac97_set_dac_rate(codec, rate);
- if(new_rate != rate) {
- dmabuf->rate = (new_rate * 48000)/clocking;
- }
-#ifdef DEBUG
- printk("i810_audio: called i810_set_dac_rate : asked for %d, got %d\n", rate, dmabuf->rate);
-#endif
- rate = new_rate;
- return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec=state->card->ac97_codec[0];
-
- if(!(state->card->ac97_features&0x0001))
- {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
-
- rate = ( rate * clocking)/48000;
- if(strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000)/clocking;
- }
-
- new_rate = ac97_set_adc_rate(codec, rate);
-
- if(new_rate != rate) {
- dmabuf->rate = (new_rate * 48000)/clocking;
- rate = new_rate;
- }
-#ifdef DEBUG
- printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate);
-#endif
- return dmabuf->rate;
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-
-static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int civ, offset, port, port_picb, bytes = 2;
-
- if (!dmabuf->enable)
- return 0;
-
- if (rec)
- port = dmabuf->read_channel->port;
- else
- port = dmabuf->write_channel->port;
-
- if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
- port_picb = port + OFF_SR;
- bytes = 1;
- } else
- port_picb = port + OFF_PICB;
-
- do {
- civ = GET_CIV(state->card, port);
- offset = I810_IOREADW(state->card, port_picb);
- /* Must have a delay here! */
- if(offset == 0)
- udelay(1);
- /* Reread both registers and make sure that that total
- * offset from the first reading to the second is 0.
- * There is an issue with SiS hardware where it will count
- * picb down to 0, then update civ to the next value,
- * then set the new picb to fragsize bytes. We can catch
- * it between the civ update and the picb update, making
- * it look as though we are 1 fragsize ahead of where we
- * are. The next to we get the address though, it will
- * be back in the right place, and we will suddenly think
- * we just went forward dmasize - fragsize bytes, causing
- * totally stupid *huge* dma overrun messages. We are
- * assuming that the 1us delay is more than long enough
- * that we won't have to worry about the chip still being
- * out of sync with reality ;-)
- */
- } while (civ != GET_CIV(state->card, port) || offset != I810_IOREADW(state->card, port_picb));
-
- return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
- % dmabuf->dmasize);
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct i810_card *card = state->card;
-
- dmabuf->enable &= ~ADC_RUNNING;
- I810_IOWRITEB(0, card, PI_CR);
- // wait for the card to acknowledge shutdown
- while( I810_IOREADB(card, PI_CR) != 0 ) ;
- // now clear any latent interrupt bits (like the halt bit)
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB );
- else
- I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR );
- I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA);
-}
-
-static void stop_adc(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __stop_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->enable |= ADC_RUNNING;
- // Interrupt enable, LVI enable, DMA enable
- I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR);
- }
-}
-
-static void start_adc(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __start_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct i810_card *card = state->card;
-
- dmabuf->enable &= ~DAC_RUNNING;
- I810_IOWRITEB(0, card, PO_CR);
- // wait for the card to acknowledge shutdown
- while( I810_IOREADB(card, PO_CR) != 0 ) ;
- // now clear any latent interrupt bits (like the halt bit)
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB );
- else
- I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR );
- I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA);
-}
-
-static void stop_dac(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __stop_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_dac(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->enable |= DAC_RUNNING;
- // Interrupt enable, LVI enable, DMA enable
- I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR);
- }
-}
-static void start_dac(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __start_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback and recording buffer should be allocated separately */
-static int alloc_dmabuf(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- void *rawbuf= NULL;
- int order, size;
- struct page *page, *pend;
-
- /* If we don't have any oss frag params, then use our default ones */
- if(dmabuf->ossmaxfrags == 0)
- dmabuf->ossmaxfrags = 4;
- if(dmabuf->ossfragsize == 0)
- dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
- size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
- if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
- return 0;
- /* alloc enough to satisfy the oss params */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- if ( (PAGE_SIZE<<order) > size )
- continue;
- if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
- PAGE_SIZE << order,
- &dmabuf->dma_handle)))
- break;
- }
- if (!rawbuf)
- return -ENOMEM;
-
-
-#ifdef DEBUG
- printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, rawbuf);
-#endif
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(rawbuf); page <= pend; page++)
- SetPageReserved(page);
-
- return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct page *page, *pend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_handle);
- }
- dmabuf->rawbuf = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct i810_state *state, unsigned rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct i810_channel *c;
- struct sg_item *sg;
- unsigned long flags;
- int ret;
- unsigned fragint;
- int i;
-
- spin_lock_irqsave(&state->card->lock, flags);
- if(dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if(dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- dmabuf->total_bytes = 0;
- dmabuf->count = dmabuf->error = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* allocate DMA buffer, let alloc_dmabuf determine if we are already
- * allocated well enough or if we should replace the current buffer
- * (assuming one is already allocated, if it isn't, then allocate it).
- */
- if ((ret = alloc_dmabuf(state)))
- return ret;
-
- /* FIXME: figure out all this OSS fragment stuff */
- /* I did, it now does what it should according to the OSS API. DL */
- /* We may not have realloced our dmabuf, but the fragment size to
- * fragment number ratio may have changed, so go ahead and reprogram
- * things
- */
- dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
- dmabuf->numfrag = SG_LEN;
- dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
- dmabuf->fragsamples = dmabuf->fragsize >> 1;
- dmabuf->fragshift = ffs(dmabuf->fragsize) - 1;
- dmabuf->userfragsize = dmabuf->ossfragsize;
- dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize;
-
- memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
- if(dmabuf->ossmaxfrags == 4) {
- fragint = 8;
- } else if (dmabuf->ossmaxfrags == 8) {
- fragint = 4;
- } else if (dmabuf->ossmaxfrags == 16) {
- fragint = 2;
- } else {
- fragint = 1;
- }
- /*
- * Now set up the ring
- */
- if(dmabuf->read_channel)
- c = dmabuf->read_channel;
- else
- c = dmabuf->write_channel;
- while(c != NULL) {
- sg=&c->sg[0];
- /*
- * Load up 32 sg entries and take an interrupt at half
- * way (we might want more interrupts later..)
- */
-
- for(i=0;i<dmabuf->numfrag;i++)
- {
- sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
- // the card will always be doing 16bit stereo
- sg->control=dmabuf->fragsamples;
- if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
- sg->control <<= 1;
- sg->control|=CON_BUFPAD;
- // set us up to get IOC interrupts as often as needed to
- // satisfy numfrag requirements, no more
- if( ((i+1) % fragint) == 0) {
- sg->control|=CON_IOC;
- }
- sg++;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */
- while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ;
- I810_IOWRITEL((u32)state->card->chandma +
- c->num*sizeof(struct i810_channel),
- state->card, c->port+OFF_BDBAR);
- CIV_TO_LVI(state->card, c->port, 0);
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if(c != dmabuf->write_channel)
- c = dmabuf->write_channel;
- else
- c = NULL;
- }
-
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
-
-#ifdef DEBUG
- printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, "
- "fragsize = %d dmasize = %d\n",
- dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
- return 0;
-}
-
-static void __i810_update_lvi(struct i810_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int x, port;
- int trigger;
- int count, fragsize;
- void (*start)(struct i810_state *);
-
- count = dmabuf->count;
- if (rec) {
- port = dmabuf->read_channel->port;
- trigger = PCM_ENABLE_INPUT;
- start = __start_adc;
- count = dmabuf->dmasize - count;
- } else {
- port = dmabuf->write_channel->port;
- trigger = PCM_ENABLE_OUTPUT;
- start = __start_dac;
- }
-
- /* Do not process partial fragments. */
- fragsize = dmabuf->fragsize;
- if (count < fragsize)
- return;
-
- /* if we are currently stopped, then our CIV is actually set to our
- * *last* sg segment and we are ready to wrap to the next. However,
- * if we set our LVI to the last sg segment, then it won't wrap to
- * the next sg segment, it won't even get a start. So, instead, when
- * we are stopped, we set both the LVI value and also we increment
- * the CIV value to the next sg segment to be played so that when
- * we call start, things will operate properly. Since the CIV can't
- * be written to directly for this purpose, we set the LVI to CIV + 1
- * temporarily. Once the engine has started we set the LVI to its
- * final value.
- */
- if (!dmabuf->enable && dmabuf->ready) {
- if (!(dmabuf->trigger & trigger))
- return;
-
- CIV_TO_LVI(state->card, port, 1);
-
- start(state);
- while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2))))
- ;
- }
-
- /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
- x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
- x >>= dmabuf->fragshift;
- I810_IOWRITEB(x, state->card, port + OFF_LVI);
-}
-
-static void i810_update_lvi(struct i810_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
-
- if(!dmabuf->ready)
- return;
- spin_lock_irqsave(&state->card->lock, flags);
- __i810_update_lvi(state, rec);
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void i810_update_ptr(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned hwptr;
- unsigned fragmask, dmamask;
- int diff;
-
- fragmask = MASKP2(~0, dmabuf->fragsize);
- dmamask = MODULOP2(~0, dmabuf->dmasize);
-
- /* error handling and process wake up for ADC */
- if (dmabuf->enable == ADC_RUNNING) {
- /* update hardware pointer */
- hwptr = i810_get_dma_addr(state, 1) & fragmask;
- diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
- printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count += diff;
- if (dmabuf->count > dmabuf->dmasize) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a read */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if (GET_CIV(state->card, PI_BASE) !=
- GET_LVI(state->card, PI_BASE)) {
- printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
- dmabuf->error++;
- }
- }
- if (diff)
- wake_up(&dmabuf->wait);
- }
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == DAC_RUNNING) {
- /* update hardware pointer */
- hwptr = i810_get_dma_addr(state, 0) & fragmask;
- diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
- printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count -= diff;
- if (dmabuf->count < 0) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a write */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if (GET_CIV(state->card, PO_BASE) !=
- GET_LVI(state->card, PO_BASE)) {
- printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
- printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
- "count %d\n",
- GET_CIV(state->card, PO_BASE),
- GET_LVI(state->card, PO_BASE),
- dmabuf->hwptr, dmabuf->count);
- dmabuf->error++;
- }
- }
- if (diff)
- wake_up(&dmabuf->wait);
- }
-}
-
-static inline int i810_get_free_write_space(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int free;
-
- i810_update_ptr(state);
- // catch underruns during playback
- if (dmabuf->count < 0) {
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- }
- free = dmabuf->dmasize - dmabuf->count;
- if(free < 0)
- return(0);
- return(free);
-}
-
-static inline int i810_get_available_read_data(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int avail;
-
- i810_update_ptr(state);
- // catch overruns during record
- if (dmabuf->count > dmabuf->dmasize) {
- dmabuf->count = dmabuf->dmasize;
- dmabuf->swptr = dmabuf->hwptr;
- }
- avail = dmabuf->count;
- if(avail < 0)
- return(0);
- return(avail);
-}
-
-static inline void fill_partial_frag(struct dmabuf *dmabuf)
-{
- unsigned fragsize;
- unsigned swptr, len;
-
- fragsize = dmabuf->fragsize;
- swptr = dmabuf->swptr;
- len = fragsize - MODULOP2(dmabuf->swptr, fragsize);
- if (len == fragsize)
- return;
-
- memset(dmabuf->rawbuf + swptr, '\0', len);
- dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize);
- dmabuf->count += len;
-}
-
-static int drain_dac(struct i810_state *state, int signals_allowed)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned long tmo;
- int count;
-
- if (!dmabuf->ready)
- return 0;
- if(dmabuf->mapped) {
- stop_dac(state);
- return 0;
- }
-
- spin_lock_irqsave(&state->card->lock, flags);
-
- fill_partial_frag(dmabuf);
-
- /*
- * This will make sure that our LVI is correct, that our
- * pointer is updated, and that the DAC is running. We
- * have to force the setting of dmabuf->trigger to avoid
- * any possible deadlocks.
- */
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- __i810_update_lvi(state, 0);
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
-
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- count = dmabuf->count;
-
- /* It seems that we have to set the current state to
- * TASK_INTERRUPTIBLE every time to make the process
- * really go to sleep. This also has to be *after* the
- * update_ptr() call because update_ptr is likely to
- * do a wake_up() which will unset this before we ever
- * try to sleep, resuling in a tight loop in this code
- * instead of actually sleeping and waiting for an
- * interrupt to wake us up!
- */
- __set_current_state(signals_allowed ?
- TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (count <= 0)
- break;
-
- if (signal_pending(current) && signals_allowed) {
- break;
- }
-
- /*
- * set the timeout to significantly longer than it *should*
- * take for the DAC to drain the DMA buffer
- */
- tmo = (count * HZ) / (dmabuf->rate);
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
- printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
- count = 0;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &wait);
- if(count > 0 && signal_pending(current) && signals_allowed)
- return -ERESTARTSYS;
- stop_dac(state);
- return 0;
-}
-
-static void i810_channel_interrupt(struct i810_card *card)
-{
- int i, count;
-
-#ifdef DEBUG_INTERRUPTS
- printk("CHANNEL ");
-#endif
- for(i=0;i<NR_HW_CH;i++)
- {
- struct i810_state *state = card->states[i];
- struct i810_channel *c;
- struct dmabuf *dmabuf;
- unsigned long port;
- u16 status;
-
- if(!state)
- continue;
- if(!state->dmabuf.ready)
- continue;
- dmabuf = &state->dmabuf;
- if(dmabuf->enable & DAC_RUNNING) {
- c=dmabuf->write_channel;
- } else if(dmabuf->enable & ADC_RUNNING) {
- c=dmabuf->read_channel;
- } else /* This can occur going from R/W to close */
- continue;
-
- port = c->port;
-
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- status = I810_IOREADW(card, port + OFF_PICB);
- else
- status = I810_IOREADW(card, port + OFF_SR);
-
-#ifdef DEBUG_INTERRUPTS
- printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
-#endif
- if(status & DMA_INT_COMPLETE)
- {
- /* only wake_up() waiters if this interrupt signals
- * us being beyond a userfragsize of data open or
- * available, and i810_update_ptr() does that for
- * us
- */
- i810_update_ptr(state);
-#ifdef DEBUG_INTERRUPTS
- printk("COMP %d ", dmabuf->hwptr /
- dmabuf->fragsize);
-#endif
- }
- if(status & (DMA_INT_LVI | DMA_INT_DCH))
- {
- /* wake_up() unconditionally on LVI and DCH */
- i810_update_ptr(state);
- wake_up(&dmabuf->wait);
-#ifdef DEBUG_INTERRUPTS
- if(status & DMA_INT_LVI)
- printk("LVI ");
- if(status & DMA_INT_DCH)
- printk("DCH -");
-#endif
- count = dmabuf->count;
- if(dmabuf->enable & ADC_RUNNING)
- count = dmabuf->dmasize - count;
- if (count >= (int)dmabuf->fragsize) {
- I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR);
-#ifdef DEBUG_INTERRUPTS
- printk(" CONTINUE ");
-#endif
- } else {
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- dmabuf->enable = 0;
-#ifdef DEBUG_INTERRUPTS
- printk(" STOP ");
-#endif
- }
- }
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB);
- else
- I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR);
- }
-#ifdef DEBUG_INTERRUPTS
- printk(")\n");
-#endif
-}
-
-static irqreturn_t i810_interrupt(int irq, void *dev_id)
-{
- struct i810_card *card = dev_id;
- u32 status;
-
- spin_lock(&card->lock);
-
- status = I810_IOREADL(card, GLOB_STA);
-
- if(!(status & INT_MASK))
- {
- spin_unlock(&card->lock);
- return IRQ_NONE; /* not for us */
- }
-
- if(status & (INT_PO|INT_PI|INT_MC))
- i810_channel_interrupt(card);
-
- /* clear 'em */
- I810_IOWRITEL(status & INT_MASK, card, GLOB_STA);
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is
- waiting to be copied to the user's buffer. It is filled by the dma
- machine and drained by this loop. */
-
-static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_card *card=state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt;
- int pending;
- DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
- printk("i810_audio: i810_read called, count = %d\n", count);
-#endif
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & DAC_RUNNING)
- return -ENODEV;
- if (!dmabuf->read_channel) {
- dmabuf->ready = 0;
- dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
- if (!dmabuf->read_channel) {
- return -EBUSY;
- }
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- pending = 0;
-
- add_wait_queue(&dmabuf->wait, &waita);
- while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- schedule();
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
- cnt = i810_get_available_read_data(state);
- swptr = dmabuf->swptr;
- // this is to make the copy_to_user simpler below
- if(cnt > (dmabuf->dmasize - swptr))
- cnt = dmabuf->dmasize - swptr;
- spin_unlock_irqrestore(&card->lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- /*
- * Don't let us deadlock. The ADC won't start if
- * dmabuf->trigger isn't set. A call to SETTRIGGER
- * could have turned it off after we set it to on
- * previously.
- */
- dmabuf->trigger = PCM_ENABLE_INPUT;
- /*
- * This does three things. Updates LVI to be correct,
- * makes sure the ADC is running, and updates the
- * hwptr.
- */
- i810_update_lvi(state,1);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- goto done;
- }
- /* Set the timeout to how long it would take to fill
- * two of our buffers. If we haven't been woke up
- * by then, then we know something is wrong.
- */
- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer overrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
- printk(KERN_ERR "i810_audio: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer overrun, we delay the recovery until next time the
- while loop begin and we REALLY have space to record */
- }
- if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- goto done;
- }
- continue;
- }
-
- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret) ret = -EFAULT;
- goto done;
- }
-
- swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
- dmabuf->swptr = swptr;
- pending = dmabuf->count -= cnt;
- spin_unlock_irqrestore(&card->lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
- done:
- pending = dmabuf->dmasize - pending;
- if (dmabuf->enable || pending >= dmabuf->userfragsize)
- i810_update_lvi(state, 1);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
- the soundcard. it is drained by the dma machine and filled by this loop. */
-static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_card *card=state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr = 0;
- int pending;
- int cnt;
- DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
- printk("i810_audio: i810_write called, count = %d\n", count);
-#endif
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & ADC_RUNNING)
- return -ENODEV;
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel = card->alloc_pcm_channel(card);
- if(!dmabuf->write_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- pending = 0;
-
- add_wait_queue(&dmabuf->wait, &waita);
- while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&state->card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- schedule();
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
-
- cnt = i810_get_free_write_space(state);
- swptr = dmabuf->swptr;
- /* Bound the maximum size to how much we can copy to the
- * dma buffer before we hit the end. If we have more to
- * copy then it will get done in a second pass of this
- * loop starting from the beginning of the buffer.
- */
- if(cnt > (dmabuf->dmasize - swptr))
- cnt = dmabuf->dmasize - swptr;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
-#ifdef DEBUG2
- printk(KERN_INFO "i810_audio: i810_write: %d bytes available space\n", cnt);
-#endif
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- // There is data waiting to be played
- /*
- * Force the trigger setting since we would
- * deadlock with it set any other way
- */
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- i810_update_lvi(state,0);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- goto ret;
- }
- /* Not strictly correct but works */
- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer underrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
- printk(KERN_ERR "i810_audio: playback schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer underrun, we delay the recovery until next time the
- while loop begin and we REALLY have data to play */
- //return ret;
- }
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- goto ret;
- }
- continue;
- }
- if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) {
- if (!ret) ret = -EFAULT;
- goto ret;
- }
-
- swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
- spin_lock_irqsave(&state->card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
-
- dmabuf->swptr = swptr;
- pending = dmabuf->count += cnt;
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
-ret:
- if (dmabuf->enable || pending >= dmabuf->userfragsize)
- i810_update_lvi(state, 0);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned int mask = 0;
-
- if(!dmabuf->ready)
- return 0;
- poll_wait(file, &dmabuf->wait, wait);
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable & ADC_RUNNING ||
- dmabuf->trigger & PCM_ENABLE_INPUT) {
- if (i810_get_available_read_data(state) >=
- (signed)dmabuf->userfragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (dmabuf->enable & DAC_RUNNING ||
- dmabuf->trigger & PCM_ENABLE_OUTPUT) {
- if (i810_get_free_write_space(state) >=
- (signed)dmabuf->userfragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
- return mask;
-}
-
-static int i810_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- int ret = -EINVAL;
- unsigned long size;
-
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if (!dmabuf->write_channel &&
- (dmabuf->write_channel =
- state->card->alloc_pcm_channel(state->card)) == NULL) {
- ret = -EBUSY;
- goto out;
- }
- }
- if (vma->vm_flags & VM_READ) {
- if (!dmabuf->read_channel &&
- (dmabuf->read_channel =
- state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
- ret = -EBUSY;
- goto out;
- }
- }
- if ((ret = prog_dmabuf(state, 0)) != 0)
- goto out;
-
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << dmabuf->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- dmabuf->mapped = 1;
- dmabuf->trigger = 0;
- ret = 0;
-#ifdef DEBUG_MMAP
- printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
-#endif
-out:
- unlock_kernel();
- return ret;
-}
-
-static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_channel *c = NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- unsigned int i_glob_cnt;
- int val = 0, ret;
- struct ac97_codec *codec = state->card->ac97_codec[0];
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
-#ifdef DEBUG
- printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0);
-#endif
-
- switch (cmd)
- {
- case OSS_GETVERSION:
-#ifdef DEBUG
- printk("OSS_GETVERSION\n");
-#endif
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_RESET:
-#ifdef DEBUG
- printk("SNDCTL_DSP_RESET\n");
-#endif
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable == DAC_RUNNING) {
- c = dmabuf->write_channel;
- __stop_dac(state);
- }
- if (dmabuf->enable == ADC_RUNNING) {
- c = dmabuf->read_channel;
- __stop_adc(state);
- }
- if (c != NULL) {
- I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */
- while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )
- cpu_relax();
- I810_IOWRITEL((u32)state->card->chandma +
- c->num*sizeof(struct i810_channel),
- state->card, c->port+OFF_BDBAR);
- CIV_TO_LVI(state->card, c->port, 0);
- }
-
- spin_unlock_irqrestore(&state->card->lock, flags);
- synchronize_irq(state->card->pci_dev->irq);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- return 0;
-
- case SNDCTL_DSP_SYNC:
-#ifdef DEBUG
- printk("SNDCTL_DSP_SYNC\n");
-#endif
- if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
- return 0;
- if((val = drain_dac(state, 1)))
- return val;
- dmabuf->total_bytes = 0;
- return 0;
-
- case SNDCTL_DSP_SPEED: /* set smaple rate */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SPEED\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_WRITE) {
- if ( (state->card->ac97_status & SPDIF_ON) ) { /* S/PDIF Enabled */
- /* AD1886 only supports 48000, need to check that */
- if ( i810_valid_spdif_rate ( codec, val ) ) {
- /* Set DAC rate */
- i810_set_spdif_output ( state, -1, 0 );
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- /* Set S/PDIF transmitter rate. */
- i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );
- if ( ! (state->card->ac97_status & SPDIF_ON) ) {
- val = dmabuf->rate;
- }
- } else { /* Not a valid rate for S/PDIF, ignore it */
- val = dmabuf->rate;
- }
- } else {
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_adc_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- return put_user(dmabuf->rate, p);
-
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
-#ifdef DEBUG
- printk("SNDCTL_DSP_STEREO\n");
-#endif
- if (dmabuf->enable & DAC_RUNNING) {
- stop_dac(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- return put_user(1, p);
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
- return val;
- }
- if (file->f_mode & FMODE_READ) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
- return val;
- }
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
-#endif
- return put_user(dmabuf->userfragsize, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETFMTS\n");
-#endif
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Select sample format */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETFMT\n");
-#endif
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_CHANNELS:
-#ifdef DEBUG
- printk("SNDCTL_DSP_CHANNELS\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- if (val > 0) {
- if (dmabuf->enable & DAC_RUNNING) {
- stop_dac(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- } else {
- return put_user(state->card->channels, p);
- }
-
- /* ICH and ICH0 only support 2 channels */
- if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5
- || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5)
- return put_user(2, p);
-
- /* Multi-channel support was added with ICH2. Bits in */
- /* Global Status and Global Control register are now */
- /* used to indicate this. */
-
- i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);
-
- /* Current # of channels enabled */
- if ( i_glob_cnt & 0x0100000 )
- ret = 4;
- else if ( i_glob_cnt & 0x0200000 )
- ret = 6;
- else
- ret = 2;
-
- switch ( val ) {
- case 2: /* 2 channels is always supported */
- I810_IOWRITEL(i_glob_cnt & 0xffcfffff,
- state->card, GLOB_CNT);
- /* Do we need to change mixer settings???? */
- break;
- case 4: /* Supported on some chipsets, better check first */
- if ( state->card->channels >= 4 ) {
- I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000,
- state->card, GLOB_CNT);
- /* Do we need to change mixer settings??? */
- } else {
- val = ret;
- }
- break;
- case 6: /* Supported on some chipsets, better check first */
- if ( state->card->channels >= 6 ) {
- I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000,
- state->card, GLOB_CNT);
- /* Do we need to change mixer settings??? */
- } else {
- val = ret;
- }
- break;
- default: /* nothing else is ever supported by the chipset */
- val = ret;
- break;
- }
-
- return put_user(val, p);
-
- case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
- /* we update the swptr to the end of the last sg segment then return */
-#ifdef DEBUG
- printk("SNDCTL_DSP_POST\n");
-#endif
- if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
- return 0;
- if((dmabuf->swptr % dmabuf->fragsize) != 0) {
- val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
- dmabuf->swptr += val;
- dmabuf->count += val;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if (dmabuf->subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
-#ifdef DEBUG
- printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
-#endif
- dmabuf->subdivision = val;
- dmabuf->ready = 0;
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
-
- dmabuf->ossfragsize = 1<<(val & 0xffff);
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
- return -EINVAL;
- /*
- * Bound the frag size into our allowed range of 256 - 4096
- */
- if (dmabuf->ossfragsize < 256)
- dmabuf->ossfragsize = 256;
- else if (dmabuf->ossfragsize > 4096)
- dmabuf->ossfragsize = 4096;
- /*
- * The numfrags could be something reasonable, or it could
- * be 0xffff meaning "Give me as much as possible". So,
- * we check the numfrags * fragsize doesn't exceed our
- * 64k buffer limit, nor is it less than our 8k minimum.
- * If it fails either one of these checks, then adjust the
- * number of fragments, not the size of them. It's OK if
- * our number of fragments doesn't equal 32 or anything
- * like our hardware based number now since we are using
- * a different frag count for the hardware. Before we get
- * into this though, bound the maxfrags to avoid overflow
- * issues. A reasonable bound would be 64k / 256 since our
- * maximum buffer size is 64k and our minimum frag size is
- * 256. On the other end, our minimum buffer size is 8k and
- * our maximum frag size is 4k, so the lower bound should
- * be 2.
- */
-
- if(dmabuf->ossmaxfrags > 256)
- dmabuf->ossmaxfrags = 256;
- else if (dmabuf->ossmaxfrags < 2)
- dmabuf->ossmaxfrags = 2;
-
- val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
- while (val < 8192) {
- val <<= 1;
- dmabuf->ossmaxfrags <<= 1;
- }
- while (val > 65536) {
- val >>= 1;
- dmabuf->ossmaxfrags >>= 1;
- }
- dmabuf->ready = 0;
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
- dmabuf->ossfragsize, dmabuf->ossmaxfrags);
-#endif
-
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- if (dmabuf->mapped)
- abinfo.bytes = dmabuf->dmasize;
- else
- abinfo.bytes = i810_get_free_write_space(state);
- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
- abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- val = i810_get_free_write_space(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.ptr = dmabuf->hwptr;
- cinfo.blocks = val/dmabuf->userfragsize;
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __i810_update_lvi(state, 0);
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
- cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- abinfo.bytes = i810_get_available_read_data(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
- abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- val = i810_get_available_read_data(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = val/dmabuf->userfragsize;
- cinfo.ptr = dmabuf->hwptr;
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->count -= val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __i810_update_lvi(state, 1);
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
- cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
-#ifdef DEBUG
- printk("SNDCTL_DSP_NONBLOCK\n");
-#endif
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETCAPS\n");
-#endif
- return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
- p);
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
-#endif
- return put_user(dmabuf->trigger, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
-#endif
- /* silently ignore invalid PCM_ENABLE_xxx bits,
- * like the other drivers do
- */
- if (!(file->f_mode & FMODE_READ ))
- val &= ~PCM_ENABLE_INPUT;
- if (!(file->f_mode & FMODE_WRITE ))
- val &= ~PCM_ENABLE_OUTPUT;
- if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
- stop_adc(state);
- }
- if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
- stop_dac(state);
- }
- dmabuf->trigger = val;
- if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
- if (!dmabuf->write_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = i810_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- i810_update_lvi(state, 0);
- start_dac(state);
- }
- if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
- if (!dmabuf->read_channel) {
- dmabuf->ready = 0;
- dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
- if (!dmabuf->read_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- i810_update_lvi(state, 1);
- start_adc(state);
- }
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETDUPLEX\n");
-#endif
- return -EINVAL;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- val = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
-#endif
- return put_user(val, p);
-
- case SOUND_PCM_READ_RATE:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
-#endif
- return put_user(dmabuf->rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_CHANNELS\n");
-#endif
- return put_user(2, p);
-
- case SOUND_PCM_READ_BITS:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_BITS\n");
-#endif
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETSPDIF\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- /* Check to make sure the codec supports S/PDIF transmitter */
-
- if((state->card->ac97_features & 4)) {
- /* mask out the transmitter speed bits so the user can't set them */
- val &= ~0x3000;
-
- /* Add the current transmitter speed bits to the passed value */
- ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
- val |= (ret & 0x3000);
-
- i810_ac97_set(codec, AC97_SPDIF_CONTROL, val);
- if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) {
- printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
- return -EFAULT;
- }
- }
-#ifdef DEBUG
- else
- printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
- return put_user(val, p);
-
- case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETSPDIF\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- /* Check to make sure the codec supports S/PDIF transmitter */
-
- if(!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
- printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
- val = 0;
- } else {
- val = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
- }
- //return put_user((val & 0xcfff), p);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETCHANNELMASK:
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETCHANNELMASK\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- /* Based on AC'97 DAC support, not ICH hardware */
- val = DSP_BIND_FRONT;
- if ( state->card->ac97_features & 0x0004 )
- val |= DSP_BIND_SPDIF;
-
- if ( state->card->ac97_features & 0x0080 )
- val |= DSP_BIND_SURR;
- if ( state->card->ac97_features & 0x0140 )
- val |= DSP_BIND_CENTER_LFE;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_BIND_CHANNEL:
-#ifdef DEBUG
- printk("SNDCTL_DSP_BIND_CHANNEL\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if ( val == DSP_BIND_QUERY ) {
- val = DSP_BIND_FRONT; /* Always report this as being enabled */
- if ( state->card->ac97_status & SPDIF_ON )
- val |= DSP_BIND_SPDIF;
- else {
- if ( state->card->ac97_status & SURR_ON )
- val |= DSP_BIND_SURR;
- if ( state->card->ac97_status & CENTER_LFE_ON )
- val |= DSP_BIND_CENTER_LFE;
- }
- } else { /* Not a query, set it */
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if ( dmabuf->enable == DAC_RUNNING ) {
- stop_dac(state);
- }
- if ( val & DSP_BIND_SPDIF ) { /* Turn on SPDIF */
- /* Ok, this should probably define what slots
- * to use. For now, we'll only set it to the
- * defaults:
- *
- * non multichannel codec maps to slots 3&4
- * 2 channel codec maps to slots 7&8
- * 4 channel codec maps to slots 6&9
- * 6 channel codec maps to slots 10&11
- *
- * there should be some way for the app to
- * select the slot assignment.
- */
-
- i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate );
- if ( !(state->card->ac97_status & SPDIF_ON) )
- val &= ~DSP_BIND_SPDIF;
- } else {
- int mask;
- int channels;
-
- /* Turn off S/PDIF if it was on */
- if ( state->card->ac97_status & SPDIF_ON )
- i810_set_spdif_output ( state, -1, 0 );
-
- mask = val & (DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE);
- switch (mask) {
- case DSP_BIND_FRONT:
- channels = 2;
- break;
- case DSP_BIND_FRONT|DSP_BIND_SURR:
- channels = 4;
- break;
- case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
- channels = 6;
- break;
- default:
- val = DSP_BIND_FRONT;
- channels = 2;
- break;
- }
- i810_set_dac_channels ( state, channels );
-
- /* check that they really got turned on */
- if (!(state->card->ac97_status & SURR_ON))
- val &= ~DSP_BIND_SURR;
- if (!(state->card->ac97_status & CENTER_LFE_ON))
- val &= ~DSP_BIND_CENTER_LFE;
- }
- }
- return put_user(val, p);
-
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
-#ifdef DEBUG
- printk("SNDCTL_* -EINVAL\n");
-#endif
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static int i810_open(struct inode *inode, struct file *file)
-{
- int i = 0;
- struct i810_card *card = devs;
- struct i810_state *state = NULL;
- struct dmabuf *dmabuf = NULL;
-
- /* find an avaiable virtual channel (instance of /dev/dsp) */
- while (card != NULL) {
- /*
- * If we are initializing and then fail, card could go
- * away unuexpectedly while we are in the for() loop.
- * So, check for card on each iteration before we check
- * for card->initializing to avoid a possible oops.
- * This usually only matters for times when the driver is
- * autoloaded by kmod.
- */
- for (i = 0; i < 50 && card && card->initializing; i++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
- if (card->states[i] == NULL) {
- state = card->states[i] = (struct i810_state *)
- kzalloc(sizeof(struct i810_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
- dmabuf = &state->dmabuf;
- goto found_virt;
- }
- }
- card = card->next;
- }
- /* no more virtual channel avaiable */
- if (!state)
- return -ENODEV;
-
-found_virt:
- /* initialize the virtual channel */
- state->virt = i;
- state->card = card;
- state->magic = I810_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- file->private_data = state;
- dmabuf->trigger = 0;
-
- /* allocate hardware channels */
- if(file->f_mode & FMODE_READ) {
- if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
- kfree (card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= PCM_ENABLE_INPUT;
- i810_set_adc_rate(state, 8000);
- }
- if(file->f_mode & FMODE_WRITE) {
- if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
- /* make sure we free the record channel allocated above */
- if(file->f_mode & FMODE_READ)
- card->free_pcm_channel(card,dmabuf->read_channel->num);
- kfree (card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- /* Initialize to 8kHz? What if we don't support 8kHz? */
- /* Let's change this to check for S/PDIF stuff */
-
- dmabuf->trigger |= PCM_ENABLE_OUTPUT;
- if ( spdif_locked ) {
- i810_set_dac_rate(state, spdif_locked);
- i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
- } else {
- i810_set_dac_rate(state, 8000);
- /* Put the ACLink in 2 channel mode by default */
- i = I810_IOREADL(card, GLOB_CNT);
- I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT);
- }
- }
-
- /* set default sample format. According to OSS Programmer's Guide /dev/dsp
- should be default to unsigned 8-bits, mono, with sample rate 8kHz and
- /dev/dspW will accept 16-bits sample, but we don't support those so we
- set it immediately to stereo and 16bit, which is all we do support */
- dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO;
- dmabuf->ossfragsize = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
-
- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
- return nonseekable_open(inode, file);
-}
-
-static int i810_release(struct inode *inode, struct file *file)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_card *card = state->card;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
-
- lock_kernel();
-
- /* stop DMA state machine and free DMA buffers/channels */
- if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
- drain_dac(state, 0);
- }
- if(dmabuf->trigger & PCM_ENABLE_INPUT) {
- stop_adc(state);
- }
- spin_lock_irqsave(&card->lock, flags);
- dealloc_dmabuf(state);
- if (file->f_mode & FMODE_WRITE) {
- state->card->free_pcm_channel(state->card, dmabuf->write_channel->num);
- }
- if (file->f_mode & FMODE_READ) {
- state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
- }
-
- state->card->states[state->virt] = NULL;
- kfree(state);
- spin_unlock_irqrestore(&card->lock, flags);
- unlock_kernel();
-
- return 0;
-}
-
-static /*const*/ struct file_operations i810_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = i810_read,
- .write = i810_write,
- .poll = i810_poll,
- .ioctl = i810_ioctl,
- .mmap = i810_mmap,
- .open = i810_open,
- .release = i810_release,
-};
-
-/* Write AC97 codec registers */
-
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (readb(card->iobase_mmio + CAS) & 1))
- udelay(1);
-
-#ifdef DEBUG_MMIO
- {
- u16 ans = readw(card->ac97base_mmio + reg_set);
- printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
- return ans;
- }
-#else
- return readw(card->ac97base_mmio + reg_set);
-#endif
-}
-
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (I810_IOREADB(card, CAS) & 1))
- udelay(1);
-
- return inw(card->ac97base + reg_set);
-}
-
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (readb(card->iobase_mmio + CAS) & 1))
- udelay(1);
-
- writew(data, card->ac97base_mmio + reg_set);
-
-#ifdef DEBUG_MMIO
- printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
-#endif
-}
-
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (I810_IOREADB(card, CAS) & 1))
- udelay(1);
-
- outw(data, card->ac97base + reg_set);
-}
-
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
-{
- struct i810_card *card = dev->private_data;
- u16 ret;
-
- spin_lock(&card->ac97_lock);
- if (card->use_mmio) {
- ret = i810_ac97_get_mmio(dev, reg);
- }
- else {
- ret = i810_ac97_get_io(dev, reg);
- }
- spin_unlock(&card->ac97_lock);
-
- return ret;
-}
-
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct i810_card *card = dev->private_data;
-
- spin_lock(&card->ac97_lock);
- if (card->use_mmio) {
- i810_ac97_set_mmio(dev, reg, data);
- }
- else {
- i810_ac97_set_io(dev, reg, data);
- }
- spin_unlock(&card->ac97_lock);
-}
-
-
-/* OSS /dev/mixer file operation methods */
-
-static int i810_open_mixdev(struct inode *inode, struct file *file)
-{
- int i;
- int minor = iminor(inode);
- struct i810_card *card = devs;
-
- for (card = devs; card != NULL; card = card->next) {
- /*
- * If we are initializing and then fail, card could go
- * away unuexpectedly while we are in the for() loop.
- * So, check for card on each iteration before we check
- * for card->initializing to avoid a possible oops.
- * This usually only matters for times when the driver is
- * autoloaded by kmod.
- */
- for (i = 0; i < 50 && card && card->initializing; i++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
- if (card->ac97_codec[i] != NULL &&
- card->ac97_codec[i]->dev_mixer == minor) {
- file->private_data = card->ac97_codec[i];
- return nonseekable_open(inode, file);
- }
- }
- return -ENODEV;
-}
-
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations i810_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = i810_ioctl_mixdev,
- .open = i810_open_mixdev,
-};
-
-/* AC97 codec initialisation. These small functions exist so we don't
- duplicate code between module init and apm resume */
-
-static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
-{
- u32 reg = I810_IOREADL(card, GLOB_STA);
- switch (ac97_number) {
- case 0:
- return reg & (1<<8);
- case 1:
- return reg & (1<<9);
- case 2:
- return reg & (1<<28);
- }
- return 0;
-}
-
-static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
- i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
- i810_ac97_set(codec,AC97_EXTENDED_STATUS,
- i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);
-
- return (i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1);
-}
-
-
-static int i810_ac97_probe_and_powerup(struct i810_card *card,struct ac97_codec *codec)
-{
- /* Returns 0 on failure */
- int i;
-
- if (ac97_probe_codec(codec) == 0) return 0;
-
- /* power it all up */
- i810_ac97_set(codec, AC97_POWER_CONTROL,
- i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
-
- /* wait for analog ready */
- for (i=100; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- return i;
-}
-
-static int is_new_ich(u16 pci_id)
-{
- switch (pci_id) {
- case PCI_DEVICE_ID_INTEL_82801DB_5:
- case PCI_DEVICE_ID_INTEL_82801EB_5:
- case PCI_DEVICE_ID_INTEL_ESB_5:
- case PCI_DEVICE_ID_INTEL_ICH6_18:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
-
-static inline int ich_use_mmio(struct i810_card *card)
-{
- return is_new_ich(card->pci_id) && card->use_mmio;
-}
-
-/**
- * i810_ac97_power_up_bus - bring up AC97 link
- * @card : ICH audio device to power up
- *
- * Bring up the ACLink AC97 codec bus
- */
-
-static int i810_ac97_power_up_bus(struct i810_card *card)
-{
- u32 reg = I810_IOREADL(card, GLOB_CNT);
- int i;
- int primary_codec_id = 0;
-
- if((reg&2)==0) /* Cold required */
- reg|=2;
- else
- reg|=4; /* Warm */
-
- reg&=~8; /* ACLink on */
-
- /* At this point we deassert AC_RESET # */
- I810_IOWRITEL(reg , card, GLOB_CNT);
-
- /* We must now allow time for the Codec initialisation.
- 600mS is the specified time */
-
- for(i=0;i<10;i++)
- {
- if((I810_IOREADL(card, GLOB_CNT)&4)==0)
- break;
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- if(i==10)
- {
- printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
- return 0;
- }
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/2);
-
- /*
- * See if the primary codec comes ready. This must happen
- * before we start doing DMA stuff
- */
- /* see i810_ac97_init for the next 10 lines (jsaw) */
- if (card->use_mmio)
- readw(card->ac97base_mmio);
- else
- inw(card->ac97base);
- if (ich_use_mmio(card)) {
- primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
- printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
- primary_codec_id);
- }
-
- if(! i810_ac97_exists(card, primary_codec_id))
- {
- printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ); /* actually 600mS by the spec */
-
- if(i810_ac97_exists(card, primary_codec_id))
- printk("OK\n");
- else
- printk("no response.\n");
- }
- if (card->use_mmio)
- readw(card->ac97base_mmio);
- else
- inw(card->ac97base);
- return 1;
-}
-
-static int __devinit i810_ac97_init(struct i810_card *card)
-{
- int num_ac97 = 0;
- int ac97_id;
- int total_channels = 0;
- int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
- struct ac97_codec *codec;
- u16 eid;
- u32 reg;
-
- if(!i810_ac97_power_up_bus(card)) return 0;
-
- /* Number of channels supported */
- /* What about the codec? Just because the ICH supports */
- /* multiple channels doesn't mean the codec does. */
- /* we'll have to modify this in the codec section below */
- /* to reflect what the codec has. */
- /* ICH and ICH0 only support 2 channels so don't bother */
- /* to check.... */
-
- card->channels = 2;
- reg = I810_IOREADL(card, GLOB_STA);
- if ( reg & 0x0200000 )
- card->channels = 6;
- else if ( reg & 0x0100000 )
- card->channels = 4;
- printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
- printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
- reg = I810_IOREADL(card, GLOB_CNT);
- I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT);
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++)
- card->ac97_codec[num_ac97] = NULL;
-
- /*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
- if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
-
- for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
- /* codec reset */
- printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
- if (card->use_mmio)
- readw(card->ac97base_mmio + 0x80*num_ac97);
- else
- inw(card->ac97base + 0x80*num_ac97);
-
- /* If we have the SDATA_IN Map Register, as on ICH4, we
- do not loop thru all possible codec IDs but thru all
- possible IO channels. Bit 0:1 of SDM then holds the
- last codec ID spoken to.
- */
- if (ich_use_mmio(card)) {
- ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
- printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
- num_ac97, ac97_id);
- }
- else {
- ac97_id = num_ac97;
- }
-
- /* The ICH programmer's reference says you should */
- /* check the ready status before probing. So we chk */
- /* What do we do if it's not ready? Wait and try */
- /* again, or abort? */
- if (!i810_ac97_exists(card, ac97_id)) {
- if(num_ac97 == 0)
- printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
- }
-
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- /* initialize some basic codec information, other fields will be filled
- in ac97_probe_codec */
- codec->private_data = card;
- codec->id = ac97_id;
- card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
-
- if (card->use_mmio) {
- codec->codec_read = i810_ac97_get_mmio;
- codec->codec_write = i810_ac97_set_mmio;
- }
- else {
- codec->codec_read = i810_ac97_get_io;
- codec->codec_write = i810_ac97_set_io;
- }
-
- if(!i810_ac97_probe_and_powerup(card,codec)) {
- printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
- ac97_release_codec(codec);
- break; /* it didn't work */
- }
- /* Store state information about S/PDIF transmitter */
- card->ac97_status = 0;
-
- /* Don't attempt to get eid until powerup is complete */
- eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-
- if(eid==0xFFFF)
- {
- printk(KERN_WARNING "i810_audio: no codec attached ?\n");
- ac97_release_codec(codec);
- break;
- }
-
- /* Check for an AC97 1.0 soft modem (ID1) */
-
- if(codec->modem)
- {
- printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
- ac97_release_codec(codec);
- continue;
- }
-
- card->ac97_features = eid;
-
- /* Now check the codec for useful features to make up for
- the dumbness of the 810 hardware engine */
-
- if(!(eid&0x0001))
- printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
- else
- {
- if(!i810_ac97_enable_variable_rate(codec)) {
- printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n");
- card->ac97_features&=~1;
- }
- }
-
- /* Turn on the amplifier */
-
- codec->codec_write(codec, AC97_POWER_CONTROL,
- codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
-
- /* Determine how many channels the codec(s) support */
- /* - The primary codec always supports 2 */
- /* - If the codec supports AMAP, surround DACs will */
- /* automaticlly get assigned to slots. */
- /* * Check for surround DACs and increment if */
- /* found. */
- /* - Else check if the codec is revision 2.2 */
- /* * If surround DACs exist, assign them to slots */
- /* and increment channel count. */
-
- /* All of this only applies to ICH2 and above. ICH */
- /* and ICH0 only support 2 channels. ICH2 will only */
- /* support multiple codecs in a "split audio" config. */
- /* as described above. */
-
- /* TODO: Remove all the debugging messages! */
-
- if((eid & 0xc000) == 0) /* primary codec */
- total_channels += 2;
-
- if(eid & 0x200) { /* GOOD, AMAP support */
- if (eid & 0x0080) /* L/R Surround channels */
- total_channels += 2;
- if (eid & 0x0140) /* LFE and Center channels */
- total_channels += 2;
- printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
- } else if (eid & 0x0400) { /* this only works on 2.2 compliant codecs */
- eid &= 0xffcf;
- if((eid & 0xc000) != 0) {
- switch ( total_channels ) {
- case 2:
- /* Set dsa1, dsa0 to 01 */
- eid |= 0x0010;
- break;
- case 4:
- /* Set dsa1, dsa0 to 10 */
- eid |= 0x0020;
- break;
- case 6:
- /* Set dsa1, dsa0 to 11 */
- eid |= 0x0030;
- break;
- }
- total_channels += 2;
- }
- i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
- eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
- printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
- if (eid & 0x0080) /* L/R Surround channels */
- total_channels += 2;
- if (eid & 0x0140) /* LFE and Center channels */
- total_channels += 2;
- printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
- } else {
- printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
- }
-
- if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
- ac97_release_codec(codec);
- break;
- }
-
- card->ac97_codec[num_ac97] = codec;
- }
-
- /* tune up the primary codec */
- ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk);
-
- /* pick the minimum of channels supported by ICHx or codec(s) */
- card->channels = (card->channels > total_channels)?total_channels:card->channels;
-
- return num_ac97;
-}
-
-static void __devinit i810_configure_clocking (void)
-{
- struct i810_card *card;
- struct i810_state *state;
- struct dmabuf *dmabuf;
- unsigned int i, offset, new_offset;
- unsigned long flags;
-
- card = devs;
- /* We could try to set the clocking for multiple cards, but can you even have
- * more than one i810 in a machine? Besides, clocking is global, so unless
- * someone actually thinks more than one i810 in a machine is possible and
- * decides to rewrite that little bit, setting the rate for more than one card
- * is a waste of time.
- */
- if(card != NULL) {
- state = card->states[0] = (struct i810_state *)
- kzalloc(sizeof(struct i810_state), GFP_KERNEL);
- if (state == NULL)
- return;
- dmabuf = &state->dmabuf;
-
- dmabuf->write_channel = card->alloc_pcm_channel(card);
- state->virt = 0;
- state->card = card;
- state->magic = I810_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- i810_set_spdif_output(state, -1, 0);
- i810_set_dac_channels(state, 2);
- i810_set_dac_rate(state, 48000);
- if(prog_dmabuf(state, 0) != 0) {
- goto config_out_nodmabuf;
- }
- if(dmabuf->dmasize < 16384) {
- goto config_out;
- }
- dmabuf->count = dmabuf->dmasize;
- CIV_TO_LVI(card, dmabuf->write_channel->port, -1);
- local_irq_save(flags);
- start_dac(state);
- offset = i810_get_dma_addr(state, 0);
- mdelay(50);
- new_offset = i810_get_dma_addr(state, 0);
- stop_dac(state);
- local_irq_restore(flags);
- i = new_offset - offset;
-#ifdef DEBUG_INTERRUPTS
- printk("i810_audio: %d bytes in 50 milliseconds\n", i);
-#endif
- if(i == 0)
- goto config_out;
- i = i / 4 * 20;
- if (i > 48500 || i < 47500) {
- clocking = clocking * clocking / i;
- printk("i810_audio: setting clocking to %d\n", clocking);
- }
-config_out:
- dealloc_dmabuf(state);
-config_out_nodmabuf:
- state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num);
- kfree(state);
- card->states[0] = NULL;
- }
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
- until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-
-static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- struct i810_card *card;
-
- if (pci_enable_device(pci_dev))
- return -EIO;
-
- if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) {
- printk(KERN_ERR "i810_audio: architecture does not support"
- " 32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if ((card = kzalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "i810_audio: out of memory\n");
- return -ENOMEM;
- }
-
- card->initializing = 1;
- card->pci_dev = pci_dev;
- card->pci_id = pci_id->device;
- card->ac97base = pci_resource_start (pci_dev, 0);
- card->iobase = pci_resource_start (pci_dev, 1);
-
- if (!(card->ac97base) || !(card->iobase)) {
- card->ac97base = 0;
- card->iobase = 0;
- }
-
- /* if chipset could have mmio capability, check it */
- if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
- card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
- card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
-
- if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
- card->use_mmio = 1;
- }
- else {
- card->ac97base_mmio_phys = 0;
- card->iobase_mmio_phys = 0;
- }
- }
-
- if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) {
- printk(KERN_ERR "i810_audio: No I/O resources available.\n");
- goto out_mem;
- }
-
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = I810_CARD_MAGIC;
-#ifdef CONFIG_PM
- card->pm_suspended=0;
-#endif
- spin_lock_init(&card->lock);
- spin_lock_init(&card->ac97_lock);
- devs = card;
-
- pci_set_master(pci_dev);
-
- printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
- "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
- card_names[pci_id->driver_data],
- card->iobase, card->ac97base,
- card->ac97base_mmio_phys, card->iobase_mmio_phys,
- card->irq);
-
- card->alloc_pcm_channel = i810_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
- card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
- card->free_pcm_channel = i810_free_pcm_channel;
-
- if ((card->channel = pci_alloc_consistent(pci_dev,
- sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
- printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
- goto out_mem;
- }
-
- { /* We may dispose of this altogether some time soon, so... */
- struct i810_channel *cp = card->channel;
-
- cp[0].offset = 0;
- cp[0].port = 0x00;
- cp[0].num = 0;
- cp[1].offset = 0;
- cp[1].port = 0x10;
- cp[1].num = 1;
- cp[2].offset = 0;
- cp[2].port = 0x20;
- cp[2].num = 2;
- }
-
- /* claim our iospace and irq */
- if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) {
- printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->iobase);
- goto out_region1;
- }
- if (!request_region(card->ac97base, 256, card_names[pci_id->driver_data])) {
- printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->ac97base);
- goto out_region2;
- }
-
- if (card->use_mmio) {
- if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
- if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
- if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
- if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
- printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
- card_names[pci_id->driver_data],
- (unsigned long) card->ac97base_mmio,
- (unsigned long) card->iobase_mmio);
- }
- else {
- iounmap(card->ac97base_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- release_mem_region(card->iobase_mmio_phys, 512);
- card->use_mmio = 0;
- }
- }
- else {
- iounmap(card->ac97base_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- card->use_mmio = 0;
- }
- }
- }
- else {
- card->use_mmio = 0;
- }
- }
-
- /* initialize AC97 codec and register /dev/mixer */
- if (i810_ac97_init(card) <= 0)
- goto out_iospace;
- pci_set_drvdata(pci_dev, card);
-
- if(clocking == 0) {
- clocking = 48000;
- i810_configure_clocking();
- }
-
- /* register /dev/dsp */
- if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
- int i;
- printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- }
- goto out_iospace;
- }
-
- if (request_irq(card->irq, &i810_interrupt, IRQF_SHARED,
- card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
- goto out_iospace;
- }
-
-
- card->initializing = 0;
- return 0;
-
-out_iospace:
- if (card->use_mmio) {
- iounmap(card->ac97base_mmio);
- iounmap(card->iobase_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- release_mem_region(card->iobase_mmio_phys, 256);
- }
- release_region(card->ac97base, 256);
-out_region2:
- release_region(card->iobase, 64);
-out_region1:
- pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
- card->channel, card->chandma);
-out_mem:
- kfree(card);
- return -ENODEV;
-}
-
-static void __devexit i810_remove(struct pci_dev *pci_dev)
-{
- int i;
- struct i810_card *card = pci_get_drvdata(pci_dev);
- /* free hardware resources */
- free_irq(card->irq, devs);
- release_region(card->iobase, 64);
- release_region(card->ac97base, 256);
- pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
- card->channel, card->chandma);
- if (card->use_mmio) {
- iounmap(card->ac97base_mmio);
- iounmap(card->iobase_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- release_mem_region(card->iobase_mmio_phys, 256);
- }
-
- /* unregister audio devices */
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- card->ac97_codec[i] = NULL;
- }
- unregister_sound_dsp(card->dev_audio);
- kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
- struct i810_card *card = pci_get_drvdata(dev);
- struct i810_state *state;
- unsigned long flags;
- struct dmabuf *dmabuf;
- int i,num_ac97;
-#ifdef DEBUG
- printk("i810_audio: i810_pm_suspend called\n");
-#endif
- if(!card) return 0;
- spin_lock_irqsave(&card->lock, flags);
- card->pm_suspended=1;
- for(i=0;i<NR_HW_CH;i++) {
- state = card->states[i];
- if(!state) continue;
- /* this happens only if there are open files */
- dmabuf = &state->dmabuf;
- if(dmabuf->enable & DAC_RUNNING ||
- (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
- state->pm_saved_dac_rate=dmabuf->rate;
- stop_dac(state);
- } else {
- state->pm_saved_dac_rate=0;
- }
- if(dmabuf->enable & ADC_RUNNING) {
- state->pm_saved_adc_rate=dmabuf->rate;
- stop_adc(state);
- } else {
- state->pm_saved_adc_rate=0;
- }
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- /* save mixer settings */
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- struct ac97_codec *codec = card->ac97_codec[num_ac97];
- if(!codec) continue;
- for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
- if((supported_mixer(codec,i)) &&
- (codec->read_mixer)) {
- card->pm_saved_mixer_settings[i][num_ac97]=
- codec->read_mixer(codec,i);
- }
- }
- }
- pci_save_state(dev); /* XXX do we need this? */
- pci_disable_device(dev); /* disable busmastering */
- pci_set_power_state(dev,3); /* Zzz. */
-
- return 0;
-}
-
-
-static int i810_pm_resume(struct pci_dev *dev)
-{
- int num_ac97,i=0;
- struct i810_card *card=pci_get_drvdata(dev);
- pci_enable_device(dev);
- pci_restore_state (dev);
-
- /* observation of a toshiba portege 3440ct suggests that the
- hardware has to be more or less completely reinitialized from
- scratch after an apm suspend. Works For Me. -dan */
-
- i810_ac97_power_up_bus(card);
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- struct ac97_codec *codec = card->ac97_codec[num_ac97];
- /* check they haven't stolen the hardware while we were
- away */
- if(!codec || !i810_ac97_exists(card,num_ac97)) {
- if(num_ac97) continue;
- else BUG();
- }
- if(!i810_ac97_probe_and_powerup(card,codec)) BUG();
-
- if((card->ac97_features&0x0001)) {
- /* at probe time we found we could do variable
- rates, but APM suspend has made it forget
- its magical powers */
- if(!i810_ac97_enable_variable_rate(codec)) BUG();
- }
- /* we lost our mixer settings, so restore them */
- for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
- if(supported_mixer(codec,i)){
- int val=card->
- pm_saved_mixer_settings[i][num_ac97];
- codec->mixer_state[i]=val;
- codec->write_mixer(codec,i,
- (val & 0xff) ,
- ((val >> 8) & 0xff) );
- }
- }
- }
-
- /* we need to restore the sample rate from whatever it was */
- for(i=0;i<NR_HW_CH;i++) {
- struct i810_state * state=card->states[i];
- if(state) {
- if(state->pm_saved_adc_rate)
- i810_set_adc_rate(state,state->pm_saved_adc_rate);
- if(state->pm_saved_dac_rate)
- i810_set_dac_rate(state,state->pm_saved_dac_rate);
- }
- }
-
-
- card->pm_suspended = 0;
-
- /* any processes that were reading/writing during the suspend
- probably ended up here */
- for(i=0;i<NR_HW_CH;i++) {
- struct i810_state *state = card->states[i];
- if(state) wake_up(&state->dmabuf.wait);
- }
-
- return 0;
-}
-#endif /* CONFIG_PM */
-
-MODULE_AUTHOR("The Linux kernel team");
-MODULE_DESCRIPTION("Intel 810 audio support");
-MODULE_LICENSE("GPL");
-module_param(ftsodell, int, 0444);
-module_param(clocking, uint, 0444);
-module_param(strict_clocking, int, 0444);
-module_param(spdif_locked, int, 0444);
-
-#define I810_MODULE_NAME "i810_audio"
-
-static struct pci_driver i810_pci_driver = {
- .name = I810_MODULE_NAME,
- .id_table = i810_pci_tbl,
- .probe = i810_probe,
- .remove = __devexit_p(i810_remove),
-#ifdef CONFIG_PM
- .suspend = i810_pm_suspend,
- .resume = i810_pm_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init i810_init_module (void)
-{
- int retval;
-
- printk(KERN_INFO "Intel 810 + AC97 Audio, version "
- DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
- retval = pci_register_driver(&i810_pci_driver);
- if (retval)
- return retval;
-
- if(ftsodell != 0) {
- printk("i810_audio: ftsodell is now a deprecated option.\n");
- }
- if(spdif_locked > 0 ) {
- if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
- printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
- } else {
- printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- spdif_locked = 0;
- }
- }
-
- return 0;
-}
-
-static void __exit i810_cleanup_module (void)
-{
- pci_unregister_driver(&i810_pci_driver);
-}
-
-module_init(i810_init_module);
-module_exit(i810_cleanup_module);
-
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
index ece428b..16ed069 100644
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -232,14 +232,12 @@
return 1;
}
-static int set_io_base(pss_confdata * devc, int dev, int base)
+static void set_io_base(pss_confdata * devc, int dev, int base)
{
unsigned short tmp = inw(REG(dev)) & 0x003f;
unsigned short bits = (base & 0x0ffc) << 4;
outw(bits | tmp, REG(dev));
-
- return 1;
}
static int set_dma(pss_confdata * devc, int dev, int dma)
@@ -673,20 +671,12 @@
/* Configure CDROM port */
- if(pss_cdrom_port == -1) /* If cdrom port enablation wasn't requested */
- {
+ if (pss_cdrom_port == -1) { /* If cdrom port enablation wasn't requested */
printk(KERN_INFO "PSS: CDROM port not enabled.\n");
- }
- else if(check_region(pss_cdrom_port, 2))
- {
+ } else if (check_region(pss_cdrom_port, 2)) {
printk(KERN_ERR "PSS: CDROM I/O port conflict.\n");
- }
- else if(!set_io_base(devc, CONF_CDROM, pss_cdrom_port))
- {
- printk(KERN_ERR "PSS: CDROM I/O port could not be set.\n");
- }
- else /* CDROM port successfully configured */
- {
+ } else {
+ set_io_base(devc, CONF_CDROM, pss_cdrom_port);
printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port);
}
}
@@ -758,10 +748,7 @@
printk(KERN_ERR "PSS: MPU I/O port conflict\n");
return 0;
}
- if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) {
- printk(KERN_ERR "PSS: MIDI base could not be set.\n");
- goto fail;
- }
+ set_io_base(devc, CONF_MIDI, hw_config->io_base);
if (!set_irq(devc, CONF_MIDI, hw_config->irq)) {
printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n");
goto fail;
@@ -1057,10 +1044,7 @@
release_region(hw_config->io_base, 4);
return 0;
}
- if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) {
- printk("PSS: WSS base not settable.\n");
- goto fail;
- }
+ set_io_base(devc, CONF_WSS, hw_config->io_base);
if (!set_irq(devc, CONF_WSS, hw_config->irq)) {
printk("PSS: WSS IRQ allocation error.\n");
goto fail;
diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
index 07cbacf..77d0e5e 100644
--- a/sound/oss/sb_common.c
+++ b/sound/oss/sb_common.c
@@ -1228,7 +1228,8 @@
}
attach_mpu401(hw_config, owner);
if (last_sb->irq == -hw_config->irq)
- last_sb->midi_irq_cookie=(void *)hw_config->slots[1];
+ last_sb->midi_irq_cookie =
+ (void *)(long) hw_config->slots[1];
return 1;
}
#endif
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 96adc479..6959ee1 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -2935,7 +2935,7 @@
do {
if ((inw(TRID_REG(card, address)) & busy) == 0)
break;
- } while (count--);
+ } while (--count);
data |= (mask | (reg & AC97_REG_ADDR));
@@ -2996,7 +2996,7 @@
data = inl(TRID_REG(card, address));
if ((data & busy) == 0)
break;
- } while (count--);
+ } while (--count);
spin_unlock_irqrestore(&card->lock, flags);
if (count == 0) {
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
deleted file mode 100644
index 5d3c037..0000000
--- a/sound/oss/via82cxxx_audio.c
+++ /dev/null
@@ -1,3618 +0,0 @@
-/*
- * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999,2000 Jeff Garzik
- *
- * Updated to support the VIA 8233/8235 audio subsystem
- * Alan Cox <alan@redhat.com> (C) Copyright 2002, 2003 Red Hat Inc
- *
- * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
- * See the "COPYING" file distributed with this software for more info.
- * NO WARRANTY
- *
- * For a list of known bugs (errata) and documentation,
- * see via-audio.pdf in Documentation/DocBook.
- * If this documentation does not exist, run "make pdfdocs".
- */
-
-
-#define VIA_VERSION "1.9.1-ac4-2.5"
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/poison.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/sound.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#include "sound_config.h"
-#include "dev_table.h"
-#include "mpu401.h"
-
-
-#undef VIA_DEBUG /* define to enable debugging output and checks */
-#ifdef VIA_DEBUG
-/* note: prints function name for you */
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#undef VIA_NDEBUG /* define to disable lightweight runtime checks */
-#ifdef VIA_NDEBUG
-#define assert(expr)
-#else
-#define assert(expr) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
-#endif
-
-#define VIA_SUPPORT_MMAP 1 /* buggy, for now... */
-
-#define MAX_CARDS 1
-
-#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
-#define VIA_MODULE_NAME "via82cxxx"
-#define PFX VIA_MODULE_NAME ": "
-
-#define VIA_COUNTER_LIMIT 100000
-
-/* size of DMA buffers */
-#define VIA_MAX_BUFFER_DMA_PAGES 32
-
-/* buffering default values in ms */
-#define VIA_DEFAULT_FRAG_TIME 20
-#define VIA_DEFAULT_BUFFER_TIME 500
-
-/* the hardware has a 256 fragment limit */
-#define VIA_MIN_FRAG_NUMBER 2
-#define VIA_MAX_FRAG_NUMBER 128
-
-#define VIA_MAX_FRAG_SIZE PAGE_SIZE
-#define VIA_MIN_FRAG_SIZE (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE / VIA_MAX_FRAG_NUMBER)
-
-
-/* 82C686 function 5 (audio codec) PCI configuration registers */
-#define VIA_ACLINK_STATUS 0x40
-#define VIA_ACLINK_CTRL 0x41
-#define VIA_FUNC_ENABLE 0x42
-#define VIA_PNP_CONTROL 0x43
-#define VIA_FM_NMI_CTRL 0x48
-
-/*
- * controller base 0 (scatter-gather) registers
- *
- * NOTE: Via datasheet lists first channel as "read"
- * channel and second channel as "write" channel.
- * I changed the naming of the constants to be more
- * clear than I felt the datasheet to be.
- */
-
-#define VIA_BASE0_PCM_OUT_CHAN 0x00 /* output PCM to user */
-#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
-#define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01
-#define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02
-
-#define VIA_BASE0_PCM_IN_CHAN 0x10 /* input PCM from user */
-#define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10
-#define VIA_BASE0_PCM_IN_CHAN_CTRL 0x11
-#define VIA_BASE0_PCM_IN_CHAN_TYPE 0x12
-
-/* offsets from base */
-#define VIA_PCM_STATUS 0x00
-#define VIA_PCM_CONTROL 0x01
-#define VIA_PCM_TYPE 0x02
-#define VIA_PCM_LEFTVOL 0x02
-#define VIA_PCM_RIGHTVOL 0x03
-#define VIA_PCM_TABLE_ADDR 0x04
-#define VIA_PCM_STOPRATE 0x08 /* 8233+ */
-#define VIA_PCM_BLOCK_COUNT 0x0C
-
-/* XXX unused DMA channel for FM PCM data */
-#define VIA_BASE0_FM_OUT_CHAN 0x20
-#define VIA_BASE0_FM_OUT_CHAN_STATUS 0x20
-#define VIA_BASE0_FM_OUT_CHAN_CTRL 0x21
-#define VIA_BASE0_FM_OUT_CHAN_TYPE 0x22
-
-/* Six channel audio output on 8233 */
-#define VIA_BASE0_MULTI_OUT_CHAN 0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_STATUS 0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_CTRL 0x41
-#define VIA_BASE0_MULTI_OUT_CHAN_TYPE 0x42
-
-#define VIA_BASE0_AC97_CTRL 0x80
-#define VIA_BASE0_SGD_STATUS_SHADOW 0x84
-#define VIA_BASE0_GPI_INT_ENABLE 0x8C
-#define VIA_INTR_OUT ((1<<0) | (1<<4) | (1<<8))
-#define VIA_INTR_IN ((1<<1) | (1<<5) | (1<<9))
-#define VIA_INTR_FM ((1<<2) | (1<<6) | (1<<10))
-#define VIA_INTR_MASK (VIA_INTR_OUT | VIA_INTR_IN | VIA_INTR_FM)
-
-/* Newer VIA we need to monitor the low 3 bits of each channel. This
- mask covers the channels we don't yet use as well
- */
-
-#define VIA_NEW_INTR_MASK 0x77077777UL
-
-/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
-#define VIA_IRQ_ON_FLAG (1<<0) /* int on each flagged scatter block */
-#define VIA_IRQ_ON_EOL (1<<1) /* int at end of scatter list */
-#define VIA_INT_SEL_PCI_LAST_LINE_READ (0) /* int at PCI read of last line */
-#define VIA_INT_SEL_LAST_SAMPLE_SENT (1<<2) /* int at last sample sent */
-#define VIA_INT_SEL_ONE_LINE_LEFT (1<<3) /* int at less than one line to send */
-#define VIA_PCM_FMT_STEREO (1<<4) /* PCM stereo format (bit clear == mono) */
-#define VIA_PCM_FMT_16BIT (1<<5) /* PCM 16-bit format (bit clear == 8-bit) */
-#define VIA_PCM_REC_FIFO (1<<6) /* PCM Recording FIFO */
-#define VIA_RESTART_SGD_ON_EOL (1<<7) /* restart scatter-gather at EOL */
-#define VIA_PCM_FMT_MASK (VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT)
-#define VIA_CHAN_TYPE_MASK (VIA_RESTART_SGD_ON_EOL | \
- VIA_IRQ_ON_FLAG | \
- VIA_IRQ_ON_EOL)
-#define VIA_CHAN_TYPE_INT_SELECT (VIA_INT_SEL_LAST_SAMPLE_SENT)
-
-/* PCI configuration register bits and masks */
-#define VIA_CR40_AC97_READY 0x01
-#define VIA_CR40_AC97_LOW_POWER 0x02
-#define VIA_CR40_SECONDARY_READY 0x04
-
-#define VIA_CR41_AC97_ENABLE 0x80 /* enable AC97 codec */
-#define VIA_CR41_AC97_RESET 0x40 /* clear bit to reset AC97 */
-#define VIA_CR41_AC97_WAKEUP 0x20 /* wake up from power-down mode */
-#define VIA_CR41_AC97_SDO 0x10 /* force Serial Data Out (SDO) high */
-#define VIA_CR41_VRA 0x08 /* enable variable sample rate */
-#define VIA_CR41_PCM_ENABLE 0x04 /* AC Link SGD Read Channel PCM Data Output */
-#define VIA_CR41_FM_PCM_ENABLE 0x02 /* AC Link FM Channel PCM Data Out */
-#define VIA_CR41_SB_PCM_ENABLE 0x01 /* AC Link SB PCM Data Output */
-#define VIA_CR41_BOOT_MASK (VIA_CR41_AC97_ENABLE | \
- VIA_CR41_AC97_WAKEUP | \
- VIA_CR41_AC97_SDO)
-#define VIA_CR41_RUN_MASK (VIA_CR41_AC97_ENABLE | \
- VIA_CR41_AC97_RESET | \
- VIA_CR41_VRA | \
- VIA_CR41_PCM_ENABLE)
-
-#define VIA_CR42_SB_ENABLE 0x01
-#define VIA_CR42_MIDI_ENABLE 0x02
-#define VIA_CR42_FM_ENABLE 0x04
-#define VIA_CR42_GAME_ENABLE 0x08
-#define VIA_CR42_MIDI_IRQMASK 0x40
-#define VIA_CR42_MIDI_PNP 0x80
-
-#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6)
-#define VIA_CR44_AC_LINK_ACCESS (1 << 7)
-
-#define VIA_CR48_FM_TRAP_TO_NMI (1 << 2)
-
-/* controller base 0 register bitmasks */
-#define VIA_INT_DISABLE_MASK (~(0x01|0x02))
-#define VIA_SGD_STOPPED (1 << 2)
-#define VIA_SGD_PAUSED (1 << 6)
-#define VIA_SGD_ACTIVE (1 << 7)
-#define VIA_SGD_TERMINATE (1 << 6)
-#define VIA_SGD_FLAG (1 << 0)
-#define VIA_SGD_EOL (1 << 1)
-#define VIA_SGD_START (1 << 7)
-
-#define VIA_CR80_FIRST_CODEC 0
-#define VIA_CR80_SECOND_CODEC (1 << 30)
-#define VIA_CR80_FIRST_CODEC_VALID (1 << 25)
-#define VIA_CR80_VALID (1 << 25)
-#define VIA_CR80_SECOND_CODEC_VALID (1 << 27)
-#define VIA_CR80_BUSY (1 << 24)
-#define VIA_CR83_BUSY (1)
-#define VIA_CR83_FIRST_CODEC_VALID (1 << 1)
-#define VIA_CR80_READ (1 << 23)
-#define VIA_CR80_WRITE_MODE 0
-#define VIA_CR80_REG_IDX(idx) ((((idx) & 0xFF) >> 1) << 16)
-
-/* capabilities we announce */
-#ifdef VIA_SUPPORT_MMAP
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | DSP_CAP_MMAP | \
- DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#else
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | \
- DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#endif
-
-/* scatter-gather DMA table entry, exactly as passed to hardware */
-struct via_sgd_table {
- u32 addr;
- u32 count; /* includes additional VIA_xxx bits also */
-};
-
-#define VIA_EOL (1 << 31)
-#define VIA_FLAG (1 << 30)
-#define VIA_STOP (1 << 29)
-
-
-enum via_channel_states {
- sgd_stopped = 0,
- sgd_in_progress = 1,
-};
-
-
-struct via_buffer_pgtbl {
- dma_addr_t handle;
- void *cpuaddr;
-};
-
-
-struct via_channel {
- atomic_t n_frags;
- atomic_t hw_ptr;
- wait_queue_head_t wait;
-
- unsigned int sw_ptr;
- unsigned int slop_len;
- unsigned int n_irqs;
- int bytes;
-
- unsigned is_active : 1;
- unsigned is_record : 1;
- unsigned is_mapped : 1;
- unsigned is_enabled : 1;
- unsigned is_multi: 1; /* 8233 6 channel */
- u8 pcm_fmt; /* VIA_PCM_FMT_xxx */
- u8 channels; /* Channel count */
-
- unsigned rate; /* sample rate */
- unsigned int frag_size;
- unsigned int frag_number;
-
- unsigned char intmask;
-
- volatile struct via_sgd_table *sgtable;
- dma_addr_t sgt_handle;
-
- unsigned int page_number;
- struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES];
-
- long iobase;
-
- const char *name;
-};
-
-
-/* data stored for each chip */
-struct via_info {
- struct pci_dev *pdev;
- long baseaddr;
-
- struct ac97_codec *ac97;
- spinlock_t ac97_lock;
- spinlock_t lock;
- int card_num; /* unique card number, from 0 */
-
- int dev_dsp; /* /dev/dsp index from register_sound_dsp() */
-
- unsigned rev_h : 1;
- unsigned legacy: 1; /* Has legacy ports */
- unsigned intmask: 1; /* Needs int bits */
- unsigned sixchannel: 1; /* 8233/35 with 6 channel support */
- unsigned volume: 1;
-
- unsigned locked_rate : 1;
-
- int mixer_vol; /* 8233/35 volume - not yet implemented */
-
- struct mutex syscall_mutex;
- struct mutex open_mutex;
-
- /* The 8233/8235 have 4 DX audio channels, two record and
- one six channel out. We bind ch_in to DX 1, ch_out to multichannel
- and ch_fm to DX 2. DX 3 and REC0/REC1 are unused at the
- moment */
-
- struct via_channel ch_in;
- struct via_channel ch_out;
- struct via_channel ch_fm;
-
-#ifdef CONFIG_MIDI_VIA82CXXX
- void *midi_devc;
- struct address_info midi_info;
-#endif
-};
-
-
-/* number of cards, used for assigning unique numbers to cards */
-static unsigned via_num_cards;
-
-
-
-/****************************************************************
- *
- * prototypes
- *
- *
- */
-
-static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id);
-static void __devexit via_remove_one (struct pci_dev *pdev);
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait);
-static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int via_dsp_open (struct inode *inode, struct file *file);
-static int via_dsp_release(struct inode *inode, struct file *file);
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma);
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
-static u8 via_ac97_wait_idle (struct via_info *card);
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan);
-static void via_chan_clear (struct via_info *card, struct via_channel *chan);
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset);
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan);
-
-
-/****************************************************************
- *
- * Various data the driver needs
- *
- *
- */
-
-
-static struct pci_device_id via_pci_tbl[] = {
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci,via_pci_tbl);
-
-
-static struct pci_driver via_driver = {
- .name = VIA_MODULE_NAME,
- .id_table = via_pci_tbl,
- .probe = via_init_one,
- .remove = __devexit_p(via_remove_one),
-};
-
-
-/****************************************************************
- *
- * Low-level base 0 register read/write helpers
- *
- *
- */
-
-/**
- * via_chan_stop - Terminate DMA on specified PCM channel
- * @iobase: PCI base address for SGD channel registers
- *
- * Terminate scatter-gather DMA operation for given
- * channel (derived from @iobase), if DMA is active.
- *
- * Note that @iobase is not the PCI base address,
- * but the PCI base address plus an offset to
- * one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_stop (long iobase)
-{
- if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
- outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
-}
-
-
-/**
- * via_chan_status_clear - Clear status flags on specified DMA channel
- * @iobase: PCI base address for SGD channel registers
- *
- * Clear any pending status flags for the given
- * DMA channel (derived from @iobase), if any
- * flags are asserted.
- *
- * Note that @iobase is not the PCI base address,
- * but the PCI base address plus an offset to
- * one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_status_clear (long iobase)
-{
- u8 tmp = inb (iobase + VIA_PCM_STATUS);
-
- if (tmp != 0)
- outb (tmp, iobase + VIA_PCM_STATUS);
-}
-
-
-/**
- * sg_begin - Begin recording or playback on a PCM channel
- * @chan: Channel for which DMA operation shall begin
- *
- * Start scatter-gather DMA for the given channel.
- *
- */
-
-static inline void sg_begin (struct via_channel *chan)
-{
- DPRINTK("Start with intmask %d\n", chan->intmask);
- DPRINTK("About to start from %d to %d\n",
- inl(chan->iobase + VIA_PCM_BLOCK_COUNT),
- inb(chan->iobase + VIA_PCM_STOPRATE + 3));
- outb (VIA_SGD_START|chan->intmask, chan->iobase + VIA_PCM_CONTROL);
- DPRINTK("Status is now %02X\n", inb(chan->iobase + VIA_PCM_STATUS));
- DPRINTK("Control is now %02X\n", inb(chan->iobase + VIA_PCM_CONTROL));
-}
-
-
-static int sg_active (long iobase)
-{
- u8 tmp = inb (iobase + VIA_PCM_STATUS);
- if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) {
- printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n");
- return 0;
- }
- if (tmp & VIA_SGD_ACTIVE)
- return 1;
- return 0;
-}
-
-static int via_sg_offset(struct via_channel *chan)
-{
- return inl (chan->iobase + VIA_PCM_BLOCK_COUNT) & 0x00FFFFFF;
-}
-
-/****************************************************************
- *
- * Miscellaneous debris
- *
- *
- */
-
-
-/**
- * via_syscall_down - down the card-specific syscell semaphore
- * @card: Private info for specified board
- * @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- * Encapsulates standard method of acquiring the syscall sem.
- *
- * Returns negative errno on error, or zero for success.
- */
-
-static inline int via_syscall_down (struct via_info *card, int nonblock)
-{
- /* Thomas Sailer:
- * EAGAIN is supposed to be used if IO is pending,
- * not if there is contention on some internal
- * synchronization primitive which should be
- * held only for a short time anyway
- */
- nonblock = 0;
-
- if (nonblock) {
- if (!mutex_trylock(&card->syscall_mutex))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&card->syscall_mutex))
- return -ERESTARTSYS;
- }
-
- return 0;
-}
-
-
-/**
- * via_stop_everything - Stop all audio operations
- * @card: Private info for specified board
- *
- * Stops all DMA operations and interrupts, and clear
- * any pending status bits resulting from those operations.
- */
-
-static void via_stop_everything (struct via_info *card)
-{
- u8 tmp, new_tmp;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- /*
- * terminate any existing operations on audio read/write channels
- */
- via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
- via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
- via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
- if(card->sixchannel)
- via_chan_stop (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
- /*
- * clear any existing stops / flags (sanity check mainly)
- */
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
- if(card->sixchannel)
- via_chan_status_clear (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
- /*
- * clear any enabled interrupt bits
- */
- tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
-
- tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
-
- tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-
- if(card->sixchannel)
- {
- tmp = inb (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
- }
-
- udelay(10);
-
- /*
- * clear any existing flags
- */
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-
- DPRINTK ("EXIT\n");
-}
-
-
-/**
- * via_set_rate - Set PCM rate for given channel
- * @ac97: Pointer to generic codec info struct
- * @chan: Private info for specified channel
- * @rate: Desired PCM sample rate, in Khz
- *
- * Sets the PCM sample rate for a channel.
- *
- * Values for @rate are clamped to a range of 4000 Khz through 48000 Khz,
- * due to hardware constraints.
- */
-
-static int via_set_rate (struct ac97_codec *ac97,
- struct via_channel *chan, unsigned rate)
-{
- struct via_info *card = ac97->private_data;
- int rate_reg;
- u32 dacp;
- u32 mast_vol, phone_vol, mono_vol, pcm_vol;
- u32 mute_vol = 0x8000; /* The mute volume? -- Seems to work! */
-
- DPRINTK ("ENTER, rate = %d\n", rate);
-
- if (chan->rate == rate)
- goto out;
- if (card->locked_rate) {
- chan->rate = 48000;
- goto out;
- }
-
- if (rate > 48000) rate = 48000;
- if (rate < 4000) rate = 4000;
-
- rate_reg = chan->is_record ? AC97_PCM_LR_ADC_RATE :
- AC97_PCM_FRONT_DAC_RATE;
-
- /* Save current state */
- dacp=via_ac97_read_reg(ac97, AC97_POWER_CONTROL);
- mast_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_STEREO);
- mono_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_MONO);
- phone_vol = via_ac97_read_reg(ac97, AC97_HEADPHONE_VOL);
- pcm_vol = via_ac97_read_reg(ac97, AC97_PCMOUT_VOL);
- /* Mute - largely reduces popping */
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mute_vol);
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mute_vol);
- via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, mute_vol);
- via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, mute_vol);
- /* Power down the DAC */
- via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp|0x0200);
-
- /* Set new rate */
- via_ac97_write_reg (ac97, rate_reg, rate);
-
- /* Power DAC back up */
- via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp);
- udelay (200); /* reduces popping */
-
- /* Restore volumes */
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mast_vol);
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mono_vol);
- via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, phone_vol);
- via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, pcm_vol);
-
- /* the hardware might return a value different than what we
- * passed to it, so read the rate value back from hardware
- * to see what we came up with
- */
- chan->rate = via_ac97_read_reg (ac97, rate_reg);
-
- if (chan->rate == 0) {
- card->locked_rate = 1;
- chan->rate = 48000;
- printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
- }
-
-out:
- DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate);
- return chan->rate;
-}
-
-
-/****************************************************************
- *
- * Channel-specific operations
- *
- *
- */
-
-
-/**
- * via_chan_init_defaults - Initialize a struct via_channel
- * @card: Private audio chip info
- * @chan: Channel to be initialized
- *
- * Zero @chan, and then set all static defaults for the structure.
- */
-
-static void via_chan_init_defaults (struct via_info *card, struct via_channel *chan)
-{
- memset (chan, 0, sizeof (*chan));
-
- if(card->intmask)
- chan->intmask = 0x23; /* Turn on the IRQ bits */
-
- if (chan == &card->ch_out) {
- chan->name = "PCM-OUT";
- if(card->sixchannel)
- {
- chan->iobase = card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN;
- chan->is_multi = 1;
- DPRINTK("Using multichannel for pcm out\n");
- }
- else
- chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;
- } else if (chan == &card->ch_in) {
- chan->name = "PCM-IN";
- chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN;
- chan->is_record = 1;
- } else if (chan == &card->ch_fm) {
- chan->name = "PCM-OUT-FM";
- chan->iobase = card->baseaddr + VIA_BASE0_FM_OUT_CHAN;
- } else {
- BUG();
- }
-
- init_waitqueue_head (&chan->wait);
-
- chan->pcm_fmt = VIA_PCM_FMT_MASK;
- chan->is_enabled = 1;
-
- chan->frag_number = 0;
- chan->frag_size = 0;
- atomic_set(&chan->n_frags, 0);
- atomic_set (&chan->hw_ptr, 0);
-}
-
-/**
- * via_chan_init - Initialize PCM channel
- * @card: Private audio chip info
- * @chan: Channel to be initialized
- *
- * Performs some of the preparations necessary to begin
- * using a PCM channel.
- *
- * Currently the preparations consist of
- * setting the PCM channel to a known state.
- */
-
-
-static void via_chan_init (struct via_info *card, struct via_channel *chan)
-{
-
- DPRINTK ("ENTER\n");
-
- /* bzero channel structure, and init members to defaults */
- via_chan_init_defaults (card, chan);
-
- /* stop any existing channel output */
- via_chan_clear (card, chan);
- via_chan_status_clear (chan->iobase);
- via_chan_pcm_fmt (chan, 1);
-
- DPRINTK ("EXIT\n");
-}
-
-/**
- * via_chan_buffer_init - Initialize PCM channel buffer
- * @card: Private audio chip info
- * @chan: Channel to be initialized
- *
- * Performs some of the preparations necessary to begin
- * using a PCM channel.
- *
- * Currently the preparations include allocating the
- * scatter-gather DMA table and buffers,
- * and passing the
- * address of the DMA table to the hardware.
- *
- * Note that special care is taken when passing the
- * DMA table address to hardware, because it was found
- * during driver development that the hardware did not
- * always "take" the address.
- */
-
-static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan)
-{
- int page, offset;
- int i;
-
- DPRINTK ("ENTER\n");
-
-
- chan->intmask = 0;
- if(card->intmask)
- chan->intmask = 0x23; /* Turn on the IRQ bits */
-
- if (chan->sgtable != NULL) {
- DPRINTK ("EXIT\n");
- return 0;
- }
-
- /* alloc DMA-able memory for scatter-gather table */
- chan->sgtable = pci_alloc_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * chan->frag_number),
- &chan->sgt_handle);
- if (!chan->sgtable) {
- printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
- DPRINTK ("EXIT\n");
- return -ENOMEM;
- }
-
- memset ((void*)chan->sgtable, 0,
- (sizeof (struct via_sgd_table) * chan->frag_number));
-
- /* alloc DMA-able memory for scatter-gather buffers */
-
- chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE +
- (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0);
-
- for (i = 0; i < chan->page_number; i++) {
- chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE,
- &chan->pgtbl[i].handle);
-
- if (!chan->pgtbl[i].cpuaddr) {
- chan->page_number = i;
- goto err_out_nomem;
- }
-
-#ifndef VIA_NDEBUG
- memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size);
-#endif
-
-#if 1
- DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n",
- i, (long)chan->pgtbl[i].handle,
- virt_to_phys(chan->pgtbl[i].cpuaddr),
- chan->pgtbl[i].cpuaddr);
-#endif
- }
-
- for (i = 0; i < chan->frag_number; i++) {
-
- page = i / (PAGE_SIZE / chan->frag_size);
- offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
- chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
- chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset);
-
-#if 1
- DPRINTK ("dmabuf #%d (32(h)=%lx)\n",
- i,
- (long)chan->sgtable[i].addr);
-#endif
- }
-
- /* overwrite the last buffer information */
- chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
-
- /* set location of DMA-able scatter-gather info table */
- DPRINTK ("outl (0x%X, 0x%04lX)\n",
- chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
-
- via_ac97_wait_idle (card);
- outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
- udelay (20);
- via_ac97_wait_idle (card);
- /* load no rate adaption, stereo 16bit, set up ring slots */
- if(card->sixchannel)
- {
- if(!chan->is_multi)
- {
- outl (0xFFFFF | (0x3 << 20) | (chan->frag_number << 24), chan->iobase + VIA_PCM_STOPRATE);
- udelay (20);
- via_ac97_wait_idle (card);
- }
- }
-
- DPRINTK ("inl (0x%lX) = %x\n",
- chan->iobase + VIA_PCM_TABLE_ADDR,
- inl(chan->iobase + VIA_PCM_TABLE_ADDR));
-
- DPRINTK ("EXIT\n");
- return 0;
-
-err_out_nomem:
- printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
- via_chan_buffer_free (card, chan);
- DPRINTK ("EXIT\n");
- return -ENOMEM;
-}
-
-
-/**
- * via_chan_free - Release a PCM channel
- * @card: Private audio chip info
- * @chan: Channel to be released
- *
- * Performs all the functions necessary to clean up
- * an initialized channel.
- *
- * Currently these functions include disabled any
- * active DMA operations, setting the PCM channel
- * back to a known state, and releasing any allocated
- * sound buffers.
- */
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan)
-{
- DPRINTK ("ENTER\n");
-
- spin_lock_irq (&card->lock);
-
- /* stop any existing channel output */
- via_chan_status_clear (chan->iobase);
- via_chan_stop (chan->iobase);
- via_chan_status_clear (chan->iobase);
-
- spin_unlock_irq (&card->lock);
-
- synchronize_irq(card->pdev->irq);
-
- DPRINTK ("EXIT\n");
-}
-
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan)
-{
- int i;
-
- DPRINTK ("ENTER\n");
-
- /* zero location of DMA-able scatter-gather info table */
- via_ac97_wait_idle(card);
- outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
-
- for (i = 0; i < chan->page_number; i++)
- if (chan->pgtbl[i].cpuaddr) {
- pci_free_consistent (card->pdev, PAGE_SIZE,
- chan->pgtbl[i].cpuaddr,
- chan->pgtbl[i].handle);
- chan->pgtbl[i].cpuaddr = NULL;
- chan->pgtbl[i].handle = 0;
- }
-
- chan->page_number = 0;
-
- if (chan->sgtable) {
- pci_free_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * chan->frag_number),
- (void*)chan->sgtable, chan->sgt_handle);
- chan->sgtable = NULL;
- }
-
- DPRINTK ("EXIT\n");
-}
-
-
-/**
- * via_chan_pcm_fmt - Update PCM channel settings
- * @chan: Channel to be updated
- * @reset: Boolean. If non-zero, channel will be reset
- * to 8-bit mono mode.
- *
- * Stores the settings of the current PCM format,
- * 8-bit or 16-bit, and mono/stereo, into the
- * hardware settings for the specified channel.
- * If @reset is non-zero, the channel is reset
- * to 8-bit mono mode. Otherwise, the channel
- * is set to the values stored in the channel
- * information struct @chan.
- */
-
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset)
-{
- DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n",
- chan->pcm_fmt, reset ? "yes" : "no");
-
- assert (chan != NULL);
-
- if (reset)
- {
- /* reset to 8-bit mono mode */
- chan->pcm_fmt = 0;
- chan->channels = 1;
- }
-
- /* enable interrupts on FLAG and EOL */
- chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;
-
- /* if we are recording, enable recording fifo bit */
- if (chan->is_record)
- chan->pcm_fmt |= VIA_PCM_REC_FIFO;
- /* set interrupt select bits where applicable (PCM in & out channels) */
- if (!chan->is_record)
- chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
-
- DPRINTK("SET FMT - %02x %02x\n", chan->intmask , chan->is_multi);
-
- if(chan->intmask)
- {
- u32 m;
-
- /*
- * Channel 0x4 is up to 6 x 16bit and has to be
- * programmed differently
- */
-
- if(chan->is_multi)
- {
- u8 c = 0;
-
- /*
- * Load the type bit for num channels
- * and 8/16bit
- */
-
- if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
- c = 1 << 7;
- if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
- c |= (2<<4);
- else
- c |= (1<<4);
-
- outb(c, chan->iobase + VIA_PCM_TYPE);
-
- /*
- * Set the channel steering
- * Mono
- * Channel 0 to slot 3
- * Channel 0 to slot 4
- * Stereo
- * Channel 0 to slot 3
- * Channel 1 to slot 4
- */
-
- switch(chan->channels)
- {
- case 1:
- outl(0xFF000000 | (1<<0) | (1<<4) , chan->iobase + VIA_PCM_STOPRATE);
- break;
- case 2:
- outl(0xFF000000 | (1<<0) | (2<<4) , chan->iobase + VIA_PCM_STOPRATE);
- break;
- case 4:
- outl(0xFF000000 | (1<<0) | (2<<4) | (3<<8) | (4<<12), chan->iobase + VIA_PCM_STOPRATE);
- break;
- case 6:
- outl(0xFF000000 | (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20), chan->iobase + VIA_PCM_STOPRATE);
- break;
- }
- }
- else
- {
- /*
- * New style, turn off channel volume
- * control, set bits in the right register
- */
- outb(0x0, chan->iobase + VIA_PCM_LEFTVOL);
- outb(0x0, chan->iobase + VIA_PCM_RIGHTVOL);
-
- m = inl(chan->iobase + VIA_PCM_STOPRATE);
- m &= ~(3<<20);
- if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
- m |= (1 << 20);
- if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
- m |= (1 << 21);
- outl(m, chan->iobase + VIA_PCM_STOPRATE);
- }
- }
- else
- outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
-
-
- DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
- chan->pcm_fmt,
- inb (chan->iobase + VIA_PCM_TYPE));
-}
-
-
-/**
- * via_chan_clear - Stop DMA channel operation, and reset pointers
- * @card: the chip to accessed
- * @chan: Channel to be cleared
- *
- * Call via_chan_stop to halt DMA operations, and then resets
- * all software pointers which track DMA operation.
- */
-
-static void via_chan_clear (struct via_info *card, struct via_channel *chan)
-{
- DPRINTK ("ENTER\n");
- via_chan_stop (chan->iobase);
- via_chan_buffer_free(card, chan);
- chan->is_active = 0;
- chan->is_mapped = 0;
- chan->is_enabled = 1;
- chan->slop_len = 0;
- chan->sw_ptr = 0;
- chan->n_irqs = 0;
- atomic_set (&chan->hw_ptr, 0);
- DPRINTK ("EXIT\n");
-}
-
-
-/**
- * via_chan_set_speed - Set PCM sample rate for given channel
- * @card: Private info for specified board
- * @chan: Channel whose sample rate will be adjusted
- * @val: New sample rate, in Khz
- *
- * Helper function for the %SNDCTL_DSP_SPEED ioctl. OSS semantics
- * demand that all audio operations halt (if they are not already
- * halted) when the %SNDCTL_DSP_SPEED is given.
- *
- * This function halts all audio operations for the given channel
- * @chan, and then calls via_set_rate to set the audio hardware
- * to the new rate.
- */
-
-static int via_chan_set_speed (struct via_info *card,
- struct via_channel *chan, int val)
-{
- DPRINTK ("ENTER, requested rate = %d\n", val);
-
- via_chan_clear (card, chan);
-
- val = via_set_rate (card->ac97, chan, val);
-
- DPRINTK ("EXIT, returning %d\n", val);
- return val;
-}
-
-
-/**
- * via_chan_set_fmt - Set PCM sample size for given channel
- * @card: Private info for specified board
- * @chan: Channel whose sample size will be adjusted
- * @val: New sample size, use the %AFMT_xxx constants
- *
- * Helper function for the %SNDCTL_DSP_SETFMT ioctl. OSS semantics
- * demand that all audio operations halt (if they are not already
- * halted) when the %SNDCTL_DSP_SETFMT is given.
- *
- * This function halts all audio operations for the given channel
- * @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- * to the new sample size, either 8-bit or 16-bit.
- */
-
-static int via_chan_set_fmt (struct via_info *card,
- struct via_channel *chan, int val)
-{
- DPRINTK ("ENTER, val=%s\n",
- val == AFMT_U8 ? "AFMT_U8" :
- val == AFMT_S16_LE ? "AFMT_S16_LE" :
- "unknown");
-
- via_chan_clear (card, chan);
-
- assert (val != AFMT_QUERY); /* this case is handled elsewhere */
-
- switch (val) {
- case AFMT_S16_LE:
- if ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) == 0) {
- chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
- via_chan_pcm_fmt (chan, 0);
- }
- break;
-
- case AFMT_U8:
- if (chan->pcm_fmt & VIA_PCM_FMT_16BIT) {
- chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT;
- via_chan_pcm_fmt (chan, 0);
- }
- break;
-
- default:
- DPRINTK ("unknown AFMT: 0x%X\n", val);
- val = AFMT_S16_LE;
- }
-
- DPRINTK ("EXIT\n");
- return val;
-}
-
-
-/**
- * via_chan_set_stereo - Enable or disable stereo for a DMA channel
- * @card: Private info for specified board
- * @chan: Channel whose stereo setting will be adjusted
- * @val: New sample size, use the %AFMT_xxx constants
- *
- * Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls. OSS semantics
- * demand that all audio operations halt (if they are not already
- * halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given.
- *
- * This function halts all audio operations for the given channel
- * @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- * to enable or disable stereo.
- */
-
-static int via_chan_set_stereo (struct via_info *card,
- struct via_channel *chan, int val)
-{
- DPRINTK ("ENTER, channels = %d\n", val);
-
- via_chan_clear (card, chan);
-
- switch (val) {
-
- /* mono */
- case 1:
- chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;
- chan->channels = 1;
- via_chan_pcm_fmt (chan, 0);
- break;
-
- /* stereo */
- case 2:
- chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
- chan->channels = 2;
- via_chan_pcm_fmt (chan, 0);
- break;
-
- case 4:
- case 6:
- if(chan->is_multi)
- {
- chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
- chan->channels = val;
- break;
- }
- /* unknown */
- default:
- val = -EINVAL;
- break;
- }
-
- DPRINTK ("EXIT, returning %d\n", val);
- return val;
-}
-
-static int via_chan_set_buffering (struct via_info *card,
- struct via_channel *chan, int val)
-{
- int shift;
-
- DPRINTK ("ENTER\n");
-
- /* in both cases the buffer cannot be changed */
- if (chan->is_active || chan->is_mapped) {
- DPRINTK ("EXIT\n");
- return -EINVAL;
- }
-
- /* called outside SETFRAGMENT */
- /* set defaults or do nothing */
- if (val < 0) {
-
- if (chan->frag_size && chan->frag_number)
- goto out;
-
- DPRINTK ("\n");
-
- chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * chan->channels
- * ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
-
- shift = 0;
- while (chan->frag_size) {
- chan->frag_size >>= 1;
- shift++;
- }
- chan->frag_size = 1 << shift;
-
- chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);
-
- DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);
- } else {
- chan->frag_size = 1 << (val & 0xFFFF);
- chan->frag_number = (val >> 16) & 0xFFFF;
-
- DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);
- }
-
- /* quake3 wants frag_number to be a power of two */
- shift = 0;
- while (chan->frag_number) {
- chan->frag_number >>= 1;
- shift++;
- }
- chan->frag_number = 1 << shift;
-
- if (chan->frag_size > VIA_MAX_FRAG_SIZE)
- chan->frag_size = VIA_MAX_FRAG_SIZE;
- else if (chan->frag_size < VIA_MIN_FRAG_SIZE)
- chan->frag_size = VIA_MIN_FRAG_SIZE;
-
- if (chan->frag_number < VIA_MIN_FRAG_NUMBER)
- chan->frag_number = VIA_MIN_FRAG_NUMBER;
- if (chan->frag_number > VIA_MAX_FRAG_NUMBER)
- chan->frag_number = VIA_MAX_FRAG_NUMBER;
-
- if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)
- chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;
-
-out:
- if (chan->is_record)
- atomic_set (&chan->n_frags, 0);
- else
- atomic_set (&chan->n_frags, chan->frag_number);
-
- DPRINTK ("EXIT\n");
-
- return 0;
-}
-
-#ifdef VIA_CHAN_DUMP_BUFS
-/**
- * via_chan_dump_bufs - Display DMA table contents
- * @chan: Channel whose DMA table will be displayed
- *
- * Debugging function which displays the contents of the
- * scatter-gather DMA table for the given channel @chan.
- */
-
-static void via_chan_dump_bufs (struct via_channel *chan)
-{
- int i;
-
- for (i = 0; i < chan->frag_number; i++) {
- DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
- i, chan->sgtable[i].addr,
- chan->sgtable[i].count & 0x00FFFFFF,
- chan->sgtable[i].count & VIA_FLAG ? 1 : 0,
- chan->sgtable[i].count & VIA_EOL ? 1 : 0);
- }
- DPRINTK ("buf_in_use = %d, nextbuf = %d\n",
- atomic_read (&chan->buf_in_use),
- atomic_read (&chan->sw_ptr));
-}
-#endif /* VIA_CHAN_DUMP_BUFS */
-
-
-/**
- * via_chan_flush_frag - Flush partially-full playback buffer to hardware
- * @chan: Channel whose DMA table will be flushed
- *
- * Flushes partially-full playback buffer to hardware.
- */
-
-static void via_chan_flush_frag (struct via_channel *chan)
-{
- DPRINTK ("ENTER\n");
-
- assert (chan->slop_len > 0);
-
- if (chan->sw_ptr == (chan->frag_number - 1))
- chan->sw_ptr = 0;
- else
- chan->sw_ptr++;
-
- chan->slop_len = 0;
-
- assert (atomic_read (&chan->n_frags) > 0);
- atomic_dec (&chan->n_frags);
-
- DPRINTK ("EXIT\n");
-}
-
-
-
-/**
- * via_chan_maybe_start - Initiate audio hardware DMA operation
- * @chan: Channel whose DMA is to be started
- *
- * Initiate DMA operation, if the DMA engine for the given
- * channel @chan is not already active.
- */
-
-static inline void via_chan_maybe_start (struct via_channel *chan)
-{
- assert (chan->is_active == sg_active(chan->iobase));
-
- DPRINTK ("MAYBE START %s\n", chan->name);
- if (!chan->is_active && chan->is_enabled) {
- chan->is_active = 1;
- sg_begin (chan);
- DPRINTK ("starting channel %s\n", chan->name);
- }
-}
-
-
-/****************************************************************
- *
- * Interface to ac97-codec module
- *
- *
- */
-
-/**
- * via_ac97_wait_idle - Wait until AC97 codec is not busy
- * @card: Private info for specified board
- *
- * Sleep until the AC97 codec is no longer busy.
- * Returns the final value read from the SGD
- * register being polled.
- */
-
-static u8 via_ac97_wait_idle (struct via_info *card)
-{
- u8 tmp8;
- int counter = VIA_COUNTER_LIMIT;
-
- DPRINTK ("ENTER/EXIT\n");
-
- assert (card != NULL);
- assert (card->pdev != NULL);
-
- do {
- udelay (15);
-
- tmp8 = inb (card->baseaddr + 0x83);
- } while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0));
-
- if (tmp8 & VIA_CR83_BUSY)
- printk (KERN_WARNING PFX "timeout waiting on AC97 codec\n");
- return tmp8;
-}
-
-
-/**
- * via_ac97_read_reg - Read AC97 standard register
- * @codec: Pointer to generic AC97 codec info
- * @reg: Index of AC97 register to be read
- *
- * Read the value of a single AC97 codec register,
- * as defined by the Intel AC97 specification.
- *
- * Defines the standard AC97 read-register operation
- * required by the kernel's ac97_codec interface.
- *
- * Returns the 16-bit value stored in the specified
- * register.
- */
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg)
-{
- unsigned long data;
- struct via_info *card;
- int counter;
-
- DPRINTK ("ENTER\n");
-
- assert (codec != NULL);
- assert (codec->private_data != NULL);
-
- card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- /* Every time we write to register 80 we cause a transaction.
- The only safe way to clear the valid bit is to write it at
- the same time as the command */
- data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID;
-
- outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
- udelay (20);
-
- for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
- udelay (1);
- if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) &
- (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID))
- goto out;
- }
-
- printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data);
- goto err_out;
-
-out:
- /* Once the valid bit has become set, we must wait a complete AC97
- frame before the data has settled. */
- udelay(25);
- data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL);
-
- outb (0x02, card->baseaddr + 0x83);
-
- if (((data & 0x007F0000) >> 16) == reg) {
- DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n",
- data, data & 0x0000FFFF);
- spin_unlock(&card->ac97_lock);
- return data & 0x0000FFFF;
- }
-
- printk (KERN_WARNING "via82cxxx_audio: not our index: reg=0x%x, newreg=0x%lx\n",
- reg, ((data & 0x007F0000) >> 16));
-
-err_out:
- spin_unlock(&card->ac97_lock);
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/**
- * via_ac97_write_reg - Write AC97 standard register
- * @codec: Pointer to generic AC97 codec info
- * @reg: Index of AC97 register to be written
- * @value: Value to be written to AC97 register
- *
- * Write the value of a single AC97 codec register,
- * as defined by the Intel AC97 specification.
- *
- * Defines the standard AC97 write-register operation
- * required by the kernel's ac97_codec interface.
- */
-
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value)
-{
- u32 data;
- struct via_info *card;
- int counter;
-
- DPRINTK ("ENTER\n");
-
- assert (codec != NULL);
- assert (codec->private_data != NULL);
-
- card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- data = (reg << 16) + value;
- outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
- udelay (10);
-
- for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
- if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0)
- goto out;
-
- udelay (15);
- }
-
- printk (KERN_WARNING PFX "timeout after AC97 codec write (0x%X, 0x%X)\n", reg, value);
-
-out:
- spin_unlock(&card->ac97_lock);
- DPRINTK ("EXIT\n");
-}
-
-
-static int via_mixer_open (struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct via_info *card;
- struct pci_dev *pdev = NULL;
- struct pci_driver *drvr;
-
- DPRINTK ("ENTER\n");
-
- while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- drvr = pci_dev_driver (pdev);
- if (drvr == &via_driver) {
- assert (pci_get_drvdata (pdev) != NULL);
-
- card = pci_get_drvdata (pdev);
- if (card->ac97->dev_mixer == minor)
- goto match;
- }
- }
-
- DPRINTK ("EXIT, returning -ENODEV\n");
- return -ENODEV;
-
-match:
- pci_dev_put(pdev);
- file->private_data = card->ac97;
-
- DPRINTK ("EXIT, returning 0\n");
- return nonseekable_open(inode, file);
-}
-
-static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = file->private_data;
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc;
-
- DPRINTK ("ENTER\n");
-
- assert (codec != NULL);
- card = codec->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
-#if 0
- /*
- * Intercept volume control on 8233 and 8235
- */
- if(card->volume)
- {
- switch(cmd)
- {
- case SOUND_MIXER_READ_VOLUME:
- return card->mixer_vol;
- case SOUND_MIXER_WRITE_VOLUME:
- {
- int v;
- if(get_user(v, (int *)arg))
- {
- rc = -EFAULT;
- goto out;
- }
- card->mixer_vol = v;
- }
- }
- }
-#endif
- rc = codec->mixer_ioctl(codec, cmd, arg);
-
- mutex_unlock(&card->syscall_mutex);
-
-out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-static const struct file_operations via_mixer_fops = {
- .owner = THIS_MODULE,
- .open = via_mixer_open,
- .llseek = no_llseek,
- .ioctl = via_mixer_ioctl,
-};
-
-
-static int __devinit via_ac97_reset (struct via_info *card)
-{
- struct pci_dev *pdev = card->pdev;
- u8 tmp8;
- u16 tmp16;
-
- DPRINTK ("ENTER\n");
-
- assert (pdev != NULL);
-
-#ifndef NDEBUG
- {
- u8 r40,r41,r42,r43,r44,r48;
- pci_read_config_byte (card->pdev, 0x40, &r40);
- pci_read_config_byte (card->pdev, 0x41, &r41);
- pci_read_config_byte (card->pdev, 0x42, &r42);
- pci_read_config_byte (card->pdev, 0x43, &r43);
- pci_read_config_byte (card->pdev, 0x44, &r44);
- pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
- r40,r41,r42,r43,r44,r48);
-
- spin_lock_irq (&card->lock);
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
- spin_unlock_irq (&card->lock);
-
- }
-#endif
-
- /*
- * Reset AC97 controller: enable, disable, enable,
- * pausing after each command for good luck. Only
- * do this if the codec is not ready, because it causes
- * loud pops and such due to such a hard codec reset.
- */
- pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8);
- if ((tmp8 & VIA_CR40_AC97_READY) == 0) {
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE |
- VIA_CR41_AC97_RESET |
- VIA_CR41_AC97_WAKEUP);
- udelay (100);
-
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
- udelay (100);
-
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE |
- VIA_CR41_PCM_ENABLE |
- VIA_CR41_VRA | VIA_CR41_AC97_RESET);
- udelay (100);
- }
-
- /* Make sure VRA is enabled, in case we didn't do a
- * complete codec reset, above
- */
- pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
- if (((tmp8 & VIA_CR41_VRA) == 0) ||
- ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) ||
- ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) ||
- ((tmp8 & VIA_CR41_AC97_RESET) == 0)) {
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE |
- VIA_CR41_PCM_ENABLE |
- VIA_CR41_VRA | VIA_CR41_AC97_RESET);
- udelay (100);
- }
-
- if(card->legacy)
- {
-#if 0 /* this breaks on K7M */
- /* disable legacy stuff */
- pci_write_config_byte (pdev, 0x42, 0x00);
- udelay(10);
-#endif
-
- /* route FM trap to IRQ, disable FM trap */
- pci_write_config_byte (pdev, 0x48, 0x05);
- udelay(10);
- }
-
- /* disable all codec GPI interrupts */
- outl (0, pci_resource_start (pdev, 0) + 0x8C);
-
- /* WARNING: this line is magic. Remove this
- * and things break. */
- /* enable variable rate */
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0)
- via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-static void via_ac97_codec_wait (struct ac97_codec *codec)
-{
- assert (codec->private_data != NULL);
- via_ac97_wait_idle (codec->private_data);
-}
-
-
-static int __devinit via_ac97_init (struct via_info *card)
-{
- int rc;
- u16 tmp16;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- card->ac97 = ac97_alloc_codec();
- if(card->ac97 == NULL)
- return -ENOMEM;
-
- card->ac97->private_data = card;
- card->ac97->codec_read = via_ac97_read_reg;
- card->ac97->codec_write = via_ac97_write_reg;
- card->ac97->codec_wait = via_ac97_codec_wait;
-
- card->ac97->dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
- if (card->ac97->dev_mixer < 0) {
- printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
- DPRINTK ("EXIT, returning -EIO\n");
- ac97_release_codec(card->ac97);
- return -EIO;
- }
-
- rc = via_ac97_reset (card);
- if (rc) {
- printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");
- goto err_out;
- }
-
- mdelay(10);
-
- if (ac97_probe_codec (card->ac97) == 0) {
- printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");
- rc = -EIO;
- goto err_out;
- }
-
- /* enable variable rate */
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
- /*
- * If we cannot enable VRA, we have a locked-rate codec.
- * We try again to enable VRA before assuming so, however.
- */
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0) {
- via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0) {
- card->locked_rate = 1;
- printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
- }
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out:
- unregister_sound_mixer (card->ac97->dev_mixer);
- DPRINTK ("EXIT, returning %d\n", rc);
- ac97_release_codec(card->ac97);
- return rc;
-}
-
-
-static void via_ac97_cleanup (struct via_info *card)
-{
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->ac97->dev_mixer >= 0);
-
- unregister_sound_mixer (card->ac97->dev_mixer);
- ac97_release_codec(card->ac97);
-
- DPRINTK ("EXIT\n");
-}
-
-
-
-/****************************************************************
- *
- * Interrupt-related code
- *
- */
-
-/**
- * via_intr_channel - handle an interrupt for a single channel
- * @card: unused
- * @chan: handle interrupt for this channel
- *
- * This is the "meat" of the interrupt handler,
- * containing the actions taken each time an interrupt
- * occurs. All communication and coordination with
- * userspace takes place here.
- *
- * Locking: inside card->lock
- */
-
-static void via_intr_channel (struct via_info *card, struct via_channel *chan)
-{
- u8 status;
- int n;
-
- /* check pertinent bits of status register for action bits */
- status = inb (chan->iobase) & (VIA_SGD_FLAG | VIA_SGD_EOL | VIA_SGD_STOPPED);
- if (!status)
- return;
-
- /* acknowledge any flagged bits ASAP */
- outb (status, chan->iobase);
-
- if (!chan->sgtable) /* XXX: temporary solution */
- return;
-
- /* grab current h/w ptr value */
- n = atomic_read (&chan->hw_ptr);
-
- /* sanity check: make sure our h/w ptr doesn't have a weird value */
- assert (n >= 0);
- assert (n < chan->frag_number);
-
-
- /* reset SGD data structure in memory to reflect a full buffer,
- * and advance the h/w ptr, wrapping around to zero if needed
- */
- if (n == (chan->frag_number - 1)) {
- chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL);
- atomic_set (&chan->hw_ptr, 0);
- } else {
- chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG);
- atomic_inc (&chan->hw_ptr);
- }
-
- /* accounting crap for SNDCTL_DSP_GETxPTR */
- chan->n_irqs++;
- chan->bytes += chan->frag_size;
- /* FIXME - signed overflow is undefined */
- if (chan->bytes < 0) /* handle overflow of 31-bit value */
- chan->bytes = chan->frag_size;
- /* all following checks only occur when not in mmap(2) mode */
- if (!chan->is_mapped)
- {
- /* If we are recording, then n_frags represents the number
- * of fragments waiting to be handled by userspace.
- * If we are playback, then n_frags represents the number
- * of fragments remaining to be filled by userspace.
- * We increment here. If we reach max number of fragments,
- * this indicates an underrun/overrun. For this case under OSS,
- * we stop the record/playback process.
- */
- if (atomic_read (&chan->n_frags) < chan->frag_number)
- atomic_inc (&chan->n_frags);
- assert (atomic_read (&chan->n_frags) <= chan->frag_number);
- if (atomic_read (&chan->n_frags) == chan->frag_number) {
- chan->is_active = 0;
- via_chan_stop (chan->iobase);
- }
- }
- /* wake up anyone listening to see when interrupts occur */
- wake_up_all (&chan->wait);
-
- DPRINTK ("%s intr, status=0x%02X, hwptr=0x%lX, chan->hw_ptr=%d\n",
- chan->name, status, (long) inl (chan->iobase + 0x04),
- atomic_read (&chan->hw_ptr));
-
- DPRINTK ("%s intr, channel n_frags == %d, missed %d\n", chan->name,
- atomic_read (&chan->n_frags), missed);
-}
-
-
-static irqreturn_t via_interrupt(int irq, void *dev_id)
-{
- struct via_info *card = dev_id;
- u32 status32;
-
- /* to minimize interrupt sharing costs, we use the SGD status
- * shadow register to check the status of all inputs and
- * outputs with a single 32-bit bus read. If no interrupt
- * conditions are flagged, we exit immediately
- */
- status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
- if (!(status32 & VIA_INTR_MASK))
- {
-#ifdef CONFIG_MIDI_VIA82CXXX
- if (card->midi_devc)
- uart401intr(irq, card->midi_devc);
-#endif
- return IRQ_HANDLED;
- }
- DPRINTK ("intr, status32 == 0x%08X\n", status32);
-
- /* synchronize interrupt handling under SMP. this spinlock
- * goes away completely on UP
- */
- spin_lock (&card->lock);
-
- if (status32 & VIA_INTR_OUT)
- via_intr_channel (card, &card->ch_out);
- if (status32 & VIA_INTR_IN)
- via_intr_channel (card, &card->ch_in);
- if (status32 & VIA_INTR_FM)
- via_intr_channel (card, &card->ch_fm);
-
- spin_unlock (&card->lock);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t via_new_interrupt(int irq, void *dev_id)
-{
- struct via_info *card = dev_id;
- u32 status32;
-
- /* to minimize interrupt sharing costs, we use the SGD status
- * shadow register to check the status of all inputs and
- * outputs with a single 32-bit bus read. If no interrupt
- * conditions are flagged, we exit immediately
- */
- status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
- if (!(status32 & VIA_NEW_INTR_MASK))
- return IRQ_NONE;
- /*
- * goes away completely on UP
- */
- spin_lock (&card->lock);
-
- via_intr_channel (card, &card->ch_out);
- via_intr_channel (card, &card->ch_in);
- via_intr_channel (card, &card->ch_fm);
-
- spin_unlock (&card->lock);
- return IRQ_HANDLED;
-}
-
-
-/**
- * via_interrupt_init - Initialize interrupt handling
- * @card: Private info for specified board
- *
- * Obtain and reserve IRQ for using in handling audio events.
- * Also, disable any IRQ-generating resources, to make sure
- * we don't get interrupts before we want them.
- */
-
-static int via_interrupt_init (struct via_info *card)
-{
- u8 tmp8;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->pdev != NULL);
-
- /* check for sane IRQ number. can this ever happen? */
- if (card->pdev->irq < 2) {
- printk (KERN_ERR PFX "insane IRQ %d, aborting\n",
- card->pdev->irq);
- DPRINTK ("EXIT, returning -EIO\n");
- return -EIO;
- }
-
- /* VIA requires this is done */
- pci_write_config_byte(card->pdev, PCI_INTERRUPT_LINE, card->pdev->irq);
-
- if(card->legacy)
- {
- /* make sure FM irq is not routed to us */
- pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
- if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
- tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
- pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
- }
- if (request_irq (card->pdev->irq, via_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
- printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
- card->pdev->irq);
- DPRINTK ("EXIT, returning -EBUSY\n");
- return -EBUSY;
- }
- }
- else
- {
- if (request_irq (card->pdev->irq, via_new_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
- printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
- card->pdev->irq);
- DPRINTK ("EXIT, returning -EBUSY\n");
- return -EBUSY;
- }
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/****************************************************************
- *
- * OSS DSP device
- *
- */
-
-static const struct file_operations via_dsp_fops = {
- .owner = THIS_MODULE,
- .open = via_dsp_open,
- .release = via_dsp_release,
- .read = via_dsp_read,
- .write = via_dsp_write,
- .poll = via_dsp_poll,
- .llseek = no_llseek,
- .ioctl = via_dsp_ioctl,
- .mmap = via_dsp_mmap,
-};
-
-
-static int __devinit via_dsp_init (struct via_info *card)
-{
- u8 tmp8;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- if(card->legacy)
- {
- /* turn off legacy features, if not already */
- pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
- if (tmp8 & (VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE)) {
- tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);
- pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
- }
- }
-
- via_stop_everything (card);
-
- card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1);
- if (card->dev_dsp < 0) {
- DPRINTK ("EXIT, returning -ENODEV\n");
- return -ENODEV;
- }
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-static void via_dsp_cleanup (struct via_info *card)
-{
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->dev_dsp >= 0);
-
- via_stop_everything (card);
-
- unregister_sound_dsp (card->dev_dsp);
-
- DPRINTK ("EXIT\n");
-}
-
-
-static struct page * via_mm_nopage (struct vm_area_struct * vma,
- unsigned long address, int *type)
-{
- struct via_info *card = vma->vm_private_data;
- struct via_channel *chan = &card->ch_out;
- struct page *dmapage;
- unsigned long pgoff;
- int rd, wr;
-
- DPRINTK ("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n",
- vma->vm_start,
- address - vma->vm_start,
- (address - vma->vm_start) >> PAGE_SHIFT,
- address);
-
- if (address > vma->vm_end) {
- DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
- return NOPAGE_SIGBUS; /* Disallow mremap */
- }
- if (!card) {
- DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
- return NOPAGE_SIGBUS; /* Nothing allocated */
- }
-
- pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);
- rd = card->ch_in.is_mapped;
- wr = card->ch_out.is_mapped;
-
-#ifndef VIA_NDEBUG
- {
- unsigned long max_bufs = chan->frag_number;
- if (rd && wr) max_bufs *= 2;
- /* via_dsp_mmap() should ensure this */
- assert (pgoff < max_bufs);
- }
-#endif
-
- /* if full-duplex (read+write) and we have two sets of bufs,
- * then the playback buffers come first, sez soundcard.c */
- if (pgoff >= chan->page_number) {
- pgoff -= chan->page_number;
- chan = &card->ch_in;
- } else if (!wr)
- chan = &card->ch_in;
-
- assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);
-
- dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);
- DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",
- dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);
- get_page (dmapage);
- if (type)
- *type = VM_FAULT_MINOR;
- return dmapage;
-}
-
-
-#ifndef VM_RESERVED
-static int via_mm_swapout (struct page *page, struct file *filp)
-{
- return 0;
-}
-#endif /* VM_RESERVED */
-
-
-static struct vm_operations_struct via_mm_ops = {
- .nopage = via_mm_nopage,
-
-#ifndef VM_RESERVED
- .swapout = via_mm_swapout,
-#endif
-};
-
-
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc = -EINVAL, rd=0, wr=0;
- unsigned long max_size, size, start, offset;
-
- assert (file != NULL);
- assert (vma != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- DPRINTK ("ENTER, start %lXh, size %ld, pgoff %ld\n",
- vma->vm_start,
- vma->vm_end - vma->vm_start,
- vma->vm_pgoff);
-
- max_size = 0;
- if (vma->vm_flags & VM_READ) {
- rd = 1;
- via_chan_set_buffering(card, &card->ch_in, -1);
- via_chan_buffer_init (card, &card->ch_in);
- max_size += card->ch_in.page_number << PAGE_SHIFT;
- }
- if (vma->vm_flags & VM_WRITE) {
- wr = 1;
- via_chan_set_buffering(card, &card->ch_out, -1);
- via_chan_buffer_init (card, &card->ch_out);
- max_size += card->ch_out.page_number << PAGE_SHIFT;
- }
-
- start = vma->vm_start;
- offset = (vma->vm_pgoff << PAGE_SHIFT);
- size = vma->vm_end - vma->vm_start;
-
- /* some basic size/offset sanity checks */
- if (size > max_size)
- goto out;
- if (offset > max_size - size)
- goto out;
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
- vma->vm_ops = &via_mm_ops;
- vma->vm_private_data = card;
-
-#ifdef VM_RESERVED
- vma->vm_flags |= VM_RESERVED;
-#endif
-
- if (rd)
- card->ch_in.is_mapped = 1;
- if (wr)
- card->ch_out.is_mapped = 1;
-
- mutex_unlock(&card->syscall_mutex);
- rc = 0;
-
-out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-static ssize_t via_dsp_do_read (struct via_info *card,
- char __user *userbuf, size_t count,
- int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- const char __user *orig_userbuf = userbuf;
- struct via_channel *chan = &card->ch_in;
- size_t size;
- int n, tmp;
- ssize_t ret = 0;
-
- /* if SGD has not yet been started, start it */
- via_chan_maybe_start (chan);
-
-handle_one_block:
- /* just to be a nice neighbor */
- /* Thomas Sailer:
- * But also to ourselves, release semaphore if we do so */
- if (need_resched()) {
- mutex_unlock(&card->syscall_mutex);
- schedule ();
- ret = via_syscall_down (card, nonblock);
- if (ret)
- goto out;
- }
-
- /* grab current channel software pointer. In the case of
- * recording, this is pointing to the next buffer that
- * will receive data from the audio hardware.
- */
- n = chan->sw_ptr;
-
- /* n_frags represents the number of fragments waiting
- * to be copied to userland. sleep until at least
- * one buffer has been read from the audio hardware.
- */
- add_wait_queue(&chan->wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- tmp = atomic_read (&chan->n_frags);
- assert (tmp >= 0);
- assert (tmp <= chan->frag_number);
- if (tmp)
- break;
- if (nonblock || !chan->is_active) {
- ret = -EAGAIN;
- break;
- }
-
- mutex_unlock(&card->syscall_mutex);
-
- DPRINTK ("Sleeping on block %d\n", n);
- schedule();
-
- ret = via_syscall_down (card, nonblock);
- if (ret)
- break;
-
- if (signal_pending (current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&chan->wait, &wait);
- if (ret)
- goto out;
-
- /* Now that we have a buffer we can read from, send
- * as much as sample data possible to userspace.
- */
- while ((count > 0) && (chan->slop_len < chan->frag_size)) {
- size_t slop_left = chan->frag_size - chan->slop_len;
- void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr;
- unsigned ofs = (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
- size = (count < slop_left) ? count : slop_left;
- if (copy_to_user (userbuf,
- base + ofs + chan->slop_len,
- size)) {
- ret = -EFAULT;
- goto out;
- }
-
- count -= size;
- chan->slop_len += size;
- userbuf += size;
- }
-
- /* If we didn't copy the buffer completely to userspace,
- * stop now.
- */
- if (chan->slop_len < chan->frag_size)
- goto out;
-
- /*
- * If we get to this point, we copied one buffer completely
- * to userspace, give the buffer back to the hardware.
- */
-
- /* advance channel software pointer to point to
- * the next buffer from which we will copy
- */
- if (chan->sw_ptr == (chan->frag_number - 1))
- chan->sw_ptr = 0;
- else
- chan->sw_ptr++;
-
- /* mark one less buffer waiting to be processed */
- assert (atomic_read (&chan->n_frags) > 0);
- atomic_dec (&chan->n_frags);
-
- /* we are at a block boundary, there is no fragment data */
- chan->slop_len = 0;
-
- DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
-
- if (count > 0)
- goto handle_one_block;
-
-out:
- return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret;
-}
-
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc;
-
- DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
- file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
- if (card->ch_in.is_mapped) {
- rc = -ENXIO;
- goto out_up;
- }
-
- via_chan_set_buffering(card, &card->ch_in, -1);
- rc = via_chan_buffer_init (card, &card->ch_in);
-
- if (rc)
- goto out_up;
-
- rc = via_dsp_do_read (card, buffer, count, nonblock);
-
-out_up:
- mutex_unlock(&card->syscall_mutex);
-out:
- DPRINTK ("EXIT, returning %ld\n",(long) rc);
- return rc;
-}
-
-
-static ssize_t via_dsp_do_write (struct via_info *card,
- const char __user *userbuf, size_t count,
- int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- const char __user *orig_userbuf = userbuf;
- struct via_channel *chan = &card->ch_out;
- volatile struct via_sgd_table *sgtable = chan->sgtable;
- size_t size;
- int n, tmp;
- ssize_t ret = 0;
-
-handle_one_block:
- /* just to be a nice neighbor */
- /* Thomas Sailer:
- * But also to ourselves, release semaphore if we do so */
- if (need_resched()) {
- mutex_unlock(&card->syscall_mutex);
- schedule ();
- ret = via_syscall_down (card, nonblock);
- if (ret)
- goto out;
- }
-
- /* grab current channel fragment pointer. In the case of
- * playback, this is pointing to the next fragment that
- * should receive data from userland.
- */
- n = chan->sw_ptr;
-
- /* n_frags represents the number of fragments remaining
- * to be filled by userspace. Sleep until
- * at least one fragment is available for our use.
- */
- add_wait_queue(&chan->wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- tmp = atomic_read (&chan->n_frags);
- assert (tmp >= 0);
- assert (tmp <= chan->frag_number);
- if (tmp)
- break;
- if (nonblock || !chan->is_active) {
- ret = -EAGAIN;
- break;
- }
-
- mutex_unlock(&card->syscall_mutex);
-
- DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
- schedule();
-
- ret = via_syscall_down (card, nonblock);
- if (ret)
- break;
-
- if (signal_pending (current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&chan->wait, &wait);
- if (ret)
- goto out;
-
- /* Now that we have at least one fragment we can write to, fill the buffer
- * as much as possible with data from userspace.
- */
- while ((count > 0) && (chan->slop_len < chan->frag_size)) {
- size_t slop_left = chan->frag_size - chan->slop_len;
-
- size = (count < slop_left) ? count : slop_left;
- if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,
- userbuf, size)) {
- ret = -EFAULT;
- goto out;
- }
-
- count -= size;
- chan->slop_len += size;
- userbuf += size;
- }
-
- /* If we didn't fill up the buffer with data, stop now.
- * Put a 'stop' marker in the DMA table too, to tell the
- * audio hardware to stop if it gets here.
- */
- if (chan->slop_len < chan->frag_size) {
- sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);
- goto out;
- }
-
- /*
- * If we get to this point, we have filled a buffer with
- * audio data, flush the buffer to audio hardware.
- */
-
- /* Record the true size for the audio hardware to notice */
- if (n == (chan->frag_number - 1))
- sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
- else
- sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
-
- /* advance channel software pointer to point to
- * the next buffer we will fill with data
- */
- if (chan->sw_ptr == (chan->frag_number - 1))
- chan->sw_ptr = 0;
- else
- chan->sw_ptr++;
-
- /* mark one less buffer as being available for userspace consumption */
- assert (atomic_read (&chan->n_frags) > 0);
- atomic_dec (&chan->n_frags);
-
- /* we are at a block boundary, there is no fragment data */
- chan->slop_len = 0;
-
- /* if SGD has not yet been started, start it */
- via_chan_maybe_start (chan);
-
- DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
- DPRINTK ("regs==S=%02X C=%02X TP=%02X BP=%08X RT=%08X SG=%08X CC=%08X SS=%08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x08),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
-
- if (count > 0)
- goto handle_one_block;
-
-out:
- if (userbuf - orig_userbuf)
- return userbuf - orig_userbuf;
- else
- return ret;
-}
-
-
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct via_info *card;
- ssize_t rc;
- int nonblock = (file->f_flags & O_NONBLOCK);
-
- DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
- file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
- if (card->ch_out.is_mapped) {
- rc = -ENXIO;
- goto out_up;
- }
-
- via_chan_set_buffering(card, &card->ch_out, -1);
- rc = via_chan_buffer_init (card, &card->ch_out);
-
- if (rc)
- goto out_up;
-
- rc = via_dsp_do_write (card, buffer, count, nonblock);
-
-out_up:
- mutex_unlock(&card->syscall_mutex);
-out:
- DPRINTK ("EXIT, returning %ld\n",(long) rc);
- return rc;
-}
-
-
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct via_info *card;
- struct via_channel *chan;
- unsigned int mask = 0;
-
- DPRINTK ("ENTER\n");
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- if (file->f_mode & FMODE_READ) {
- chan = &card->ch_in;
- if (sg_active (chan->iobase))
- poll_wait(file, &chan->wait, wait);
- if (atomic_read (&chan->n_frags) > 0)
- mask |= POLLIN | POLLRDNORM;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- chan = &card->ch_out;
- if (sg_active (chan->iobase))
- poll_wait(file, &chan->wait, wait);
- if (atomic_read (&chan->n_frags) > 0)
- mask |= POLLOUT | POLLWRNORM;
- }
-
- DPRINTK ("EXIT, returning %u\n", mask);
- return mask;
-}
-
-
-/**
- * via_dsp_drain_playback - sleep until all playback samples are flushed
- * @card: Private info for specified board
- * @chan: Channel to drain
- * @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- * Sleeps until all playback has been flushed to the audio
- * hardware.
- *
- * Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_drain_playback (struct via_info *card,
- struct via_channel *chan, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- int ret = 0;
-
- DPRINTK ("ENTER, nonblock = %d\n", nonblock);
-
- if (chan->slop_len > 0)
- via_chan_flush_frag (chan);
-
- if (atomic_read (&chan->n_frags) == chan->frag_number)
- goto out;
-
- via_chan_maybe_start (chan);
-
- add_wait_queue(&chan->wait, &wait);
- for (;;) {
- DPRINTK ("FRAGS %d FRAGNUM %d\n", atomic_read(&chan->n_frags), chan->frag_number);
- __set_current_state(TASK_INTERRUPTIBLE);
- if (atomic_read (&chan->n_frags) >= chan->frag_number)
- break;
-
- if (nonblock) {
- DPRINTK ("EXIT, returning -EAGAIN\n");
- ret = -EAGAIN;
- break;
- }
-
-#ifdef VIA_DEBUG
- {
- u8 r40,r41,r42,r43,r44,r48;
- pci_read_config_byte (card->pdev, 0x40, &r40);
- pci_read_config_byte (card->pdev, 0x41, &r41);
- pci_read_config_byte (card->pdev, 0x42, &r42);
- pci_read_config_byte (card->pdev, 0x43, &r43);
- pci_read_config_byte (card->pdev, 0x44, &r44);
- pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
- r40,r41,r42,r43,r44,r48);
-
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
- }
-
- if (!chan->is_active)
- printk (KERN_ERR "sleeping but not active\n");
-#endif
-
- mutex_unlock(&card->syscall_mutex);
-
- DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
- schedule();
-
- if ((ret = via_syscall_down (card, nonblock)))
- break;
-
- if (signal_pending (current)) {
- DPRINTK ("EXIT, returning -ERESTARTSYS\n");
- ret = -ERESTARTSYS;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&chan->wait, &wait);
-
-#ifdef VIA_DEBUG
- {
- u8 r40,r41,r42,r43,r44,r48;
- pci_read_config_byte (card->pdev, 0x40, &r40);
- pci_read_config_byte (card->pdev, 0x41, &r41);
- pci_read_config_byte (card->pdev, 0x42, &r42);
- pci_read_config_byte (card->pdev, 0x43, &r43);
- pci_read_config_byte (card->pdev, 0x44, &r44);
- pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
- r40,r41,r42,r43,r44,r48);
-
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
-
- DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));
- }
-#endif
-
-out:
- DPRINTK ("EXIT, returning %d\n", ret);
- return ret;
-}
-
-
-/**
- * via_dsp_ioctl_space - get information about channel buffering
- * @card: Private info for specified board
- * @chan: pointer to channel-specific info
- * @arg: user buffer for returned information
- *
- * Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE.
- *
- * Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_space (struct via_info *card,
- struct via_channel *chan,
- void __user *arg)
-{
- audio_buf_info info;
-
- via_chan_set_buffering(card, chan, -1);
-
- info.fragstotal = chan->frag_number;
- info.fragsize = chan->frag_size;
-
- /* number of full fragments we can read/write without blocking */
- info.fragments = atomic_read (&chan->n_frags);
-
- if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))
- info.fragments--;
-
- /* number of bytes that can be read or written immediately
- * without blocking.
- */
- info.bytes = (info.fragments * chan->frag_size);
- if (chan->slop_len % chan->frag_size > 0)
- info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);
-
- DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
- info.fragstotal,
- info.fragsize,
- info.fragments,
- info.bytes);
-
- return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-/**
- * via_dsp_ioctl_ptr - get information about hardware buffer ptr
- * @card: Private info for specified board
- * @chan: pointer to channel-specific info
- * @arg: user buffer for returned information
- *
- * Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR.
- *
- * Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_ptr (struct via_info *card,
- struct via_channel *chan,
- void __user *arg)
-{
- count_info info;
-
- spin_lock_irq (&card->lock);
-
- info.bytes = chan->bytes;
- info.blocks = chan->n_irqs;
- chan->n_irqs = 0;
-
- spin_unlock_irq (&card->lock);
-
- if (chan->is_active) {
- unsigned long extra;
- info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
- extra = chan->frag_size - via_sg_offset(chan);
- info.ptr += extra;
- info.bytes += extra;
- } else {
- info.ptr = 0;
- }
-
- DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n",
- info.bytes,
- info.blocks,
- info.ptr);
-
- return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-static int via_dsp_ioctl_trigger (struct via_channel *chan, int val)
-{
- int enable, do_something;
-
- if (chan->is_record)
- enable = (val & PCM_ENABLE_INPUT);
- else
- enable = (val & PCM_ENABLE_OUTPUT);
-
- if (!chan->is_enabled && enable) {
- do_something = 1;
- } else if (chan->is_enabled && !enable) {
- do_something = -1;
- } else {
- do_something = 0;
- }
-
- DPRINTK ("enable=%d, do_something=%d\n",
- enable, do_something);
-
- if (chan->is_active && do_something)
- return -EINVAL;
-
- if (do_something == 1) {
- chan->is_enabled = 1;
- via_chan_maybe_start (chan);
- DPRINTK ("Triggering input\n");
- }
-
- else if (do_something == -1) {
- chan->is_enabled = 0;
- DPRINTK ("Setup input trigger\n");
- }
-
- return 0;
-}
-
-
-static int via_dsp_ioctl (struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int rc, rd=0, wr=0, val=0;
- struct via_info *card;
- struct via_channel *chan;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int __user *ip = (int __user *)arg;
- void __user *p = (void __user *)arg;
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- if (file->f_mode & FMODE_WRITE)
- wr = 1;
- if (file->f_mode & FMODE_READ)
- rd = 1;
-
- rc = via_syscall_down (card, nonblock);
- if (rc)
- return rc;
- rc = -EINVAL;
-
- switch (cmd) {
-
- /* OSS API version. XXX unverified */
- case OSS_GETVERSION:
- DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
- rc = put_user (SOUND_VERSION, ip);
- break;
-
- /* list of supported PCM data formats */
- case SNDCTL_DSP_GETFMTS:
- DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
- rc = put_user (AFMT_U8 | AFMT_S16_LE, ip);
- break;
-
- /* query or set current channel's PCM data format */
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SETFMT, val==%d\n", val);
- if (val != AFMT_QUERY) {
- rc = 0;
-
- if (rd)
- rc = via_chan_set_fmt (card, &card->ch_in, val);
-
- if (rc >= 0 && wr)
- rc = via_chan_set_fmt (card, &card->ch_out, val);
-
- if (rc < 0)
- break;
-
- val = rc;
- } else {
- if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
- (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT)))
- val = AFMT_S16_LE;
- else
- val = AFMT_U8;
- }
- DPRINTK ("SETFMT EXIT, returning %d\n", val);
- rc = put_user (val, ip);
- break;
-
- /* query or set number of channels (1=mono, 2=stereo, 4/6 for multichannel) */
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_CHANNELS, val==%d\n", val);
- if (val != 0) {
- rc = 0;
-
- if (rd)
- rc = via_chan_set_stereo (card, &card->ch_in, val);
-
- if (rc >= 0 && wr)
- rc = via_chan_set_stereo (card, &card->ch_out, val);
-
- if (rc < 0)
- break;
-
- val = rc;
- } else {
- if (rd)
- val = card->ch_in.channels;
- else
- val = card->ch_out.channels;
- }
- DPRINTK ("CHANNELS EXIT, returning %d\n", val);
- rc = put_user (val, ip);
- break;
-
- /* enable (val is not zero) or disable (val == 0) stereo */
- case SNDCTL_DSP_STEREO:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_STEREO, val==%d\n", val);
- rc = 0;
-
- if (rd)
- rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
- if (rc >= 0 && wr)
- rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
-
- if (rc < 0)
- break;
-
- val = rc - 1;
-
- DPRINTK ("STEREO EXIT, returning %d\n", val);
- rc = put_user(val, ip);
- break;
-
- /* query or set sampling rate */
- case SNDCTL_DSP_SPEED:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SPEED, val==%d\n", val);
- if (val < 0) {
- rc = -EINVAL;
- break;
- }
- if (val > 0) {
- rc = 0;
-
- if (rd)
- rc = via_chan_set_speed (card, &card->ch_in, val);
- if (rc >= 0 && wr)
- rc = via_chan_set_speed (card, &card->ch_out, val);
-
- if (rc < 0)
- break;
-
- val = rc;
- } else {
- if (rd)
- val = card->ch_in.rate;
- else if (wr)
- val = card->ch_out.rate;
- else
- val = 0;
- }
- DPRINTK ("SPEED EXIT, returning %d\n", val);
- rc = put_user (val, ip);
- break;
-
- /* wait until all buffers have been played, and then stop device */
- case SNDCTL_DSP_SYNC:
- DPRINTK ("DSP_SYNC\n");
- rc = 0;
- if (wr) {
- DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n");
- rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
- }
- break;
-
- /* stop recording/playback immediately */
- case SNDCTL_DSP_RESET:
- DPRINTK ("DSP_RESET\n");
- if (rd) {
- via_chan_clear (card, &card->ch_in);
- card->ch_in.frag_number = 0;
- card->ch_in.frag_size = 0;
- atomic_set(&card->ch_in.n_frags, 0);
- }
-
- if (wr) {
- via_chan_clear (card, &card->ch_out);
- card->ch_out.frag_number = 0;
- card->ch_out.frag_size = 0;
- atomic_set(&card->ch_out.n_frags, 0);
- }
-
- rc = 0;
- break;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- rc = 0;
- break;
-
- /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
- case SNDCTL_DSP_GETCAPS:
- DPRINTK ("DSP_GETCAPS\n");
- rc = put_user(VIA_DSP_CAP, ip);
- break;
-
- /* obtain buffer fragment size */
- case SNDCTL_DSP_GETBLKSIZE:
- DPRINTK ("DSP_GETBLKSIZE\n");
-
- if (rd) {
- via_chan_set_buffering(card, &card->ch_in, -1);
- rc = put_user(card->ch_in.frag_size, ip);
- } else if (wr) {
- via_chan_set_buffering(card, &card->ch_out, -1);
- rc = put_user(card->ch_out.frag_size, ip);
- }
- break;
-
- /* obtain information about input buffering */
- case SNDCTL_DSP_GETISPACE:
- DPRINTK ("DSP_GETISPACE\n");
- if (rd)
- rc = via_dsp_ioctl_space (card, &card->ch_in, p);
- break;
-
- /* obtain information about output buffering */
- case SNDCTL_DSP_GETOSPACE:
- DPRINTK ("DSP_GETOSPACE\n");
- if (wr)
- rc = via_dsp_ioctl_space (card, &card->ch_out, p);
- break;
-
- /* obtain information about input hardware pointer */
- case SNDCTL_DSP_GETIPTR:
- DPRINTK ("DSP_GETIPTR\n");
- if (rd)
- rc = via_dsp_ioctl_ptr (card, &card->ch_in, p);
- break;
-
- /* obtain information about output hardware pointer */
- case SNDCTL_DSP_GETOPTR:
- DPRINTK ("DSP_GETOPTR\n");
- if (wr)
- rc = via_dsp_ioctl_ptr (card, &card->ch_out, p);
- break;
-
- /* return number of bytes remaining to be played by DMA engine */
- case SNDCTL_DSP_GETODELAY:
- {
- DPRINTK ("DSP_GETODELAY\n");
-
- chan = &card->ch_out;
-
- if (!wr)
- break;
-
- if (chan->is_active) {
-
- val = chan->frag_number - atomic_read (&chan->n_frags);
-
- assert(val >= 0);
-
- if (val > 0) {
- val *= chan->frag_size;
- val -= chan->frag_size - via_sg_offset(chan);
- }
- val += chan->slop_len % chan->frag_size;
- } else
- val = 0;
-
- assert (val <= (chan->frag_size * chan->frag_number));
-
- DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val);
- rc = put_user (val, ip);
- break;
- }
-
- /* handle the quick-start of a channel,
- * or the notification that a quick-start will
- * occur in the future
- */
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
- rd, wr, card->ch_in.is_active, card->ch_out.is_active,
- card->ch_in.is_enabled, card->ch_out.is_enabled);
-
- rc = 0;
-
- if (rd)
- rc = via_dsp_ioctl_trigger (&card->ch_in, val);
-
- if (!rc && wr)
- rc = via_dsp_ioctl_trigger (&card->ch_out, val);
-
- break;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled)
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled)
- val |= PCM_ENABLE_OUTPUT;
- rc = put_user(val, ip);
- break;
-
- /* Enable full duplex. Since we do this as soon as we are opened
- * with O_RDWR, this is mainly a no-op that always returns success.
- */
- case SNDCTL_DSP_SETDUPLEX:
- DPRINTK ("DSP_SETDUPLEX\n");
- if (!rd || !wr)
- break;
- rc = 0;
- break;
-
- /* set fragment size. implemented as a successful no-op for now */
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val);
-
- if (rd)
- rc = via_chan_set_buffering(card, &card->ch_in, val);
-
- if (wr)
- rc = via_chan_set_buffering(card, &card->ch_out, val);
-
- DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
- val & 0xFFFF,
- val & 0xFFFF,
- (val >> 16) & 0xFFFF,
- (val >> 16) & 0xFFFF);
-
- rc = 0;
- break;
-
- /* inform device of an upcoming pause in input (or output). */
- case SNDCTL_DSP_POST:
- DPRINTK ("DSP_POST\n");
- if (wr) {
- if (card->ch_out.slop_len > 0)
- via_chan_flush_frag (&card->ch_out);
- via_chan_maybe_start (&card->ch_out);
- }
-
- rc = 0;
- break;
-
- /* not implemented */
- default:
- DPRINTK ("unhandled ioctl, cmd==%u, arg==%p\n",
- cmd, p);
- break;
- }
-
- mutex_unlock(&card->syscall_mutex);
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-static int via_dsp_open (struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct via_info *card;
- struct pci_dev *pdev = NULL;
- struct via_channel *chan;
- struct pci_driver *drvr;
- int nonblock = (file->f_flags & O_NONBLOCK);
-
- DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode);
-
- if (!(file->f_mode & (FMODE_READ | FMODE_WRITE))) {
- DPRINTK ("EXIT, returning -EINVAL\n");
- return -EINVAL;
- }
-
- card = NULL;
- while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- drvr = pci_dev_driver (pdev);
- if (drvr == &via_driver) {
- assert (pci_get_drvdata (pdev) != NULL);
-
- card = pci_get_drvdata (pdev);
- DPRINTK ("dev_dsp = %d, minor = %d, assn = %d\n",
- card->dev_dsp, minor,
- (card->dev_dsp ^ minor) & ~0xf);
-
- if (((card->dev_dsp ^ minor) & ~0xf) == 0)
- goto match;
- }
- }
-
- DPRINTK ("no matching %s found\n", card ? "minor" : "driver");
- return -ENODEV;
-
-match:
- pci_dev_put(pdev);
- if (nonblock) {
- if (!mutex_trylock(&card->open_mutex)) {
- DPRINTK ("EXIT, returning -EAGAIN\n");
- return -EAGAIN;
- }
- } else {
- if (mutex_lock_interruptible(&card->open_mutex)) {
- DPRINTK ("EXIT, returning -ERESTARTSYS\n");
- return -ERESTARTSYS;
- }
- }
-
- file->private_data = card;
- DPRINTK ("file->f_mode == 0x%x\n", file->f_mode);
-
- /* handle input from analog source */
- if (file->f_mode & FMODE_READ) {
- chan = &card->ch_in;
-
- via_chan_init (card, chan);
-
- /* why is this forced to 16-bit stereo in all drivers? */
- chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
- chan->channels = 2;
-
- // TO DO - use FIFO: via_capture_fifo(card, 1);
- via_chan_pcm_fmt (chan, 0);
- via_set_rate (card->ac97, chan, 44100);
- }
-
- /* handle output to analog source */
- if (file->f_mode & FMODE_WRITE) {
- chan = &card->ch_out;
-
- via_chan_init (card, chan);
-
- if (file->f_mode & FMODE_READ) {
- /* if in duplex mode make the recording and playback channels
- have the same settings */
- chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
- chan->channels = 2;
- via_chan_pcm_fmt (chan, 0);
- via_set_rate (card->ac97, chan, 44100);
- } else {
- if ((minor & 0xf) == SND_DEV_DSP16) {
- chan->pcm_fmt = VIA_PCM_FMT_16BIT;
- via_chan_pcm_fmt (chan, 0);
- via_set_rate (card->ac97, chan, 44100);
- } else {
- via_chan_pcm_fmt (chan, 1);
- via_set_rate (card->ac97, chan, 8000);
- }
- }
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return nonseekable_open(inode, file);
-}
-
-
-static int via_dsp_release(struct inode *inode, struct file *file)
-{
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc;
-
- DPRINTK ("ENTER\n");
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) {
- DPRINTK ("EXIT (syscall_down error), rc=%d\n", rc);
- return rc;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
- if (rc && rc != -ERESTARTSYS) /* Nobody needs to know about ^C */
- printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
-
- via_chan_free (card, &card->ch_out);
- via_chan_buffer_free(card, &card->ch_out);
- }
-
- if (file->f_mode & FMODE_READ) {
- via_chan_free (card, &card->ch_in);
- via_chan_buffer_free (card, &card->ch_in);
- }
-
- mutex_unlock(&card->syscall_mutex);
- mutex_unlock(&card->open_mutex);
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/****************************************************************
- *
- * Chip setup and kernel registration
- *
- *
- */
-
-static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
-{
-#ifdef CONFIG_MIDI_VIA82CXXX
- u8 r42;
-#endif
- int rc;
- struct via_info *card;
- static int printed_version;
-
- DPRINTK ("ENTER\n");
-
- if (printed_version++ == 0)
- printk (KERN_INFO "Via 686a/8233/8235 audio driver " VIA_VERSION "\n");
-
- rc = pci_enable_device (pdev);
- if (rc)
- goto err_out;
-
- rc = pci_request_regions (pdev, "via82cxxx_audio");
- if (rc)
- goto err_out_disable;
-
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc)
- goto err_out_res;
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc)
- goto err_out_res;
-
- card = kmalloc (sizeof (*card), GFP_KERNEL);
- if (!card) {
- printk (KERN_ERR PFX "out of memory, aborting\n");
- rc = -ENOMEM;
- goto err_out_res;
- }
-
- pci_set_drvdata (pdev, card);
-
- memset (card, 0, sizeof (*card));
- card->pdev = pdev;
- card->baseaddr = pci_resource_start (pdev, 0);
- card->card_num = via_num_cards++;
- spin_lock_init (&card->lock);
- spin_lock_init (&card->ac97_lock);
- mutex_init(&card->syscall_mutex);
- mutex_init(&card->open_mutex);
-
- /* we must init these now, in case the intr handler needs them */
- via_chan_init_defaults (card, &card->ch_out);
- via_chan_init_defaults (card, &card->ch_in);
- via_chan_init_defaults (card, &card->ch_fm);
-
- /* if BAR 2 is present, chip is Rev H or later,
- * which means it has a few extra features */
- if (pci_resource_start (pdev, 2) > 0)
- card->rev_h = 1;
-
- /* Overkill for now, but more flexible done right */
-
- card->intmask = id->driver_data;
- card->legacy = !card->intmask;
- card->sixchannel = id->driver_data;
-
- if(card->sixchannel)
- printk(KERN_INFO PFX "Six channel audio available\n");
- if (pdev->irq < 1) {
- printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq);
- rc = -ENODEV;
- goto err_out_kfree;
- }
-
- if (!(pci_resource_flags (pdev, 0) & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "unable to locate I/O resources, aborting\n");
- rc = -ENODEV;
- goto err_out_kfree;
- }
-
- pci_set_master(pdev);
-
- /*
- * init AC97 mixer and codec
- */
- rc = via_ac97_init (card);
- if (rc) {
- printk (KERN_ERR PFX "AC97 init failed, aborting\n");
- goto err_out_kfree;
- }
-
- /*
- * init DSP device
- */
- rc = via_dsp_init (card);
- if (rc) {
- printk (KERN_ERR PFX "DSP device init failed, aborting\n");
- goto err_out_have_mixer;
- }
-
- /*
- * init and turn on interrupts, as the last thing we do
- */
- rc = via_interrupt_init (card);
- if (rc) {
- printk (KERN_ERR PFX "interrupt init failed, aborting\n");
- goto err_out_have_dsp;
- }
-
- printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n",
- card->card_num + 1, card->baseaddr, pdev->irq);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
- /* Disable by default */
- card->midi_info.io_base = 0;
-
- if(card->legacy)
- {
- pci_read_config_byte (pdev, 0x42, &r42);
- /* Disable MIDI interrupt */
- pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK);
- if (r42 & VIA_CR42_MIDI_ENABLE)
- {
- if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */
- card->midi_info.io_base = pci_resource_start (pdev, 2);
- else /* Address selected by byte 0x43 */
- {
- u8 r43;
- pci_read_config_byte (pdev, 0x43, &r43);
- card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2);
- }
-
- card->midi_info.irq = -pdev->irq;
- if (probe_uart401(& card->midi_info, THIS_MODULE))
- {
- card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc;
- pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK);
- printk("Enabled Via MIDI\n");
- }
- }
- }
-#endif
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out_have_dsp:
- via_dsp_cleanup (card);
-
-err_out_have_mixer:
- via_ac97_cleanup (card);
-
-err_out_kfree:
-#ifndef VIA_NDEBUG
- memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
- kfree (card);
-
-err_out_res:
- pci_release_regions (pdev);
-
-err_out_disable:
- pci_disable_device (pdev);
-
-err_out:
- pci_set_drvdata (pdev, NULL);
- DPRINTK ("EXIT - returning %d\n", rc);
- return rc;
-}
-
-
-static void __devexit via_remove_one (struct pci_dev *pdev)
-{
- struct via_info *card;
-
- DPRINTK ("ENTER\n");
-
- assert (pdev != NULL);
- card = pci_get_drvdata (pdev);
- assert (card != NULL);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
- if (card->midi_info.io_base)
- unload_uart401(&card->midi_info);
-#endif
-
- free_irq (card->pdev->irq, card);
- via_dsp_cleanup (card);
- via_ac97_cleanup (card);
-
-#ifndef VIA_NDEBUG
- memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
- kfree (card);
-
- pci_set_drvdata (pdev, NULL);
-
- pci_release_regions (pdev);
- pci_disable_device (pdev);
- pci_set_power_state (pdev, 3); /* ...zzzzzz */
-
- DPRINTK ("EXIT\n");
- return;
-}
-
-
-/****************************************************************
- *
- * Driver initialization and cleanup
- *
- *
- */
-
-static int __init init_via82cxxx_audio(void)
-{
- int rc;
-
- DPRINTK ("ENTER\n");
-
- rc = pci_register_driver (&via_driver);
- if (rc) {
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-static void __exit cleanup_via82cxxx_audio(void)
-{
- DPRINTK ("ENTER\n");
-
- pci_unregister_driver (&via_driver);
-
- DPRINTK ("EXIT\n");
-}
-
-
-module_init(init_via82cxxx_audio);
-module_exit(cleanup_via82cxxx_audio);
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("DSP audio and mixer driver for Via 82Cxxx audio devices");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 6495534e..1558a5c 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -84,7 +84,7 @@
us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
}
area->vm_ops = &us428ctls_vm_ops;
- area->vm_flags |= VM_RESERVED;
+ area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
area->vm_private_data = hw->private_data;
return 0;
}
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 800b5ce..117946f 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -722,7 +722,7 @@
return -ENODEV;
}
area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
- area->vm_flags |= VM_RESERVED;
+ area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
area->vm_private_data = hw->private_data;
return 0;
}