merge linus into release branch

Conflicts:

	drivers/acpi/acpi_memhotplug.c
This commit is contained in:
Len Brown 2006-06-29 19:57:46 -04:00
commit d120cfb544
1387 changed files with 50185 additions and 18084 deletions

View file

@ -3401,10 +3401,10 @@ S: Czech Republic
N: Thibaut Varene N: Thibaut Varene
E: T-Bone@parisc-linux.org E: T-Bone@parisc-linux.org
W: http://www.parisc-linux.org/ W: http://www.parisc-linux.org/~varenet/
P: 1024D/B7D2F063 E67C 0D43 A75E 12A5 BB1C FA2F 1E32 C3DA B7D2 F063 P: 1024D/B7D2F063 E67C 0D43 A75E 12A5 BB1C FA2F 1E32 C3DA B7D2 F063
D: PA-RISC port minion, PDC and GSCPS2 drivers, debuglocks and other bits D: PA-RISC port minion, PDC and GSCPS2 drivers, debuglocks and other bits
D: Some bits in an ARM port, S1D13XXX FB driver, random patches here and there D: Some ARM at91rm9200 bits, S1D13XXX FB driver, random patches here and there
D: AD1889 sound driver D: AD1889 sound driver
S: Paris, France S: Paris, France

View file

@ -181,8 +181,8 @@ Intel IA32 microcode
-------------------- --------------------
A driver has been added to allow updating of Intel IA32 microcode, A driver has been added to allow updating of Intel IA32 microcode,
accessible as both a devfs regular file and as a normal (misc) accessible as a normal (misc) character device. If you are not using
character device. If you are not using devfs you may need to: udev you may need to:
mkdir /dev/cpu mkdir /dev/cpu
mknod /dev/cpu/microcode c 10 184 mknod /dev/cpu/microcode c 10 184
@ -201,7 +201,9 @@ with programs using shared memory.
udev udev
---- ----
udev is a userspace application for populating /dev dynamically with udev is a userspace application for populating /dev dynamically with
only entries for devices actually present. udev replaces devfs. only entries for devices actually present. udev replaces the basic
functionality of devfs, while allowing persistant device naming for
devices.
FUSE FUSE
---- ----
@ -231,18 +233,13 @@ The PPP driver has been restructured to support multilink and to
enable it to operate over diverse media layers. If you use PPP, enable it to operate over diverse media layers. If you use PPP,
upgrade pppd to at least 2.4.0. upgrade pppd to at least 2.4.0.
If you are not using devfs, you must have the device file /dev/ppp If you are not using udev, you must have the device file /dev/ppp
which can be made by: which can be made by:
mknod /dev/ppp c 108 0 mknod /dev/ppp c 108 0
as root. as root.
If you use devfsd and build ppp support as modules, you will need
the following in your /etc/devfsd.conf file:
LOOKUP PPP MODLOAD
Isdn4k-utils Isdn4k-utils
------------ ------------

View file

@ -10,7 +10,8 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
procfs-guide.xml writing_usb_driver.xml \ procfs-guide.xml writing_usb_driver.xml \
kernel-api.xml journal-api.xml lsm.xml usb.xml \ kernel-api.xml journal-api.xml lsm.xml usb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
genericirq.xml
### ###
# The build process is as follows (targets): # The build process is as follows (targets):

View file

@ -0,0 +1,474 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<book id="Generic-IRQ-Guide">
<bookinfo>
<title>Linux generic IRQ handling</title>
<authorgroup>
<author>
<firstname>Thomas</firstname>
<surname>Gleixner</surname>
<affiliation>
<address>
<email>tglx@linutronix.de</email>
</address>
</affiliation>
</author>
<author>
<firstname>Ingo</firstname>
<surname>Molnar</surname>
<affiliation>
<address>
<email>mingo@elte.hu</email>
</address>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2005-2006</year>
<holder>Thomas Gleixner</holder>
</copyright>
<copyright>
<year>2005-2006</year>
<holder>Ingo Molnar</holder>
</copyright>
<legalnotice>
<para>
This documentation is free software; you can redistribute
it and/or modify it under the terms of the GNU General Public
License version 2 as published by the Free Software Foundation.
</para>
<para>
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
</para>
<para>
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
</para>
<para>
For more details see the file COPYING in the source
distribution of Linux.
</para>
</legalnotice>
</bookinfo>
<toc></toc>
<chapter id="intro">
<title>Introduction</title>
<para>
The generic interrupt handling layer is designed to provide a
complete abstraction of interrupt handling for device drivers.
It is able to handle all the different types of interrupt controller
hardware. Device drivers use generic API functions to request, enable,
disable and free interrupts. The drivers do not have to know anything
about interrupt hardware details, so they can be used on different
platforms without code changes.
</para>
<para>
This documentation is provided to developers who want to implement
an interrupt subsystem based for their architecture, with the help
of the generic IRQ handling layer.
</para>
</chapter>
<chapter id="rationale">
<title>Rationale</title>
<para>
The original implementation of interrupt handling in Linux is using
the __do_IRQ() super-handler, which is able to deal with every
type of interrupt logic.
</para>
<para>
Originally, Russell King identified different types of handlers to
build a quite universal set for the ARM interrupt handler
implementation in Linux 2.5/2.6. He distinguished between:
<itemizedlist>
<listitem><para>Level type</para></listitem>
<listitem><para>Edge type</para></listitem>
<listitem><para>Simple type</para></listitem>
</itemizedlist>
In the SMP world of the __do_IRQ() super-handler another type
was identified:
<itemizedlist>
<listitem><para>Per CPU type</para></listitem>
</itemizedlist>
</para>
<para>
This split implementation of highlevel IRQ handlers allows us to
optimize the flow of the interrupt handling for each specific
interrupt type. This reduces complexity in that particular codepath
and allows the optimized handling of a given type.
</para>
<para>
The original general IRQ implementation used hw_interrupt_type
structures and their ->ack(), ->end() [etc.] callbacks to
differentiate the flow control in the super-handler. This leads to
a mix of flow logic and lowlevel hardware logic, and it also leads
to unnecessary code duplication: for example in i386, there is a
ioapic_level_irq and a ioapic_edge_irq irq-type which share many
of the lowlevel details but have different flow handling.
</para>
<para>
A more natural abstraction is the clean separation of the
'irq flow' and the 'chip details'.
</para>
<para>
Analysing a couple of architecture's IRQ subsystem implementations
reveals that most of them can use a generic set of 'irq flow'
methods and only need to add the chip level specific code.
The separation is also valuable for (sub)architectures
which need specific quirks in the irq flow itself but not in the
chip-details - and thus provides a more transparent IRQ subsystem
design.
</para>
<para>
Each interrupt descriptor is assigned its own highlevel flow
handler, which is normally one of the generic
implementations. (This highlevel flow handler implementation also
makes it simple to provide demultiplexing handlers which can be
found in embedded platforms on various architectures.)
</para>
<para>
The separation makes the generic interrupt handling layer more
flexible and extensible. For example, an (sub)architecture can
use a generic irq-flow implementation for 'level type' interrupts
and add a (sub)architecture specific 'edge type' implementation.
</para>
<para>
To make the transition to the new model easier and prevent the
breakage of existing implementations, the __do_IRQ() super-handler
is still available. This leads to a kind of duality for the time
being. Over time the new model should be used in more and more
architectures, as it enables smaller and cleaner IRQ subsystems.
</para>
</chapter>
<chapter id="bugs">
<title>Known Bugs And Assumptions</title>
<para>
None (knock on wood).
</para>
</chapter>
<chapter id="Abstraction">
<title>Abstraction layers</title>
<para>
There are three main levels of abstraction in the interrupt code:
<orderedlist>
<listitem><para>Highlevel driver API</para></listitem>
<listitem><para>Highlevel IRQ flow handlers</para></listitem>
<listitem><para>Chiplevel hardware encapsulation</para></listitem>
</orderedlist>
</para>
<sect1>
<title>Interrupt control flow</title>
<para>
Each interrupt is described by an interrupt descriptor structure
irq_desc. The interrupt is referenced by an 'unsigned int' numeric
value which selects the corresponding interrupt decription structure
in the descriptor structures array.
The descriptor structure contains status information and pointers
to the interrupt flow method and the interrupt chip structure
which are assigned to this interrupt.
</para>
<para>
Whenever an interrupt triggers, the lowlevel arch code calls into
the generic interrupt code by calling desc->handle_irq().
This highlevel IRQ handling function only uses desc->chip primitives
referenced by the assigned chip descriptor structure.
</para>
</sect1>
<sect1>
<title>Highlevel Driver API</title>
<para>
The highlevel Driver API consists of following functions:
<itemizedlist>
<listitem><para>request_irq()</para></listitem>
<listitem><para>free_irq()</para></listitem>
<listitem><para>disable_irq()</para></listitem>
<listitem><para>enable_irq()</para></listitem>
<listitem><para>disable_irq_nosync() (SMP only)</para></listitem>
<listitem><para>synchronize_irq() (SMP only)</para></listitem>
<listitem><para>set_irq_type()</para></listitem>
<listitem><para>set_irq_wake()</para></listitem>
<listitem><para>set_irq_data()</para></listitem>
<listitem><para>set_irq_chip()</para></listitem>
<listitem><para>set_irq_chip_data()</para></listitem>
</itemizedlist>
See the autogenerated function documentation for details.
</para>
</sect1>
<sect1>
<title>Highlevel IRQ flow handlers</title>
<para>
The generic layer provides a set of pre-defined irq-flow methods:
<itemizedlist>
<listitem><para>handle_level_irq</para></listitem>
<listitem><para>handle_edge_irq</para></listitem>
<listitem><para>handle_simple_irq</para></listitem>
<listitem><para>handle_percpu_irq</para></listitem>
</itemizedlist>
The interrupt flow handlers (either predefined or architecture
specific) are assigned to specific interrupts by the architecture
either during bootup or during device initialization.
</para>
<sect2>
<title>Default flow implementations</title>
<sect3>
<title>Helper functions</title>
<para>
The helper functions call the chip primitives and
are used by the default flow implementations.
The following helper functions are implemented (simplified excerpt):
<programlisting>
default_enable(irq)
{
desc->chip->unmask(irq);
}
default_disable(irq)
{
if (!delay_disable(irq))
desc->chip->mask(irq);
}
default_ack(irq)
{
chip->ack(irq);
}
default_mask_ack(irq)
{
if (chip->mask_ack) {
chip->mask_ack(irq);
} else {
chip->mask(irq);
chip->ack(irq);
}
}
noop(irq)
{
}
</programlisting>
</para>
</sect3>
</sect2>
<sect2>
<title>Default flow handler implementations</title>
<sect3>
<title>Default Level IRQ flow handler</title>
<para>
handle_level_irq provides a generic implementation
for level-triggered interrupts.
</para>
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
desc->chip->start();
handle_IRQ_event(desc->action);
desc->chip->end();
</programlisting>
</para>
</sect3>
<sect3>
<title>Default Edge IRQ flow handler</title>
<para>
handle_edge_irq provides a generic implementation
for edge-triggered interrupts.
</para>
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
if (desc->status &amp; running) {
desc->chip->hold();
desc->status |= pending | masked;
return;
}
desc->chip->start();
desc->status |= running;
do {
if (desc->status &amp; masked)
desc->chip->enable();
desc-status &amp;= ~pending;
handle_IRQ_event(desc->action);
} while (status &amp; pending);
desc-status &amp;= ~running;
desc->chip->end();
</programlisting>
</para>
</sect3>
<sect3>
<title>Default simple IRQ flow handler</title>
<para>
handle_simple_irq provides a generic implementation
for simple interrupts.
</para>
<para>
Note: The simple flow handler does not call any
handler/chip primitives.
</para>
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
handle_IRQ_event(desc->action);
</programlisting>
</para>
</sect3>
<sect3>
<title>Default per CPU flow handler</title>
<para>
handle_percpu_irq provides a generic implementation
for per CPU interrupts.
</para>
<para>
Per CPU interrupts are only available on SMP and
the handler provides a simplified version without
locking.
</para>
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
desc->chip->start();
handle_IRQ_event(desc->action);
desc->chip->end();
</programlisting>
</para>
</sect3>
</sect2>
<sect2>
<title>Quirks and optimizations</title>
<para>
The generic functions are intended for 'clean' architectures and chips,
which have no platform-specific IRQ handling quirks. If an architecture
needs to implement quirks on the 'flow' level then it can do so by
overriding the highlevel irq-flow handler.
</para>
</sect2>
<sect2>
<title>Delayed interrupt disable</title>
<para>
This per interrupt selectable feature, which was introduced by Russell
King in the ARM interrupt implementation, does not mask an interrupt
at the hardware level when disable_irq() is called. The interrupt is
kept enabled and is masked in the flow handler when an interrupt event
happens. This prevents losing edge interrupts on hardware which does
not store an edge interrupt event while the interrupt is disabled at
the hardware level. When an interrupt arrives while the IRQ_DISABLED
flag is set, then the interrupt is masked at the hardware level and
the IRQ_PENDING bit is set. When the interrupt is re-enabled by
enable_irq() the pending bit is checked and if it is set, the
interrupt is resent either via hardware or by a software resend
mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when
you want to use the delayed interrupt disable feature and your
hardware is not capable of retriggering an interrupt.)
The delayed interrupt disable can be runtime enabled, per interrupt,
by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field.
</para>
</sect2>
</sect1>
<sect1>
<title>Chiplevel hardware encapsulation</title>
<para>
The chip level hardware descriptor structure irq_chip
contains all the direct chip relevant functions, which
can be utilized by the irq flow implementations.
<itemizedlist>
<listitem><para>ack()</para></listitem>
<listitem><para>mask_ack() - Optional, recommended for performance</para></listitem>
<listitem><para>mask()</para></listitem>
<listitem><para>unmask()</para></listitem>
<listitem><para>retrigger() - Optional</para></listitem>
<listitem><para>set_type() - Optional</para></listitem>
<listitem><para>set_wake() - Optional</para></listitem>
</itemizedlist>
These primitives are strictly intended to mean what they say: ack means
ACK, masking means masking of an IRQ line, etc. It is up to the flow
handler(s) to use these basic units of lowlevel functionality.
</para>
</sect1>
</chapter>
<chapter id="doirq">
<title>__do_IRQ entry point</title>
<para>
The original implementation __do_IRQ() is an alternative entry
point for all types of interrupts.
</para>
<para>
This handler turned out to be not suitable for all
interrupt hardware and was therefore reimplemented with split
functionality for egde/level/simple/percpu interrupts. This is not
only a functional optimization. It also shortens code paths for
interrupts.
</para>
<para>
To make use of the split implementation, replace the call to
__do_IRQ by a call to desc->chip->handle_irq() and associate
the appropriate handler function to desc->chip->handle_irq().
In most cases the generic handler implementations should
be sufficient.
</para>
</chapter>
<chapter id="locking">
<title>Locking on SMP</title>
<para>
The locking of chip registers is up to the architecture that
defines the chip primitives. There is a chip->lock field that can be used
for serialization, but the generic layer does not touch it. The per-irq
structure is protected via desc->lock, by the generic layer.
</para>
</chapter>
<chapter id="structs">
<title>Structures</title>
<para>
This chapter contains the autogenerated documentation of the structures which are
used in the generic IRQ layer.
</para>
!Iinclude/linux/irq.h
</chapter>
<chapter id="pubfunctions">
<title>Public Functions Provided</title>
<para>
This chapter contains the autogenerated documentation of the kernel API functions
which are exported.
</para>
!Ekernel/irq/manage.c
!Ekernel/irq/chip.c
</chapter>
<chapter id="intfunctions">
<title>Internal Functions Provided</title>
<para>
This chapter contains the autogenerated documentation of the internal functions.
</para>
!Ikernel/irq/handle.c
!Ikernel/irq/chip.c
</chapter>
<chapter id="credits">
<title>Credits</title>
<para>
The following people have contributed to this document:
<orderedlist>
<listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
<listitem><para>Ingo Molnar<email>mingo@elte.hu</email></para></listitem>
</orderedlist>
</para>
</chapter>
</book>

View file

@ -348,11 +348,6 @@ X!Earch/i386/kernel/mca.c
</sect1> </sect1>
</chapter> </chapter>
<chapter id="devfs">
<title>The Device File System</title>
!Efs/devfs/base.c
</chapter>
<chapter id="sysfs"> <chapter id="sysfs">
<title>The Filesystem for Exporting Kernel Objects</title> <title>The Filesystem for Exporting Kernel Objects</title>
!Efs/sysfs/file.c !Efs/sysfs/file.c

22
Documentation/IRQ.txt Normal file
View file

@ -0,0 +1,22 @@
What is an IRQ?
An IRQ is an interrupt request from a device.
Currently they can come in over a pin, or over a packet.
Several devices may be connected to the same pin thus
sharing an IRQ.
An IRQ number is a kernel identifier used to talk about a hardware
interrupt source. Typically this is an index into the global irq_desc
array, but except for what linux/interrupt.h implements the details
are architecture specific.
An IRQ number is an enumeration of the possible interrupt sources on a
machine. Typically what is enumerated is the number of input pins on
all of the interrupt controller in the system. In the case of ISA
what is enumerated are the 16 input pins on the two i8259 interrupt
controllers.
Architectures can assign additional meaning to the IRQ numbers, and
are encouraged to in the case where there is any manual configuration
of the hardware involved. The ISA IRQs are a classic example of
assigning this kind of additional meaning.

View file

@ -7,7 +7,7 @@ The CONFIG_RCU_TORTURE_TEST config option is available for all RCU
implementations. It creates an rcutorture kernel module that can implementations. It creates an rcutorture kernel module that can
be loaded to run a torture test. The test periodically outputs be loaded to run a torture test. The test periodically outputs
status messages via printk(), which can be examined via the dmesg status messages via printk(), which can be examined via the dmesg
command (perhaps grepping for "rcutorture"). The test is started command (perhaps grepping for "torture"). The test is started
when the module is loaded, and stops when the module is unloaded. when the module is loaded, and stops when the module is unloaded.
However, actually setting this config option to "y" results in the system However, actually setting this config option to "y" results in the system
@ -35,6 +35,19 @@ stat_interval The number of seconds between output of torture
be printed -only- when the module is unloaded, and this be printed -only- when the module is unloaded, and this
is the default. is the default.
shuffle_interval
The number of seconds to keep the test threads affinitied
to a particular subset of the CPUs. Used in conjunction
with test_no_idle_hz.
test_no_idle_hz Whether or not to test the ability of RCU to operate in
a kernel that disables the scheduling-clock interrupt to
idle CPUs. Boolean parameter, "1" to test, "0" otherwise.
torture_type The type of RCU to test: "rcu" for the rcu_read_lock()
API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
for the "srcu_read_lock()" API.
verbose Enable debug printk()s. Default is disabled. verbose Enable debug printk()s. Default is disabled.
@ -42,14 +55,14 @@ OUTPUT
The statistics output is as follows: The statistics output is as follows:
rcutorture: --- Start of test: nreaders=16 stat_interval=0 verbose=0 rcu-torture: --- Start of test: nreaders=16 stat_interval=0 verbose=0
rcutorture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915 rcu-torture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915
rcutorture: Reader Pipe: 1466408 9747 0 0 0 0 0 0 0 0 0 rcu-torture: Reader Pipe: 1466408 9747 0 0 0 0 0 0 0 0 0
rcutorture: Reader Batch: 1464477 11678 0 0 0 0 0 0 0 0 rcu-torture: Reader Batch: 1464477 11678 0 0 0 0 0 0 0 0
rcutorture: Free-Block Circulation: 1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0 rcu-torture: Free-Block Circulation: 1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0
rcutorture: --- End of test rcu-torture: --- End of test
The command "dmesg | grep rcutorture:" will extract this information on The command "dmesg | grep torture:" will extract this information on
most systems. On more esoteric configurations, it may be necessary to most systems. On more esoteric configurations, it may be necessary to
use other commands to access the output of the printk()s used by use other commands to access the output of the printk()s used by
the RCU torture test. The printk()s use KERN_ALERT, so they should the RCU torture test. The printk()s use KERN_ALERT, so they should
@ -115,8 +128,9 @@ The following script may be used to torture RCU:
modprobe rcutorture modprobe rcutorture
sleep 100 sleep 100
rmmod rcutorture rmmod rcutorture
dmesg | grep rcutorture: dmesg | grep torture:
The output can be manually inspected for the error flag of "!!!". The output can be manually inspected for the error flag of "!!!".
One could of course create a more elaborate script that automatically One could of course create a more elaborate script that automatically
checked for such errors. checked for such errors. The "rmmod" command forces a "SUCCESS" or
"FAILURE" indication to be printk()ed.

View file

@ -78,9 +78,9 @@ also known as "System Drives", and Drive Groups are also called "Packs". Both
terms are in use in the Mylex documentation; I have chosen to standardize on terms are in use in the Mylex documentation; I have chosen to standardize on
the more generic "Logical Drive" and "Drive Group". the more generic "Logical Drive" and "Drive Group".
DAC960 RAID disk devices are named in the style of the Device File System DAC960 RAID disk devices are named in the style of the obsolete Device File
(DEVFS). The device corresponding to Logical Drive D on Controller C is System (DEVFS). The device corresponding to Logical Drive D on Controller C
referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1 is referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1
through /dev/rd/cCdDp7. For example, partition 3 of Logical Drive 5 on through /dev/rd/cCdDp7. For example, partition 3 of Logical Drive 5 on
Controller 2 is referred to as /dev/rd/c2d5p3. Note that unlike with SCSI Controller 2 is referred to as /dev/rd/c2d5p3. Note that unlike with SCSI
disks the device names will not change in the event of a disk drive failure. disks the device names will not change in the event of a disk drive failure.

View file

@ -6,17 +6,6 @@ be removed from this file.
--------------------------- ---------------------------
What: devfs
When: July 2005
Files: fs/devfs/*, include/linux/devfs_fs*.h and assorted devfs
function calls throughout the kernel tree
Why: It has been unmaintained for a number of years, has unfixable
races, contains a naming policy within the kernel that is
against the LSB, and can be replaced by using udev.
Who: Greg Kroah-Hartman <greg@kroah.com>
---------------------------
What: RAW driver (CONFIG_RAW_DRIVER) What: RAW driver (CONFIG_RAW_DRIVER)
When: December 2005 When: December 2005
Why: declared obsolete since kernel 2.6.3 Why: declared obsolete since kernel 2.6.3
@ -132,16 +121,6 @@ Who: NeilBrown <neilb@suse.de>
--------------------------- ---------------------------
What: au1x00_uart driver
When: January 2006
Why: The 8250 serial driver now has the ability to deal with the differences
between the standard 8250 family of UARTs and their slightly strange
brother on Alchemy SOCs. The loss of features is not considered an
issue.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: eepro100 network driver What: eepro100 network driver
When: January 2007 When: January 2007
Why: replaced by the e100 driver Why: replaced by the e100 driver
@ -177,6 +156,16 @@ Who: Jean Delvare <khali@linux-fr.org>
--------------------------- ---------------------------
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.
When: before 2.6.19
Why: Unused symbols are both increasing the size of the kernel binary
and are often a sign of "wrong API"
Who: Arjan van de Ven <arjan@linux.intel.com>
---------------------------
What: remove EXPORT_SYMBOL(tasklist_lock) What: remove EXPORT_SYMBOL(tasklist_lock)
When: August 2006 When: August 2006
Files: kernel/fork.c Files: kernel/fork.c
@ -224,3 +213,47 @@ Why: The interface no longer has any callers left in the kernel. It
Who: Nick Piggin <npiggin@suse.de> Who: Nick Piggin <npiggin@suse.de>
--------------------------- ---------------------------
What: Support for the MIPS EV96100 evaluation board
When: September 2006
Why: Does no longer build since at least November 15, 2003, apparently
no userbase left.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board
When: September 2006
Why: Does no longer build since quite some time, and was never popular,
due to the platform being replaced by successor models. Apparently
no user base left. It also is one of the last users of
WANT_PAGE_VIRTUAL.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: Support for the Momentum Ocelot, Ocelot 3, Ocelot C and Ocelot G
When: September 2006
Why: Some do no longer build and apparently there is no user base left
for these platforms.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: Support for MIPS Technologies' Altas and SEAD evaluation board
When: September 2006
Why: Some do no longer build and apparently there is no user base left
for these platforms. Hardware out of production since several years.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: Support for the IT8172-based platforms, ITE 8172G and Globespan IVR
When: September 2006
Why: Code does no longer build since at least 2.6.0, apparently there is
no user base left for these platforms. Hardware out of production
since several years and hardly a trace of the manufacturer left on
the net.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,40 +0,0 @@
Device File System (devfs) ToDo List
Richard Gooch <rgooch@atnf.csiro.au>
3-JUL-2000
This is a list of things to be done for better devfs support in the
Linux kernel. If you'd like to contribute to the devfs, please have a
look at this list for anything that is unallocated. Also, if there are
items missing (surely), please contact me so I can add them to the
list (preferably with your name attached to them:-).
- >256 ptys
Thanks to C. Scott Ananian <cananian@alumni.princeton.edu>
- Amiga floppy driver (drivers/block/amiflop.c)
- Atari floppy driver (drivers/block/ataflop.c)
- SWIM3 (Super Woz Integrated Machine 3) floppy driver (drivers/block/swim3.c)
- Amiga ZorroII ramdisc driver (drivers/block/z2ram.c)
- Parallel port ATAPI CD-ROM (drivers/block/paride/pcd.c)
- Parallel port ATAPI floppy (drivers/block/paride/pf.c)
- AP1000 block driver (drivers/ap1000/ap.c, drivers/ap1000/ddv.c)
- Archimedes floppy (drivers/acorn/block/fd1772.c)
- MFM hard drive (drivers/acorn/block/mfmhd.c)
- I2O block device (drivers/message/i2o/i2o_block.c)
- ST-RAM device (arch/m68k/atari/stram.c)
- Raw devices

View file

@ -1,65 +0,0 @@
/* -*- auto-fill -*- */
Device File System (devfs) Boot Options
Richard Gooch <rgooch@atnf.csiro.au>
18-AUG-2001
When CONFIG_DEVFS_DEBUG is enabled, you can pass several boot options
to the kernel to debug devfs. The boot options are prefixed by
"devfs=", and are separated by commas. Spaces are not allowed. The
syntax looks like this:
devfs=<option1>,<option2>,<option3>
and so on. For example, if you wanted to turn on debugging for module
load requests and device registration, you would do:
devfs=dmod,dreg
You may prefix "no" to any option. This will invert the option.
Debugging Options
=================
These requires CONFIG_DEVFS_DEBUG to be enabled.
Note that all debugging options have 'd' as the first character. By
default all options are off. All debugging output is sent to the
kernel logs. The debugging options do not take effect until the devfs
version message appears (just prior to the root filesystem being
mounted).
These are the options:
dmod print module load requests to <request_module>
dreg print device register requests to <devfs_register>
dunreg print device unregister requests to <devfs_unregister>
dchange print device change requests to <devfs_set_flags>
dilookup print inode lookup requests
diget print VFS inode allocations
diunlink print inode unlinks
dichange print inode changes
dimknod print calls to mknod(2)
dall some debugging turned on
Other Options
=============
These control the default behaviour of devfs. The options are:
mount mount devfs onto /dev at boot time
only disable non-devfs device nodes for devfs-capable drivers

View file

@ -67,8 +67,7 @@ initrd adds the following new options:
as the last process has closed it, all data is freed and /dev/initrd as the last process has closed it, all data is freed and /dev/initrd
can't be opened anymore. can't be opened anymore.
root=/dev/ram0 (without devfs) root=/dev/ram0
root=/dev/rd/0 (with devfs)
initrd is mounted as root, and the normal boot procedure is followed, initrd is mounted as root, and the normal boot procedure is followed,
with the RAM disk still mounted as root. with the RAM disk still mounted as root.
@ -90,8 +89,7 @@ you're building an install floppy), the root file system creation
procedure should create the /initrd directory. procedure should create the /initrd directory.
If initrd will not be mounted in some cases, its content is still If initrd will not be mounted in some cases, its content is still
accessible if the following device has been created (note that this accessible if the following device has been created:
does not work if using devfs):
# mknod /dev/initrd b 1 250 # mknod /dev/initrd b 1 250
# chmod 400 /dev/initrd # chmod 400 /dev/initrd
@ -119,8 +117,7 @@ We'll describe the loopback device method:
(if space is critical, you may want to use the Minix FS instead of Ext2) (if space is critical, you may want to use the Minix FS instead of Ext2)
3) mount the file system, e.g. 3) mount the file system, e.g.
# mount -t ext2 -o loop initrd /mnt # mount -t ext2 -o loop initrd /mnt
4) create the console device (not necessary if using devfs, but it can't 4) create the console device:
hurt to do it anyway):
# mkdir /mnt/dev # mkdir /mnt/dev
# mknod /mnt/dev/console c 5 1 # mknod /mnt/dev/console c 5 1
5) copy all the files that are needed to properly use the initrd 5) copy all the files that are needed to properly use the initrd
@ -152,12 +149,7 @@ have to be given:
root=/dev/ram0 init=/linuxrc rw root=/dev/ram0 init=/linuxrc rw
if not using devfs, or (rw is only necessary if writing to the initrd file system.)
root=/dev/rd/0 init=/linuxrc rw
if using devfs. (rw is only necessary if writing to the initrd file
system.)
With LOADLIN, you simply execute With LOADLIN, you simply execute
@ -217,9 +209,9 @@ following command:
# exec chroot . what-follows <dev/console >dev/console 2>&1 # exec chroot . what-follows <dev/console >dev/console 2>&1
Where what-follows is a program under the new root, e.g. /sbin/init Where what-follows is a program under the new root, e.g. /sbin/init
If the new root file system will be used with devfs and has no valid If the new root file system will be used with udev and has no valid
/dev directory, devfs must be mounted before invoking chroot in order to /dev directory, udev must be initialized before invoking chroot in order
provide /dev/console. to provide /dev/console.
Note: implementation details of pivot_root may change with time. In order Note: implementation details of pivot_root may change with time. In order
to ensure compatibility, the following points should be observed: to ensure compatibility, the following points should be observed:
@ -236,7 +228,7 @@ Now, the initrd can be unmounted and the memory allocated by the RAM
disk can be freed: disk can be freed:
# umount /initrd # umount /initrd
# blockdev --flushbufs /dev/ram0 # /dev/rd/0 if using devfs # blockdev --flushbufs /dev/ram0
It is also possible to use initrd with an NFS-mounted root, see the It is also possible to use initrd with an NFS-mounted root, see the
pivot_root(8) man page for details. pivot_root(8) man page for details.

View file

@ -119,7 +119,6 @@ Code Seq# Include File Comments
'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/comstats.h conflict!
'c' 00-7F linux/coda.h conflict! 'c' 00-7F linux/coda.h conflict!
'd' 00-FF linux/char/drm/drm/h conflict! 'd' 00-FF linux/char/drm/drm/h conflict!
'd' 00-1F linux/devfs_fs.h conflict!
'd' 00-DF linux/video_decoder.h conflict! 'd' 00-DF linux/video_decoder.h conflict!
'd' F0-FF linux/digi1.h 'd' F0-FF linux/digi1.h
'e' all linux/digi1.h conflict! 'e' all linux/digi1.h conflict!

View file

@ -35,7 +35,6 @@ parameter is applicable:
APM Advanced Power Management support is enabled. APM Advanced Power Management support is enabled.
AX25 Appropriate AX.25 support is enabled. AX25 Appropriate AX.25 support is enabled.
CD Appropriate CD support is enabled. CD Appropriate CD support is enabled.
DEVFS devfs support is enabled.
DRM Direct Rendering Management support is enabled. DRM Direct Rendering Management support is enabled.
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
EFI EFI Partitioning (GPT) is enabled EFI EFI Partitioning (GPT) is enabled
@ -440,9 +439,6 @@ running once the system is up.
Format: <area>[,<node>] Format: <area>[,<node>]
See also Documentation/networking/decnet.txt. See also Documentation/networking/decnet.txt.
devfs= [DEVFS]
See Documentation/filesystems/devfs/boot-options.
dhash_entries= [KNL] dhash_entries= [KNL]
Set number of hash buckets for dentry cache. Set number of hash buckets for dentry cache.
@ -1669,6 +1665,10 @@ running once the system is up.
usbhid.mousepoll= usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at. [USBHID] The interval which mice are to be polled at.
vdso= [IA-32]
vdso=1: enable VDSO (default)
vdso=0: disable VDSO mapping
video= [FB] Frame buffer configuration video= [FB] Frame buffer configuration
See Documentation/fb/modedb.txt. See Documentation/fb/modedb.txt.
@ -1685,9 +1685,14 @@ running once the system is up.
decrease the size and leave more room for directly decrease the size and leave more room for directly
mapped kernel RAM. mapped kernel RAM.
vmhalt= [KNL,S390] vmhalt= [KNL,S390] Perform z/VM CP command after system halt.
Format: <command>
vmpoff= [KNL,S390] vmpanic= [KNL,S390] Perform z/VM CP command after kernel panic.
Format: <command>
vmpoff= [KNL,S390] Perform z/VM CP command after power off.
Format: <command>
waveartist= [HW,OSS] waveartist= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2> Format: <io>,<irq>,<dma>,<dma2>

View file

@ -3,16 +3,23 @@
=================== ===================
The key request service is part of the key retention service (refer to The key request service is part of the key retention service (refer to
Documentation/keys.txt). This document explains more fully how that the Documentation/keys.txt). This document explains more fully how the requesting
requesting algorithm works. algorithm works.
The process starts by either the kernel requesting a service by calling The process starts by either the kernel requesting a service by calling
request_key(): request_key*():
struct key *request_key(const struct key_type *type, struct key *request_key(const struct key_type *type,
const char *description, const char *description,
const char *callout_string); const char *callout_string);
or:
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
const char *callout_string,
void *aux);
Or by userspace invoking the request_key system call: Or by userspace invoking the request_key system call:
key_serial_t request_key(const char *type, key_serial_t request_key(const char *type,
@ -20,16 +27,26 @@ Or by userspace invoking the request_key system call:
const char *callout_info, const char *callout_info,
key_serial_t dest_keyring); key_serial_t dest_keyring);
The main difference between the two access points is that the in-kernel The main difference between the access points is that the in-kernel interface
interface does not need to link the key to a keyring to prevent it from being does not need to link the key to a keyring to prevent it from being immediately
immediately destroyed. The kernel interface returns a pointer directly to the destroyed. The kernel interface returns a pointer directly to the key, and
key, and it's up to the caller to destroy the key. it's up to the caller to destroy the key.
The request_key_with_auxdata() call is like the in-kernel request_key() call,
except that it permits auxiliary data to be passed to the upcaller (the default
is NULL). This is only useful for those key types that define their own upcall
mechanism rather than using /sbin/request-key.
The userspace interface links the key to a keyring associated with the process The userspace interface links the key to a keyring associated with the process
to prevent the key from going away, and returns the serial number of the key to to prevent the key from going away, and returns the serial number of the key to
the caller. the caller.
The following example assumes that the key types involved don't define their
own upcall mechanisms. If they do, then those should be substituted for the
forking and execution of /sbin/request-key.
=========== ===========
THE PROCESS THE PROCESS
=========== ===========
@ -40,8 +57,8 @@ A request proceeds in the following manner:
interface]. interface].
(2) request_key() searches the process's subscribed keyrings to see if there's (2) request_key() searches the process's subscribed keyrings to see if there's
a suitable key there. If there is, it returns the key. If there isn't, and a suitable key there. If there is, it returns the key. If there isn't,
callout_info is not set, an error is returned. Otherwise the process and callout_info is not set, an error is returned. Otherwise the process
proceeds to the next step. proceeds to the next step.
(3) request_key() sees that A doesn't have the desired key yet, so it creates (3) request_key() sees that A doesn't have the desired key yet, so it creates
@ -62,7 +79,7 @@ A request proceeds in the following manner:
instantiation. instantiation.
(7) The program may want to access another key from A's context (say a (7) The program may want to access another key from A's context (say a
Kerberos TGT key). It just requests the appropriate key, and the keyring Kerberos TGT key). It just requests the appropriate key, and the keyring
search notes that the session keyring has auth key V in its bottom level. search notes that the session keyring has auth key V in its bottom level.
This will permit it to then search the keyrings of process A with the This will permit it to then search the keyrings of process A with the
@ -79,10 +96,11 @@ A request proceeds in the following manner:
(10) The program then exits 0 and request_key() deletes key V and returns key (10) The program then exits 0 and request_key() deletes key V and returns key
U to the caller. U to the caller.
This also extends further. If key W (step 7 above) didn't exist, key W would be This also extends further. If key W (step 7 above) didn't exist, key W would
created uninstantiated, another auth key (X) would be created (as per step 3) be created uninstantiated, another auth key (X) would be created (as per step
and another copy of /sbin/request-key spawned (as per step 4); but the context 3) and another copy of /sbin/request-key spawned (as per step 4); but the
specified by auth key X will still be process A, as it was in auth key V. context specified by auth key X will still be process A, as it was in auth key
V.
This is because process A's keyrings can't simply be attached to This is because process A's keyrings can't simply be attached to
/sbin/request-key at the appropriate places because (a) execve will discard two /sbin/request-key at the appropriate places because (a) execve will discard two
@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion:
(2) It considers all the non-keyring keys within that keyring and, if any key (2) It considers all the non-keyring keys within that keyring and, if any key
matches the criteria specified, calls key_permission(SEARCH) on it to see matches the criteria specified, calls key_permission(SEARCH) on it to see
if the key is allowed to be found. If it is, that key is returned; if if the key is allowed to be found. If it is, that key is returned; if
not, the search continues, and the error code is retained if of higher not, the search continues, and the error code is retained if of higher
priority than the one currently set. priority than the one currently set.
(3) It then considers all the keyring-type keys in the keyring it's currently (3) It then considers all the keyring-type keys in the keyring it's currently
searching. It calls key_permission(SEARCH) on each keyring, and if this searching. It calls key_permission(SEARCH) on each keyring, and if this
grants permission, it recurses, executing steps (2) and (3) on that grants permission, it recurses, executing steps (2) and (3) on that
keyring. keyring.
The process stops immediately a valid key is found with permission granted to The process stops immediately a valid key is found with permission granted to
use it. Any error from a previous match attempt is discarded and the key is use it. Any error from a previous match attempt is discarded and the key is
returned. returned.
When search_process_keyrings() is invoked, it performs the following searches When search_process_keyrings() is invoked, it performs the following searches
@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is
returned. returned.
Only if all these fail does the whole thing fail with the highest priority Only if all these fail does the whole thing fail with the highest priority
error. Note that several errors may have come from LSM. error. Note that several errors may have come from LSM.
The error priority is: The error priority is:

View file

@ -780,6 +780,17 @@ payload contents" for more information.
See also Documentation/keys-request-key.txt. See also Documentation/keys-request-key.txt.
(*) To search for a key, passing auxiliary data to the upcaller, call:
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
const char *callout_string,
void *aux);
This is identical to request_key(), except that the auxiliary data is
passed to the key_type->request_key() op if it exists.
(*) When it is no longer required, the key should be released using: (*) When it is no longer required, the key should be released using:
void key_put(struct key *key); void key_put(struct key *key);
@ -1031,6 +1042,24 @@ The structure has a number of fields, some of which are mandatory:
as might happen when the userspace buffer is accessed. as might happen when the userspace buffer is accessed.
(*) int (*request_key)(struct key *key, struct key *authkey, const char *op,
void *aux);
This method is optional. If provided, request_key() and
request_key_with_auxdata() will invoke this function rather than
upcalling to /sbin/request-key to operate upon a key of this type.
The aux parameter is as passed to request_key_with_auxdata() or is NULL
otherwise. Also passed are the key to be operated upon, the
authorisation key for this operation and the operation type (currently
only "create").
This function should return only when the upcall is complete. Upon return
the authorisation key will be revoked, and the target key will be
negatively instantiated if it is still uninstantiated. The error will be
returned to the caller of request_key*().
============================ ============================
REQUEST-KEY CALLBACK SERVICE REQUEST-KEY CALLBACK SERVICE
============================ ============================

121
Documentation/pi-futex.txt Normal file
View file

@ -0,0 +1,121 @@
Lightweight PI-futexes
----------------------
We are calling them lightweight for 3 reasons:
- in the user-space fastpath a PI-enabled futex involves no kernel work
(or any other PI complexity) at all. No registration, no extra kernel
calls - just pure fast atomic ops in userspace.
- even in the slowpath, the system call and scheduling pattern is very
similar to normal futexes.
- the in-kernel PI implementation is streamlined around the mutex
abstraction, with strict rules that keep the implementation
relatively simple: only a single owner may own a lock (i.e. no
read-write lock support), only the owner may unlock a lock, no
recursive locking, etc.
Priority Inheritance - why?
---------------------------
The short reply: user-space PI helps achieving/improving determinism for
user-space applications. In the best-case, it can help achieve
determinism and well-bound latencies. Even in the worst-case, PI will
improve the statistical distribution of locking related application
delays.
The longer reply:
-----------------
Firstly, sharing locks between multiple tasks is a common programming
technique that often cannot be replaced with lockless algorithms. As we
can see it in the kernel [which is a quite complex program in itself],
lockless structures are rather the exception than the norm - the current
ratio of lockless vs. locky code for shared data structures is somewhere
between 1:10 and 1:100. Lockless is hard, and the complexity of lockless
algorithms often endangers to ability to do robust reviews of said code.
I.e. critical RT apps often choose lock structures to protect critical
data structures, instead of lockless algorithms. Furthermore, there are
cases (like shared hardware, or other resource limits) where lockless
access is mathematically impossible.
Media players (such as Jack) are an example of reasonable application
design with multiple tasks (with multiple priority levels) sharing
short-held locks: for example, a highprio audio playback thread is
combined with medium-prio construct-audio-data threads and low-prio
display-colory-stuff threads. Add video and decoding to the mix and
we've got even more priority levels.
So once we accept that synchronization objects (locks) are an
unavoidable fact of life, and once we accept that multi-task userspace
apps have a very fair expectation of being able to use locks, we've got
to think about how to offer the option of a deterministic locking
implementation to user-space.
Most of the technical counter-arguments against doing priority
inheritance only apply to kernel-space locks. But user-space locks are
different, there we cannot disable interrupts or make the task
non-preemptible in a critical section, so the 'use spinlocks' argument
does not apply (user-space spinlocks have the same priority inversion
problems as other user-space locking constructs). Fact is, pretty much
the only technique that currently enables good determinism for userspace
locks (such as futex-based pthread mutexes) is priority inheritance:
Currently (without PI), if a high-prio and a low-prio task shares a lock
[this is a quite common scenario for most non-trivial RT applications],
even if all critical sections are coded carefully to be deterministic
(i.e. all critical sections are short in duration and only execute a
limited number of instructions), the kernel cannot guarantee any
deterministic execution of the high-prio task: any medium-priority task
could preempt the low-prio task while it holds the shared lock and
executes the critical section, and could delay it indefinitely.
Implementation:
---------------
As mentioned before, the userspace fastpath of PI-enabled pthread
mutexes involves no kernel work at all - they behave quite similarly to
normal futex-based locks: a 0 value means unlocked, and a value==TID
means locked. (This is the same method as used by list-based robust
futexes.) Userspace uses atomic ops to lock/unlock these mutexes without
entering the kernel.
To handle the slowpath, we have added two new futex ops:
FUTEX_LOCK_PI
FUTEX_UNLOCK_PI
If the lock-acquire fastpath fails, [i.e. an atomic transition from 0 to
TID fails], then FUTEX_LOCK_PI is called. The kernel does all the
remaining work: if there is no futex-queue attached to the futex address
yet then the code looks up the task that owns the futex [it has put its
own TID into the futex value], and attaches a 'PI state' structure to
the futex-queue. The pi_state includes an rt-mutex, which is a PI-aware,
kernel-based synchronization object. The 'other' task is made the owner
of the rt-mutex, and the FUTEX_WAITERS bit is atomically set in the
futex value. Then this task tries to lock the rt-mutex, on which it
blocks. Once it returns, it has the mutex acquired, and it sets the
futex value to its own TID and returns. Userspace has no other work to
perform - it now owns the lock, and futex value contains
FUTEX_WAITERS|TID.
If the unlock side fastpath succeeds, [i.e. userspace manages to do a
TID -> 0 atomic transition of the futex value], then no kernel work is
triggered.
If the unlock fastpath fails (because the FUTEX_WAITERS bit is set),
then FUTEX_UNLOCK_PI is called, and the kernel unlocks the futex on the
behalf of userspace - and it also unlocks the attached
pi_state->rt_mutex and thus wakes up any potential waiters.
Note that under this approach, contrary to previous PI-futex approaches,
there is no prior 'registration' of a PI-futex. [which is not quite
possible anyway, due to existing ABI properties of pthread mutexes.]
Also, under this scheme, 'robustness' and 'PI' are two orthogonal
properties of futexes, and all four combinations are possible: futex,
robust-futex, PI-futex, robust+PI-futex.
More details about priority inheritance can be found in
Documentation/rtmutex.txt.

View file

@ -95,7 +95,7 @@ comparison. If the thread has registered a list, then normally the list
is empty. If the thread/process crashed or terminated in some incorrect is empty. If the thread/process crashed or terminated in some incorrect
way then the list might be non-empty: in this case the kernel carefully way then the list might be non-empty: in this case the kernel carefully
walks the list [not trusting it], and marks all locks that are owned by walks the list [not trusting it], and marks all locks that are owned by
this thread with the FUTEX_OWNER_DEAD bit, and wakes up one waiter (if this thread with the FUTEX_OWNER_DIED bit, and wakes up one waiter (if
any). any).
The list is guaranteed to be private and per-thread at do_exit() time, The list is guaranteed to be private and per-thread at do_exit() time,

View file

@ -0,0 +1,781 @@
#
# Copyright (c) 2006 Steven Rostedt
# Licensed under the GNU Free Documentation License, Version 1.2
#
RT-mutex implementation design
------------------------------
This document tries to describe the design of the rtmutex.c implementation.
It doesn't describe the reasons why rtmutex.c exists. For that please see
Documentation/rt-mutex.txt. Although this document does explain problems
that happen without this code, but that is in the concept to understand
what the code actually is doing.
The goal of this document is to help others understand the priority
inheritance (PI) algorithm that is used, as well as reasons for the
decisions that were made to implement PI in the manner that was done.
Unbounded Priority Inversion
----------------------------
Priority inversion is when a lower priority process executes while a higher
priority process wants to run. This happens for several reasons, and
most of the time it can't be helped. Anytime a high priority process wants
to use a resource that a lower priority process has (a mutex for example),
the high priority process must wait until the lower priority process is done
with the resource. This is a priority inversion. What we want to prevent
is something called unbounded priority inversion. That is when the high
priority process is prevented from running by a lower priority process for
an undetermined amount of time.
The classic example of unbounded priority inversion is were you have three
processes, let's call them processes A, B, and C, where A is the highest
priority process, C is the lowest, and B is in between. A tries to grab a lock
that C owns and must wait and lets C run to release the lock. But in the
meantime, B executes, and since B is of a higher priority than C, it preempts C,
but by doing so, it is in fact preempting A which is a higher priority process.
Now there's no way of knowing how long A will be sleeping waiting for C
to release the lock, because for all we know, B is a CPU hog and will
never give C a chance to release the lock. This is called unbounded priority
inversion.
Here's a little ASCII art to show the problem.
grab lock L1 (owned by C)
|
A ---+
C preempted by B
|
C +----+
B +-------->
B now keeps A from running.
Priority Inheritance (PI)
-------------------------
There are several ways to solve this issue, but other ways are out of scope
for this document. Here we only discuss PI.
PI is where a process inherits the priority of another process if the other
process blocks on a lock owned by the current process. To make this easier
to understand, let's use the previous example, with processes A, B, and C again.
This time, when A blocks on the lock owned by C, C would inherit the priority
of A. So now if B becomes runnable, it would not preempt C, since C now has
the high priority of A. As soon as C releases the lock, it loses its
inherited priority, and A then can continue with the resource that C had.
Terminology
-----------
Here I explain some terminology that is used in this document to help describe
the design that is used to implement PI.
PI chain - The PI chain is an ordered series of locks and processes that cause
processes to inherit priorities from a previous process that is
blocked on one of its locks. This is described in more detail
later in this document.
mutex - In this document, to differentiate from locks that implement
PI and spin locks that are used in the PI code, from now on
the PI locks will be called a mutex.
lock - In this document from now on, I will use the term lock when
referring to spin locks that are used to protect parts of the PI
algorithm. These locks disable preemption for UP (when
CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
entering critical sections simultaneously.
spin lock - Same as lock above.
waiter - A waiter is a struct that is stored on the stack of a blocked
process. Since the scope of the waiter is within the code for
a process being blocked on the mutex, it is fine to allocate
the waiter on the process's stack (local variable). This
structure holds a pointer to the task, as well as the mutex that
the task is blocked on. It also has the plist node structures to
place the task in the waiter_list of a mutex as well as the
pi_list of a mutex owner task (described below).
waiter is sometimes used in reference to the task that is waiting
on a mutex. This is the same as waiter->task.
waiters - A list of processes that are blocked on a mutex.
top waiter - The highest priority process waiting on a specific mutex.
top pi waiter - The highest priority process waiting on one of the mutexes
that a specific process owns.
Note: task and process are used interchangeably in this document, mostly to
differentiate between two processes that are being described together.
PI chain
--------
The PI chain is a list of processes and mutexes that may cause priority
inheritance to take place. Multiple chains may converge, but a chain
would never diverge, since a process can't be blocked on more than one
mutex at a time.
Example:
Process: A, B, C, D, E
Mutexes: L1, L2, L3, L4
A owns: L1
B blocked on L1
B owns L2
C blocked on L2
C owns L3
D blocked on L3
D owns L4
E blocked on L4
The chain would be:
E->L4->D->L3->C->L2->B->L1->A
To show where two chains merge, we could add another process F and
another mutex L5 where B owns L5 and F is blocked on mutex L5.
The chain for F would be:
F->L5->B->L1->A
Since a process may own more than one mutex, but never be blocked on more than
one, the chains merge.
Here we show both chains:
E->L4->D->L3->C->L2-+
|
+->B->L1->A
|
F->L5-+
For PI to work, the processes at the right end of these chains (or we may
also call it the Top of the chain) must be equal to or higher in priority
than the processes to the left or below in the chain.
Also since a mutex may have more than one process blocked on it, we can
have multiple chains merge at mutexes. If we add another process G that is
blocked on mutex L2:
G->L2->B->L1->A
And once again, to show how this can grow I will show the merging chains
again.
E->L4->D->L3->C-+
+->L2-+
| |
G-+ +->B->L1->A
|
F->L5-+
Plist
-----
Before I go further and talk about how the PI chain is stored through lists
on both mutexes and processes, I'll explain the plist. This is similar to
the struct list_head functionality that is already in the kernel.
The implementation of plist is out of scope for this document, but it is
very important to understand what it does.
There are a few differences between plist and list, the most important one
being that plist is a priority sorted linked list. This means that the
priorities of the plist are sorted, such that it takes O(1) to retrieve the
highest priority item in the list. Obviously this is useful to store processes
based on their priorities.
Another difference, which is important for implementation, is that, unlike
list, the head of the list is a different element than the nodes of a list.
So the head of the list is declared as struct plist_head and nodes that will
be added to the list are declared as struct plist_node.
Mutex Waiter List
-----------------
Every mutex keeps track of all the waiters that are blocked on itself. The mutex
has a plist to store these waiters by priority. This list is protected by
a spin lock that is located in the struct of the mutex. This lock is called
wait_lock. Since the modification of the waiter list is never done in
interrupt context, the wait_lock can be taken without disabling interrupts.
Task PI List
------------
To keep track of the PI chains, each process has its own PI list. This is
a list of all top waiters of the mutexes that are owned by the process.
Note that this list only holds the top waiters and not all waiters that are
blocked on mutexes owned by the process.
The top of the task's PI list is always the highest priority task that
is waiting on a mutex that is owned by the task. So if the task has
inherited a priority, it will always be the priority of the task that is
at the top of this list.
This list is stored in the task structure of a process as a plist called
pi_list. This list is protected by a spin lock also in the task structure,
called pi_lock. This lock may also be taken in interrupt context, so when
locking the pi_lock, interrupts must be disabled.
Depth of the PI Chain
---------------------
The maximum depth of the PI chain is not dynamic, and could actually be
defined. But is very complex to figure it out, since it depends on all
the nesting of mutexes. Let's look at the example where we have 3 mutexes,
L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
The following shows a locking order of L1->L2->L3, but may not actually
be directly nested that way.
void func1(void)
{
mutex_lock(L1);
/* do anything */
mutex_unlock(L1);
}
void func2(void)
{
mutex_lock(L1);
mutex_lock(L2);
/* do something */
mutex_unlock(L2);
mutex_unlock(L1);
}
void func3(void)
{
mutex_lock(L2);
mutex_lock(L3);
/* do something else */
mutex_unlock(L3);
mutex_unlock(L2);
}
void func4(void)
{
mutex_lock(L3);
/* do something again */
mutex_unlock(L3);
}
Now we add 4 processes that run each of these functions separately.
Processes A, B, C, and D which run functions func1, func2, func3 and func4
respectively, and such that D runs first and A last. With D being preempted
in func4 in the "do something again" area, we have a locking that follows:
D owns L3
C blocked on L3
C owns L2
B blocked on L2
B owns L1
A blocked on L1
And thus we have the chain A->L1->B->L2->C->L3->D.
This gives us a PI depth of 4 (four processes), but looking at any of the
functions individually, it seems as though they only have at most a locking
depth of two. So, although the locking depth is defined at compile time,
it still is very difficult to find the possibilities of that depth.
Now since mutexes can be defined by user-land applications, we don't want a DOS
type of application that nests large amounts of mutexes to create a large
PI chain, and have the code holding spin locks while looking at a large
amount of data. So to prevent this, the implementation not only implements
a maximum lock depth, but also only holds at most two different locks at a
time, as it walks the PI chain. More about this below.
Mutex owner and flags
---------------------
The mutex structure contains a pointer to the owner of the mutex. If the
mutex is not owned, this owner is set to NULL. Since all architectures
have the task structure on at least a four byte alignment (and if this is
not true, the rtmutex.c code will be broken!), this allows for the two
least significant bits to be used as flags. This part is also described
in Documentation/rt-mutex.txt, but will also be briefly described here.
Bit 0 is used as the "Pending Owner" flag. This is described later.
Bit 1 is used as the "Has Waiters" flags. This is also described later
in more detail, but is set whenever there are waiters on a mutex.
cmpxchg Tricks
--------------
Some architectures implement an atomic cmpxchg (Compare and Exchange). This
is used (when applicable) to keep the fast path of grabbing and releasing
mutexes short.
cmpxchg is basically the following function performed atomically:
unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
{
unsigned long T = *A;
if (*A == *B) {
*A = *C;
}
return T;
}
#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
This is really nice to have, since it allows you to only update a variable
if the variable is what you expect it to be. You know if it succeeded if
the return value (the old value of A) is equal to B.
The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
the architecture does not support CMPXCHG, then this macro is simply set
to fail every time. But if CMPXCHG is supported, then this will
help out extremely to keep the fast path short.
The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
the system for architectures that support it. This will also be explained
later in this document.
Priority adjustments
--------------------
The implementation of the PI code in rtmutex.c has several places that a
process must adjust its priority. With the help of the pi_list of a
process this is rather easy to know what needs to be adjusted.
The functions implementing the task adjustments are rt_mutex_adjust_prio,
__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
to already be taken), rt_mutex_get_prio, and rt_mutex_setprio.
rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
rt_mutex_getprio returns the priority that the task should have. Either the
task's own normal priority, or if a process of a higher priority is waiting on
a mutex owned by the task, then that higher priority should be returned.
Since the pi_list of a task holds an order by priority list of all the top
waiters of all the mutexes that the task owns, rt_mutex_getprio simply needs
to compare the top pi waiter to its own normal priority, and return the higher
priority back.
(Note: if looking at the code, you will notice that the lower number of
prio is returned. This is because the prio field in the task structure
is an inverse order of the actual priority. So a "prio" of 5 is
of higher priority than a "prio" of 10.)
__rt_mutex_adjust_prio examines the result of rt_mutex_getprio, and if the
result does not equal the task's current priority, then rt_mutex_setprio
is called to adjust the priority of the task to the new priority.
Note that rt_mutex_setprio is defined in kernel/sched.c to implement the
actual change in priority.
It is interesting to note that __rt_mutex_adjust_prio can either increase
or decrease the priority of the task. In the case that a higher priority
process has just blocked on a mutex owned by the task, __rt_mutex_adjust_prio
would increase/boost the task's priority. But if a higher priority task
were for some reason to leave the mutex (timeout or signal), this same function
would decrease/unboost the priority of the task. That is because the pi_list
always contains the highest priority task that is waiting on a mutex owned
by the task, so we only need to compare the priority of that top pi waiter
to the normal priority of the given task.
High level overview of the PI chain walk
----------------------------------------
The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.
The implementation has gone through several iterations, and has ended up
with what we believe is the best. It walks the PI chain by only grabbing
at most two locks at a time, and is very efficient.
The rt_mutex_adjust_prio_chain can be used either to boost or lower process
priorities.
rt_mutex_adjust_prio_chain is called with a task to be checked for PI
(de)boosting (the owner of a mutex that a process is blocking on), a flag to
check for deadlocking, the mutex that the task owns, and a pointer to a waiter
that is the process's waiter struct that is blocked on the mutex (although this
parameter may be NULL for deboosting).
For this explanation, I will not mention deadlock detection. This explanation
will try to stay at a high level.
When this function is called, there are no locks held. That also means
that the state of the owner and lock can change when entered into this function.
Before this function is called, the task has already had rt_mutex_adjust_prio
performed on it. This means that the task is set to the priority that it
should be at, but the plist nodes of the task's waiter have not been updated
with the new priorities, and that this task may not be in the proper locations
in the pi_lists and wait_lists that the task is blocked on. This function
solves all that.
A loop is entered, where task is the owner to be checked for PI changes that
was passed by parameter (for the first iteration). The pi_lock of this task is
taken to prevent any more changes to the pi_list of the task. This also
prevents new tasks from completing the blocking on a mutex that is owned by this
task.
If the task is not blocked on a mutex then the loop is exited. We are at
the top of the PI chain.
A check is now done to see if the original waiter (the process that is blocked
on the current mutex) is the top pi waiter of the task. That is, is this
waiter on the top of the task's pi_list. If it is not, it either means that
there is another process higher in priority that is blocked on one of the
mutexes that the task owns, or that the waiter has just woken up via a signal
or timeout and has left the PI chain. In either case, the loop is exited, since
we don't need to do any more changes to the priority of the current task, or any
task that owns a mutex that this current task is waiting on. A priority chain
walk is only needed when a new top pi waiter is made to a task.
The next check sees if the task's waiter plist node has the priority equal to
the priority the task is set at. If they are equal, then we are done with
the loop. Remember that the function started with the priority of the
task adjusted, but the plist nodes that hold the task in other processes
pi_lists have not been adjusted.
Next, we look at the mutex that the task is blocked on. The mutex's wait_lock
is taken. This is done by a spin_trylock, because the locking order of the
pi_lock and wait_lock goes in the opposite direction. If we fail to grab the
lock, the pi_lock is released, and we restart the loop.
Now that we have both the pi_lock of the task as well as the wait_lock of
the mutex the task is blocked on, we update the task's waiter's plist node
that is located on the mutex's wait_list.
Now we release the pi_lock of the task.
Next the owner of the mutex has its pi_lock taken, so we can update the
task's entry in the owner's pi_list. If the task is the highest priority
process on the mutex's wait_list, then we remove the previous top waiter
from the owner's pi_list, and replace it with the task.
Note: It is possible that the task was the current top waiter on the mutex,
in which case the task is not yet on the pi_list of the waiter. This
is OK, since plist_del does nothing if the plist node is not on any
list.
If the task was not the top waiter of the mutex, but it was before we
did the priority updates, that means we are deboosting/lowering the
task. In this case, the task is removed from the pi_list of the owner,
and the new top waiter is added.
Lastly, we unlock both the pi_lock of the task, as well as the mutex's
wait_lock, and continue the loop again. On the next iteration of the
loop, the previous owner of the mutex will be the task that will be
processed.
Note: One might think that the owner of this mutex might have changed
since we just grab the mutex's wait_lock. And one could be right.
The important thing to remember is that the owner could not have
become the task that is being processed in the PI chain, since
we have taken that task's pi_lock at the beginning of the loop.
So as long as there is an owner of this mutex that is not the same
process as the tasked being worked on, we are OK.
Looking closely at the code, one might be confused. The check for the
end of the PI chain is when the task isn't blocked on anything or the
task's waiter structure "task" element is NULL. This check is
protected only by the task's pi_lock. But the code to unlock the mutex
sets the task's waiter structure "task" element to NULL with only
the protection of the mutex's wait_lock, which was not taken yet.
Isn't this a race condition if the task becomes the new owner?
The answer is No! The trick is the spin_trylock of the mutex's
wait_lock. If we fail that lock, we release the pi_lock of the
task and continue the loop, doing the end of PI chain check again.
In the code to release the lock, the wait_lock of the mutex is held
the entire time, and it is not let go when we grab the pi_lock of the
new owner of the mutex. So if the switch of a new owner were to happen
after the check for end of the PI chain and the grabbing of the
wait_lock, the unlocking code would spin on the new owner's pi_lock
but never give up the wait_lock. So the PI chain loop is guaranteed to
fail the spin_trylock on the wait_lock, release the pi_lock, and
try again.
If you don't quite understand the above, that's OK. You don't have to,
unless you really want to make a proof out of it ;)
Pending Owners and Lock stealing
--------------------------------
One of the flags in the owner field of the mutex structure is "Pending Owner".
What this means is that an owner was chosen by the process releasing the
mutex, but that owner has yet to wake up and actually take the mutex.
Why is this important? Why can't we just give the mutex to another process
and be done with it?
The PI code is to help with real-time processes, and to let the highest
priority process run as long as possible with little latencies and delays.
If a high priority process owns a mutex that a lower priority process is
blocked on, when the mutex is released it would be given to the lower priority
process. What if the higher priority process wants to take that mutex again.
The high priority process would fail to take that mutex that it just gave up
and it would need to boost the lower priority process to run with full
latency of that critical section (since the low priority process just entered
it).
There's no reason a high priority process that gives up a mutex should be
penalized if it tries to take that mutex again. If the new owner of the
mutex has not woken up yet, there's no reason that the higher priority process
could not take that mutex away.
To solve this, we introduced Pending Ownership and Lock Stealing. When a
new process is given a mutex that it was blocked on, it is only given
pending ownership. This means that it's the new owner, unless a higher
priority process comes in and tries to grab that mutex. If a higher priority
process does come along and wants that mutex, we let the higher priority
process "steal" the mutex from the pending owner (only if it is still pending)
and continue with the mutex.
Taking of a mutex (The walk through)
------------------------------------
OK, now let's take a look at the detailed walk through of what happens when
taking a mutex.
The first thing that is tried is the fast taking of the mutex. This is
done when we have CMPXCHG enabled (otherwise the fast taking automatically
fails). Only when the owner field of the mutex is NULL can the lock be
taken with the CMPXCHG and nothing else needs to be done.
If there is contention on the lock, whether it is owned or pending owner
we go about the slow path (rt_mutex_slowlock).
The slow path function is where the task's waiter structure is created on
the stack. This is because the waiter structure is only needed for the
scope of this function. The waiter structure holds the nodes to store
the task on the wait_list of the mutex, and if need be, the pi_list of
the owner.
The wait_lock of the mutex is taken since the slow path of unlocking the
mutex also takes this lock.
We then call try_to_take_rt_mutex. This is where the architecture that
does not implement CMPXCHG would always grab the lock (if there's no
contention).
try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
slow path. The first thing that is done here is an atomic setting of
the "Has Waiters" flag of the mutex's owner field. Yes, this could really
be false, because if the the mutex has no owner, there are no waiters and
the current task also won't have any waiters. But we don't have the lock
yet, so we assume we are going to be a waiter. The reason for this is to
play nice for those architectures that do have CMPXCHG. By setting this flag
now, the owner of the mutex can't release the mutex without going into the
slow unlock path, and it would then need to grab the wait_lock, which this
code currently holds. So setting the "Has Waiters" flag forces the owner
to synchronize with this code.
Now that we know that we can't have any races with the owner releasing the
mutex, we check to see if we can take the ownership. This is done if the
mutex doesn't have a owner, or if we can steal the mutex from a pending
owner. Let's look at the situations we have here.
1) Has owner that is pending
----------------------------
The mutex has a owner, but it hasn't woken up and the mutex flag
"Pending Owner" is set. The first check is to see if the owner isn't the
current task. This is because this function is also used for the pending
owner to grab the mutex. When a pending owner wakes up, it checks to see
if it can take the mutex, and this is done if the owner is already set to
itself. If so, we succeed and leave the function, clearing the "Pending
Owner" bit.
If the pending owner is not current, we check to see if the current priority is
higher than the pending owner. If not, we fail the function and return.
There's also something special about a pending owner. That is a pending owner
is never blocked on a mutex. So there is no PI chain to worry about. It also
means that if the mutex doesn't have any waiters, there's no accounting needed
to update the pending owner's pi_list, since we only worry about processes
blocked on the current mutex.
If there are waiters on this mutex, and we just stole the ownership, we need
to take the top waiter, remove it from the pi_list of the pending owner, and
add it to the current pi_list. Note that at this moment, the pending owner
is no longer on the list of waiters. This is fine, since the pending owner
would add itself back when it realizes that it had the ownership stolen
from itself. When the pending owner tries to grab the mutex, it will fail
in try_to_take_rt_mutex if the owner field points to another process.
2) No owner
-----------
If there is no owner (or we successfully stole the lock), we set the owner
of the mutex to current, and set the flag of "Has Waiters" if the current
mutex actually has waiters, or we clear the flag if it doesn't. See, it was
OK that we set that flag early, since now it is cleared.
3) Failed to grab ownership
---------------------------
The most interesting case is when we fail to take ownership. This means that
there exists an owner, or there's a pending owner with equal or higher
priority than the current task.
We'll continue on the failed case.
If the mutex has a timeout, we set up a timer to go off to break us out
of this mutex if we failed to get it after a specified amount of time.
Now we enter a loop that will continue to try to take ownership of the mutex, or
fail from a timeout or signal.
Once again we try to take the mutex. This will usually fail the first time
in the loop, since it had just failed to get the mutex. But the second time
in the loop, this would likely succeed, since the task would likely be
the pending owner.
If the mutex is TASK_INTERRUPTIBLE a check for signals and timeout is done
here.
The waiter structure has a "task" field that points to the task that is blocked
on the mutex. This field can be NULL the first time it goes through the loop
or if the task is a pending owner and had it's mutex stolen. If the "task"
field is NULL then we need to set up the accounting for it.
Task blocks on mutex
--------------------
The accounting of a mutex and process is done with the waiter structure of
the process. The "task" field is set to the process, and the "lock" field
to the mutex. The plist nodes are initialized to the processes current
priority.
Since the wait_lock was taken at the entry of the slow lock, we can safely
add the waiter to the wait_list. If the current process is the highest
priority process currently waiting on this mutex, then we remove the
previous top waiter process (if it exists) from the pi_list of the owner,
and add the current process to that list. Since the pi_list of the owner
has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
should adjust its priority accordingly.
If the owner is also blocked on a lock, and had its pi_list changed
(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
and run rt_mutex_adjust_prio_chain on the owner, as described earlier.
Now all locks are released, and if the current process is still blocked on a
mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).
Waking up in the loop
---------------------
The schedule can then wake up for a few reasons.
1) we were given pending ownership of the mutex.
2) we received a signal and was TASK_INTERRUPTIBLE
3) we had a timeout and was TASK_INTERRUPTIBLE
In any of these cases, we continue the loop and once again try to grab the
ownership of the mutex. If we succeed, we exit the loop, otherwise we continue
and on signal and timeout, will exit the loop, or if we had the mutex stolen
we just simply add ourselves back on the lists and go back to sleep.
Note: For various reasons, because of timeout and signals, the steal mutex
algorithm needs to be careful. This is because the current process is
still on the wait_list. And because of dynamic changing of priorities,
especially on SCHED_OTHER tasks, the current process can be the
highest priority task on the wait_list.
Failed to get mutex on Timeout or Signal
----------------------------------------
If a timeout or signal occurred, the waiter's "task" field would not be
NULL and the task needs to be taken off the wait_list of the mutex and perhaps
pi_list of the owner. If this process was a high priority process, then
the rt_mutex_adjust_prio_chain needs to be executed again on the owner,
but this time it will be lowering the priorities.
Unlocking the Mutex
-------------------
The unlocking of a mutex also has a fast path for those architectures with
CMPXCHG. Since the taking of a mutex on contention always sets the
"Has Waiters" flag of the mutex's owner, we use this to know if we need to
take the slow path when unlocking the mutex. If the mutex doesn't have any
waiters, the owner field of the mutex would equal the current process and
the mutex can be unlocked by just replacing the owner field with NULL.
If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
the slow unlock path is taken.
The first thing done in the slow unlock path is to take the wait_lock of the
mutex. This synchronizes the locking and unlocking of the mutex.
A check is made to see if the mutex has waiters or not. On architectures that
do not have CMPXCHG, this is the location that the owner of the mutex will
determine if a waiter needs to be awoken or not. On architectures that
do have CMPXCHG, that check is done in the fast path, but it is still needed
in the slow path too. If a waiter of a mutex woke up because of a signal
or timeout between the time the owner failed the fast path CMPXCHG check and
the grabbing of the wait_lock, the mutex may not have any waiters, thus the
owner still needs to make this check. If there are no waiters than the mutex
owner field is set to NULL, the wait_lock is released and nothing more is
needed.
If there are waiters, then we need to wake one up and give that waiter
pending ownership.
On the wake up code, the pi_lock of the current owner is taken. The top
waiter of the lock is found and removed from the wait_list of the mutex
as well as the pi_list of the current owner. The task field of the new
pending owner's waiter structure is set to NULL, and the owner field of the
mutex is set to the new owner with the "Pending Owner" bit set, as well
as the "Has Waiters" bit if there still are other processes blocked on the
mutex.
The pi_lock of the previous owner is released, and the new pending owner's
pi_lock is taken. Remember that this is the trick to prevent the race
condition in rt_mutex_adjust_prio_chain from adding itself as a waiter
on the mutex.
We now clear the "pi_blocked_on" field of the new pending owner, and if
the mutex still has waiters pending, we add the new top waiter to the pi_list
of the pending owner.
Finally we unlock the pi_lock of the pending owner and wake it up.
Contact
-------
For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>
Credits
-------
Author: Steven Rostedt <rostedt@goodmis.org>
Reviewers: Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and Randy Dunlap
Updates
-------
This document was originally written for 2.6.17-rc3-mm1

View file

@ -0,0 +1,79 @@
RT-mutex subsystem with PI support
----------------------------------
RT-mutexes with priority inheritance are used to support PI-futexes,
which enable pthread_mutex_t priority inheritance attributes
(PTHREAD_PRIO_INHERIT). [See Documentation/pi-futex.txt for more details
about PI-futexes.]
This technology was developed in the -rt tree and streamlined for
pthread_mutex support.
Basic principles:
-----------------
RT-mutexes extend the semantics of simple mutexes by the priority
inheritance protocol.
A low priority owner of a rt-mutex inherits the priority of a higher
priority waiter until the rt-mutex is released. If the temporarily
boosted owner blocks on a rt-mutex itself it propagates the priority
boosting to the owner of the other rt_mutex it gets blocked on. The
priority boosting is immediately removed once the rt_mutex has been
unlocked.
This approach allows us to shorten the block of high-prio tasks on
mutexes which protect shared resources. Priority inheritance is not a
magic bullet for poorly designed applications, but it allows
well-designed applications to use userspace locks in critical parts of
an high priority thread, without losing determinism.
The enqueueing of the waiters into the rtmutex waiter list is done in
priority order. For same priorities FIFO order is chosen. For each
rtmutex, only the top priority waiter is enqueued into the owner's
priority waiters list. This list too queues in priority order. Whenever
the top priority waiter of a task changes (for example it timed out or
got a signal), the priority of the owner task is readjusted. [The
priority enqueueing is handled by "plists", see include/linux/plist.h
for more details.]
RT-mutexes are optimized for fastpath operations and have no internal
locking overhead when locking an uncontended mutex or unlocking a mutex
without waiters. The optimized fastpath operations require cmpxchg
support. [If that is not available then the rt-mutex internal spinlock
is used]
The state of the rt-mutex is tracked via the owner field of the rt-mutex
structure:
rt_mutex->owner holds the task_struct pointer of the owner. Bit 0 and 1
are used to keep track of the "owner is pending" and "rtmutex has
waiters" state.
owner bit1 bit0
NULL 0 0 mutex is free (fast acquire possible)
NULL 0 1 invalid state
NULL 1 0 Transitional state*
NULL 1 1 invalid state
taskpointer 0 0 mutex is held (fast release possible)
taskpointer 0 1 task is pending owner
taskpointer 1 0 mutex is held and has waiters
taskpointer 1 1 task is pending owner and mutex has waiters
Pending-ownership handling is a performance optimization:
pending-ownership is assigned to the first (highest priority) waiter of
the mutex, when the mutex is released. The thread is woken up and once
it starts executing it can acquire the mutex. Until the mutex is taken
by it (bit 0 is cleared) a competing higher priority thread can "steal"
the mutex which puts the woken up thread back on the waiters list.
The pending-ownership optimization is especially important for the
uninterrupted workflow of high-prio tasks which repeatedly
takes/releases locks that have lower-prio waiters. Without this
optimization the higher-prio thread would ping-pong to the lower-prio
task [because at unlock time we always assign a new owner].
(*) The "mutex has waiters" bit gets set to take the lock. If the lock
doesn't already have an owner, this bit is quickly cleared if there are
no waiters. So this is a transitional state to synchronize with looking
at the owner field of the mutex and the mutex owner releasing the lock.

View file

@ -472,6 +472,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported. The power-management is supported.
Module snd-darla20
------------------
Module for Echoaudio Darla20
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-darla24
------------------
Module for Echoaudio Darla24
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-dt019x Module snd-dt019x
----------------- -----------------
@ -499,6 +515,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported. The power-management is supported.
Module snd-echo3g
-----------------
Module for Echoaudio 3G cards (Gina3G/Layla3G)
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-emu10k1 Module snd-emu10k1
------------------ ------------------
@ -657,6 +681,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported. The power-management is supported.
Module snd-gina20
-----------------
Module for Echoaudio Gina20
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-gina24
-----------------
Module for Echoaudio Gina24
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-gusclassic Module snd-gusclassic
--------------------- ---------------------
@ -760,12 +800,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
basic fixed pin assignment w/o SPDIF basic fixed pin assignment w/o SPDIF
auto auto-config reading BIOS (default) auto auto-config reading BIOS (default)
ALC882/883/885 ALC882/885
3stack-dig 3-jack with SPDIF I/O 3stack-dig 3-jack with SPDIF I/O
6stck-dig 6-jack digital with SPDIF I/O 6stck-dig 6-jack digital with SPDIF I/O
auto auto-config reading BIOS (default) auto auto-config reading BIOS (default)
ALC861 ALC883/888
3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O
6stack-dig-demo 6-stack digital for Intel demo board
auto auto-config reading BIOS (default)
ALC861/660
3stack 3-jack 3stack 3-jack
3stack-dig 3-jack with SPDIF I/O 3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack with SPDIF I/O 6stack-dig 6-jack with SPDIF I/O
@ -937,6 +983,30 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
driver isn't configured properly or you want to try another driver isn't configured properly or you want to try another
type for testing. type for testing.
Module snd-indigo
-----------------
Module for Echoaudio Indigo
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-indigodj
-------------------
Module for Echoaudio Indigo DJ
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-indigoio
-------------------
Module for Echoaudio Indigo IO
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-intel8x0 Module snd-intel8x0
------------------- -------------------
@ -1036,6 +1106,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple cards. This module supports multiple cards.
Module snd-layla20
------------------
Module for Echoaudio Layla20
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-layla24
------------------
Module for Echoaudio Layla24
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-maestro3 Module snd-maestro3
------------------- -------------------
@ -1056,6 +1142,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported. The power-management is supported.
Module snd-mia
---------------
Module for Echoaudio Mia
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-miro Module snd-miro
--------------- ---------------
@ -1088,6 +1182,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
When no hotplug fw loader is available, you need to load the When no hotplug fw loader is available, you need to load the
firmware via mixartloader utility in alsa-tools package. firmware via mixartloader utility in alsa-tools package.
Module snd-mona
---------------
Module for Echoaudio Mona
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
Module snd-mpu401 Module snd-mpu401
----------------- -----------------

View file

@ -0,0 +1,212 @@
$Id$
Mike Isely <isely@pobox.com>
pvrusb2 driver
Background:
This driver is intended for the "Hauppauge WinTV PVR USB 2.0", which
is a USB 2.0 hosted TV Tuner. This driver is a work in progress.
Its history started with the reverse-engineering effort by Björn
Danielsson <pvrusb2@dax.nu> whose web page can be found here:
http://pvrusb2.dax.nu/
From there Aurelien Alleaume <slts@free.fr> began an effort to
create a video4linux compatible driver. I began with Aurelien's
last known snapshot and evolved the driver to the state it is in
here.
More information on this driver can be found at:
http://www.isely.net/pvrusb2.html
This driver has a strong separation of layers. They are very
roughly:
1a. Low level wire-protocol implementation with the device.
1b. I2C adaptor implementation and corresponding I2C client drivers
implemented elsewhere in V4L.
1c. High level hardware driver implementation which coordinates all
activities that ensure correct operation of the device.
2. A "context" layer which manages instancing of driver, setup,
tear-down, arbitration, and interaction with high level
interfaces appropriately as devices are hotplugged in the
system.
3. High level interfaces which glue the driver to various published
Linux APIs (V4L, sysfs, maybe DVB in the future).
The most important shearing layer is between the top 2 layers. A
lot of work went into the driver to ensure that any kind of
conceivable API can be laid on top of the core driver. (Yes, the
driver internally leverages V4L to do its work but that really has
nothing to do with the API published by the driver to the outside
world.) The architecture allows for different APIs to
simultaneously access the driver. I have a strong sense of fairness
about APIs and also feel that it is a good design principle to keep
implementation and interface isolated from each other. Thus while
right now the V4L high level interface is the most complete, the
sysfs high level interface will work equally well for similar
functions, and there's no reason I see right now why it shouldn't be
possible to produce a DVB high level interface that can sit right
alongside V4L.
NOTE: Complete documentation on the pvrusb2 driver is contained in
the html files within the doc directory; these are exactly the same
as what is on the web site at the time. Browse those files
(especially the FAQ) before asking questions.
Building
To build these modules essentially amounts to just running "Make",
but you need the kernel source tree nearby and you will likely also
want to set a few controlling environment variables first in order
to link things up with that source tree. Please see the Makefile
here for comments that explain how to do that.
Source file list / functional overview:
(Note: The term "module" used below generally refers to loosely
defined functional units within the pvrusb2 driver and bears no
relation to the Linux kernel's concept of a loadable module.)
pvrusb2-audio.[ch] - This is glue logic that resides between this
driver and the msp3400.ko I2C client driver (which is found
elsewhere in V4L).
pvrusb2-context.[ch] - This module implements the context for an
instance of the driver. Everything else eventually ties back to
or is otherwise instanced within the data structures implemented
here. Hotplugging is ultimately coordinated here. All high level
interfaces tie into the driver through this module. This module
helps arbitrate each interface's access to the actual driver core,
and is designed to allow concurrent access through multiple
instances of multiple interfaces (thus you can for example change
the tuner's frequency through sysfs while simultaneously streaming
video through V4L out to an instance of mplayer).
pvrusb2-debug.h - This header defines a printk() wrapper and a mask
of debugging bit definitions for the various kinds of debug
messages that can be enabled within the driver.
pvrusb2-debugifc.[ch] - This module implements a crude command line
oriented debug interface into the driver. Aside from being part
of the process for implementing manual firmware extraction (see
the pvrusb2 web site mentioned earlier), probably I'm the only one
who has ever used this. It is mainly a debugging aid.
pvrusb2-eeprom.[ch] - This is glue logic that resides between this
driver the tveeprom.ko module, which is itself implemented
elsewhere in V4L.
pvrusb2-encoder.[ch] - This module implements all protocol needed to
interact with the Conexant mpeg2 encoder chip within the pvrusb2
device. It is a crude echo of corresponding logic in ivtv,
however the design goals (strict isolation) and physical layer
(proxy through USB instead of PCI) are enough different that this
implementation had to be completely different.
pvrusb2-hdw-internal.h - This header defines the core data structure
in the driver used to track ALL internal state related to control
of the hardware. Nobody outside of the core hardware-handling
modules should have any business using this header. All external
access to the driver should be through one of the high level
interfaces (e.g. V4L, sysfs, etc), and in fact even those high
level interfaces are restricted to the API defined in
pvrusb2-hdw.h and NOT this header.
pvrusb2-hdw.h - This header defines the full internal API for
controlling the hardware. High level interfaces (e.g. V4L, sysfs)
will work through here.
pvrusb2-hdw.c - This module implements all the various bits of logic
that handle overall control of a specific pvrusb2 device.
(Policy, instantiation, and arbitration of pvrusb2 devices fall
within the jurisdiction of pvrusb-context not here).
pvrusb2-i2c-chips-*.c - These modules implement the glue logic to
tie together and configure various I2C modules as they attach to
the I2C bus. There are two versions of this file. The "v4l2"
version is intended to be used in-tree alongside V4L, where we
implement just the logic that makes sense for a pure V4L
environment. The "all" version is intended for use outside of
V4L, where we might encounter other possibly "challenging" modules
from ivtv or older kernel snapshots (or even the support modules
in the standalone snapshot).
pvrusb2-i2c-cmd-v4l1.[ch] - This module implements generic V4L1
compatible commands to the I2C modules. It is here where state
changes inside the pvrusb2 driver are translated into V4L1
commands that are in turn send to the various I2C modules.
pvrusb2-i2c-cmd-v4l2.[ch] - This module implements generic V4L2
compatible commands to the I2C modules. It is here where state
changes inside the pvrusb2 driver are translated into V4L2
commands that are in turn send to the various I2C modules.
pvrusb2-i2c-core.[ch] - This module provides an implementation of a
kernel-friendly I2C adaptor driver, through which other external
I2C client drivers (e.g. msp3400, tuner, lirc) may connect and
operate corresponding chips within the the pvrusb2 device. It is
through here that other V4L modules can reach into this driver to
operate specific pieces (and those modules are in turn driven by
glue logic which is coordinated by pvrusb2-hdw, doled out by
pvrusb2-context, and then ultimately made available to users
through one of the high level interfaces).
pvrusb2-io.[ch] - This module implements a very low level ring of
transfer buffers, required in order to stream data from the
device. This module is *very* low level. It only operates the
buffers and makes no attempt to define any policy or mechanism for
how such buffers might be used.
pvrusb2-ioread.[ch] - This module layers on top of pvrusb2-io.[ch]
to provide a streaming API usable by a read() system call style of
I/O. Right now this is the only layer on top of pvrusb2-io.[ch],
however the underlying architecture here was intended to allow for
other styles of I/O to be implemented with additonal modules, like
mmap()'ed buffers or something even more exotic.
pvrusb2-main.c - This is the top level of the driver. Module level
and USB core entry points are here. This is our "main".
pvrusb2-sysfs.[ch] - This is the high level interface which ties the
pvrusb2 driver into sysfs. Through this interface you can do
everything with the driver except actually stream data.
pvrusb2-tuner.[ch] - This is glue logic that resides between this
driver and the tuner.ko I2C client driver (which is found
elsewhere in V4L).
pvrusb2-util.h - This header defines some common macros used
throughout the driver. These macros are not really specific to
the driver, but they had to go somewhere.
pvrusb2-v4l2.[ch] - This is the high level interface which ties the
pvrusb2 driver into video4linux. It is through here that V4L
applications can open and operate the driver in the usual V4L
ways. Note that **ALL** V4L functionality is published only
through here and nowhere else.
pvrusb2-video-*.[ch] - This is glue logic that resides between this
driver and the saa711x.ko I2C client driver (which is found
elsewhere in V4L). Note that saa711x.ko used to be known as
saa7115.ko in ivtv. There are two versions of this; one is
selected depending on the particular saa711[5x].ko that is found.
pvrusb2.h - This header contains compile time tunable parameters
(and at the moment the driver has very little that needs to be
tuned).
-Mike Isely
isely@pobox.com

View file

@ -22,78 +22,9 @@
to run the program with an "&" to run it in the background!) to run the program with an "&" to run it in the background!)
If you want to write a program to be compatible with the PC Watchdog If you want to write a program to be compatible with the PC Watchdog
driver, simply do the following: driver, simply use of modify the watchdog test program:
Documentation/watchdog/src/watchdog-test.c
-- Snippet of code --
/*
* Watchdog Driver Test Program
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/watchdog.h>
int fd;
/*
* This function simply sends an IOCTL to the driver, which in turn ticks
* the PC Watchdog card to reset its internal timer so it doesn't trigger
* a computer reset.
*/
void keep_alive(void)
{
int dummy;
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
}
/*
* The main program. Run the program with "-d" to disable the card,
* or "-e" to enable the card.
*/
int main(int argc, char *argv[])
{
fd = open("/dev/watchdog", O_WRONLY);
if (fd == -1) {
fprintf(stderr, "Watchdog device not enabled.\n");
fflush(stderr);
exit(-1);
}
if (argc > 1) {
if (!strncasecmp(argv[1], "-d", 2)) {
ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
fprintf(stderr, "Watchdog card disabled.\n");
fflush(stderr);
exit(0);
} else if (!strncasecmp(argv[1], "-e", 2)) {
ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
fprintf(stderr, "Watchdog card enabled.\n");
fflush(stderr);
exit(0);
} else {
fprintf(stderr, "-d to disable, -e to enable.\n");
fprintf(stderr, "run by itself to tick the card.\n");
fflush(stderr);
exit(0);
}
} else {
fprintf(stderr, "Watchdog Ticking Away!\n");
fflush(stderr);
}
while(1) {
keep_alive();
sleep(1);
}
}
-- End snippet --
Other IOCTL functions include: Other IOCTL functions include:

View file

@ -0,0 +1,15 @@
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, const char *argv[]) {
int fd = open("/dev/watchdog", O_WRONLY);
if (fd == -1) {
perror("watchdog");
exit(1);
}
while (1) {
write(fd, "\0", 1);
fsync(fd);
sleep(10);
}
}

View file

@ -0,0 +1,68 @@
/*
* Watchdog Driver Test Program
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/watchdog.h>
int fd;
/*
* This function simply sends an IOCTL to the driver, which in turn ticks
* the PC Watchdog card to reset its internal timer so it doesn't trigger
* a computer reset.
*/
void keep_alive(void)
{
int dummy;
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
}
/*
* The main program. Run the program with "-d" to disable the card,
* or "-e" to enable the card.
*/
int main(int argc, char *argv[])
{
fd = open("/dev/watchdog", O_WRONLY);
if (fd == -1) {
fprintf(stderr, "Watchdog device not enabled.\n");
fflush(stderr);
exit(-1);
}
if (argc > 1) {
if (!strncasecmp(argv[1], "-d", 2)) {
ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
fprintf(stderr, "Watchdog card disabled.\n");
fflush(stderr);
exit(0);
} else if (!strncasecmp(argv[1], "-e", 2)) {
ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
fprintf(stderr, "Watchdog card enabled.\n");
fflush(stderr);
exit(0);
} else {
fprintf(stderr, "-d to disable, -e to enable.\n");
fprintf(stderr, "run by itself to tick the card.\n");
fflush(stderr);
exit(0);
}
} else {
fprintf(stderr, "Watchdog Ticking Away!\n");
fflush(stderr);
}
while(1) {
keep_alive();
sleep(1);
}
}

View file

@ -34,22 +34,7 @@ activates as soon as /dev/watchdog is opened and will reboot unless
the watchdog is pinged within a certain time, this time is called the the watchdog is pinged within a certain time, this time is called the
timeout or margin. The simplest way to ping the watchdog is to write timeout or margin. The simplest way to ping the watchdog is to write
some data to the device. So a very simple watchdog daemon would look some data to the device. So a very simple watchdog daemon would look
like this: like this source file: see Documentation/watchdog/src/watchdog-simple.c
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, const char *argv[]) {
int fd=open("/dev/watchdog",O_WRONLY);
if (fd==-1) {
perror("watchdog");
exit(1);
}
while(1) {
write(fd, "\0", 1);
sleep(10);
}
}
A more advanced driver could for example check that a HTTP server is A more advanced driver could for example check that a HTTP server is
still responding before doing the write call to ping the watchdog. still responding before doing the write call to ping the watchdog.
@ -110,7 +95,40 @@ current timeout using the GETTIMEOUT ioctl.
ioctl(fd, WDIOC_GETTIMEOUT, &timeout); ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
printf("The timeout was is %d seconds\n", timeout); printf("The timeout was is %d seconds\n", timeout);
Envinronmental monitoring: Pretimeouts:
Some watchdog timers can be set to have a trigger go off before the
actual time they will reset the system. This can be done with an NMI,
interrupt, or other mechanism. This allows Linux to record useful
information (like panic information and kernel coredumps) before it
resets.
pretimeout = 10;
ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
Note that the pretimeout is the number of seconds before the time
when the timeout will go off. It is not the number of seconds until
the pretimeout. So, for instance, if you set the timeout to 60 seconds
and the pretimeout to 10 seconds, the pretimout will go of in 50
seconds. Setting a pretimeout to zero disables it.
There is also a get function for getting the pretimeout:
ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout);
printf("The pretimeout was is %d seconds\n", timeout);
Not all watchdog drivers will support a pretimeout.
Get the number of seconds before reboot:
Some watchdog drivers have the ability to report the remaining time
before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl
that returns the number of seconds before reboot.
ioctl(fd, WDIOC_GETTIMELEFT, &timeleft);
printf("The timeout was is %d seconds\n", timeleft);
Environmental monitoring:
All watchdog drivers are required return more information about the system, All watchdog drivers are required return more information about the system,
some do temperature, fan and power level monitoring, some can tell you some do temperature, fan and power level monitoring, some can tell you
@ -169,6 +187,10 @@ The watchdog saw a keepalive ping since it was last queried.
WDIOF_SETTIMEOUT Can set/get the timeout WDIOF_SETTIMEOUT Can set/get the timeout
The watchdog can do pretimeouts.
WDIOF_PRETIMEOUT Pretimeout (in seconds), get/set
For those drivers that return any bits set in the option field, the For those drivers that return any bits set in the option field, the
GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current

View file

@ -65,28 +65,7 @@ The external event interfaces on the WDT boards are not currently supported.
Minor numbers are however allocated for it. Minor numbers are however allocated for it.
Example Watchdog Driver Example Watchdog Driver: see Documentation/watchdog/src/watchdog-simple.c
-----------------------
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
int fd=open("/dev/watchdog",O_WRONLY);
if(fd==-1)
{
perror("watchdog");
exit(1);
}
while(1)
{
write(fd,"\0",1);
fsync(fd);
sleep(10);
}
}
Contact Information Contact Information

View file

@ -49,15 +49,15 @@ select_smp_affinity(unsigned int irq)
static int last_cpu; static int last_cpu;
int cpu = last_cpu + 1; int cpu = last_cpu + 1;
if (!irq_desc[irq].handler->set_affinity || irq_user_affinity[irq]) if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq])
return 1; return 1;
while (!cpu_possible(cpu)) while (!cpu_possible(cpu))
cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
last_cpu = cpu; last_cpu = cpu;
irq_affinity[irq] = cpumask_of_cpu(cpu); irq_desc[irq].affinity = cpumask_of_cpu(cpu);
irq_desc[irq].handler->set_affinity(irq, cpumask_of_cpu(cpu)); irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu));
return 0; return 0;
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
@ -93,7 +93,7 @@ show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq]); seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq]);
#endif #endif
seq_printf(p, " %14s", irq_desc[irq].handler->typename); seq_printf(p, " %14s", irq_desc[irq].chip->typename);
seq_printf(p, " %c%s", seq_printf(p, " %c%s",
(action->flags & SA_INTERRUPT)?'+':' ', (action->flags & SA_INTERRUPT)?'+':' ',
action->name); action->name);

View file

@ -233,7 +233,7 @@ void __init
init_rtc_irq(void) init_rtc_irq(void)
{ {
irq_desc[RTC_IRQ].status = IRQ_DISABLED; irq_desc[RTC_IRQ].status = IRQ_DISABLED;
irq_desc[RTC_IRQ].handler = &rtc_irq_type; irq_desc[RTC_IRQ].chip = &rtc_irq_type;
setup_irq(RTC_IRQ, &timer_irqaction); setup_irq(RTC_IRQ, &timer_irqaction);
} }

View file

@ -109,7 +109,7 @@ init_i8259a_irqs(void)
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
irq_desc[i].status = IRQ_DISABLED; irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].handler = &i8259a_irq_type; irq_desc[i].chip = &i8259a_irq_type;
} }
setup_irq(2, &cascade); setup_irq(2, &cascade);

View file

@ -120,7 +120,7 @@ init_pyxis_irqs(unsigned long ignore_mask)
if ((ignore_mask >> i) & 1) if ((ignore_mask >> i) & 1)
continue; continue;
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &pyxis_irq_type; irq_desc[i].chip = &pyxis_irq_type;
} }
setup_irq(16+7, &isa_cascade_irqaction); setup_irq(16+7, &isa_cascade_irqaction);

View file

@ -67,7 +67,7 @@ init_srm_irqs(long max, unsigned long ignore_mask)
if (i < 64 && ((ignore_mask >> i) & 1)) if (i < 64 && ((ignore_mask >> i) & 1))
continue; continue;
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &srm_irq_type; irq_desc[i].chip = &srm_irq_type;
} }
} }

View file

@ -124,12 +124,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);
void void
pcibios_align_resource(void *data, struct resource *res, pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align) resource_size_t size, resource_size_t align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
struct pci_controller *hose = dev->sysdata; struct pci_controller *hose = dev->sysdata;
unsigned long alignto; unsigned long alignto;
unsigned long start = res->start; resource_size_t start = res->start;
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
/* Make sure we start at our min on all hoses */ /* Make sure we start at our min on all hoses */

View file

@ -481,7 +481,7 @@ register_cpus(void)
struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
register_cpu(p, i, NULL); register_cpu(p, i);
} }
return 0; return 0;
} }

View file

@ -144,7 +144,7 @@ alcor_init_irq(void)
if (i >= 16+20 && i <= 16+30) if (i >= 16+20 && i <= 16+30)
continue; continue;
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &alcor_irq_type; irq_desc[i].chip = &alcor_irq_type;
} }
i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq; i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;

View file

@ -124,7 +124,7 @@ common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
for (i = 16; i < 35; ++i) { for (i = 16; i < 35; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &cabriolet_irq_type; irq_desc[i].chip = &cabriolet_irq_type;
} }
} }

View file

@ -300,7 +300,7 @@ init_tsunami_irqs(struct hw_interrupt_type * ops, int imin, int imax)
long i; long i;
for (i = imin; i <= imax; ++i) { for (i = imin; i <= imax; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = ops; irq_desc[i].chip = ops;
} }
} }

View file

@ -137,7 +137,7 @@ eb64p_init_irq(void)
for (i = 16; i < 32; ++i) { for (i = 16; i < 32; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &eb64p_irq_type; irq_desc[i].chip = &eb64p_irq_type;
} }
common_init_isa_dma(); common_init_isa_dma();

View file

@ -154,7 +154,7 @@ eiger_init_irq(void)
for (i = 16; i < 128; ++i) { for (i = 16; i < 128; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &eiger_irq_type; irq_desc[i].chip = &eiger_irq_type;
} }
} }

View file

@ -206,11 +206,11 @@ jensen_init_irq(void)
{ {
init_i8259a_irqs(); init_i8259a_irqs();
irq_desc[1].handler = &jensen_local_irq_type; irq_desc[1].chip = &jensen_local_irq_type;
irq_desc[4].handler = &jensen_local_irq_type; irq_desc[4].chip = &jensen_local_irq_type;
irq_desc[3].handler = &jensen_local_irq_type; irq_desc[3].chip = &jensen_local_irq_type;
irq_desc[7].handler = &jensen_local_irq_type; irq_desc[7].chip = &jensen_local_irq_type;
irq_desc[9].handler = &jensen_local_irq_type; irq_desc[9].chip = &jensen_local_irq_type;
common_init_isa_dma(); common_init_isa_dma();
} }

View file

@ -303,7 +303,7 @@ init_io7_irqs(struct io7 *io7,
/* Set up the lsi irqs. */ /* Set up the lsi irqs. */
for (i = 0; i < 128; ++i) { for (i = 0; i < 128; ++i) {
irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[base + i].handler = lsi_ops; irq_desc[base + i].chip = lsi_ops;
} }
/* Disable the implemented irqs in hardware. */ /* Disable the implemented irqs in hardware. */
@ -317,7 +317,7 @@ init_io7_irqs(struct io7 *io7,
/* Set up the msi irqs. */ /* Set up the msi irqs. */
for (i = 128; i < (128 + 512); ++i) { for (i = 128; i < (128 + 512); ++i) {
irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[base + i].handler = msi_ops; irq_desc[base + i].chip = msi_ops;
} }
for (i = 0; i < 16; ++i) for (i = 0; i < 16; ++i)
@ -335,7 +335,7 @@ marvel_init_irq(void)
/* Reserve the legacy irqs. */ /* Reserve the legacy irqs. */
for (i = 0; i < 16; ++i) { for (i = 0; i < 16; ++i) {
irq_desc[i].status = IRQ_DISABLED; irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].handler = &marvel_legacy_irq_type; irq_desc[i].chip = &marvel_legacy_irq_type;
} }
/* Init the io7 irqs. */ /* Init the io7 irqs. */

View file

@ -117,7 +117,7 @@ mikasa_init_irq(void)
for (i = 16; i < 32; ++i) { for (i = 16; i < 32; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &mikasa_irq_type; irq_desc[i].chip = &mikasa_irq_type;
} }
init_i8259a_irqs(); init_i8259a_irqs();

View file

@ -139,7 +139,7 @@ noritake_init_irq(void)
for (i = 16; i < 48; ++i) { for (i = 16; i < 48; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &noritake_irq_type; irq_desc[i].chip = &noritake_irq_type;
} }
init_i8259a_irqs(); init_i8259a_irqs();

View file

@ -180,7 +180,7 @@ rawhide_init_irq(void)
for (i = 16; i < 128; ++i) { for (i = 16; i < 128; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &rawhide_irq_type; irq_desc[i].chip = &rawhide_irq_type;
} }
init_i8259a_irqs(); init_i8259a_irqs();

View file

@ -117,7 +117,7 @@ rx164_init_irq(void)
rx164_update_irq_hw(0); rx164_update_irq_hw(0);
for (i = 16; i < 40; ++i) { for (i = 16; i < 40; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &rx164_irq_type; irq_desc[i].chip = &rx164_irq_type;
} }
init_i8259a_irqs(); init_i8259a_irqs();

View file

@ -537,7 +537,7 @@ sable_lynx_init_irq(int nr_irqs)
for (i = 0; i < nr_irqs; ++i) { for (i = 0; i < nr_irqs; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &sable_lynx_irq_type; irq_desc[i].chip = &sable_lynx_irq_type;
} }
common_init_isa_dma(); common_init_isa_dma();

View file

@ -154,7 +154,7 @@ takara_init_irq(void)
for (i = 16; i < 128; ++i) { for (i = 16; i < 128; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = &takara_irq_type; irq_desc[i].chip = &takara_irq_type;
} }
common_init_isa_dma(); common_init_isa_dma();

View file

@ -189,7 +189,7 @@ init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
long i; long i;
for (i = imin; i <= imax; ++i) { for (i = imin; i <= imax; ++i) {
irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i].handler = ops; irq_desc[i].chip = ops;
} }
} }

View file

@ -199,14 +199,14 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
if (i == 2) if (i == 2)
continue; continue;
irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i+irq_bias].handler = &wildfire_irq_type; irq_desc[i+irq_bias].chip = &wildfire_irq_type;
} }
irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[36+irq_bias].handler = &wildfire_irq_type; irq_desc[36+irq_bias].chip = &wildfire_irq_type;
for (i = 40; i < 64; ++i) { for (i = 40; i < 64; ++i) {
irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[i+irq_bias].handler = &wildfire_irq_type; irq_desc[i+irq_bias].chip = &wildfire_irq_type;
} }
setup_irq(32+irq_bias, &isa_enable); setup_irq(32+irq_bias, &isa_enable);

View file

@ -188,23 +188,27 @@ config ARCH_IMX
config ARCH_IOP3XX config ARCH_IOP3XX
bool "IOP3xx-based" bool "IOP3xx-based"
depends on MMU
select PCI select PCI
help help
Support for Intel's IOP3XX (XScale) family of processors. Support for Intel's IOP3XX (XScale) family of processors.
config ARCH_IXP4XX config ARCH_IXP4XX
bool "IXP4xx-based" bool "IXP4xx-based"
depends on MMU
help help
Support for Intel's IXP4XX (XScale) family of processors. Support for Intel's IXP4XX (XScale) family of processors.
config ARCH_IXP2000 config ARCH_IXP2000
bool "IXP2400/2800-based" bool "IXP2400/2800-based"
depends on MMU
select PCI select PCI
help help
Support for Intel's IXP2400/2800 (XScale) family of processors. Support for Intel's IXP2400/2800 (XScale) family of processors.
config ARCH_IXP23XX config ARCH_IXP23XX
bool "IXP23XX-based" bool "IXP23XX-based"
depends on MMU
select PCI select PCI
help help
Support for Intel's IXP23xx (XScale) family of processors. Support for Intel's IXP23xx (XScale) family of processors.
@ -229,6 +233,7 @@ config ARCH_PNX4008
config ARCH_PXA config ARCH_PXA
bool "PXA2xx-based" bool "PXA2xx-based"
depends on MMU
select ARCH_MTD_XIP select ARCH_MTD_XIP
help help
Support for Intel's PXA2XX processor line. Support for Intel's PXA2XX processor line.
@ -339,6 +344,10 @@ config XSCALE_PMU
depends on CPU_XSCALE && !XSCALE_PMU_TIMER depends on CPU_XSCALE && !XSCALE_PMU_TIMER
default y default y
if !MMU
source "arch/arm/Kconfig-nommu"
endif
endmenu endmenu
source "arch/arm/common/Kconfig" source "arch/arm/common/Kconfig"

View file

@ -22,6 +22,9 @@ obj-$(CONFIG_PCI) += bios32.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
obj-$(CONFIG_IWMMXT) += iwmmxt.o obj-$(CONFIG_IWMMXT) += iwmmxt.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt

View file

@ -109,11 +109,13 @@ EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(__memzero); EXPORT_SYMBOL(__memzero);
/* user mem (segment) */ /* user mem (segment) */
EXPORT_SYMBOL(__arch_copy_from_user); EXPORT_SYMBOL(__strnlen_user);
EXPORT_SYMBOL(__arch_copy_to_user); EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__arch_clear_user);
EXPORT_SYMBOL(__arch_strnlen_user); #ifdef CONFIG_MMU
EXPORT_SYMBOL(__arch_strncpy_from_user); EXPORT_SYMBOL(__copy_from_user);
EXPORT_SYMBOL(__copy_to_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(__get_user_1); EXPORT_SYMBOL(__get_user_1);
EXPORT_SYMBOL(__get_user_2); EXPORT_SYMBOL(__get_user_2);
@ -123,6 +125,7 @@ EXPORT_SYMBOL(__put_user_1);
EXPORT_SYMBOL(__put_user_2); EXPORT_SYMBOL(__put_user_2);
EXPORT_SYMBOL(__put_user_4); EXPORT_SYMBOL(__put_user_4);
EXPORT_SYMBOL(__put_user_8); EXPORT_SYMBOL(__put_user_8);
#endif
/* crypto hash */ /* crypto hash */
EXPORT_SYMBOL(sha_transform); EXPORT_SYMBOL(sha_transform);

View file

@ -59,6 +59,9 @@ int main(void)
DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate));
#ifdef CONFIG_IWMMXT #ifdef CONFIG_IWMMXT
DEFINE(TI_IWMMXT_STATE, offsetof(struct thread_info, fpstate.iwmmxt)); DEFINE(TI_IWMMXT_STATE, offsetof(struct thread_info, fpstate.iwmmxt));
#endif
#ifdef CONFIG_CRUNCH
DEFINE(TI_CRUNCH_STATE, offsetof(struct thread_info, crunchstate));
#endif #endif
BLANK(); BLANK();
DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0)); DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0));

View file

@ -304,7 +304,7 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev)
static void __devinit static void __devinit
pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
{ {
unsigned long offset; resource_size_t offset;
int i; int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) { for (i = 0; i < PCI_NUM_RESOURCES; i++) {
@ -634,9 +634,9 @@ char * __init pcibios_setup(char *str)
* which might be mirrored at 0x0100-0x03ff.. * which might be mirrored at 0x0100-0x03ff..
*/ */
void pcibios_align_resource(void *data, struct resource *res, void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align) resource_size_t size, resource_size_t align)
{ {
unsigned long start = res->start; resource_size_t start = res->start;
if (res->flags & IORESOURCE_IO && start & 0x300) if (res->flags & IORESOURCE_IO && start & 0x300)
start = (start + 0x3ff) & ~0x3ff; start = (start + 0x3ff) & ~0x3ff;

View file

@ -0,0 +1,305 @@
/*
* arch/arm/kernel/crunch-bits.S
* Cirrus MaverickCrunch context switching and handling
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
*
* Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
* Copyright (c) 2003-2004, 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/linkage.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
#include <asm/arch/ep93xx-regs.h>
/*
* We can't use hex constants here due to a bug in gas.
*/
#define CRUNCH_MVDX0 0
#define CRUNCH_MVDX1 8
#define CRUNCH_MVDX2 16
#define CRUNCH_MVDX3 24
#define CRUNCH_MVDX4 32
#define CRUNCH_MVDX5 40
#define CRUNCH_MVDX6 48
#define CRUNCH_MVDX7 56
#define CRUNCH_MVDX8 64
#define CRUNCH_MVDX9 72
#define CRUNCH_MVDX10 80
#define CRUNCH_MVDX11 88
#define CRUNCH_MVDX12 96
#define CRUNCH_MVDX13 104
#define CRUNCH_MVDX14 112
#define CRUNCH_MVDX15 120
#define CRUNCH_MVAX0L 128
#define CRUNCH_MVAX0M 132
#define CRUNCH_MVAX0H 136
#define CRUNCH_MVAX1L 140
#define CRUNCH_MVAX1M 144
#define CRUNCH_MVAX1H 148
#define CRUNCH_MVAX2L 152
#define CRUNCH_MVAX2M 156
#define CRUNCH_MVAX2H 160
#define CRUNCH_MVAX3L 164
#define CRUNCH_MVAX3M 168
#define CRUNCH_MVAX3H 172
#define CRUNCH_DSPSC 176
#define CRUNCH_SIZE 184
.text
/*
* Lazy switching of crunch coprocessor context
*
* r10 = struct thread_info pointer
* r9 = ret_from_exception
* lr = undefined instr exit
*
* called from prefetch exception handler with interrupts disabled
*/
ENTRY(crunch_task_enable)
ldr r8, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr
ldr r1, [r8, #0x80]
tst r1, #0x00800000 @ access to crunch enabled?
movne pc, lr @ if so no business here
mov r3, #0xaa @ unlock syscon swlock
str r3, [r8, #0xc0]
orr r1, r1, #0x00800000 @ enable access to crunch
str r1, [r8, #0x80]
ldr r3, =crunch_owner
add r0, r10, #TI_CRUNCH_STATE @ get task crunch save area
ldr r2, [sp, #60] @ current task pc value
ldr r1, [r3] @ get current crunch owner
str r0, [r3] @ this task now owns crunch
sub r2, r2, #4 @ adjust pc back
str r2, [sp, #60]
ldr r2, [r8, #0x80]
mov r2, r2 @ flush out enable (@@@)
teq r1, #0 @ test for last ownership
mov lr, r9 @ normal exit from exception
beq crunch_load @ no owner, skip save
crunch_save:
cfstr64 mvdx0, [r1, #CRUNCH_MVDX0] @ save 64b registers
cfstr64 mvdx1, [r1, #CRUNCH_MVDX1]
cfstr64 mvdx2, [r1, #CRUNCH_MVDX2]
cfstr64 mvdx3, [r1, #CRUNCH_MVDX3]
cfstr64 mvdx4, [r1, #CRUNCH_MVDX4]
cfstr64 mvdx5, [r1, #CRUNCH_MVDX5]
cfstr64 mvdx6, [r1, #CRUNCH_MVDX6]
cfstr64 mvdx7, [r1, #CRUNCH_MVDX7]
cfstr64 mvdx8, [r1, #CRUNCH_MVDX8]
cfstr64 mvdx9, [r1, #CRUNCH_MVDX9]
cfstr64 mvdx10, [r1, #CRUNCH_MVDX10]
cfstr64 mvdx11, [r1, #CRUNCH_MVDX11]
cfstr64 mvdx12, [r1, #CRUNCH_MVDX12]
cfstr64 mvdx13, [r1, #CRUNCH_MVDX13]
cfstr64 mvdx14, [r1, #CRUNCH_MVDX14]
cfstr64 mvdx15, [r1, #CRUNCH_MVDX15]
#ifdef __ARMEB__
#error fix me for ARMEB
#endif
cfmv32al mvfx0, mvax0 @ save 72b accumulators
cfstr32 mvfx0, [r1, #CRUNCH_MVAX0L]
cfmv32am mvfx0, mvax0
cfstr32 mvfx0, [r1, #CRUNCH_MVAX0M]
cfmv32ah mvfx0, mvax0
cfstr32 mvfx0, [r1, #CRUNCH_MVAX0H]
cfmv32al mvfx0, mvax1
cfstr32 mvfx0, [r1, #CRUNCH_MVAX1L]
cfmv32am mvfx0, mvax1
cfstr32 mvfx0, [r1, #CRUNCH_MVAX1M]
cfmv32ah mvfx0, mvax1
cfstr32 mvfx0, [r1, #CRUNCH_MVAX1H]
cfmv32al mvfx0, mvax2
cfstr32 mvfx0, [r1, #CRUNCH_MVAX2L]
cfmv32am mvfx0, mvax2
cfstr32 mvfx0, [r1, #CRUNCH_MVAX2M]
cfmv32ah mvfx0, mvax2
cfstr32 mvfx0, [r1, #CRUNCH_MVAX2H]
cfmv32al mvfx0, mvax3
cfstr32 mvfx0, [r1, #CRUNCH_MVAX3L]
cfmv32am mvfx0, mvax3
cfstr32 mvfx0, [r1, #CRUNCH_MVAX3M]
cfmv32ah mvfx0, mvax3
cfstr32 mvfx0, [r1, #CRUNCH_MVAX3H]
cfmv32sc mvdx0, dspsc @ save status word
cfstr64 mvdx0, [r1, #CRUNCH_DSPSC]
teq r0, #0 @ anything to load?
cfldr64eq mvdx0, [r1, #CRUNCH_MVDX0] @ mvdx0 was clobbered
moveq pc, lr
crunch_load:
cfldr64 mvdx0, [r0, #CRUNCH_DSPSC] @ load status word
cfmvsc32 dspsc, mvdx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX0L] @ load 72b accumulators
cfmval32 mvax0, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX0M]
cfmvam32 mvax0, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX0H]
cfmvah32 mvax0, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX1L]
cfmval32 mvax1, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX1M]
cfmvam32 mvax1, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX1H]
cfmvah32 mvax1, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX2L]
cfmval32 mvax2, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX2M]
cfmvam32 mvax2, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX2H]
cfmvah32 mvax2, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX3L]
cfmval32 mvax3, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX3M]
cfmvam32 mvax3, mvfx0
cfldr32 mvfx0, [r0, #CRUNCH_MVAX3H]
cfmvah32 mvax3, mvfx0
cfldr64 mvdx0, [r0, #CRUNCH_MVDX0] @ load 64b registers
cfldr64 mvdx1, [r0, #CRUNCH_MVDX1]
cfldr64 mvdx2, [r0, #CRUNCH_MVDX2]
cfldr64 mvdx3, [r0, #CRUNCH_MVDX3]
cfldr64 mvdx4, [r0, #CRUNCH_MVDX4]
cfldr64 mvdx5, [r0, #CRUNCH_MVDX5]
cfldr64 mvdx6, [r0, #CRUNCH_MVDX6]
cfldr64 mvdx7, [r0, #CRUNCH_MVDX7]
cfldr64 mvdx8, [r0, #CRUNCH_MVDX8]
cfldr64 mvdx9, [r0, #CRUNCH_MVDX9]
cfldr64 mvdx10, [r0, #CRUNCH_MVDX10]
cfldr64 mvdx11, [r0, #CRUNCH_MVDX11]
cfldr64 mvdx12, [r0, #CRUNCH_MVDX12]
cfldr64 mvdx13, [r0, #CRUNCH_MVDX13]
cfldr64 mvdx14, [r0, #CRUNCH_MVDX14]
cfldr64 mvdx15, [r0, #CRUNCH_MVDX15]
mov pc, lr
/*
* Back up crunch regs to save area and disable access to them
* (mainly for gdb or sleep mode usage)
*
* r0 = struct thread_info pointer of target task or NULL for any
*/
ENTRY(crunch_task_disable)
stmfd sp!, {r4, r5, lr}
mrs ip, cpsr
orr r2, ip, #PSR_I_BIT @ disable interrupts
msr cpsr_c, r2
ldr r4, =(EP93XX_APB_VIRT_BASE + 0x00130000) @ syscon addr
ldr r3, =crunch_owner
add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area
ldr r1, [r3] @ get current crunch owner
teq r1, #0 @ any current owner?
beq 1f @ no: quit
teq r0, #0 @ any owner?
teqne r1, r2 @ or specified one?
bne 1f @ no: quit
ldr r5, [r4, #0x80] @ enable access to crunch
mov r2, #0xaa
str r2, [r4, #0xc0]
orr r5, r5, #0x00800000
str r5, [r4, #0x80]
mov r0, #0 @ nothing to load
str r0, [r3] @ no more current owner
ldr r2, [r4, #0x80] @ flush out enable (@@@)
mov r2, r2
bl crunch_save
mov r2, #0xaa @ disable access to crunch
str r2, [r4, #0xc0]
bic r5, r5, #0x00800000
str r5, [r4, #0x80]
ldr r5, [r4, #0x80] @ flush out enable (@@@)
mov r5, r5
1: msr cpsr_c, ip @ restore interrupt mode
ldmfd sp!, {r4, r5, pc}
/*
* Copy crunch state to given memory address
*
* r0 = struct thread_info pointer of target task
* r1 = memory address where to store crunch state
*
* this is called mainly in the creation of signal stack frames
*/
ENTRY(crunch_task_copy)
mrs ip, cpsr
orr r2, ip, #PSR_I_BIT @ disable interrupts
msr cpsr_c, r2
ldr r3, =crunch_owner
add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area
ldr r3, [r3] @ get current crunch owner
teq r2, r3 @ does this task own it...
beq 1f
@ current crunch values are in the task save area
msr cpsr_c, ip @ restore interrupt mode
mov r0, r1
mov r1, r2
mov r2, #CRUNCH_SIZE
b memcpy
1: @ this task owns crunch regs -- grab a copy from there
mov r0, #0 @ nothing to load
mov r3, lr @ preserve return address
bl crunch_save
msr cpsr_c, ip @ restore interrupt mode
mov pc, r3
/*
* Restore crunch state from given memory address
*
* r0 = struct thread_info pointer of target task
* r1 = memory address where to get crunch state from
*
* this is used to restore crunch state when unwinding a signal stack frame
*/
ENTRY(crunch_task_restore)
mrs ip, cpsr
orr r2, ip, #PSR_I_BIT @ disable interrupts
msr cpsr_c, r2
ldr r3, =crunch_owner
add r2, r0, #TI_CRUNCH_STATE @ get task crunch save area
ldr r3, [r3] @ get current crunch owner
teq r2, r3 @ does this task own it...
beq 1f
@ this task doesn't own crunch regs -- use its save area
msr cpsr_c, ip @ restore interrupt mode
mov r0, r2
mov r2, #CRUNCH_SIZE
b memcpy
1: @ this task owns crunch regs -- load them directly
mov r0, r1
mov r1, #0 @ nothing to save
mov r3, lr @ preserve return address
bl crunch_load
msr cpsr_c, ip @ restore interrupt mode
mov pc, r3

83
arch/arm/kernel/crunch.c Normal file
View file

@ -0,0 +1,83 @@
/*
* arch/arm/kernel/crunch.c
* Cirrus MaverickCrunch context switching and handling
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/arch/ep93xx-regs.h>
#include <asm/thread_notify.h>
#include <asm/io.h>
struct crunch_state *crunch_owner;
void crunch_task_release(struct thread_info *thread)
{
local_irq_disable();
if (crunch_owner == &thread->crunchstate)
crunch_owner = NULL;
local_irq_enable();
}
static int crunch_enabled(u32 devcfg)
{
return !!(devcfg & EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE);
}
static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
{
struct thread_info *thread = (struct thread_info *)t;
struct crunch_state *crunch_state;
u32 devcfg;
crunch_state = &thread->crunchstate;
switch (cmd) {
case THREAD_NOTIFY_FLUSH:
memset(crunch_state, 0, sizeof(*crunch_state));
/*
* FALLTHROUGH: Ensure we don't try to overwrite our newly
* initialised state information on the first fault.
*/
case THREAD_NOTIFY_RELEASE:
crunch_task_release(thread);
break;
case THREAD_NOTIFY_SWITCH:
devcfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
devcfg ^= EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(devcfg, EP93XX_SYSCON_DEVICE_CONFIG);
}
break;
}
return NOTIFY_DONE;
}
static struct notifier_block crunch_notifier_block = {
.notifier_call = crunch_do,
};
static int __init crunch_init(void)
{
thread_register_notifier(&crunch_notifier_block);
return 0;
}
late_initcall(crunch_init);

View file

@ -492,9 +492,15 @@ call_fpe:
b do_fpe @ CP#1 (FPE) b do_fpe @ CP#1 (FPE)
b do_fpe @ CP#2 (FPE) b do_fpe @ CP#2 (FPE)
mov pc, lr @ CP#3 mov pc, lr @ CP#3
#ifdef CONFIG_CRUNCH
b crunch_task_enable @ CP#4 (MaverickCrunch)
b crunch_task_enable @ CP#5 (MaverickCrunch)
b crunch_task_enable @ CP#6 (MaverickCrunch)
#else
mov pc, lr @ CP#4 mov pc, lr @ CP#4
mov pc, lr @ CP#5 mov pc, lr @ CP#5
mov pc, lr @ CP#6 mov pc, lr @ CP#6
#endif
mov pc, lr @ CP#7 mov pc, lr @ CP#7
mov pc, lr @ CP#8 mov pc, lr @ CP#8
mov pc, lr @ CP#9 mov pc, lr @ CP#9

View file

@ -634,6 +634,32 @@ static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp)
#endif #endif
#ifdef CONFIG_CRUNCH
/*
* Get the child Crunch state.
*/
static int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp)
{
struct thread_info *thread = task_thread_info(tsk);
crunch_task_disable(thread); /* force it to ram */
return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE)
? -EFAULT : 0;
}
/*
* Set the child Crunch state.
*/
static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
{
struct thread_info *thread = task_thread_info(tsk);
crunch_task_release(thread); /* force a reload */
return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE)
? -EFAULT : 0;
}
#endif
long arch_ptrace(struct task_struct *child, long request, long addr, long data) long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{ {
unsigned long tmp; unsigned long tmp;
@ -765,6 +791,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
child->ptrace_message = data; child->ptrace_message = data;
break; break;
#ifdef CONFIG_CRUNCH
case PTRACE_GETCRUNCHREGS:
ret = ptrace_getcrunchregs(child, (void __user *)data);
break;
case PTRACE_SETCRUNCHREGS:
ret = ptrace_setcrunchregs(child, (void __user *)data);
break;
#endif
default: default:
ret = ptrace_request(child, request, addr, data); ret = ptrace_request(child, request, addr, data);
break; break;

View file

@ -119,9 +119,24 @@ DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
* Standard memory resources * Standard memory resources
*/ */
static struct resource mem_res[] = { static struct resource mem_res[] = {
{ "Video RAM", 0, 0, IORESOURCE_MEM }, {
{ "Kernel text", 0, 0, IORESOURCE_MEM }, .name = "Video RAM",
{ "Kernel data", 0, 0, IORESOURCE_MEM } .start = 0,
.end = 0,
.flags = IORESOURCE_MEM
},
{
.name = "Kernel text",
.start = 0,
.end = 0,
.flags = IORESOURCE_MEM
},
{
.name = "Kernel data",
.start = 0,
.end = 0,
.flags = IORESOURCE_MEM
}
}; };
#define video_ram mem_res[0] #define video_ram mem_res[0]
@ -129,9 +144,24 @@ static struct resource mem_res[] = {
#define kernel_data mem_res[2] #define kernel_data mem_res[2]
static struct resource io_res[] = { static struct resource io_res[] = {
{ "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY }, {
{ "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY }, .name = "reserved",
{ "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY } .start = 0x3bc,
.end = 0x3be,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
},
{
.name = "reserved",
.start = 0x378,
.end = 0x37f,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
},
{
.name = "reserved",
.start = 0x278,
.end = 0x27f,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
}
}; };
#define lp0 io_res[0] #define lp0 io_res[0]
@ -808,7 +838,7 @@ static int __init topology_init(void)
int cpu; int cpu;
for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu, NULL); register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
return 0; return 0;
} }

View file

@ -132,6 +132,37 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
return ret; return ret;
} }
#ifdef CONFIG_CRUNCH
static int preserve_crunch_context(struct crunch_sigframe *frame)
{
char kbuf[sizeof(*frame) + 8];
struct crunch_sigframe *kframe;
/* the crunch context must be 64 bit aligned */
kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
kframe->magic = CRUNCH_MAGIC;
kframe->size = CRUNCH_STORAGE_SIZE;
crunch_task_copy(current_thread_info(), &kframe->storage);
return __copy_to_user(frame, kframe, sizeof(*frame));
}
static int restore_crunch_context(struct crunch_sigframe *frame)
{
char kbuf[sizeof(*frame) + 8];
struct crunch_sigframe *kframe;
/* the crunch context must be 64 bit aligned */
kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
if (__copy_from_user(kframe, frame, sizeof(*frame)))
return -1;
if (kframe->magic != CRUNCH_MAGIC ||
kframe->size != CRUNCH_STORAGE_SIZE)
return -1;
crunch_task_restore(current_thread_info(), &kframe->storage);
return 0;
}
#endif
#ifdef CONFIG_IWMMXT #ifdef CONFIG_IWMMXT
static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
@ -214,6 +245,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
err |= !valid_user_regs(regs); err |= !valid_user_regs(regs);
aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
#ifdef CONFIG_CRUNCH
if (err == 0)
err |= restore_crunch_context(&aux->crunch);
#endif
#ifdef CONFIG_IWMMXT #ifdef CONFIG_IWMMXT
if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
err |= restore_iwmmxt_context(&aux->iwmmxt); err |= restore_iwmmxt_context(&aux->iwmmxt);
@ -333,6 +368,10 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
#ifdef CONFIG_CRUNCH
if (err == 0)
err |= preserve_crunch_context(&aux->crunch);
#endif
#ifdef CONFIG_IWMMXT #ifdef CONFIG_IWMMXT
if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
err |= preserve_iwmmxt_context(&aux->iwmmxt); err |= preserve_iwmmxt_context(&aux->iwmmxt);

View file

@ -80,6 +80,10 @@ SECTIONS
*(.exit.text) *(.exit.text)
*(.exit.data) *(.exit.data)
*(.exitcall.exit) *(.exitcall.exit)
#ifndef CONFIG_MMU
*(.fixup)
*(__ex_table)
#endif
} }
.text : { /* Real text segment */ .text : { /* Real text segment */
@ -87,7 +91,9 @@ SECTIONS
*(.text) *(.text)
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
#ifdef CONFIG_MMU
*(.fixup) *(.fixup)
#endif
*(.gnu.warning) *(.gnu.warning)
*(.rodata) *(.rodata)
*(.rodata.*) *(.rodata.*)
@ -142,7 +148,9 @@ SECTIONS
*/ */
. = ALIGN(32); . = ALIGN(32);
__start___ex_table = .; __start___ex_table = .;
#ifdef CONFIG_MMU
*(__ex_table) *(__ex_table)
#endif
__stop___ex_table = .; __stop___ex_table = .;
/* /*

View file

@ -6,28 +6,31 @@
lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
copy_page.o delay.o findbit.o memchr.o memcpy.o \ delay.o findbit.o memchr.o memcpy.o \
memmove.o memset.o memzero.o setbit.o \ memmove.o memset.o memzero.o setbit.o \
strncpy_from_user.o strnlen_user.o \ strncpy_from_user.o strnlen_user.o \
strchr.o strrchr.o \ strchr.o strrchr.o \
testchangebit.o testclearbit.o testsetbit.o \ testchangebit.o testclearbit.o testsetbit.o \
getuser.o putuser.o clear_user.o \
ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
ucmpdi2.o lib1funcs.o div64.o sha1.o \ ucmpdi2.o lib1funcs.o div64.o sha1.o \
io-readsb.o io-writesb.o io-readsl.o io-writesl.o io-readsb.o io-writesb.o io-readsl.o io-writesl.o
mmu-y := clear_user.o copy_page.o getuser.o putuser.o
# the code in uaccess.S is not preemption safe and # the code in uaccess.S is not preemption safe and
# probably faster on ARMv3 only # probably faster on ARMv3 only
ifeq ($(CONFIG_PREEMPT),y) ifeq ($(CONFIG_PREEMPT),y)
lib-y += copy_from_user.o copy_to_user.o mmu-y += copy_from_user.o copy_to_user.o
else else
ifneq ($(CONFIG_CPU_32v3),y) ifneq ($(CONFIG_CPU_32v3),y)
lib-y += copy_from_user.o copy_to_user.o mmu-y += copy_from_user.o copy_to_user.o
else else
lib-y += uaccess.o mmu-y += uaccess.o
endif endif
endif endif
lib-$(CONFIG_MMU) += $(mmu-y)
ifeq ($(CONFIG_CPU_32v3),y) ifeq ($(CONFIG_CPU_32v3),y)
lib-y += io-readsw-armv3.o io-writesw-armv3.o lib-y += io-readsw-armv3.o io-writesw-armv3.o
else else

View file

@ -97,16 +97,13 @@ ENTRY(c_backtrace)
b 1007f b 1007f
/* /*
* Fixup for LDMDB * Fixup for LDMDB. Note that this must not be in the fixup section.
*/ */
.section .fixup,"ax"
.align 0
1007: ldr r0, =.Lbad 1007: ldr r0, =.Lbad
mov r1, frame mov r1, frame
bl printk bl printk
ldmfd sp!, {r4 - r8, pc} ldmfd sp!, {r4 - r8, pc}
.ltorg .ltorg
.previous
.section __ex_table,"a" .section __ex_table,"a"
.align 3 .align 3

View file

@ -12,13 +12,13 @@
.text .text
/* Prototype: int __arch_clear_user(void *addr, size_t sz) /* Prototype: int __clear_user(void *addr, size_t sz)
* Purpose : clear some user memory * Purpose : clear some user memory
* Params : addr - user memory address to clear * Params : addr - user memory address to clear
* : sz - number of bytes to clear * : sz - number of bytes to clear
* Returns : number of bytes NOT cleared * Returns : number of bytes NOT cleared
*/ */
ENTRY(__arch_clear_user) ENTRY(__clear_user)
stmfd sp!, {r1, lr} stmfd sp!, {r1, lr}
mov r2, #0 mov r2, #0
cmp r1, #4 cmp r1, #4

View file

@ -16,7 +16,7 @@
/* /*
* Prototype: * Prototype:
* *
* size_t __arch_copy_from_user(void *to, const void *from, size_t n) * size_t __copy_from_user(void *to, const void *from, size_t n)
* *
* Purpose: * Purpose:
* *
@ -83,7 +83,7 @@
.text .text
ENTRY(__arch_copy_from_user) ENTRY(__copy_from_user)
#include "copy_template.S" #include "copy_template.S"

View file

@ -16,7 +16,7 @@
/* /*
* Prototype: * Prototype:
* *
* size_t __arch_copy_to_user(void *to, const void *from, size_t n) * size_t __copy_to_user(void *to, const void *from, size_t n)
* *
* Purpose: * Purpose:
* *
@ -86,7 +86,7 @@
.text .text
ENTRY(__arch_copy_to_user) ENTRY(__copy_to_user)
#include "copy_template.S" #include "copy_template.S"

View file

@ -20,7 +20,7 @@
* returns the number of characters copied (strlen of copied string), * returns the number of characters copied (strlen of copied string),
* -EFAULT on exception, or "len" if we fill the whole buffer * -EFAULT on exception, or "len" if we fill the whole buffer
*/ */
ENTRY(__arch_strncpy_from_user) ENTRY(__strncpy_from_user)
mov ip, r1 mov ip, r1
1: subs r2, r2, #1 1: subs r2, r2, #1
USER( ldrplbt r3, [r1], #1) USER( ldrplbt r3, [r1], #1)

View file

@ -14,13 +14,13 @@
.text .text
.align 5 .align 5
/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n) /* Prototype: unsigned long __strnlen_user(const char *str, long n)
* Purpose : get length of a string in user memory * Purpose : get length of a string in user memory
* Params : str - address of string in user memory * Params : str - address of string in user memory
* Returns : length of string *including terminator* * Returns : length of string *including terminator*
* or zero on exception, or n + 1 if too long * or zero on exception, or n + 1 if too long
*/ */
ENTRY(__arch_strnlen_user) ENTRY(__strnlen_user)
mov r2, r0 mov r2, r0
1: 1:
USER( ldrbt r3, [r0], #1) USER( ldrbt r3, [r0], #1)

View file

@ -19,7 +19,7 @@
#define PAGE_SHIFT 12 #define PAGE_SHIFT 12
/* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) /* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
* Purpose : copy a block to user memory from kernel memory * Purpose : copy a block to user memory from kernel memory
* Params : to - user memory * Params : to - user memory
* : from - kernel memory * : from - kernel memory
@ -39,7 +39,7 @@ USER( strgtbt r3, [r0], #1) @ May fault
sub r2, r2, ip sub r2, r2, ip
b .Lc2u_dest_aligned b .Lc2u_dest_aligned
ENTRY(__arch_copy_to_user) ENTRY(__copy_to_user)
stmfd sp!, {r2, r4 - r7, lr} stmfd sp!, {r2, r4 - r7, lr}
cmp r2, #4 cmp r2, #4
blt .Lc2u_not_enough blt .Lc2u_not_enough
@ -283,7 +283,7 @@ USER( strgtbt r3, [r0], #1) @ May fault
9001: ldmfd sp!, {r0, r4 - r7, pc} 9001: ldmfd sp!, {r0, r4 - r7, pc}
.previous .previous
/* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n); /* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
* Purpose : copy a block from user memory to kernel memory * Purpose : copy a block from user memory to kernel memory
* Params : to - kernel memory * Params : to - kernel memory
* : from - user memory * : from - user memory
@ -302,7 +302,7 @@ USER( ldrgtbt r3, [r1], #1) @ May fault
sub r2, r2, ip sub r2, r2, ip
b .Lcfu_dest_aligned b .Lcfu_dest_aligned
ENTRY(__arch_copy_from_user) ENTRY(__copy_from_user)
stmfd sp!, {r0, r2, r4 - r7, lr} stmfd sp!, {r0, r2, r4 - r7, lr}
cmp r2, #4 cmp r2, #4
blt .Lcfu_not_enough blt .Lcfu_not_enough

View file

@ -2,8 +2,19 @@ if ARCH_EP93XX
menu "Cirrus EP93xx Implementation Options" menu "Cirrus EP93xx Implementation Options"
config CRUNCH
bool "Support for MaverickCrunch"
help
Enable kernel support for MaverickCrunch.
comment "EP93xx Platforms" comment "EP93xx Platforms"
config MACH_EDB9315
bool "Support Cirrus Logic EDB9315"
help
Say 'Y' here if you want your kernel to support the Cirrus
Logic EDB9315 Evaluation Board.
config MACH_GESBC9312 config MACH_GESBC9312
bool "Support Glomation GESBC-9312-sx" bool "Support Glomation GESBC-9312-sx"
help help

View file

@ -6,5 +6,6 @@ obj-m :=
obj-n := obj-n :=
obj- := obj- :=
obj-$(CONFIG_MACH_EDB9315) += edb9315.o
obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o
obj-$(CONFIG_MACH_TS72XX) += ts72xx.o obj-$(CONFIG_MACH_TS72XX) += ts72xx.o

View file

@ -0,0 +1,62 @@
/*
* arch/arm/mach-ep93xx/edb9315.c
* Cirrus Logic EDB9315 support.
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
static struct physmap_flash_data edb9315_flash_data = {
.width = 4,
};
static struct resource edb9315_flash_resource = {
.start = 0x60000000,
.end = 0x61ffffff,
.flags = IORESOURCE_MEM,
};
static struct platform_device edb9315_flash = {
.name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &edb9315_flash_data,
},
.num_resources = 1,
.resource = &edb9315_flash_resource,
};
static void __init edb9315_init_machine(void)
{
ep93xx_init_devices();
platform_device_register(&edb9315_flash);
}
MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
.phys_io = EP93XX_APB_PHYS_BASE,
.io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
.boot_params = 0x00000100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
.timer = &ep93xx_timer,
.init_machine = edb9315_init_machine,
MACHINE_END

View file

@ -30,7 +30,7 @@ static struct physmap_flash_data gesbc9312_flash_data = {
static struct resource gesbc9312_flash_resource = { static struct resource gesbc9312_flash_resource = {
.start = 0x60000000, .start = 0x60000000,
.end = 0x60800000, .end = 0x607fffff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };

View file

@ -118,7 +118,7 @@ static struct physmap_flash_data ts72xx_flash_data = {
static struct resource ts72xx_flash_resource = { static struct resource ts72xx_flash_resource = {
.start = TS72XX_NOR_PHYS_BASE, .start = TS72XX_NOR_PHYS_BASE,
.end = TS72XX_NOR_PHYS_BASE + 0x01000000, .end = TS72XX_NOR_PHYS_BASE + 0x00ffffff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };

View file

@ -59,7 +59,7 @@ static struct physmap_flash_data espresso_flash_data = {
static struct resource espresso_flash_resource = { static struct resource espresso_flash_resource = {
.start = 0x90000000, .start = 0x90000000,
.end = 0x92000000, .end = 0x91ffffff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };

View file

@ -304,7 +304,7 @@ static struct physmap_flash_data ixdp2351_flash_data = {
static struct resource ixdp2351_flash_resource = { static struct resource ixdp2351_flash_resource = {
.start = 0x90000000, .start = 0x90000000,
.end = 0x94000000, .end = 0x93ffffff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };

View file

@ -143,7 +143,7 @@ static struct physmap_flash_data roadrunner_flash_data = {
static struct resource roadrunner_flash_resource = { static struct resource roadrunner_flash_resource = {
.start = 0x90000000, .start = 0x90000000,
.end = 0x94000000, .end = 0x93ffffff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };

View file

@ -88,8 +88,8 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
if (type == IRQT_PROBE) { if (type == IRQT_PROBE) {
/* Don't mess with enabled GPIOs using preconfigured edges or /* Don't mess with enabled GPIOs using preconfigured edges or
GPIOs set to alternate function during probe */ GPIOs set to alternate function or to output during probe */
if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx] | GPDR(gpio)) &
GPIO_bit(gpio)) GPIO_bit(gpio))
return 0; return 0;
if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))

View file

@ -69,6 +69,7 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
s3c_device_i2c.name = "s3c2440-i2c"; s3c_device_i2c.name = "s3c2440-i2c";
s3c_device_nand.name = "s3c2440-nand"; s3c_device_nand.name = "s3c2440-nand";
s3c_device_usbgadget.name = "s3c2440-usbgadget";
} }
void __init s3c244x_init_clocks(int xtal) void __init s3c244x_init_clocks(int xtal)

View file

@ -15,8 +15,8 @@ config CPU_ARM610
select CPU_32v3 select CPU_32v3
select CPU_CACHE_V3 select CPU_CACHE_V3
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V3 select CPU_COPY_V3 if MMU
select CPU_TLB_V3 select CPU_TLB_V3 if MMU
help help
The ARM610 is the successor to the ARM3 processor The ARM610 is the successor to the ARM3 processor
and was produced by VLSI Technology Inc. and was produced by VLSI Technology Inc.
@ -31,8 +31,8 @@ config CPU_ARM710
select CPU_32v3 select CPU_32v3
select CPU_CACHE_V3 select CPU_CACHE_V3
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V3 select CPU_COPY_V3 if MMU
select CPU_TLB_V3 select CPU_TLB_V3 if MMU
help help
A 32-bit RISC microprocessor based on the ARM7 processor core A 32-bit RISC microprocessor based on the ARM7 processor core
designed by Advanced RISC Machines Ltd. The ARM710 is the designed by Advanced RISC Machines Ltd. The ARM710 is the
@ -50,8 +50,8 @@ config CPU_ARM720T
select CPU_ABRT_LV4T select CPU_ABRT_LV4T
select CPU_CACHE_V4 select CPU_CACHE_V4
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WT select CPU_COPY_V4WT if MMU
select CPU_TLB_V4WT select CPU_TLB_V4WT if MMU
help help
A 32-bit RISC processor with 8kByte Cache, Write Buffer and A 32-bit RISC processor with 8kByte Cache, Write Buffer and
MMU built around an ARM7TDMI core. MMU built around an ARM7TDMI core.
@ -68,8 +68,8 @@ config CPU_ARM920T
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
The ARM920T is licensed to be produced by numerous vendors, The ARM920T is licensed to be produced by numerous vendors,
and is used in the Maverick EP9312 and the Samsung S3C2410. and is used in the Maverick EP9312 and the Samsung S3C2410.
@ -89,8 +89,8 @@ config CPU_ARM922T
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
The ARM922T is a version of the ARM920T, but with smaller The ARM922T is a version of the ARM920T, but with smaller
instruction and data caches. It is used in Altera's instruction and data caches. It is used in Altera's
@ -108,8 +108,8 @@ config CPU_ARM925T
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
The ARM925T is a mix between the ARM920T and ARM926T, but with The ARM925T is a mix between the ARM920T and ARM926T, but with
different instruction and data caches. It is used in TI's OMAP different instruction and data caches. It is used in TI's OMAP
@ -126,8 +126,8 @@ config CPU_ARM926T
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV5TJ select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
This is a variant of the ARM920. It has slightly different This is a variant of the ARM920. It has slightly different
instruction sequences for cache and TLB operations. Curiously, instruction sequences for cache and TLB operations. Curiously,
@ -144,8 +144,8 @@ config CPU_ARM1020
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
The ARM1020 is the 32K cached version of the ARM10 processor, The ARM1020 is the 32K cached version of the ARM10 processor,
with an addition of a floating-point unit. with an addition of a floating-point unit.
@ -161,8 +161,8 @@ config CPU_ARM1020E
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
depends on n depends on n
# ARM1022E # ARM1022E
@ -172,8 +172,8 @@ config CPU_ARM1022
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB # can probably do better select CPU_COPY_V4WB if MMU # can probably do better
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
The ARM1022E is an implementation of the ARMv5TE architecture The ARM1022E is an implementation of the ARMv5TE architecture
based upon the ARM10 integer core with a 16KiB L1 Harvard cache, based upon the ARM10 integer core with a 16KiB L1 Harvard cache,
@ -189,8 +189,8 @@ config CPU_ARM1026
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10 select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB # can probably do better select CPU_COPY_V4WB if MMU # can probably do better
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
help help
The ARM1026EJ-S is an implementation of the ARMv5TEJ architecture The ARM1026EJ-S is an implementation of the ARMv5TEJ architecture
based upon the ARM10 integer core. based upon the ARM10 integer core.
@ -207,8 +207,8 @@ config CPU_SA110
select CPU_ABRT_EV4 select CPU_ABRT_EV4
select CPU_CACHE_V4WB select CPU_CACHE_V4WB
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_COPY_V4WB select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WB select CPU_TLB_V4WB if MMU
help help
The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
is available at five speeds ranging from 100 MHz to 233 MHz. is available at five speeds ranging from 100 MHz to 233 MHz.
@ -227,7 +227,7 @@ config CPU_SA1100
select CPU_ABRT_EV4 select CPU_ABRT_EV4
select CPU_CACHE_V4WB select CPU_CACHE_V4WB
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_TLB_V4WB select CPU_TLB_V4WB if MMU
# XScale # XScale
config CPU_XSCALE config CPU_XSCALE
@ -237,7 +237,7 @@ config CPU_XSCALE
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV5T select CPU_ABRT_EV5T
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
# XScale Core Version 3 # XScale Core Version 3
config CPU_XSC3 config CPU_XSC3
@ -247,7 +247,7 @@ config CPU_XSC3
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV5T select CPU_ABRT_EV5T
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
select CPU_TLB_V4WBI select CPU_TLB_V4WBI if MMU
select IO_36 select IO_36
# ARMv6 # ARMv6
@ -258,8 +258,8 @@ config CPU_V6
select CPU_ABRT_EV6 select CPU_ABRT_EV6
select CPU_CACHE_V6 select CPU_CACHE_V6
select CPU_CACHE_VIPT select CPU_CACHE_VIPT
select CPU_COPY_V6 select CPU_COPY_V6 if MMU
select CPU_TLB_V6 select CPU_TLB_V6 if MMU
# ARMv6k # ARMv6k
config CPU_32v6K config CPU_32v6K
@ -277,17 +277,17 @@ config CPU_32v6K
# This defines the compiler instruction set which depends on the machine type. # This defines the compiler instruction set which depends on the machine type.
config CPU_32v3 config CPU_32v3
bool bool
select TLS_REG_EMUL if SMP select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
config CPU_32v4 config CPU_32v4
bool bool
select TLS_REG_EMUL if SMP select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
config CPU_32v5 config CPU_32v5
bool bool
select TLS_REG_EMUL if SMP select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
config CPU_32v6 config CPU_32v6
@ -334,6 +334,7 @@ config CPU_CACHE_VIVT
config CPU_CACHE_VIPT config CPU_CACHE_VIPT
bool bool
if MMU
# The copy-page model # The copy-page model
config CPU_COPY_V3 config CPU_COPY_V3
bool bool
@ -372,6 +373,8 @@ config CPU_TLB_V4WBI
config CPU_TLB_V6 config CPU_TLB_V6
bool bool
endif
# #
# CPU supports 36-bit I/O # CPU supports 36-bit I/O
# #

View file

@ -2,10 +2,16 @@
# Makefile for the linux arm-specific parts of the memory manager. # Makefile for the linux arm-specific parts of the memory manager.
# #
obj-y := consistent.o extable.o fault-armv.o \ obj-y := consistent.o extable.o fault.o init.o \
fault.o flush.o init.o ioremap.o mmap.o \ iomap.o
obj-$(CONFIG_MMU) += fault-armv.o flush.o ioremap.o mmap.o \
mm-armv.o mm-armv.o
ifneq ($(CONFIG_MMU),y)
obj-y += nommu.o
endif
obj-$(CONFIG_MODULES) += proc-syms.o obj-$(CONFIG_MODULES) += proc-syms.o
obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o

View file

@ -26,8 +26,6 @@
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#define TABLE_SIZE (2 * PTRS_PER_PTE * sizeof(pte_t))
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pgd_t swapper_pg_dir[PTRS_PER_PGD];

55
arch/arm/mm/iomap.c Normal file
View file

@ -0,0 +1,55 @@
/*
* linux/arch/arm/mm/iomap.c
*
* Map IO port and PCI memory spaces so that {read,write}[bwl] can
* be used to access this memory.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <asm/io.h>
#ifdef __io
void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
return __io(port);
}
EXPORT_SYMBOL(ioport_map);
void ioport_unmap(void __iomem *addr)
{
}
EXPORT_SYMBOL(ioport_unmap);
#endif
#ifdef CONFIG_PCI
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
unsigned long start = pci_resource_start(dev, bar);
unsigned long len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
return NULL;
if (maxlen && len > maxlen)
len = maxlen;
if (flags & IORESOURCE_IO)
return ioport_map(start, len);
if (flags & IORESOURCE_MEM) {
if (flags & IORESOURCE_CACHEABLE)
return ioremap(start, len);
return ioremap_nocache(start, len);
}
return NULL;
}
EXPORT_SYMBOL(pci_iomap);
void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
{
if ((unsigned long)addr >= VMALLOC_START &&
(unsigned long)addr < VMALLOC_END)
iounmap(addr);
}
EXPORT_SYMBOL(pci_iounmap);
#endif

View file

@ -176,50 +176,3 @@ void __iounmap(void __iomem *addr)
vunmap((void *)(PAGE_MASK & (unsigned long)addr)); vunmap((void *)(PAGE_MASK & (unsigned long)addr));
} }
EXPORT_SYMBOL(__iounmap); EXPORT_SYMBOL(__iounmap);
#ifdef __io
void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
return __io(port);
}
EXPORT_SYMBOL(ioport_map);
void ioport_unmap(void __iomem *addr)
{
}
EXPORT_SYMBOL(ioport_unmap);
#endif
#ifdef CONFIG_PCI
#include <linux/pci.h>
#include <linux/ioport.h>
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
unsigned long start = pci_resource_start(dev, bar);
unsigned long len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
return NULL;
if (maxlen && len > maxlen)
len = maxlen;
if (flags & IORESOURCE_IO)
return ioport_map(start, len);
if (flags & IORESOURCE_MEM) {
if (flags & IORESOURCE_CACHEABLE)
return ioremap(start, len);
return ioremap_nocache(start, len);
}
return NULL;
}
EXPORT_SYMBOL(pci_iomap);
void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
{
if ((unsigned long)addr >= VMALLOC_START &&
(unsigned long)addr < VMALLOC_END)
iounmap(addr);
}
EXPORT_SYMBOL(pci_iounmap);
#endif

39
arch/arm/mm/nommu.c Normal file
View file

@ -0,0 +1,39 @@
/*
* linux/arch/arm/mm/nommu.c
*
* ARM uCLinux supporting functions.
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <asm/cacheflush.h>
#include <asm/io.h>
#include <asm/page.h>
void flush_dcache_page(struct page *page)
{
__cpuc_flush_dcache_page(page_address(page));
}
EXPORT_SYMBOL(flush_dcache_page);
void __iomem *__ioremap_pfn(unsigned long pfn, unsigned long offset,
size_t size, unsigned long flags)
{
if (pfn >= (0x100000000ULL >> PAGE_SHIFT))
return NULL;
return (void __iomem *) (offset + (pfn << PAGE_SHIFT));
}
EXPORT_SYMBOL(__ioremap_pfn);
void __iomem *__ioremap(unsigned long phys_addr, size_t size,
unsigned long flags)
{
return (void __iomem *)phys_addr;
}
EXPORT_SYMBOL(__ioremap);
void __iounmap(void __iomem *addr)
{
}
EXPORT_SYMBOL(__iounmap);

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 2000 ARM Limited * Copyright (C) 2000 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -101,7 +102,9 @@ ENTRY(cpu_arm1020_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -359,6 +362,7 @@ ENTRY(cpu_arm1020_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1020_switch_mm) ENTRY(cpu_arm1020_switch_mm)
#ifdef CONFIG_MMU
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
mcr p15, 0, r3, c7, c10, 4 mcr p15, 0, r3, c7, c10, 4
mov r1, #0xF @ 16 segments mov r1, #0xF @ 16 segments
@ -383,6 +387,7 @@ ENTRY(cpu_arm1020_switch_mm)
mcr p15, 0, r1, c7, c10, 4 @ drain WB mcr p15, 0, r1, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
/* /*
@ -392,6 +397,7 @@ ENTRY(cpu_arm1020_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1020_set_pte) ENTRY(cpu_arm1020_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -421,6 +427,7 @@ ENTRY(cpu_arm1020_set_pte)
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
#endif #endif
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
__INIT __INIT
@ -430,7 +437,9 @@ __arm1020_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, arm1020_cr1_clear ldr r5, arm1020_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 2000 ARM Limited * Copyright (C) 2000 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -101,7 +102,9 @@ ENTRY(cpu_arm1020e_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -344,6 +347,7 @@ ENTRY(cpu_arm1020e_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1020e_switch_mm) ENTRY(cpu_arm1020e_switch_mm)
#ifdef CONFIG_MMU
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
mcr p15, 0, r3, c7, c10, 4 mcr p15, 0, r3, c7, c10, 4
mov r1, #0xF @ 16 segments mov r1, #0xF @ 16 segments
@ -367,6 +371,7 @@ ENTRY(cpu_arm1020e_switch_mm)
mcr p15, 0, r1, c7, c10, 4 @ drain WB mcr p15, 0, r1, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -376,6 +381,7 @@ ENTRY(cpu_arm1020e_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1020e_set_pte) ENTRY(cpu_arm1020e_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -403,6 +409,7 @@ ENTRY(cpu_arm1020e_set_pte)
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
#endif #endif
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
__INIT __INIT
@ -412,7 +419,9 @@ __arm1020e_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, arm1020e_cr1_clear ldr r5, arm1020e_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 2000 ARM Limited * Copyright (C) 2000 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -90,7 +91,9 @@ ENTRY(cpu_arm1022_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -333,6 +336,7 @@ ENTRY(cpu_arm1022_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1022_switch_mm) ENTRY(cpu_arm1022_switch_mm)
#ifdef CONFIG_MMU
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries 1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@ -349,6 +353,7 @@ ENTRY(cpu_arm1022_switch_mm)
mcr p15, 0, r1, c7, c10, 4 @ drain WB mcr p15, 0, r1, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -358,6 +363,7 @@ ENTRY(cpu_arm1022_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1022_set_pte) ENTRY(cpu_arm1022_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -385,6 +391,7 @@ ENTRY(cpu_arm1022_set_pte)
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
#endif #endif
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
__INIT __INIT
@ -394,7 +401,9 @@ __arm1022_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, arm1022_cr1_clear ldr r5, arm1022_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 2000 ARM Limited * Copyright (C) 2000 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -90,7 +91,9 @@ ENTRY(cpu_arm1026_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -327,6 +330,7 @@ ENTRY(cpu_arm1026_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1026_switch_mm) ENTRY(cpu_arm1026_switch_mm)
#ifdef CONFIG_MMU
mov r1, #0 mov r1, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
1: mrc p15, 0, r15, c7, c14, 3 @ test, clean, invalidate 1: mrc p15, 0, r15, c7, c14, 3 @ test, clean, invalidate
@ -338,6 +342,7 @@ ENTRY(cpu_arm1026_switch_mm)
mcr p15, 0, r1, c7, c10, 4 @ drain WB mcr p15, 0, r1, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -347,6 +352,7 @@ ENTRY(cpu_arm1026_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm1026_set_pte) ENTRY(cpu_arm1026_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -374,6 +380,7 @@ ENTRY(cpu_arm1026_set_pte)
#ifndef CONFIG_CPU_DCACHE_DISABLE #ifndef CONFIG_CPU_DCACHE_DISABLE
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
#endif #endif
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
@ -384,8 +391,10 @@ __arm1026_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
mcr p15, 0, r4, c2, c0 @ load page table pointer mcr p15, 0, r4, c2, c0 @ load page table pointer
#endif
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mov r0, #4 @ explicitly disable writeback mov r0, #4 @ explicitly disable writeback
mcr p15, 7, r0, c15, c0, 0 mcr p15, 7, r0, c15, c0, 0

View file

@ -2,6 +2,7 @@
* linux/arch/arm/mm/proc-arm6,7.S * linux/arch/arm/mm/proc-arm6,7.S
* *
* Copyright (C) 1997-2000 Russell King * Copyright (C) 1997-2000 Russell King
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@ -199,10 +200,12 @@ ENTRY(cpu_arm7_do_idle)
*/ */
ENTRY(cpu_arm6_switch_mm) ENTRY(cpu_arm6_switch_mm)
ENTRY(cpu_arm7_switch_mm) ENTRY(cpu_arm7_switch_mm)
#ifdef CONFIG_MMU
mov r1, #0 mov r1, #0
mcr p15, 0, r1, c7, c0, 0 @ flush cache mcr p15, 0, r1, c7, c0, 0 @ flush cache
mcr p15, 0, r0, c2, c0, 0 @ update page table ptr mcr p15, 0, r0, c2, c0, 0 @ update page table ptr
mcr p15, 0, r1, c5, c0, 0 @ flush TLBs mcr p15, 0, r1, c5, c0, 0 @ flush TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -214,6 +217,7 @@ ENTRY(cpu_arm7_switch_mm)
.align 5 .align 5
ENTRY(cpu_arm6_set_pte) ENTRY(cpu_arm6_set_pte)
ENTRY(cpu_arm7_set_pte) ENTRY(cpu_arm7_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -232,6 +236,7 @@ ENTRY(cpu_arm7_set_pte)
movne r2, #0 movne r2, #0
str r2, [r0] @ hardware version str r2, [r0] @ hardware version
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
/* /*
@ -243,7 +248,9 @@ ENTRY(cpu_arm6_reset)
ENTRY(cpu_arm7_reset) ENTRY(cpu_arm7_reset)
mov r1, #0 mov r1, #0
mcr p15, 0, r1, c7, c0, 0 @ flush cache mcr p15, 0, r1, c7, c0, 0 @ flush cache
#ifdef CONFIG_MMU
mcr p15, 0, r1, c5, c0, 0 @ flush TLB mcr p15, 0, r1, c5, c0, 0 @ flush TLB
#endif
mov r1, #0x30 mov r1, #0x30
mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc
mov pc, r0 mov pc, r0
@ -253,19 +260,27 @@ ENTRY(cpu_arm7_reset)
.type __arm6_setup, #function .type __arm6_setup, #function
__arm6_setup: mov r0, #0 __arm6_setup: mov r0, #0
mcr p15, 0, r0, c7, c0 @ flush caches on v3 mcr p15, 0, r0, c7, c0 @ flush caches on v3
#ifdef CONFIG_MMU
mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 mcr p15, 0, r0, c5, c0 @ flush TLBs on v3
mov r0, #0x3d @ . ..RS BLDP WCAM mov r0, #0x3d @ . ..RS BLDP WCAM
orr r0, r0, #0x100 @ . ..01 0011 1101 orr r0, r0, #0x100 @ . ..01 0011 1101
#else
mov r0, #0x3c @ . ..RS BLDP WCA.
#endif
mov pc, lr mov pc, lr
.size __arm6_setup, . - __arm6_setup .size __arm6_setup, . - __arm6_setup
.type __arm7_setup, #function .type __arm7_setup, #function
__arm7_setup: mov r0, #0 __arm7_setup: mov r0, #0
mcr p15, 0, r0, c7, c0 @ flush caches on v3 mcr p15, 0, r0, c7, c0 @ flush caches on v3
#ifdef CONFIG_MMU
mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 mcr p15, 0, r0, c5, c0 @ flush TLBs on v3
mcr p15, 0, r0, c3, c0 @ load domain access register mcr p15, 0, r0, c3, c0 @ load domain access register
mov r0, #0x7d @ . ..RS BLDP WCAM mov r0, #0x7d @ . ..RS BLDP WCAM
orr r0, r0, #0x100 @ . ..01 0111 1101 orr r0, r0, #0x100 @ . ..01 0111 1101
#else
mov r0, #0x7c @ . ..RS BLDP WCA.
#endif
mov pc, lr mov pc, lr
.size __arm7_setup, . - __arm7_setup .size __arm7_setup, . - __arm7_setup

View file

@ -4,6 +4,7 @@
* Copyright (C) 2000 Steve Hill (sjhill@cotw.com) * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
* Rob Scott (rscott@mtrob.fdns.net) * Rob Scott (rscott@mtrob.fdns.net)
* Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd. * Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2004.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -29,6 +30,7 @@
* out of 'proc-arm6,7.S' per RMK discussion * out of 'proc-arm6,7.S' per RMK discussion
* 07-25-2000 SJH Added idle function. * 07-25-2000 SJH Added idle function.
* 08-25-2000 DBS Updated for integration of ARM Ltd version. * 08-25-2000 DBS Updated for integration of ARM Ltd version.
* 04-20-2004 HSC modified for non-paged memory management mode.
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
@ -75,10 +77,12 @@ ENTRY(cpu_arm720_do_idle)
* the new. * the new.
*/ */
ENTRY(cpu_arm720_switch_mm) ENTRY(cpu_arm720_switch_mm)
#ifdef CONFIG_MMU
mov r1, #0 mov r1, #0
mcr p15, 0, r1, c7, c7, 0 @ invalidate cache mcr p15, 0, r1, c7, c7, 0 @ invalidate cache
mcr p15, 0, r0, c2, c0, 0 @ update page table ptr mcr p15, 0, r0, c2, c0, 0 @ update page table ptr
mcr p15, 0, r1, c8, c7, 0 @ flush TLB (v4) mcr p15, 0, r1, c8, c7, 0 @ flush TLB (v4)
#endif
mov pc, lr mov pc, lr
/* /*
@ -89,6 +93,7 @@ ENTRY(cpu_arm720_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm720_set_pte) ENTRY(cpu_arm720_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -107,6 +112,7 @@ ENTRY(cpu_arm720_set_pte)
movne r2, #0 movne r2, #0
str r2, [r0] @ hardware version str r2, [r0] @ hardware version
#endif
mov pc, lr mov pc, lr
/* /*
@ -117,7 +123,9 @@ ENTRY(cpu_arm720_set_pte)
ENTRY(cpu_arm720_reset) ENTRY(cpu_arm720_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate cache mcr p15, 0, ip, c7, c7, 0 @ invalidate cache
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4) mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4)
#endif
mrc p15, 0, ip, c1, c0, 0 @ get ctrl register mrc p15, 0, ip, c1, c0, 0 @ get ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x2100 @ ..v....s........ bic ip, ip, #0x2100 @ ..v....s........
@ -130,7 +138,9 @@ ENTRY(cpu_arm720_reset)
__arm710_setup: __arm710_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ invalidate caches mcr p15, 0, r0, c7, c7, 0 @ invalidate caches
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4)
#endif
mrc p15, 0, r0, c1, c0 @ get control register mrc p15, 0, r0, c1, c0 @ get control register
ldr r5, arm710_cr1_clear ldr r5, arm710_cr1_clear
bic r0, r0, r5 bic r0, r0, r5
@ -156,7 +166,9 @@ arm710_cr1_set:
__arm720_setup: __arm720_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ invalidate caches mcr p15, 0, r0, c7, c7, 0 @ invalidate caches
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4)
#endif
mrc p15, 0, r0, c1, c0 @ get control register mrc p15, 0, r0, c1, c0 @ get control register
ldr r5, arm720_cr1_clear ldr r5, arm720_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 1999,2000 ARM Limited * Copyright (C) 1999,2000 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -97,7 +98,9 @@ ENTRY(cpu_arm920_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -317,6 +320,7 @@ ENTRY(cpu_arm920_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm920_switch_mm) ENTRY(cpu_arm920_switch_mm)
#ifdef CONFIG_MMU
mov ip, #0 mov ip, #0
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
@ -337,6 +341,7 @@ ENTRY(cpu_arm920_switch_mm)
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -346,6 +351,7 @@ ENTRY(cpu_arm920_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm920_set_pte) ENTRY(cpu_arm920_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -372,6 +378,7 @@ ENTRY(cpu_arm920_set_pte)
mov r0, r0 mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
__INIT __INIT
@ -381,7 +388,9 @@ __arm920_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, arm920_cr1_clear ldr r5, arm920_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -4,6 +4,7 @@
* Copyright (C) 1999,2000 ARM Limited * Copyright (C) 1999,2000 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* Copyright (C) 2001 Altera Corporation * Copyright (C) 2001 Altera Corporation
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -99,7 +100,9 @@ ENTRY(cpu_arm922_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -321,6 +324,7 @@ ENTRY(cpu_arm922_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm922_switch_mm) ENTRY(cpu_arm922_switch_mm)
#ifdef CONFIG_MMU
mov ip, #0 mov ip, #0
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
@ -341,6 +345,7 @@ ENTRY(cpu_arm922_switch_mm)
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -350,6 +355,7 @@ ENTRY(cpu_arm922_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm922_set_pte) ENTRY(cpu_arm922_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -376,6 +382,7 @@ ENTRY(cpu_arm922_set_pte)
mov r0, r0 mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
__INIT __INIT
@ -385,7 +392,9 @@ __arm922_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, arm922_cr1_clear ldr r5, arm922_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -9,6 +9,8 @@
* Update for Linux-2.6 and cache flush improvements * Update for Linux-2.6 and cache flush improvements
* Copyright (C) 2004 Nokia Corporation by Tony Lindgren <tony@atomide.com> * Copyright (C) 2004 Nokia Corporation by Tony Lindgren <tony@atomide.com>
* *
* hacked for non-paged-MM by Hyok S. Choi, 2004.
*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -122,7 +124,9 @@ ENTRY(cpu_arm925_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -369,6 +373,7 @@ ENTRY(cpu_arm925_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm925_switch_mm) ENTRY(cpu_arm925_switch_mm)
#ifdef CONFIG_MMU
mov ip, #0 mov ip, #0
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
@ -383,6 +388,7 @@ ENTRY(cpu_arm925_switch_mm)
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -392,6 +398,7 @@ ENTRY(cpu_arm925_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm925_set_pte) ENTRY(cpu_arm925_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -420,6 +427,7 @@ ENTRY(cpu_arm925_set_pte)
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
#endif #endif
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif /* CONFIG_MMU */
mov pc, lr mov pc, lr
__INIT __INIT
@ -438,7 +446,9 @@ __arm925_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mov r0, #4 @ disable write-back on caches explicitly mov r0, #4 @ disable write-back on caches explicitly

View file

@ -3,6 +3,7 @@
* *
* Copyright (C) 1999-2001 ARM Limited * Copyright (C) 1999-2001 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd. * Copyright (C) 2000 Deep Blue Solutions Ltd.
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -85,7 +86,9 @@ ENTRY(cpu_arm926_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -329,6 +332,7 @@ ENTRY(cpu_arm926_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_arm926_switch_mm) ENTRY(cpu_arm926_switch_mm)
#ifdef CONFIG_MMU
mov ip, #0 mov ip, #0
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
@ -341,6 +345,7 @@ ENTRY(cpu_arm926_switch_mm)
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mov pc, lr mov pc, lr
/* /*
@ -350,6 +355,7 @@ ENTRY(cpu_arm926_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_arm926_set_pte) ENTRY(cpu_arm926_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -378,6 +384,7 @@ ENTRY(cpu_arm926_set_pte)
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
#endif #endif
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif
mov pc, lr mov pc, lr
__INIT __INIT
@ -387,7 +394,9 @@ __arm926_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH

View file

@ -2,6 +2,7 @@
* linux/arch/arm/mm/proc-sa110.S * linux/arch/arm/mm/proc-sa110.S
* *
* Copyright (C) 1997-2002 Russell King * Copyright (C) 1997-2002 Russell King
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@ -67,7 +68,9 @@ ENTRY(cpu_sa110_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -130,11 +133,15 @@ ENTRY(cpu_sa110_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_sa110_switch_mm) ENTRY(cpu_sa110_switch_mm)
#ifdef CONFIG_MMU
str lr, [sp, #-4]! str lr, [sp, #-4]!
bl v4wb_flush_kern_cache_all @ clears IP bl v4wb_flush_kern_cache_all @ clears IP
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
ldr pc, [sp], #4 ldr pc, [sp], #4
#else
mov pc, lr
#endif
/* /*
* cpu_sa110_set_pte(ptep, pte) * cpu_sa110_set_pte(ptep, pte)
@ -143,6 +150,7 @@ ENTRY(cpu_sa110_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_sa110_set_pte) ENTRY(cpu_sa110_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -164,6 +172,7 @@ ENTRY(cpu_sa110_set_pte)
mov r0, r0 mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif
mov pc, lr mov pc, lr
__INIT __INIT
@ -173,7 +182,9 @@ __sa110_setup:
mov r10, #0 mov r10, #0
mcr p15, 0, r10, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r10, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r10, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r10, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r10, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r10, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, sa110_cr1_clear ldr r5, sa110_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -2,6 +2,7 @@
* linux/arch/arm/mm/proc-sa1100.S * linux/arch/arm/mm/proc-sa1100.S
* *
* Copyright (C) 1997-2002 Russell King * Copyright (C) 1997-2002 Russell King
* hacked for non-paged-MM by Hyok S. Choi, 2003.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@ -77,7 +78,9 @@ ENTRY(cpu_sa1100_reset)
mov ip, #0 mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........ bic ip, ip, #0x1100 @ ...i...s........
@ -142,12 +145,16 @@ ENTRY(cpu_sa1100_dcache_clean_area)
*/ */
.align 5 .align 5
ENTRY(cpu_sa1100_switch_mm) ENTRY(cpu_sa1100_switch_mm)
#ifdef CONFIG_MMU
str lr, [sp, #-4]! str lr, [sp, #-4]!
bl v4wb_flush_kern_cache_all @ clears IP bl v4wb_flush_kern_cache_all @ clears IP
mcr p15, 0, ip, c9, c0, 0 @ invalidate RB mcr p15, 0, ip, c9, c0, 0 @ invalidate RB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
ldr pc, [sp], #4 ldr pc, [sp], #4
#else
mov pc, lr
#endif
/* /*
* cpu_sa1100_set_pte(ptep, pte) * cpu_sa1100_set_pte(ptep, pte)
@ -156,6 +163,7 @@ ENTRY(cpu_sa1100_switch_mm)
*/ */
.align 5 .align 5
ENTRY(cpu_sa1100_set_pte) ENTRY(cpu_sa1100_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
@ -177,6 +185,7 @@ ENTRY(cpu_sa1100_set_pte)
mov r0, r0 mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c10, 4 @ drain WB mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif
mov pc, lr mov pc, lr
__INIT __INIT
@ -186,7 +195,9 @@ __sa1100_setup:
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
mrc p15, 0, r0, c1, c0 @ get control register v4 mrc p15, 0, r0, c1, c0 @ get control register v4
ldr r5, sa1100_cr1_clear ldr r5, sa1100_cr1_clear
bic r0, r0, r5 bic r0, r0, r5

View file

@ -2,6 +2,7 @@
* linux/arch/arm/mm/proc-v6.S * linux/arch/arm/mm/proc-v6.S
* *
* Copyright (C) 2001 Deep Blue Solutions Ltd. * Copyright (C) 2001 Deep Blue Solutions Ltd.
* Modified by Catalin Marinas for noMMU support
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@ -88,6 +89,7 @@ ENTRY(cpu_v6_dcache_clean_area)
* - we are not using split page tables * - we are not using split page tables
*/ */
ENTRY(cpu_v6_switch_mm) ENTRY(cpu_v6_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0 mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
@ -97,6 +99,7 @@ ENTRY(cpu_v6_switch_mm)
mcr p15, 0, r2, c7, c10, 4 @ drain write buffer mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c2, c0, 0 @ set TTB 0 mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
mcr p15, 0, r1, c13, c0, 1 @ set context ID mcr p15, 0, r1, c13, c0, 1 @ set context ID
#endif
mov pc, lr mov pc, lr
/* /*
@ -119,6 +122,7 @@ ENTRY(cpu_v6_switch_mm)
* 1111 0 1 1 r/w r/w * 1111 0 1 1 r/w r/w
*/ */
ENTRY(cpu_v6_set_pte) ENTRY(cpu_v6_set_pte)
#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version str r1, [r0], #-2048 @ linux version
bic r2, r1, #0x000003f0 bic r2, r1, #0x000003f0
@ -145,6 +149,7 @@ ENTRY(cpu_v6_set_pte)
str r2, [r0] str r2, [r0]
mcr p15, 0, r0, c7, c10, 1 @ flush_pte mcr p15, 0, r0, c7, c10, 1 @ flush_pte
#endif
mov pc, lr mov pc, lr
@ -194,12 +199,14 @@ __v6_setup:
mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r0, c2, c0, 2 @ TTB control register mcr p15, 0, r0, c2, c0, 2 @ TTB control register
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
#endif #endif
mcr p15, 0, r4, c2, c0, 1 @ load TTB1 mcr p15, 0, r4, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
#ifdef CONFIG_VFP #ifdef CONFIG_VFP
mrc p15, 0, r0, c1, c0, 2 mrc p15, 0, r0, c1, c0, 2
orr r0, r0, #(0xf << 20) orr r0, r0, #(0xf << 20)

Some files were not shown because too many files have changed in this diff Show more