Merge /spare/repo/linux-2.6/
This commit is contained in:
commit
905ec87e93
4
COPYING
4
COPYING
@ -18,7 +18,7 @@
|
|||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
@ -46,6 +46,8 @@ SubmittingPatches
|
|||||||
- procedure to get a source patch included into the kernel tree.
|
- procedure to get a source patch included into the kernel tree.
|
||||||
VGA-softcursor.txt
|
VGA-softcursor.txt
|
||||||
- how to change your VGA cursor from a blinking underscore.
|
- how to change your VGA cursor from a blinking underscore.
|
||||||
|
applying-patches.txt
|
||||||
|
- description of various trees and how to apply their patches.
|
||||||
arm/
|
arm/
|
||||||
- directory with info about Linux on the ARM architecture.
|
- directory with info about Linux on the ARM architecture.
|
||||||
basic_profiling.txt
|
basic_profiling.txt
|
||||||
@ -275,7 +277,7 @@ tty.txt
|
|||||||
unicode.txt
|
unicode.txt
|
||||||
- info on the Unicode character/font mapping used in Linux.
|
- info on the Unicode character/font mapping used in Linux.
|
||||||
uml/
|
uml/
|
||||||
- directory with infomation about User Mode Linux.
|
- directory with information about User Mode Linux.
|
||||||
usb/
|
usb/
|
||||||
- directory with info regarding the Universal Serial Bus.
|
- directory with info regarding the Universal Serial Bus.
|
||||||
video4linux/
|
video4linux/
|
||||||
|
@ -236,6 +236,9 @@ ugly), but try to avoid excess. Instead, put the comments at the head
|
|||||||
of the function, telling people what it does, and possibly WHY it does
|
of the function, telling people what it does, and possibly WHY it does
|
||||||
it.
|
it.
|
||||||
|
|
||||||
|
When commenting the kernel API functions, please use the kerneldoc format.
|
||||||
|
See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc
|
||||||
|
for details.
|
||||||
|
|
||||||
Chapter 8: You've made a mess of it
|
Chapter 8: You've made a mess of it
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ pool's device.
|
|||||||
dma_addr_t addr);
|
dma_addr_t addr);
|
||||||
|
|
||||||
This puts memory back into the pool. The pool is what was passed to
|
This puts memory back into the pool. The pool is what was passed to
|
||||||
the the pool allocation routine; the cpu and dma addresses are what
|
the pool allocation routine; the cpu and dma addresses are what
|
||||||
were returned when that routine allocated the memory being freed.
|
were returned when that routine allocated the memory being freed.
|
||||||
|
|
||||||
|
|
||||||
|
151
Documentation/DMA-ISA-LPC.txt
Normal file
151
Documentation/DMA-ISA-LPC.txt
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
DMA with ISA and LPC devices
|
||||||
|
============================
|
||||||
|
|
||||||
|
Pierre Ossman <drzeus@drzeus.cx>
|
||||||
|
|
||||||
|
This document describes how to do DMA transfers using the old ISA DMA
|
||||||
|
controller. Even though ISA is more or less dead today the LPC bus
|
||||||
|
uses the same DMA system so it will be around for quite some time.
|
||||||
|
|
||||||
|
Part I - Headers and dependencies
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
To do ISA style DMA you need to include two headers:
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <asm/dma.h>
|
||||||
|
|
||||||
|
The first is the generic DMA API used to convert virtual addresses to
|
||||||
|
physical addresses (see Documentation/DMA-API.txt for details).
|
||||||
|
|
||||||
|
The second contains the routines specific to ISA DMA transfers. Since
|
||||||
|
this is not present on all platforms make sure you construct your
|
||||||
|
Kconfig to be dependent on ISA_DMA_API (not ISA) so that nobody tries
|
||||||
|
to build your driver on unsupported platforms.
|
||||||
|
|
||||||
|
Part II - Buffer allocation
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The ISA DMA controller has some very strict requirements on which
|
||||||
|
memory it can access so extra care must be taken when allocating
|
||||||
|
buffers.
|
||||||
|
|
||||||
|
(You usually need a special buffer for DMA transfers instead of
|
||||||
|
transferring directly to and from your normal data structures.)
|
||||||
|
|
||||||
|
The DMA-able address space is the lowest 16 MB of _physical_ memory.
|
||||||
|
Also the transfer block may not cross page boundaries (which are 64
|
||||||
|
or 128 KiB depending on which channel you use).
|
||||||
|
|
||||||
|
In order to allocate a piece of memory that satisfies all these
|
||||||
|
requirements you pass the flag GFP_DMA to kmalloc.
|
||||||
|
|
||||||
|
Unfortunately the memory available for ISA DMA is scarce so unless you
|
||||||
|
allocate the memory during boot-up it's a good idea to also pass
|
||||||
|
__GFP_REPEAT and __GFP_NOWARN to make the allocater try a bit harder.
|
||||||
|
|
||||||
|
(This scarcity also means that you should allocate the buffer as
|
||||||
|
early as possible and not release it until the driver is unloaded.)
|
||||||
|
|
||||||
|
Part III - Address translation
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
To translate the virtual address to a physical use the normal DMA
|
||||||
|
API. Do _not_ use isa_virt_to_phys() even though it does the same
|
||||||
|
thing. The reason for this is that the function isa_virt_to_phys()
|
||||||
|
will require a Kconfig dependency to ISA, not just ISA_DMA_API which
|
||||||
|
is really all you need. Remember that even though the DMA controller
|
||||||
|
has its origins in ISA it is used elsewhere.
|
||||||
|
|
||||||
|
Note: x86_64 had a broken DMA API when it came to ISA but has since
|
||||||
|
been fixed. If your arch has problems then fix the DMA API instead of
|
||||||
|
reverting to the ISA functions.
|
||||||
|
|
||||||
|
Part IV - Channels
|
||||||
|
------------------
|
||||||
|
|
||||||
|
A normal ISA DMA controller has 8 channels. The lower four are for
|
||||||
|
8-bit transfers and the upper four are for 16-bit transfers.
|
||||||
|
|
||||||
|
(Actually the DMA controller is really two separate controllers where
|
||||||
|
channel 4 is used to give DMA access for the second controller (0-3).
|
||||||
|
This means that of the four 16-bits channels only three are usable.)
|
||||||
|
|
||||||
|
You allocate these in a similar fashion as all basic resources:
|
||||||
|
|
||||||
|
extern int request_dma(unsigned int dmanr, const char * device_id);
|
||||||
|
extern void free_dma(unsigned int dmanr);
|
||||||
|
|
||||||
|
The ability to use 16-bit or 8-bit transfers is _not_ up to you as a
|
||||||
|
driver author but depends on what the hardware supports. Check your
|
||||||
|
specs or test different channels.
|
||||||
|
|
||||||
|
Part V - Transfer data
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Now for the good stuff, the actual DMA transfer. :)
|
||||||
|
|
||||||
|
Before you use any ISA DMA routines you need to claim the DMA lock
|
||||||
|
using claim_dma_lock(). The reason is that some DMA operations are
|
||||||
|
not atomic so only one driver may fiddle with the registers at a
|
||||||
|
time.
|
||||||
|
|
||||||
|
The first time you use the DMA controller you should call
|
||||||
|
clear_dma_ff(). This clears an internal register in the DMA
|
||||||
|
controller that is used for the non-atomic operations. As long as you
|
||||||
|
(and everyone else) uses the locking functions then you only need to
|
||||||
|
reset this once.
|
||||||
|
|
||||||
|
Next, you tell the controller in which direction you intend to do the
|
||||||
|
transfer using set_dma_mode(). Currently you have the options
|
||||||
|
DMA_MODE_READ and DMA_MODE_WRITE.
|
||||||
|
|
||||||
|
Set the address from where the transfer should start (this needs to
|
||||||
|
be 16-bit aligned for 16-bit transfers) and how many bytes to
|
||||||
|
transfer. Note that it's _bytes_. The DMA routines will do all the
|
||||||
|
required translation to values that the DMA controller understands.
|
||||||
|
|
||||||
|
The final step is enabling the DMA channel and releasing the DMA
|
||||||
|
lock.
|
||||||
|
|
||||||
|
Once the DMA transfer is finished (or timed out) you should disable
|
||||||
|
the channel again. You should also check get_dma_residue() to make
|
||||||
|
sure that all data has been transfered.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
int flags, residue;
|
||||||
|
|
||||||
|
flags = claim_dma_lock();
|
||||||
|
|
||||||
|
clear_dma_ff();
|
||||||
|
|
||||||
|
set_dma_mode(channel, DMA_MODE_WRITE);
|
||||||
|
set_dma_addr(channel, phys_addr);
|
||||||
|
set_dma_count(channel, num_bytes);
|
||||||
|
|
||||||
|
dma_enable(channel);
|
||||||
|
|
||||||
|
release_dma_lock(flags);
|
||||||
|
|
||||||
|
while (!device_done());
|
||||||
|
|
||||||
|
flags = claim_dma_lock();
|
||||||
|
|
||||||
|
dma_disable(channel);
|
||||||
|
|
||||||
|
residue = dma_get_residue(channel);
|
||||||
|
if (residue != 0)
|
||||||
|
printk(KERN_ERR "driver: Incomplete DMA transfer!"
|
||||||
|
" %d bytes left!\n", residue);
|
||||||
|
|
||||||
|
release_dma_lock(flags);
|
||||||
|
|
||||||
|
Part VI - Suspend/resume
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
It is the driver's responsibility to make sure that the machine isn't
|
||||||
|
suspended while a DMA transfer is in progress. Also, all DMA settings
|
||||||
|
are lost when the system suspends so if your driver relies on the DMA
|
||||||
|
controller being in a certain state then you have to restore these
|
||||||
|
registers upon resume.
|
@ -116,7 +116,7 @@ filesystem. Almost.
|
|||||||
|
|
||||||
You still need to actually journal your filesystem changes, this
|
You still need to actually journal your filesystem changes, this
|
||||||
is done by wrapping them into transactions. Additionally you
|
is done by wrapping them into transactions. Additionally you
|
||||||
also need to wrap the modification of each of the the buffers
|
also need to wrap the modification of each of the buffers
|
||||||
with calls to the journal layer, so it knows what the modifications
|
with calls to the journal layer, so it knows what the modifications
|
||||||
you are actually making are. To do this use journal_start() which
|
you are actually making are. To do this use journal_start() which
|
||||||
returns a transaction handle.
|
returns a transaction handle.
|
||||||
@ -128,7 +128,7 @@ and its counterpart journal_stop(), which indicates the end of a transaction
|
|||||||
are nestable calls, so you can reenter a transaction if necessary,
|
are nestable calls, so you can reenter a transaction if necessary,
|
||||||
but remember you must call journal_stop() the same number of times as
|
but remember you must call journal_stop() the same number of times as
|
||||||
journal_start() before the transaction is completed (or more accurately
|
journal_start() before the transaction is completed (or more accurately
|
||||||
leaves the the update phase). Ext3/VFS makes use of this feature to simplify
|
leaves the update phase). Ext3/VFS makes use of this feature to simplify
|
||||||
quota support.
|
quota support.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
<authorgroup>
|
<authorgroup>
|
||||||
<author>
|
<author>
|
||||||
<firstname>Paul</firstname>
|
<firstname>Rusty</firstname>
|
||||||
<othername>Rusty</othername>
|
|
||||||
<surname>Russell</surname>
|
<surname>Russell</surname>
|
||||||
<affiliation>
|
<affiliation>
|
||||||
<address>
|
<address>
|
||||||
@ -20,7 +19,7 @@
|
|||||||
</authorgroup>
|
</authorgroup>
|
||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
<year>2001</year>
|
<year>2005</year>
|
||||||
<holder>Rusty Russell</holder>
|
<holder>Rusty Russell</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
@ -64,7 +63,7 @@
|
|||||||
<chapter id="introduction">
|
<chapter id="introduction">
|
||||||
<title>Introduction</title>
|
<title>Introduction</title>
|
||||||
<para>
|
<para>
|
||||||
Welcome, gentle reader, to Rusty's Unreliable Guide to Linux
|
Welcome, gentle reader, to Rusty's Remarkably Unreliable Guide to Linux
|
||||||
Kernel Hacking. This document describes the common routines and
|
Kernel Hacking. This document describes the common routines and
|
||||||
general requirements for kernel code: its goal is to serve as a
|
general requirements for kernel code: its goal is to serve as a
|
||||||
primer for Linux kernel development for experienced C
|
primer for Linux kernel development for experienced C
|
||||||
@ -96,13 +95,13 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
not associated with any process, serving a softirq, tasklet or bh;
|
not associated with any process, serving a softirq or tasklet;
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
running in kernel space, associated with a process;
|
running in kernel space, associated with a process (user context);
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@ -114,11 +113,12 @@
|
|||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There is a strict ordering between these: other than the last
|
There is an ordering between these. The bottom two can preempt
|
||||||
category (userspace) each can only be pre-empted by those above.
|
each other, but above that is a strict hierarchy: each can only be
|
||||||
For example, while a softirq is running on a CPU, no other
|
preempted by the ones above it. For example, while a softirq is
|
||||||
softirq will pre-empt it, but a hardware interrupt can. However,
|
running on a CPU, no other softirq will preempt it, but a hardware
|
||||||
any other CPUs in the system execute independently.
|
interrupt can. However, any other CPUs in the system execute
|
||||||
|
independently.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -130,10 +130,10 @@
|
|||||||
<title>User Context</title>
|
<title>User Context</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
User context is when you are coming in from a system call or
|
User context is when you are coming in from a system call or other
|
||||||
other trap: you can sleep, and you own the CPU (except for
|
trap: like userspace, you can be preempted by more important tasks
|
||||||
interrupts) until you call <function>schedule()</function>.
|
and by interrupts. You can sleep, by calling
|
||||||
In other words, user context (unlike userspace) is not pre-emptable.
|
<function>schedule()</function>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
<caution>
|
<caution>
|
||||||
<para>
|
<para>
|
||||||
Beware that if you have interrupts or bottom halves disabled
|
Beware that if you have preemption or softirqs disabled
|
||||||
(see below), <function>in_interrupt()</function> will return a
|
(see below), <function>in_interrupt()</function> will return a
|
||||||
false positive.
|
false positive.
|
||||||
</para>
|
</para>
|
||||||
@ -168,10 +168,10 @@
|
|||||||
<hardware>keyboard</hardware> are examples of real
|
<hardware>keyboard</hardware> are examples of real
|
||||||
hardware which produce interrupts at any time. The kernel runs
|
hardware which produce interrupts at any time. The kernel runs
|
||||||
interrupt handlers, which services the hardware. The kernel
|
interrupt handlers, which services the hardware. The kernel
|
||||||
guarantees that this handler is never re-entered: if another
|
guarantees that this handler is never re-entered: if the same
|
||||||
interrupt arrives, it is queued (or dropped). Because it
|
interrupt arrives, it is queued (or dropped). Because it
|
||||||
disables interrupts, this handler has to be fast: frequently it
|
disables interrupts, this handler has to be fast: frequently it
|
||||||
simply acknowledges the interrupt, marks a `software interrupt'
|
simply acknowledges the interrupt, marks a 'software interrupt'
|
||||||
for execution and exits.
|
for execution and exits.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -188,60 +188,52 @@
|
|||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="basics-softirqs">
|
<sect1 id="basics-softirqs">
|
||||||
<title>Software Interrupt Context: Bottom Halves, Tasklets, softirqs</title>
|
<title>Software Interrupt Context: Softirqs and Tasklets</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Whenever a system call is about to return to userspace, or a
|
Whenever a system call is about to return to userspace, or a
|
||||||
hardware interrupt handler exits, any `software interrupts'
|
hardware interrupt handler exits, any 'software interrupts'
|
||||||
which are marked pending (usually by hardware interrupts) are
|
which are marked pending (usually by hardware interrupts) are
|
||||||
run (<filename>kernel/softirq.c</filename>).
|
run (<filename>kernel/softirq.c</filename>).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Much of the real interrupt handling work is done here. Early in
|
Much of the real interrupt handling work is done here. Early in
|
||||||
the transition to <acronym>SMP</acronym>, there were only `bottom
|
the transition to <acronym>SMP</acronym>, there were only 'bottom
|
||||||
halves' (BHs), which didn't take advantage of multiple CPUs. Shortly
|
halves' (BHs), which didn't take advantage of multiple CPUs. Shortly
|
||||||
after we switched from wind-up computers made of match-sticks and snot,
|
after we switched from wind-up computers made of match-sticks and snot,
|
||||||
we abandoned this limitation.
|
we abandoned this limitation and switched to 'softirqs'.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<filename class="headerfile">include/linux/interrupt.h</filename> lists the
|
<filename class="headerfile">include/linux/interrupt.h</filename> lists the
|
||||||
different BH's. No matter how many CPUs you have, no two BHs will run at
|
different softirqs. A very important softirq is the
|
||||||
the same time. This made the transition to SMP simpler, but sucks hard for
|
timer softirq (<filename
|
||||||
scalable performance. A very important bottom half is the timer
|
class="headerfile">include/linux/timer.h</filename>): you can
|
||||||
BH (<filename class="headerfile">include/linux/timer.h</filename>): you
|
register to have it call functions for you in a given length of
|
||||||
can register to have it call functions for you in a given length of time.
|
time.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
2.3.43 introduced softirqs, and re-implemented the (now
|
Softirqs are often a pain to deal with, since the same softirq
|
||||||
deprecated) BHs underneath them. Softirqs are fully-SMP
|
will run simultaneously on more than one CPU. For this reason,
|
||||||
versions of BHs: they can run on as many CPUs at once as
|
tasklets (<filename
|
||||||
required. This means they need to deal with any races in shared
|
class="headerfile">include/linux/interrupt.h</filename>) are more
|
||||||
data using their own locks. A bitmask is used to keep track of
|
often used: they are dynamically-registrable (meaning you can have
|
||||||
which are enabled, so the 32 available softirqs should not be
|
as many as you want), and they also guarantee that any tasklet
|
||||||
used up lightly. (<emphasis>Yes</emphasis>, people will
|
will only run on one CPU at any time, although different tasklets
|
||||||
notice).
|
can run simultaneously.
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
tasklets (<filename class="headerfile">include/linux/interrupt.h</filename>)
|
|
||||||
are like softirqs, except they are dynamically-registrable (meaning you
|
|
||||||
can have as many as you want), and they also guarantee that any tasklet
|
|
||||||
will only run on one CPU at any time, although different tasklets can
|
|
||||||
run simultaneously (unlike different BHs).
|
|
||||||
</para>
|
</para>
|
||||||
<caution>
|
<caution>
|
||||||
<para>
|
<para>
|
||||||
The name `tasklet' is misleading: they have nothing to do with `tasks',
|
The name 'tasklet' is misleading: they have nothing to do with 'tasks',
|
||||||
and probably more to do with some bad vodka Alexey Kuznetsov had at the
|
and probably more to do with some bad vodka Alexey Kuznetsov had at the
|
||||||
time.
|
time.
|
||||||
</para>
|
</para>
|
||||||
</caution>
|
</caution>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You can tell you are in a softirq (or bottom half, or tasklet)
|
You can tell you are in a softirq (or tasklet)
|
||||||
using the <function>in_softirq()</function> macro
|
using the <function>in_softirq()</function> macro
|
||||||
(<filename class="headerfile">include/linux/interrupt.h</filename>).
|
(<filename class="headerfile">include/linux/interrupt.h</filename>).
|
||||||
</para>
|
</para>
|
||||||
@ -288,11 +280,10 @@
|
|||||||
<term>A rigid stack limit</term>
|
<term>A rigid stack limit</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The kernel stack is about 6K in 2.2 (for most
|
Depending on configuration options the kernel stack is about 3K to 6K for most 32-bit architectures: it's
|
||||||
architectures: it's about 14K on the Alpha), and shared
|
about 14K on most 64-bit archs, and often shared with interrupts
|
||||||
with interrupts so you can't use it all. Avoid deep
|
so you can't use it all. Avoid deep recursion and huge local
|
||||||
recursion and huge local arrays on the stack (allocate
|
arrays on the stack (allocate them dynamically instead).
|
||||||
them dynamically instead).
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -339,7 +330,7 @@ asmlinkage long sys_mycall(int arg)
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
If all your routine does is read or write some parameter, consider
|
If all your routine does is read or write some parameter, consider
|
||||||
implementing a <function>sysctl</function> interface instead.
|
implementing a <function>sysfs</function> interface instead.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -417,7 +408,10 @@ cond_resched(); /* Will sleep */
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You will eventually lock up your box if you break these rules.
|
You should always compile your kernel
|
||||||
|
<symbol>CONFIG_DEBUG_SPINLOCK_SLEEP</symbol> on, and it will warn
|
||||||
|
you if you break these rules. If you <emphasis>do</emphasis> break
|
||||||
|
the rules, you will eventually lock up your box.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -515,8 +509,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
success).
|
success).
|
||||||
</para>
|
</para>
|
||||||
</caution>
|
</caution>
|
||||||
[Yes, this moronic interface makes me cringe. Please submit a
|
[Yes, this moronic interface makes me cringe. The flamewar comes up every year or so. --RR.]
|
||||||
patch and become my hero --RR.]
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The functions may sleep implicitly. This should never be called
|
The functions may sleep implicitly. This should never be called
|
||||||
@ -587,10 +580,11 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you see a <errorname>kmem_grow: Called nonatomically from int
|
If you see a <errorname>sleeping function called from invalid
|
||||||
</errorname> warning message you called a memory allocation function
|
context</errorname> warning message, then maybe you called a
|
||||||
from interrupt context without <constant>GFP_ATOMIC</constant>.
|
sleeping allocation function from interrupt context without
|
||||||
You should really fix that. Run, don't walk.
|
<constant>GFP_ATOMIC</constant>. You should really fix that.
|
||||||
|
Run, don't walk.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -639,16 +633,16 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="routines-udelay">
|
<sect1 id="routines-udelay">
|
||||||
<title><function>udelay()</function>/<function>mdelay()</function>
|
<title><function>mdelay()</function>/<function>udelay()</function>
|
||||||
<filename class="headerfile">include/asm/delay.h</filename>
|
<filename class="headerfile">include/asm/delay.h</filename>
|
||||||
<filename class="headerfile">include/linux/delay.h</filename>
|
<filename class="headerfile">include/linux/delay.h</filename>
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <function>udelay()</function> function can be used for small pauses.
|
The <function>udelay()</function> and <function>ndelay()</function> functions can be used for small pauses.
|
||||||
Do not use large values with <function>udelay()</function> as you risk
|
Do not use large values with them as you risk
|
||||||
overflow - the helper function <function>mdelay()</function> is useful
|
overflow - the helper function <function>mdelay()</function> is useful
|
||||||
here, or even consider <function>schedule_timeout()</function>.
|
here, or consider <function>msleep()</function>.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -698,8 +692,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
These routines disable soft interrupts on the local CPU, and
|
These routines disable soft interrupts on the local CPU, and
|
||||||
restore them. They are reentrant; if soft interrupts were
|
restore them. They are reentrant; if soft interrupts were
|
||||||
disabled before, they will still be disabled after this pair
|
disabled before, they will still be disabled after this pair
|
||||||
of functions has been called. They prevent softirqs, tasklets
|
of functions has been called. They prevent softirqs and tasklets
|
||||||
and bottom halves from running on the current CPU.
|
from running on the current CPU.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -708,10 +702,16 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<filename class="headerfile">include/asm/smp.h</filename></title>
|
<filename class="headerfile">include/asm/smp.h</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function>smp_processor_id()</function> returns the current
|
<function>get_cpu()</function> disables preemption (so you won't
|
||||||
processor number, between 0 and <symbol>NR_CPUS</symbol> (the
|
suddenly get moved to another CPU) and returns the current
|
||||||
maximum number of CPUs supported by Linux, currently 32). These
|
processor number, between 0 and <symbol>NR_CPUS</symbol>. Note
|
||||||
values are not necessarily continuous.
|
that the CPU numbers are not necessarily continuous. You return
|
||||||
|
it again with <function>put_cpu()</function> when you are done.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If you know you cannot be preempted by another task (ie. you are
|
||||||
|
in interrupt context, or have preemption disabled) you can use
|
||||||
|
smp_processor_id().
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -722,19 +722,14 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<para>
|
<para>
|
||||||
After boot, the kernel frees up a special section; functions
|
After boot, the kernel frees up a special section; functions
|
||||||
marked with <type>__init</type> and data structures marked with
|
marked with <type>__init</type> and data structures marked with
|
||||||
<type>__initdata</type> are dropped after boot is complete (within
|
<type>__initdata</type> are dropped after boot is complete: similarly
|
||||||
modules this directive is currently ignored). <type>__exit</type>
|
modules discard this memory after initialization. <type>__exit</type>
|
||||||
is used to declare a function which is only required on exit: the
|
is used to declare a function which is only required on exit: the
|
||||||
function will be dropped if this file is not compiled as a module.
|
function will be dropped if this file is not compiled as a module.
|
||||||
See the header file for use. Note that it makes no sense for a function
|
See the header file for use. Note that it makes no sense for a function
|
||||||
marked with <type>__init</type> to be exported to modules with
|
marked with <type>__init</type> to be exported to modules with
|
||||||
<function>EXPORT_SYMBOL()</function> - this will break.
|
<function>EXPORT_SYMBOL()</function> - this will break.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Static data structures marked as <type>__initdata</type> must be initialised
|
|
||||||
(as opposed to ordinary static data which is zeroed BSS) and cannot be
|
|
||||||
<type>const</type>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -762,9 +757,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<para>
|
<para>
|
||||||
The function can return a negative error number to cause
|
The function can return a negative error number to cause
|
||||||
module loading to fail (unfortunately, this has no effect if
|
module loading to fail (unfortunately, this has no effect if
|
||||||
the module is compiled into the kernel). For modules, this is
|
the module is compiled into the kernel). This function is
|
||||||
called in user context, with interrupts enabled, and the
|
called in user context with interrupts enabled, so it can sleep.
|
||||||
kernel lock held, so it can sleep.
|
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -779,6 +773,34 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
reached zero. This function can also sleep, but cannot fail:
|
reached zero. This function can also sleep, but cannot fail:
|
||||||
everything must be cleaned up by the time it returns.
|
everything must be cleaned up by the time it returns.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note that this macro is optional: if it is not present, your
|
||||||
|
module will not be removable (except for 'rmmod -f').
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="routines-module-use-counters">
|
||||||
|
<title> <function>try_module_get()</function>/<function>module_put()</function>
|
||||||
|
<filename class="headerfile">include/linux/module.h</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These manipulate the module usage count, to protect against
|
||||||
|
removal (a module also can't be removed if another module uses one
|
||||||
|
of its exported symbols: see below). Before calling into module
|
||||||
|
code, you should call <function>try_module_get()</function> on
|
||||||
|
that module: if it fails, then the module is being removed and you
|
||||||
|
should act as if it wasn't there. Otherwise, you can safely enter
|
||||||
|
the module, and call <function>module_put()</function> when you're
|
||||||
|
finished.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Most registerable structures have an
|
||||||
|
<structfield>owner</structfield> field, such as in the
|
||||||
|
<structname>file_operations</structname> structure. Set this field
|
||||||
|
to the macro <symbol>THIS_MODULE</symbol>.
|
||||||
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<!-- add info on new-style module refcounting here -->
|
<!-- add info on new-style module refcounting here -->
|
||||||
@ -821,7 +843,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
There is a macro to do this:
|
There is a macro to do this:
|
||||||
<function>wait_event_interruptible()</function>
|
<function>wait_event_interruptible()</function>
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/sched.h</filename> The
|
<filename class="headerfile">include/linux/wait.h</filename> The
|
||||||
first argument is the wait queue head, and the second is an
|
first argument is the wait queue head, and the second is an
|
||||||
expression which is evaluated; the macro returns
|
expression which is evaluated; the macro returns
|
||||||
<returnvalue>0</returnvalue> when this expression is true, or
|
<returnvalue>0</returnvalue> when this expression is true, or
|
||||||
@ -847,10 +869,11 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<para>
|
<para>
|
||||||
Call <function>wake_up()</function>
|
Call <function>wake_up()</function>
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/sched.h</filename>;,
|
<filename class="headerfile">include/linux/wait.h</filename>;,
|
||||||
which will wake up every process in the queue. The exception is
|
which will wake up every process in the queue. The exception is
|
||||||
if one has <constant>TASK_EXCLUSIVE</constant> set, in which case
|
if one has <constant>TASK_EXCLUSIVE</constant> set, in which case
|
||||||
the remainder of the queue will not be woken.
|
the remainder of the queue will not be woken. There are other variants
|
||||||
|
of this basic function available in the same header.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
@ -863,7 +886,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
first class of operations work on <type>atomic_t</type>
|
first class of operations work on <type>atomic_t</type>
|
||||||
|
|
||||||
<filename class="headerfile">include/asm/atomic.h</filename>; this
|
<filename class="headerfile">include/asm/atomic.h</filename>; this
|
||||||
contains a signed integer (at least 24 bits long), and you must use
|
contains a signed integer (at least 32 bits long), and you must use
|
||||||
these functions to manipulate or read atomic_t variables.
|
these functions to manipulate or read atomic_t variables.
|
||||||
<function>atomic_read()</function> and
|
<function>atomic_read()</function> and
|
||||||
<function>atomic_set()</function> get and set the counter,
|
<function>atomic_set()</function> get and set the counter,
|
||||||
@ -882,13 +905,12 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that these functions are slower than normal arithmetic, and
|
Note that these functions are slower than normal arithmetic, and
|
||||||
so should not be used unnecessarily. On some platforms they
|
so should not be used unnecessarily.
|
||||||
are much slower, like 32-bit Sparc where they use a spinlock.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The second class of atomic operations is atomic bit operations on a
|
The second class of atomic operations is atomic bit operations on an
|
||||||
<type>long</type>, defined in
|
<type>unsigned long</type>, defined in
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/bitops.h</filename>. These
|
<filename class="headerfile">include/linux/bitops.h</filename>. These
|
||||||
operations generally take a pointer to the bit pattern, and a bit
|
operations generally take a pointer to the bit pattern, and a bit
|
||||||
@ -899,7 +921,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<function>test_and_clear_bit()</function> and
|
<function>test_and_clear_bit()</function> and
|
||||||
<function>test_and_change_bit()</function> do the same thing,
|
<function>test_and_change_bit()</function> do the same thing,
|
||||||
except return true if the bit was previously set; these are
|
except return true if the bit was previously set; these are
|
||||||
particularly useful for very simple locking.
|
particularly useful for atomically setting flags.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -907,12 +929,6 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
than BITS_PER_LONG. The resulting behavior is strange on big-endian
|
than BITS_PER_LONG. The resulting behavior is strange on big-endian
|
||||||
platforms though so it is a good idea not to do this.
|
platforms though so it is a good idea not to do this.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
Note that the order of bits depends on the architecture, and in
|
|
||||||
particular, the bitfield passed to these operations must be at
|
|
||||||
least as large as a <type>long</type>.
|
|
||||||
</para>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="symbols">
|
<chapter id="symbols">
|
||||||
@ -932,11 +948,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<filename class="headerfile">include/linux/module.h</filename></title>
|
<filename class="headerfile">include/linux/module.h</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This is the classic method of exporting a symbol, and it works
|
This is the classic method of exporting a symbol: dynamically
|
||||||
for both modules and non-modules. In the kernel all these
|
loaded modules will be able to use the symbol as normal.
|
||||||
declarations are often bundled into a single file to help
|
|
||||||
genksyms (which searches source files for these declarations).
|
|
||||||
See the comment on genksyms and Makefiles below.
|
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -949,7 +962,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
symbols exported by <function>EXPORT_SYMBOL_GPL()</function> can
|
symbols exported by <function>EXPORT_SYMBOL_GPL()</function> can
|
||||||
only be seen by modules with a
|
only be seen by modules with a
|
||||||
<function>MODULE_LICENSE()</function> that specifies a GPL
|
<function>MODULE_LICENSE()</function> that specifies a GPL
|
||||||
compatible license.
|
compatible license. It implies that the function is considered
|
||||||
|
an internal implementation issue, and not really an interface.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
@ -962,12 +976,13 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<filename class="headerfile">include/linux/list.h</filename></title>
|
<filename class="headerfile">include/linux/list.h</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are three sets of linked-list routines in the kernel
|
There used to be three sets of linked-list routines in the kernel
|
||||||
headers, but this one seems to be winning out (and Linus has
|
headers, but this one is the winner. If you don't have some
|
||||||
used it). If you don't have some particular pressing need for
|
particular pressing need for a single list, it's a good choice.
|
||||||
a single list, it's a good choice. In fact, I don't care
|
</para>
|
||||||
whether it's a good choice or not, just use it so we can get
|
|
||||||
rid of the others.
|
<para>
|
||||||
|
In particular, <function>list_for_each_entry</function> is useful.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -979,14 +994,13 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
convention, and return <returnvalue>0</returnvalue> for success,
|
convention, and return <returnvalue>0</returnvalue> for success,
|
||||||
and a negative error number
|
and a negative error number
|
||||||
(eg. <returnvalue>-EFAULT</returnvalue>) for failure. This can be
|
(eg. <returnvalue>-EFAULT</returnvalue>) for failure. This can be
|
||||||
unintuitive at first, but it's fairly widespread in the networking
|
unintuitive at first, but it's fairly widespread in the kernel.
|
||||||
code, for example.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The filesystem code uses <function>ERR_PTR()</function>
|
Using <function>ERR_PTR()</function>
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/fs.h</filename>; to
|
<filename class="headerfile">include/linux/err.h</filename>; to
|
||||||
encode a negative error number into a pointer, and
|
encode a negative error number into a pointer, and
|
||||||
<function>IS_ERR()</function> and <function>PTR_ERR()</function>
|
<function>IS_ERR()</function> and <function>PTR_ERR()</function>
|
||||||
to get it back out again: avoids a separate pointer parameter for
|
to get it back out again: avoids a separate pointer parameter for
|
||||||
@ -1040,7 +1054,7 @@ static struct block_device_operations opt_fops = {
|
|||||||
supported, due to lack of general use, but the following are
|
supported, due to lack of general use, but the following are
|
||||||
considered standard (see the GCC info page section "C
|
considered standard (see the GCC info page section "C
|
||||||
Extensions" for more details - Yes, really the info page, the
|
Extensions" for more details - Yes, really the info page, the
|
||||||
man page is only a short summary of the stuff in info):
|
man page is only a short summary of the stuff in info).
|
||||||
</para>
|
</para>
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -1091,7 +1105,7 @@ static struct block_device_operations opt_fops = {
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Function names as strings (__FUNCTION__)
|
Function names as strings (__func__).
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -1164,63 +1178,35 @@ static struct block_device_operations opt_fops = {
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Usually you want a configuration option for your kernel hack.
|
Usually you want a configuration option for your kernel hack.
|
||||||
Edit <filename>Config.in</filename> in the appropriate directory
|
Edit <filename>Kconfig</filename> in the appropriate directory.
|
||||||
(but under <filename>arch/</filename> it's called
|
The Config language is simple to use by cut and paste, and there's
|
||||||
<filename>config.in</filename>). The Config Language used is not
|
complete documentation in
|
||||||
bash, even though it looks like bash; the safe way is to use only
|
<filename>Documentation/kbuild/kconfig-language.txt</filename>.
|
||||||
the constructs that you already see in
|
|
||||||
<filename>Config.in</filename> files (see
|
|
||||||
<filename>Documentation/kbuild/kconfig-language.txt</filename>).
|
|
||||||
It's good to run "make xconfig" at least once to test (because
|
|
||||||
it's the only one with a static parser).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Variables which can be Y or N use <type>bool</type> followed by a
|
|
||||||
tagline and the config define name (which must start with
|
|
||||||
CONFIG_). The <type>tristate</type> function is the same, but
|
|
||||||
allows the answer M (which defines
|
|
||||||
<symbol>CONFIG_foo_MODULE</symbol> in your source, instead of
|
|
||||||
<symbol>CONFIG_FOO</symbol>) if <symbol>CONFIG_MODULES</symbol>
|
|
||||||
is enabled.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You may well want to make your CONFIG option only visible if
|
You may well want to make your CONFIG option only visible if
|
||||||
<symbol>CONFIG_EXPERIMENTAL</symbol> is enabled: this serves as a
|
<symbol>CONFIG_EXPERIMENTAL</symbol> is enabled: this serves as a
|
||||||
warning to users. There many other fancy things you can do: see
|
warning to users. There many other fancy things you can do: see
|
||||||
the various <filename>Config.in</filename> files for ideas.
|
the various <filename>Kconfig</filename> files for ideas.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In your description of the option, make sure you address both the
|
||||||
|
expert user and the user who knows nothing about your feature. Mention
|
||||||
|
incompatibilities and issues here. <emphasis> Definitely
|
||||||
|
</emphasis> end your description with <quote> if in doubt, say N
|
||||||
|
</quote> (or, occasionally, `Y'); this is for people who have no
|
||||||
|
idea what you are talking about.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Edit the <filename>Makefile</filename>: the CONFIG variables are
|
Edit the <filename>Makefile</filename>: the CONFIG variables are
|
||||||
exported here so you can conditionalize compilation with `ifeq'.
|
exported here so you can usually just add a "obj-$(CONFIG_xxx) +=
|
||||||
If your file exports symbols then add the names to
|
xxx.o" line. The syntax is documented in
|
||||||
<varname>export-objs</varname> so that genksyms will find them.
|
<filename>Documentation/kbuild/makefiles.txt</filename>.
|
||||||
<caution>
|
|
||||||
<para>
|
|
||||||
There is a restriction on the kernel build system that objects
|
|
||||||
which export symbols must have globally unique names.
|
|
||||||
If your object does not have a globally unique name then the
|
|
||||||
standard fix is to move the
|
|
||||||
<function>EXPORT_SYMBOL()</function> statements to their own
|
|
||||||
object with a unique name.
|
|
||||||
This is why several systems have separate exporting objects,
|
|
||||||
usually suffixed with ksyms.
|
|
||||||
</para>
|
|
||||||
</caution>
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Document your option in Documentation/Configure.help. Mention
|
|
||||||
incompatibilities and issues here. <emphasis> Definitely
|
|
||||||
</emphasis> end your description with <quote> if in doubt, say N
|
|
||||||
</quote> (or, occasionally, `Y'); this is for people who have no
|
|
||||||
idea what you are talking about.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@ -1253,20 +1239,12 @@ static struct block_device_operations opt_fops = {
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<filename>include/linux/brlock.h:</filename>
|
<filename>include/asm-i386/delay.h:</filename>
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
extern inline void br_read_lock (enum brlock_indices idx)
|
#define ndelay(n) (__builtin_constant_p(n) ? \
|
||||||
{
|
((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
|
||||||
/*
|
__ndelay(n))
|
||||||
* This causes a link-time bug message if an
|
|
||||||
* invalid index is used:
|
|
||||||
*/
|
|
||||||
if (idx >= __BR_END)
|
|
||||||
__br_lock_usage_bug();
|
|
||||||
|
|
||||||
read_lock(&__brlock_array[smp_processor_id()][idx]);
|
|
||||||
}
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -841,7 +841,7 @@ usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
|
|||||||
File modification time is not updated by this request.
|
File modification time is not updated by this request.
|
||||||
</para><para>
|
</para><para>
|
||||||
Those struct members are from some interface descriptor
|
Those struct members are from some interface descriptor
|
||||||
applying to the the current configuration.
|
applying to the current configuration.
|
||||||
The interface number is the bInterfaceNumber value, and
|
The interface number is the bInterfaceNumber value, and
|
||||||
the altsetting number is the bAlternateSetting value.
|
the altsetting number is the bAlternateSetting value.
|
||||||
(This resets each endpoint in the interface.)
|
(This resets each endpoint in the interface.)
|
||||||
|
@ -430,7 +430,7 @@ which may result in system hang. The software driver of specific
|
|||||||
MSI-capable hardware is responsible for whether calling
|
MSI-capable hardware is responsible for whether calling
|
||||||
pci_enable_msi or not. A return of zero indicates the kernel
|
pci_enable_msi or not. A return of zero indicates the kernel
|
||||||
successfully initializes the MSI/MSI-X capability structure of the
|
successfully initializes the MSI/MSI-X capability structure of the
|
||||||
device funtion. The device function is now running on MSI/MSI-X mode.
|
device function. The device function is now running on MSI/MSI-X mode.
|
||||||
|
|
||||||
5.6 How to tell whether MSI/MSI-X is enabled on device function
|
5.6 How to tell whether MSI/MSI-X is enabled on device function
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ Read the F-ing Papers!
|
|||||||
|
|
||||||
|
|
||||||
This document describes RCU-related publications, and is followed by
|
This document describes RCU-related publications, and is followed by
|
||||||
the corresponding bibtex entries.
|
the corresponding bibtex entries. A number of the publications may
|
||||||
|
be found at http://www.rdrop.com/users/paulmck/RCU/.
|
||||||
|
|
||||||
The first thing resembling RCU was published in 1980, when Kung and Lehman
|
The first thing resembling RCU was published in 1980, when Kung and Lehman
|
||||||
[Kung80] recommended use of a garbage collector to defer destruction
|
[Kung80] recommended use of a garbage collector to defer destruction
|
||||||
@ -113,6 +114,10 @@ describing how to make RCU safe for soft-realtime applications [Sarma04c],
|
|||||||
and a paper describing SELinux performance with RCU [JamesMorris04b].
|
and a paper describing SELinux performance with RCU [JamesMorris04b].
|
||||||
|
|
||||||
|
|
||||||
|
2005 has seen further adaptation of RCU to realtime use, permitting
|
||||||
|
preemption of RCU realtime critical sections [PaulMcKenney05a,
|
||||||
|
PaulMcKenney05b].
|
||||||
|
|
||||||
Bibtex Entries
|
Bibtex Entries
|
||||||
|
|
||||||
@article{Kung80
|
@article{Kung80
|
||||||
@ -410,3 +415,32 @@ Oregon Health and Sciences University"
|
|||||||
\url{http://www.livejournal.com/users/james_morris/2153.html}
|
\url{http://www.livejournal.com/users/james_morris/2153.html}
|
||||||
[Viewed December 10, 2004]"
|
[Viewed December 10, 2004]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@unpublished{PaulMcKenney05a
|
||||||
|
,Author="Paul E. McKenney"
|
||||||
|
,Title="{[RFC]} {RCU} and {CONFIG\_PREEMPT\_RT} progress"
|
||||||
|
,month="May"
|
||||||
|
,year="2005"
|
||||||
|
,note="Available:
|
||||||
|
\url{http://lkml.org/lkml/2005/5/9/185}
|
||||||
|
[Viewed May 13, 2005]"
|
||||||
|
,annotation="
|
||||||
|
First publication of working lock-based deferred free patches
|
||||||
|
for the CONFIG_PREEMPT_RT environment.
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
@conference{PaulMcKenney05b
|
||||||
|
,Author="Paul E. McKenney and Dipankar Sarma"
|
||||||
|
,Title="Towards Hard Realtime Response from the Linux Kernel on SMP Hardware"
|
||||||
|
,Booktitle="linux.conf.au 2005"
|
||||||
|
,month="April"
|
||||||
|
,year="2005"
|
||||||
|
,address="Canberra, Australia"
|
||||||
|
,note="Available:
|
||||||
|
\url{http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf}
|
||||||
|
[Viewed May 13, 2005]"
|
||||||
|
,annotation="
|
||||||
|
Realtime turns into making RCU yet more realtime friendly.
|
||||||
|
"
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ is that since there is only one CPU, it should not be necessary to
|
|||||||
wait for anything else to get done, since there are no other CPUs for
|
wait for anything else to get done, since there are no other CPUs for
|
||||||
anything else to be happening on. Although this approach will -sort- -of-
|
anything else to be happening on. Although this approach will -sort- -of-
|
||||||
work a surprising amount of the time, it is a very bad idea in general.
|
work a surprising amount of the time, it is a very bad idea in general.
|
||||||
This document presents two examples that demonstrate exactly how bad an
|
This document presents three examples that demonstrate exactly how bad an
|
||||||
idea this is.
|
idea this is.
|
||||||
|
|
||||||
|
|
||||||
@ -26,6 +26,9 @@ from softirq, the list scan would find itself referencing a newly freed
|
|||||||
element B. This situation can greatly decrease the life expectancy of
|
element B. This situation can greatly decrease the life expectancy of
|
||||||
your kernel.
|
your kernel.
|
||||||
|
|
||||||
|
This same problem can occur if call_rcu() is invoked from a hardware
|
||||||
|
interrupt handler.
|
||||||
|
|
||||||
|
|
||||||
Example 2: Function-Call Fatality
|
Example 2: Function-Call Fatality
|
||||||
|
|
||||||
@ -44,8 +47,37 @@ its arguments would cause it to fail to make the fundamental guarantee
|
|||||||
underlying RCU, namely that call_rcu() defers invoking its arguments until
|
underlying RCU, namely that call_rcu() defers invoking its arguments until
|
||||||
all RCU read-side critical sections currently executing have completed.
|
all RCU read-side critical sections currently executing have completed.
|
||||||
|
|
||||||
Quick Quiz: why is it -not- legal to invoke synchronize_rcu() in
|
Quick Quiz #1: why is it -not- legal to invoke synchronize_rcu() in
|
||||||
this case?
|
this case?
|
||||||
|
|
||||||
|
|
||||||
|
Example 3: Death by Deadlock
|
||||||
|
|
||||||
|
Suppose that call_rcu() is invoked while holding a lock, and that the
|
||||||
|
callback function must acquire this same lock. In this case, if
|
||||||
|
call_rcu() were to directly invoke the callback, the result would
|
||||||
|
be self-deadlock.
|
||||||
|
|
||||||
|
In some cases, it would possible to restructure to code so that
|
||||||
|
the call_rcu() is delayed until after the lock is released. However,
|
||||||
|
there are cases where this can be quite ugly:
|
||||||
|
|
||||||
|
1. If a number of items need to be passed to call_rcu() within
|
||||||
|
the same critical section, then the code would need to create
|
||||||
|
a list of them, then traverse the list once the lock was
|
||||||
|
released.
|
||||||
|
|
||||||
|
2. In some cases, the lock will be held across some kernel API,
|
||||||
|
so that delaying the call_rcu() until the lock is released
|
||||||
|
requires that the data item be passed up via a common API.
|
||||||
|
It is far better to guarantee that callbacks are invoked
|
||||||
|
with no locks held than to have to modify such APIs to allow
|
||||||
|
arbitrary data items to be passed back up through them.
|
||||||
|
|
||||||
|
If call_rcu() directly invokes the callback, painful locking restrictions
|
||||||
|
or API changes would be required.
|
||||||
|
|
||||||
|
Quick Quiz #2: What locking restriction must RCU callbacks respect?
|
||||||
|
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
@ -53,12 +85,35 @@ Summary
|
|||||||
Permitting call_rcu() to immediately invoke its arguments or permitting
|
Permitting call_rcu() to immediately invoke its arguments or permitting
|
||||||
synchronize_rcu() to immediately return breaks RCU, even on a UP system.
|
synchronize_rcu() to immediately return breaks RCU, even on a UP system.
|
||||||
So do not do it! Even on a UP system, the RCU infrastructure -must-
|
So do not do it! Even on a UP system, the RCU infrastructure -must-
|
||||||
respect grace periods.
|
respect grace periods, and -must- invoke callbacks from a known environment
|
||||||
|
in which no locks are held.
|
||||||
|
|
||||||
|
|
||||||
Answer to Quick Quiz
|
Answer to Quick Quiz #1:
|
||||||
|
Why is it -not- legal to invoke synchronize_rcu() in this case?
|
||||||
|
|
||||||
The calling function is scanning an RCU-protected linked list, and
|
Because the calling function is scanning an RCU-protected linked
|
||||||
is therefore within an RCU read-side critical section. Therefore,
|
list, and is therefore within an RCU read-side critical section.
|
||||||
the called function has been invoked within an RCU read-side critical
|
Therefore, the called function has been invoked within an RCU
|
||||||
section, and is not permitted to block.
|
read-side critical section, and is not permitted to block.
|
||||||
|
|
||||||
|
Answer to Quick Quiz #2:
|
||||||
|
What locking restriction must RCU callbacks respect?
|
||||||
|
|
||||||
|
Any lock that is acquired within an RCU callback must be
|
||||||
|
acquired elsewhere using an _irq variant of the spinlock
|
||||||
|
primitive. For example, if "mylock" is acquired by an
|
||||||
|
RCU callback, then a process-context acquisition of this
|
||||||
|
lock must use something like spin_lock_irqsave() to
|
||||||
|
acquire the lock.
|
||||||
|
|
||||||
|
If the process-context code were to simply use spin_lock(),
|
||||||
|
then, since RCU callbacks can be invoked from softirq context,
|
||||||
|
the callback might be called from a softirq that interrupted
|
||||||
|
the process-context critical section. This would result in
|
||||||
|
self-deadlock.
|
||||||
|
|
||||||
|
This restriction might seem gratuitous, since very few RCU
|
||||||
|
callbacks acquire locks directly. However, a great many RCU
|
||||||
|
callbacks do acquire locks -indirectly-, for example, via
|
||||||
|
the kfree() primitive.
|
||||||
|
@ -43,6 +43,10 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
rcu_read_lock_bh()) in the read-side critical sections,
|
rcu_read_lock_bh()) in the read-side critical sections,
|
||||||
and are also an excellent aid to readability.
|
and are also an excellent aid to readability.
|
||||||
|
|
||||||
|
As a rough rule of thumb, any dereference of an RCU-protected
|
||||||
|
pointer must be covered by rcu_read_lock() or rcu_read_lock_bh()
|
||||||
|
or by the appropriate update-side lock.
|
||||||
|
|
||||||
3. Does the update code tolerate concurrent accesses?
|
3. Does the update code tolerate concurrent accesses?
|
||||||
|
|
||||||
The whole point of RCU is to permit readers to run without
|
The whole point of RCU is to permit readers to run without
|
||||||
@ -90,7 +94,11 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
|
|
||||||
The rcu_dereference() primitive is used by the various
|
The rcu_dereference() primitive is used by the various
|
||||||
"_rcu()" list-traversal primitives, such as the
|
"_rcu()" list-traversal primitives, such as the
|
||||||
list_for_each_entry_rcu().
|
list_for_each_entry_rcu(). Note that it is perfectly
|
||||||
|
legal (if redundant) for update-side code to use
|
||||||
|
rcu_dereference() and the "_rcu()" list-traversal
|
||||||
|
primitives. This is particularly useful in code
|
||||||
|
that is common to readers and updaters.
|
||||||
|
|
||||||
b. If the list macros are being used, the list_add_tail_rcu()
|
b. If the list macros are being used, the list_add_tail_rcu()
|
||||||
and list_add_rcu() primitives must be used in order
|
and list_add_rcu() primitives must be used in order
|
||||||
@ -150,16 +158,9 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
|
|
||||||
Use of the _rcu() list-traversal primitives outside of an
|
Use of the _rcu() list-traversal primitives outside of an
|
||||||
RCU read-side critical section causes no harm other than
|
RCU read-side critical section causes no harm other than
|
||||||
a slight performance degradation on Alpha CPUs and some
|
a slight performance degradation on Alpha CPUs. It can
|
||||||
confusion on the part of people trying to read the code.
|
also be quite helpful in reducing code bloat when common
|
||||||
|
code is shared between readers and updaters.
|
||||||
Another way of thinking of this is "If you are holding the
|
|
||||||
lock that prevents the data structure from changing, why do
|
|
||||||
you also need RCU-based protection?" That said, there may
|
|
||||||
well be situations where use of the _rcu() list-traversal
|
|
||||||
primitives while the update-side lock is held results in
|
|
||||||
simpler and more maintainable code. The jury is still out
|
|
||||||
on this question.
|
|
||||||
|
|
||||||
10. Conversely, if you are in an RCU read-side critical section,
|
10. Conversely, if you are in an RCU read-side critical section,
|
||||||
you -must- use the "_rcu()" variants of the list macros.
|
you -must- use the "_rcu()" variants of the list macros.
|
||||||
|
@ -64,6 +64,54 @@ o I hear that RCU is patented? What is with that?
|
|||||||
Of these, one was allowed to lapse by the assignee, and the
|
Of these, one was allowed to lapse by the assignee, and the
|
||||||
others have been contributed to the Linux kernel under GPL.
|
others have been contributed to the Linux kernel under GPL.
|
||||||
|
|
||||||
|
o I hear that RCU needs work in order to support realtime kernels?
|
||||||
|
|
||||||
|
Yes, work in progress.
|
||||||
|
|
||||||
o Where can I find more information on RCU?
|
o Where can I find more information on RCU?
|
||||||
|
|
||||||
See the RTFP.txt file in this directory.
|
See the RTFP.txt file in this directory.
|
||||||
|
Or point your browser at http://www.rdrop.com/users/paulmck/RCU/.
|
||||||
|
|
||||||
|
o What are all these files in this directory?
|
||||||
|
|
||||||
|
|
||||||
|
NMI-RCU.txt
|
||||||
|
|
||||||
|
Describes how to use RCU to implement dynamic
|
||||||
|
NMI handlers, which can be revectored on the fly,
|
||||||
|
without rebooting.
|
||||||
|
|
||||||
|
RTFP.txt
|
||||||
|
|
||||||
|
List of RCU-related publications and web sites.
|
||||||
|
|
||||||
|
UP.txt
|
||||||
|
|
||||||
|
Discussion of RCU usage in UP kernels.
|
||||||
|
|
||||||
|
arrayRCU.txt
|
||||||
|
|
||||||
|
Describes how to use RCU to protect arrays, with
|
||||||
|
resizeable arrays whose elements reference other
|
||||||
|
data structures being of the most interest.
|
||||||
|
|
||||||
|
checklist.txt
|
||||||
|
|
||||||
|
Lists things to check for when inspecting code that
|
||||||
|
uses RCU.
|
||||||
|
|
||||||
|
listRCU.txt
|
||||||
|
|
||||||
|
Describes how to use RCU to protect linked lists.
|
||||||
|
This is the simplest and most common use of RCU
|
||||||
|
in the Linux kernel.
|
||||||
|
|
||||||
|
rcu.txt
|
||||||
|
|
||||||
|
You are reading it!
|
||||||
|
|
||||||
|
whatisRCU.txt
|
||||||
|
|
||||||
|
Overview of how the RCU implementation works. Along
|
||||||
|
the way, presents a conceptual view of RCU.
|
||||||
|
74
Documentation/RCU/rcuref.txt
Normal file
74
Documentation/RCU/rcuref.txt
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
Refcounter framework for elements of lists/arrays protected by
|
||||||
|
RCU.
|
||||||
|
|
||||||
|
Refcounting on elements of lists which are protected by traditional
|
||||||
|
reader/writer spinlocks or semaphores are straight forward as in:
|
||||||
|
|
||||||
|
1. 2.
|
||||||
|
add() search_and_reference()
|
||||||
|
{ {
|
||||||
|
alloc_object read_lock(&list_lock);
|
||||||
|
... search_for_element
|
||||||
|
atomic_set(&el->rc, 1); atomic_inc(&el->rc);
|
||||||
|
write_lock(&list_lock); ...
|
||||||
|
add_element read_unlock(&list_lock);
|
||||||
|
... ...
|
||||||
|
write_unlock(&list_lock); }
|
||||||
|
}
|
||||||
|
|
||||||
|
3. 4.
|
||||||
|
release_referenced() delete()
|
||||||
|
{ {
|
||||||
|
... write_lock(&list_lock);
|
||||||
|
atomic_dec(&el->rc, relfunc) ...
|
||||||
|
... delete_element
|
||||||
|
} write_unlock(&list_lock);
|
||||||
|
...
|
||||||
|
if (atomic_dec_and_test(&el->rc))
|
||||||
|
kfree(el);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
If this list/array is made lock free using rcu as in changing the
|
||||||
|
write_lock in add() and delete() to spin_lock and changing read_lock
|
||||||
|
in search_and_reference to rcu_read_lock(), the rcuref_get in
|
||||||
|
search_and_reference could potentially hold reference to an element which
|
||||||
|
has already been deleted from the list/array. rcuref_lf_get_rcu takes
|
||||||
|
care of this scenario. search_and_reference should look as;
|
||||||
|
|
||||||
|
1. 2.
|
||||||
|
add() search_and_reference()
|
||||||
|
{ {
|
||||||
|
alloc_object rcu_read_lock();
|
||||||
|
... search_for_element
|
||||||
|
atomic_set(&el->rc, 1); if (rcuref_inc_lf(&el->rc)) {
|
||||||
|
write_lock(&list_lock); rcu_read_unlock();
|
||||||
|
return FAIL;
|
||||||
|
add_element }
|
||||||
|
... ...
|
||||||
|
write_unlock(&list_lock); rcu_read_unlock();
|
||||||
|
} }
|
||||||
|
3. 4.
|
||||||
|
release_referenced() delete()
|
||||||
|
{ {
|
||||||
|
... write_lock(&list_lock);
|
||||||
|
rcuref_dec(&el->rc, relfunc) ...
|
||||||
|
... delete_element
|
||||||
|
} write_unlock(&list_lock);
|
||||||
|
...
|
||||||
|
if (rcuref_dec_and_test(&el->rc))
|
||||||
|
call_rcu(&el->head, el_free);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Sometimes, reference to the element need to be obtained in the
|
||||||
|
update (write) stream. In such cases, rcuref_inc_lf might be an overkill
|
||||||
|
since the spinlock serialising list updates are held. rcuref_inc
|
||||||
|
is to be used in such cases.
|
||||||
|
For arches which do not have cmpxchg rcuref_inc_lf
|
||||||
|
api uses a hashed spinlock implementation and the same hashed spinlock
|
||||||
|
is acquired in all rcuref_xxx primitives to preserve atomicity.
|
||||||
|
Note: Use rcuref_inc api only if you need to use rcuref_inc_lf on the
|
||||||
|
refcounter atleast at one place. Mixing rcuref_inc and atomic_xxx api
|
||||||
|
might lead to races. rcuref_inc_lf() must be used in lockfree
|
||||||
|
RCU critical sections only.
|
902
Documentation/RCU/whatisRCU.txt
Normal file
902
Documentation/RCU/whatisRCU.txt
Normal file
@ -0,0 +1,902 @@
|
|||||||
|
What is RCU?
|
||||||
|
|
||||||
|
RCU is a synchronization mechanism that was added to the Linux kernel
|
||||||
|
during the 2.5 development effort that is optimized for read-mostly
|
||||||
|
situations. Although RCU is actually quite simple once you understand it,
|
||||||
|
getting there can sometimes be a challenge. Part of the problem is that
|
||||||
|
most of the past descriptions of RCU have been written with the mistaken
|
||||||
|
assumption that there is "one true way" to describe RCU. Instead,
|
||||||
|
the experience has been that different people must take different paths
|
||||||
|
to arrive at an understanding of RCU. This document provides several
|
||||||
|
different paths, as follows:
|
||||||
|
|
||||||
|
1. RCU OVERVIEW
|
||||||
|
2. WHAT IS RCU'S CORE API?
|
||||||
|
3. WHAT ARE SOME EXAMPLE USES OF CORE RCU API?
|
||||||
|
4. WHAT IF MY UPDATING THREAD CANNOT BLOCK?
|
||||||
|
5. WHAT ARE SOME SIMPLE IMPLEMENTATIONS OF RCU?
|
||||||
|
6. ANALOGY WITH READER-WRITER LOCKING
|
||||||
|
7. FULL LIST OF RCU APIs
|
||||||
|
8. ANSWERS TO QUICK QUIZZES
|
||||||
|
|
||||||
|
People who prefer starting with a conceptual overview should focus on
|
||||||
|
Section 1, though most readers will profit by reading this section at
|
||||||
|
some point. People who prefer to start with an API that they can then
|
||||||
|
experiment with should focus on Section 2. People who prefer to start
|
||||||
|
with example uses should focus on Sections 3 and 4. People who need to
|
||||||
|
understand the RCU implementation should focus on Section 5, then dive
|
||||||
|
into the kernel source code. People who reason best by analogy should
|
||||||
|
focus on Section 6. Section 7 serves as an index to the docbook API
|
||||||
|
documentation, and Section 8 is the traditional answer key.
|
||||||
|
|
||||||
|
So, start with the section that makes the most sense to you and your
|
||||||
|
preferred method of learning. If you need to know everything about
|
||||||
|
everything, feel free to read the whole thing -- but if you are really
|
||||||
|
that type of person, you have perused the source code and will therefore
|
||||||
|
never need this document anyway. ;-)
|
||||||
|
|
||||||
|
|
||||||
|
1. RCU OVERVIEW
|
||||||
|
|
||||||
|
The basic idea behind RCU is to split updates into "removal" and
|
||||||
|
"reclamation" phases. The removal phase removes references to data items
|
||||||
|
within a data structure (possibly by replacing them with references to
|
||||||
|
new versions of these data items), and can run concurrently with readers.
|
||||||
|
The reason that it is safe to run the removal phase concurrently with
|
||||||
|
readers is the semantics of modern CPUs guarantee that readers will see
|
||||||
|
either the old or the new version of the data structure rather than a
|
||||||
|
partially updated reference. The reclamation phase does the work of reclaiming
|
||||||
|
(e.g., freeing) the data items removed from the data structure during the
|
||||||
|
removal phase. Because reclaiming data items can disrupt any readers
|
||||||
|
concurrently referencing those data items, the reclamation phase must
|
||||||
|
not start until readers no longer hold references to those data items.
|
||||||
|
|
||||||
|
Splitting the update into removal and reclamation phases permits the
|
||||||
|
updater to perform the removal phase immediately, and to defer the
|
||||||
|
reclamation phase until all readers active during the removal phase have
|
||||||
|
completed, either by blocking until they finish or by registering a
|
||||||
|
callback that is invoked after they finish. Only readers that are active
|
||||||
|
during the removal phase need be considered, because any reader starting
|
||||||
|
after the removal phase will be unable to gain a reference to the removed
|
||||||
|
data items, and therefore cannot be disrupted by the reclamation phase.
|
||||||
|
|
||||||
|
So the typical RCU update sequence goes something like the following:
|
||||||
|
|
||||||
|
a. Remove pointers to a data structure, so that subsequent
|
||||||
|
readers cannot gain a reference to it.
|
||||||
|
|
||||||
|
b. Wait for all previous readers to complete their RCU read-side
|
||||||
|
critical sections.
|
||||||
|
|
||||||
|
c. At this point, there cannot be any readers who hold references
|
||||||
|
to the data structure, so it now may safely be reclaimed
|
||||||
|
(e.g., kfree()d).
|
||||||
|
|
||||||
|
Step (b) above is the key idea underlying RCU's deferred destruction.
|
||||||
|
The ability to wait until all readers are done allows RCU readers to
|
||||||
|
use much lighter-weight synchronization, in some cases, absolutely no
|
||||||
|
synchronization at all. In contrast, in more conventional lock-based
|
||||||
|
schemes, readers must use heavy-weight synchronization in order to
|
||||||
|
prevent an updater from deleting the data structure out from under them.
|
||||||
|
This is because lock-based updaters typically update data items in place,
|
||||||
|
and must therefore exclude readers. In contrast, RCU-based updaters
|
||||||
|
typically take advantage of the fact that writes to single aligned
|
||||||
|
pointers are atomic on modern CPUs, allowing atomic insertion, removal,
|
||||||
|
and replacement of data items in a linked structure without disrupting
|
||||||
|
readers. Concurrent RCU readers can then continue accessing the old
|
||||||
|
versions, and can dispense with the atomic operations, memory barriers,
|
||||||
|
and communications cache misses that are so expensive on present-day
|
||||||
|
SMP computer systems, even in absence of lock contention.
|
||||||
|
|
||||||
|
In the three-step procedure shown above, the updater is performing both
|
||||||
|
the removal and the reclamation step, but it is often helpful for an
|
||||||
|
entirely different thread to do the reclamation, as is in fact the case
|
||||||
|
in the Linux kernel's directory-entry cache (dcache). Even if the same
|
||||||
|
thread performs both the update step (step (a) above) and the reclamation
|
||||||
|
step (step (c) above), it is often helpful to think of them separately.
|
||||||
|
For example, RCU readers and updaters need not communicate at all,
|
||||||
|
but RCU provides implicit low-overhead communication between readers
|
||||||
|
and reclaimers, namely, in step (b) above.
|
||||||
|
|
||||||
|
So how the heck can a reclaimer tell when a reader is done, given
|
||||||
|
that readers are not doing any sort of synchronization operations???
|
||||||
|
Read on to learn about how RCU's API makes this easy.
|
||||||
|
|
||||||
|
|
||||||
|
2. WHAT IS RCU'S CORE API?
|
||||||
|
|
||||||
|
The core RCU API is quite small:
|
||||||
|
|
||||||
|
a. rcu_read_lock()
|
||||||
|
b. rcu_read_unlock()
|
||||||
|
c. synchronize_rcu() / call_rcu()
|
||||||
|
d. rcu_assign_pointer()
|
||||||
|
e. rcu_dereference()
|
||||||
|
|
||||||
|
There are many other members of the RCU API, but the rest can be
|
||||||
|
expressed in terms of these five, though most implementations instead
|
||||||
|
express synchronize_rcu() in terms of the call_rcu() callback API.
|
||||||
|
|
||||||
|
The five core RCU APIs are described below, the other 18 will be enumerated
|
||||||
|
later. See the kernel docbook documentation for more info, or look directly
|
||||||
|
at the function header comments.
|
||||||
|
|
||||||
|
rcu_read_lock()
|
||||||
|
|
||||||
|
void rcu_read_lock(void);
|
||||||
|
|
||||||
|
Used by a reader to inform the reclaimer that the reader is
|
||||||
|
entering an RCU read-side critical section. It is illegal
|
||||||
|
to block while in an RCU read-side critical section, though
|
||||||
|
kernels built with CONFIG_PREEMPT_RCU can preempt RCU read-side
|
||||||
|
critical sections. Any RCU-protected data structure accessed
|
||||||
|
during an RCU read-side critical section is guaranteed to remain
|
||||||
|
unreclaimed for the full duration of that critical section.
|
||||||
|
Reference counts may be used in conjunction with RCU to maintain
|
||||||
|
longer-term references to data structures.
|
||||||
|
|
||||||
|
rcu_read_unlock()
|
||||||
|
|
||||||
|
void rcu_read_unlock(void);
|
||||||
|
|
||||||
|
Used by a reader to inform the reclaimer that the reader is
|
||||||
|
exiting an RCU read-side critical section. Note that RCU
|
||||||
|
read-side critical sections may be nested and/or overlapping.
|
||||||
|
|
||||||
|
synchronize_rcu()
|
||||||
|
|
||||||
|
void synchronize_rcu(void);
|
||||||
|
|
||||||
|
Marks the end of updater code and the beginning of reclaimer
|
||||||
|
code. It does this by blocking until all pre-existing RCU
|
||||||
|
read-side critical sections on all CPUs have completed.
|
||||||
|
Note that synchronize_rcu() will -not- necessarily wait for
|
||||||
|
any subsequent RCU read-side critical sections to complete.
|
||||||
|
For example, consider the following sequence of events:
|
||||||
|
|
||||||
|
CPU 0 CPU 1 CPU 2
|
||||||
|
----------------- ------------------------- ---------------
|
||||||
|
1. rcu_read_lock()
|
||||||
|
2. enters synchronize_rcu()
|
||||||
|
3. rcu_read_lock()
|
||||||
|
4. rcu_read_unlock()
|
||||||
|
5. exits synchronize_rcu()
|
||||||
|
6. rcu_read_unlock()
|
||||||
|
|
||||||
|
To reiterate, synchronize_rcu() waits only for ongoing RCU
|
||||||
|
read-side critical sections to complete, not necessarily for
|
||||||
|
any that begin after synchronize_rcu() is invoked.
|
||||||
|
|
||||||
|
Of course, synchronize_rcu() does not necessarily return
|
||||||
|
-immediately- after the last pre-existing RCU read-side critical
|
||||||
|
section completes. For one thing, there might well be scheduling
|
||||||
|
delays. For another thing, many RCU implementations process
|
||||||
|
requests in batches in order to improve efficiencies, which can
|
||||||
|
further delay synchronize_rcu().
|
||||||
|
|
||||||
|
Since synchronize_rcu() is the API that must figure out when
|
||||||
|
readers are done, its implementation is key to RCU. For RCU
|
||||||
|
to be useful in all but the most read-intensive situations,
|
||||||
|
synchronize_rcu()'s overhead must also be quite small.
|
||||||
|
|
||||||
|
The call_rcu() API is a callback form of synchronize_rcu(),
|
||||||
|
and is described in more detail in a later section. Instead of
|
||||||
|
blocking, it registers a function and argument which are invoked
|
||||||
|
after all ongoing RCU read-side critical sections have completed.
|
||||||
|
This callback variant is particularly useful in situations where
|
||||||
|
it is illegal to block.
|
||||||
|
|
||||||
|
rcu_assign_pointer()
|
||||||
|
|
||||||
|
typeof(p) rcu_assign_pointer(p, typeof(p) v);
|
||||||
|
|
||||||
|
Yes, rcu_assign_pointer() -is- implemented as a macro, though it
|
||||||
|
would be cool to be able to declare a function in this manner.
|
||||||
|
(Compiler experts will no doubt disagree.)
|
||||||
|
|
||||||
|
The updater uses this function to assign a new value to an
|
||||||
|
RCU-protected pointer, in order to safely communicate the change
|
||||||
|
in value from the updater to the reader. This function returns
|
||||||
|
the new value, and also executes any memory-barrier instructions
|
||||||
|
required for a given CPU architecture.
|
||||||
|
|
||||||
|
Perhaps more important, it serves to document which pointers
|
||||||
|
are protected by RCU. That said, rcu_assign_pointer() is most
|
||||||
|
frequently used indirectly, via the _rcu list-manipulation
|
||||||
|
primitives such as list_add_rcu().
|
||||||
|
|
||||||
|
rcu_dereference()
|
||||||
|
|
||||||
|
typeof(p) rcu_dereference(p);
|
||||||
|
|
||||||
|
Like rcu_assign_pointer(), rcu_dereference() must be implemented
|
||||||
|
as a macro.
|
||||||
|
|
||||||
|
The reader uses rcu_dereference() to fetch an RCU-protected
|
||||||
|
pointer, which returns a value that may then be safely
|
||||||
|
dereferenced. Note that rcu_deference() does not actually
|
||||||
|
dereference the pointer, instead, it protects the pointer for
|
||||||
|
later dereferencing. It also executes any needed memory-barrier
|
||||||
|
instructions for a given CPU architecture. Currently, only Alpha
|
||||||
|
needs memory barriers within rcu_dereference() -- on other CPUs,
|
||||||
|
it compiles to nothing, not even a compiler directive.
|
||||||
|
|
||||||
|
Common coding practice uses rcu_dereference() to copy an
|
||||||
|
RCU-protected pointer to a local variable, then dereferences
|
||||||
|
this local variable, for example as follows:
|
||||||
|
|
||||||
|
p = rcu_dereference(head.next);
|
||||||
|
return p->data;
|
||||||
|
|
||||||
|
However, in this case, one could just as easily combine these
|
||||||
|
into one statement:
|
||||||
|
|
||||||
|
return rcu_dereference(head.next)->data;
|
||||||
|
|
||||||
|
If you are going to be fetching multiple fields from the
|
||||||
|
RCU-protected structure, using the local variable is of
|
||||||
|
course preferred. Repeated rcu_dereference() calls look
|
||||||
|
ugly and incur unnecessary overhead on Alpha CPUs.
|
||||||
|
|
||||||
|
Note that the value returned by rcu_dereference() is valid
|
||||||
|
only within the enclosing RCU read-side critical section.
|
||||||
|
For example, the following is -not- legal:
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
p = rcu_dereference(head.next);
|
||||||
|
rcu_read_unlock();
|
||||||
|
x = p->address;
|
||||||
|
rcu_read_lock();
|
||||||
|
y = p->data;
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
Holding a reference from one RCU read-side critical section
|
||||||
|
to another is just as illegal as holding a reference from
|
||||||
|
one lock-based critical section to another! Similarly,
|
||||||
|
using a reference outside of the critical section in which
|
||||||
|
it was acquired is just as illegal as doing so with normal
|
||||||
|
locking.
|
||||||
|
|
||||||
|
As with rcu_assign_pointer(), an important function of
|
||||||
|
rcu_dereference() is to document which pointers are protected
|
||||||
|
by RCU. And, again like rcu_assign_pointer(), rcu_dereference()
|
||||||
|
is typically used indirectly, via the _rcu list-manipulation
|
||||||
|
primitives, such as list_for_each_entry_rcu().
|
||||||
|
|
||||||
|
The following diagram shows how each API communicates among the
|
||||||
|
reader, updater, and reclaimer.
|
||||||
|
|
||||||
|
|
||||||
|
rcu_assign_pointer()
|
||||||
|
+--------+
|
||||||
|
+---------------------->| reader |---------+
|
||||||
|
| +--------+ |
|
||||||
|
| | |
|
||||||
|
| | | Protect:
|
||||||
|
| | | rcu_read_lock()
|
||||||
|
| | | rcu_read_unlock()
|
||||||
|
| rcu_dereference() | |
|
||||||
|
+---------+ | |
|
||||||
|
| updater |<---------------------+ |
|
||||||
|
+---------+ V
|
||||||
|
| +-----------+
|
||||||
|
+----------------------------------->| reclaimer |
|
||||||
|
+-----------+
|
||||||
|
Defer:
|
||||||
|
synchronize_rcu() & call_rcu()
|
||||||
|
|
||||||
|
|
||||||
|
The RCU infrastructure observes the time sequence of rcu_read_lock(),
|
||||||
|
rcu_read_unlock(), synchronize_rcu(), and call_rcu() invocations in
|
||||||
|
order to determine when (1) synchronize_rcu() invocations may return
|
||||||
|
to their callers and (2) call_rcu() callbacks may be invoked. Efficient
|
||||||
|
implementations of the RCU infrastructure make heavy use of batching in
|
||||||
|
order to amortize their overhead over many uses of the corresponding APIs.
|
||||||
|
|
||||||
|
There are no fewer than three RCU mechanisms in the Linux kernel; the
|
||||||
|
diagram above shows the first one, which is by far the most commonly used.
|
||||||
|
The rcu_dereference() and rcu_assign_pointer() primitives are used for
|
||||||
|
all three mechanisms, but different defer and protect primitives are
|
||||||
|
used as follows:
|
||||||
|
|
||||||
|
Defer Protect
|
||||||
|
|
||||||
|
a. synchronize_rcu() rcu_read_lock() / rcu_read_unlock()
|
||||||
|
call_rcu()
|
||||||
|
|
||||||
|
b. call_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh()
|
||||||
|
|
||||||
|
c. synchronize_sched() preempt_disable() / preempt_enable()
|
||||||
|
local_irq_save() / local_irq_restore()
|
||||||
|
hardirq enter / hardirq exit
|
||||||
|
NMI enter / NMI exit
|
||||||
|
|
||||||
|
These three mechanisms are used as follows:
|
||||||
|
|
||||||
|
a. RCU applied to normal data structures.
|
||||||
|
|
||||||
|
b. RCU applied to networking data structures that may be subjected
|
||||||
|
to remote denial-of-service attacks.
|
||||||
|
|
||||||
|
c. RCU applied to scheduler and interrupt/NMI-handler tasks.
|
||||||
|
|
||||||
|
Again, most uses will be of (a). The (b) and (c) cases are important
|
||||||
|
for specialized uses, but are relatively uncommon.
|
||||||
|
|
||||||
|
|
||||||
|
3. WHAT ARE SOME EXAMPLE USES OF CORE RCU API?
|
||||||
|
|
||||||
|
This section shows a simple use of the core RCU API to protect a
|
||||||
|
global pointer to a dynamically allocated structure. More typical
|
||||||
|
uses of RCU may be found in listRCU.txt, arrayRCU.txt, and NMI-RCU.txt.
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
int a;
|
||||||
|
char b;
|
||||||
|
long c;
|
||||||
|
};
|
||||||
|
DEFINE_SPINLOCK(foo_mutex);
|
||||||
|
|
||||||
|
struct foo *gbl_foo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new struct foo that is the same as the one currently
|
||||||
|
* pointed to by gbl_foo, except that field "a" is replaced
|
||||||
|
* with "new_a". Points gbl_foo to the new structure, and
|
||||||
|
* frees up the old structure after a grace period.
|
||||||
|
*
|
||||||
|
* Uses rcu_assign_pointer() to ensure that concurrent readers
|
||||||
|
* see the initialized version of the new structure.
|
||||||
|
*
|
||||||
|
* Uses synchronize_rcu() to ensure that any readers that might
|
||||||
|
* have references to the old structure complete before freeing
|
||||||
|
* the old structure.
|
||||||
|
*/
|
||||||
|
void foo_update_a(int new_a)
|
||||||
|
{
|
||||||
|
struct foo *new_fp;
|
||||||
|
struct foo *old_fp;
|
||||||
|
|
||||||
|
new_fp = kmalloc(sizeof(*fp), GFP_KERNEL);
|
||||||
|
spin_lock(&foo_mutex);
|
||||||
|
old_fp = gbl_foo;
|
||||||
|
*new_fp = *old_fp;
|
||||||
|
new_fp->a = new_a;
|
||||||
|
rcu_assign_pointer(gbl_foo, new_fp);
|
||||||
|
spin_unlock(&foo_mutex);
|
||||||
|
synchronize_rcu();
|
||||||
|
kfree(old_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the value of field "a" of the current gbl_foo
|
||||||
|
* structure. Use rcu_read_lock() and rcu_read_unlock()
|
||||||
|
* to ensure that the structure does not get deleted out
|
||||||
|
* from under us, and use rcu_dereference() to ensure that
|
||||||
|
* we see the initialized version of the structure (important
|
||||||
|
* for DEC Alpha and for people reading the code).
|
||||||
|
*/
|
||||||
|
int foo_get_a(void)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
retval = rcu_dereference(gbl_foo)->a;
|
||||||
|
rcu_read_unlock();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
So, to sum up:
|
||||||
|
|
||||||
|
o Use rcu_read_lock() and rcu_read_unlock() to guard RCU
|
||||||
|
read-side critical sections.
|
||||||
|
|
||||||
|
o Within an RCU read-side critical section, use rcu_dereference()
|
||||||
|
to dereference RCU-protected pointers.
|
||||||
|
|
||||||
|
o Use some solid scheme (such as locks or semaphores) to
|
||||||
|
keep concurrent updates from interfering with each other.
|
||||||
|
|
||||||
|
o Use rcu_assign_pointer() to update an RCU-protected pointer.
|
||||||
|
This primitive protects concurrent readers from the updater,
|
||||||
|
-not- concurrent updates from each other! You therefore still
|
||||||
|
need to use locking (or something similar) to keep concurrent
|
||||||
|
rcu_assign_pointer() primitives from interfering with each other.
|
||||||
|
|
||||||
|
o Use synchronize_rcu() -after- removing a data element from an
|
||||||
|
RCU-protected data structure, but -before- reclaiming/freeing
|
||||||
|
the data element, in order to wait for the completion of all
|
||||||
|
RCU read-side critical sections that might be referencing that
|
||||||
|
data item.
|
||||||
|
|
||||||
|
See checklist.txt for additional rules to follow when using RCU.
|
||||||
|
|
||||||
|
|
||||||
|
4. WHAT IF MY UPDATING THREAD CANNOT BLOCK?
|
||||||
|
|
||||||
|
In the example above, foo_update_a() blocks until a grace period elapses.
|
||||||
|
This is quite simple, but in some cases one cannot afford to wait so
|
||||||
|
long -- there might be other high-priority work to be done.
|
||||||
|
|
||||||
|
In such cases, one uses call_rcu() rather than synchronize_rcu().
|
||||||
|
The call_rcu() API is as follows:
|
||||||
|
|
||||||
|
void call_rcu(struct rcu_head * head,
|
||||||
|
void (*func)(struct rcu_head *head));
|
||||||
|
|
||||||
|
This function invokes func(head) after a grace period has elapsed.
|
||||||
|
This invocation might happen from either softirq or process context,
|
||||||
|
so the function is not permitted to block. The foo struct needs to
|
||||||
|
have an rcu_head structure added, perhaps as follows:
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
int a;
|
||||||
|
char b;
|
||||||
|
long c;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
};
|
||||||
|
|
||||||
|
The foo_update_a() function might then be written as follows:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new struct foo that is the same as the one currently
|
||||||
|
* pointed to by gbl_foo, except that field "a" is replaced
|
||||||
|
* with "new_a". Points gbl_foo to the new structure, and
|
||||||
|
* frees up the old structure after a grace period.
|
||||||
|
*
|
||||||
|
* Uses rcu_assign_pointer() to ensure that concurrent readers
|
||||||
|
* see the initialized version of the new structure.
|
||||||
|
*
|
||||||
|
* Uses call_rcu() to ensure that any readers that might have
|
||||||
|
* references to the old structure complete before freeing the
|
||||||
|
* old structure.
|
||||||
|
*/
|
||||||
|
void foo_update_a(int new_a)
|
||||||
|
{
|
||||||
|
struct foo *new_fp;
|
||||||
|
struct foo *old_fp;
|
||||||
|
|
||||||
|
new_fp = kmalloc(sizeof(*fp), GFP_KERNEL);
|
||||||
|
spin_lock(&foo_mutex);
|
||||||
|
old_fp = gbl_foo;
|
||||||
|
*new_fp = *old_fp;
|
||||||
|
new_fp->a = new_a;
|
||||||
|
rcu_assign_pointer(gbl_foo, new_fp);
|
||||||
|
spin_unlock(&foo_mutex);
|
||||||
|
call_rcu(&old_fp->rcu, foo_reclaim);
|
||||||
|
}
|
||||||
|
|
||||||
|
The foo_reclaim() function might appear as follows:
|
||||||
|
|
||||||
|
void foo_reclaim(struct rcu_head *rp)
|
||||||
|
{
|
||||||
|
struct foo *fp = container_of(rp, struct foo, rcu);
|
||||||
|
|
||||||
|
kfree(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
The container_of() primitive is a macro that, given a pointer into a
|
||||||
|
struct, the type of the struct, and the pointed-to field within the
|
||||||
|
struct, returns a pointer to the beginning of the struct.
|
||||||
|
|
||||||
|
The use of call_rcu() permits the caller of foo_update_a() to
|
||||||
|
immediately regain control, without needing to worry further about the
|
||||||
|
old version of the newly updated element. It also clearly shows the
|
||||||
|
RCU distinction between updater, namely foo_update_a(), and reclaimer,
|
||||||
|
namely foo_reclaim().
|
||||||
|
|
||||||
|
The summary of advice is the same as for the previous section, except
|
||||||
|
that we are now using call_rcu() rather than synchronize_rcu():
|
||||||
|
|
||||||
|
o Use call_rcu() -after- removing a data element from an
|
||||||
|
RCU-protected data structure in order to register a callback
|
||||||
|
function that will be invoked after the completion of all RCU
|
||||||
|
read-side critical sections that might be referencing that
|
||||||
|
data item.
|
||||||
|
|
||||||
|
Again, see checklist.txt for additional rules governing the use of RCU.
|
||||||
|
|
||||||
|
|
||||||
|
5. WHAT ARE SOME SIMPLE IMPLEMENTATIONS OF RCU?
|
||||||
|
|
||||||
|
One of the nice things about RCU is that it has extremely simple "toy"
|
||||||
|
implementations that are a good first step towards understanding the
|
||||||
|
production-quality implementations in the Linux kernel. This section
|
||||||
|
presents two such "toy" implementations of RCU, one that is implemented
|
||||||
|
in terms of familiar locking primitives, and another that more closely
|
||||||
|
resembles "classic" RCU. Both are way too simple for real-world use,
|
||||||
|
lacking both functionality and performance. However, they are useful
|
||||||
|
in getting a feel for how RCU works. See kernel/rcupdate.c for a
|
||||||
|
production-quality implementation, and see:
|
||||||
|
|
||||||
|
http://www.rdrop.com/users/paulmck/RCU
|
||||||
|
|
||||||
|
for papers describing the Linux kernel RCU implementation. The OLS'01
|
||||||
|
and OLS'02 papers are a good introduction, and the dissertation provides
|
||||||
|
more details on the current implementation.
|
||||||
|
|
||||||
|
|
||||||
|
5A. "TOY" IMPLEMENTATION #1: LOCKING
|
||||||
|
|
||||||
|
This section presents a "toy" RCU implementation that is based on
|
||||||
|
familiar locking primitives. Its overhead makes it a non-starter for
|
||||||
|
real-life use, as does its lack of scalability. It is also unsuitable
|
||||||
|
for realtime use, since it allows scheduling latency to "bleed" from
|
||||||
|
one read-side critical section to another.
|
||||||
|
|
||||||
|
However, it is probably the easiest implementation to relate to, so is
|
||||||
|
a good starting point.
|
||||||
|
|
||||||
|
It is extremely simple:
|
||||||
|
|
||||||
|
static DEFINE_RWLOCK(rcu_gp_mutex);
|
||||||
|
|
||||||
|
void rcu_read_lock(void)
|
||||||
|
{
|
||||||
|
read_lock(&rcu_gp_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rcu_read_unlock(void)
|
||||||
|
{
|
||||||
|
read_unlock(&rcu_gp_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronize_rcu(void)
|
||||||
|
{
|
||||||
|
write_lock(&rcu_gp_mutex);
|
||||||
|
write_unlock(&rcu_gp_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[You can ignore rcu_assign_pointer() and rcu_dereference() without
|
||||||
|
missing much. But here they are anyway. And whatever you do, don't
|
||||||
|
forget about them when submitting patches making use of RCU!]
|
||||||
|
|
||||||
|
#define rcu_assign_pointer(p, v) ({ \
|
||||||
|
smp_wmb(); \
|
||||||
|
(p) = (v); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define rcu_dereference(p) ({ \
|
||||||
|
typeof(p) _________p1 = p; \
|
||||||
|
smp_read_barrier_depends(); \
|
||||||
|
(_________p1); \
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
The rcu_read_lock() and rcu_read_unlock() primitive read-acquire
|
||||||
|
and release a global reader-writer lock. The synchronize_rcu()
|
||||||
|
primitive write-acquires this same lock, then immediately releases
|
||||||
|
it. This means that once synchronize_rcu() exits, all RCU read-side
|
||||||
|
critical sections that were in progress before synchonize_rcu() was
|
||||||
|
called are guaranteed to have completed -- there is no way that
|
||||||
|
synchronize_rcu() would have been able to write-acquire the lock
|
||||||
|
otherwise.
|
||||||
|
|
||||||
|
It is possible to nest rcu_read_lock(), since reader-writer locks may
|
||||||
|
be recursively acquired. Note also that rcu_read_lock() is immune
|
||||||
|
from deadlock (an important property of RCU). The reason for this is
|
||||||
|
that the only thing that can block rcu_read_lock() is a synchronize_rcu().
|
||||||
|
But synchronize_rcu() does not acquire any locks while holding rcu_gp_mutex,
|
||||||
|
so there can be no deadlock cycle.
|
||||||
|
|
||||||
|
Quick Quiz #1: Why is this argument naive? How could a deadlock
|
||||||
|
occur when using this algorithm in a real-world Linux
|
||||||
|
kernel? How could this deadlock be avoided?
|
||||||
|
|
||||||
|
|
||||||
|
5B. "TOY" EXAMPLE #2: CLASSIC RCU
|
||||||
|
|
||||||
|
This section presents a "toy" RCU implementation that is based on
|
||||||
|
"classic RCU". It is also short on performance (but only for updates) and
|
||||||
|
on features such as hotplug CPU and the ability to run in CONFIG_PREEMPT
|
||||||
|
kernels. The definitions of rcu_dereference() and rcu_assign_pointer()
|
||||||
|
are the same as those shown in the preceding section, so they are omitted.
|
||||||
|
|
||||||
|
void rcu_read_lock(void) { }
|
||||||
|
|
||||||
|
void rcu_read_unlock(void) { }
|
||||||
|
|
||||||
|
void synchronize_rcu(void)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
for_each_cpu(cpu)
|
||||||
|
run_on(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that rcu_read_lock() and rcu_read_unlock() do absolutely nothing.
|
||||||
|
This is the great strength of classic RCU in a non-preemptive kernel:
|
||||||
|
read-side overhead is precisely zero, at least on non-Alpha CPUs.
|
||||||
|
And there is absolutely no way that rcu_read_lock() can possibly
|
||||||
|
participate in a deadlock cycle!
|
||||||
|
|
||||||
|
The implementation of synchronize_rcu() simply schedules itself on each
|
||||||
|
CPU in turn. The run_on() primitive can be implemented straightforwardly
|
||||||
|
in terms of the sched_setaffinity() primitive. Of course, a somewhat less
|
||||||
|
"toy" implementation would restore the affinity upon completion rather
|
||||||
|
than just leaving all tasks running on the last CPU, but when I said
|
||||||
|
"toy", I meant -toy-!
|
||||||
|
|
||||||
|
So how the heck is this supposed to work???
|
||||||
|
|
||||||
|
Remember that it is illegal to block while in an RCU read-side critical
|
||||||
|
section. Therefore, if a given CPU executes a context switch, we know
|
||||||
|
that it must have completed all preceding RCU read-side critical sections.
|
||||||
|
Once -all- CPUs have executed a context switch, then -all- preceding
|
||||||
|
RCU read-side critical sections will have completed.
|
||||||
|
|
||||||
|
So, suppose that we remove a data item from its structure and then invoke
|
||||||
|
synchronize_rcu(). Once synchronize_rcu() returns, we are guaranteed
|
||||||
|
that there are no RCU read-side critical sections holding a reference
|
||||||
|
to that data item, so we can safely reclaim it.
|
||||||
|
|
||||||
|
Quick Quiz #2: Give an example where Classic RCU's read-side
|
||||||
|
overhead is -negative-.
|
||||||
|
|
||||||
|
Quick Quiz #3: If it is illegal to block in an RCU read-side
|
||||||
|
critical section, what the heck do you do in
|
||||||
|
PREEMPT_RT, where normal spinlocks can block???
|
||||||
|
|
||||||
|
|
||||||
|
6. ANALOGY WITH READER-WRITER LOCKING
|
||||||
|
|
||||||
|
Although RCU can be used in many different ways, a very common use of
|
||||||
|
RCU is analogous to reader-writer locking. The following unified
|
||||||
|
diff shows how closely related RCU and reader-writer locking can be.
|
||||||
|
|
||||||
|
@@ -13,15 +14,15 @@
|
||||||
|
struct list_head *lp;
|
||||||
|
struct el *p;
|
||||||
|
|
||||||
|
- read_lock();
|
||||||
|
- list_for_each_entry(p, head, lp) {
|
||||||
|
+ rcu_read_lock();
|
||||||
|
+ list_for_each_entry_rcu(p, head, lp) {
|
||||||
|
if (p->key == key) {
|
||||||
|
*result = p->data;
|
||||||
|
- read_unlock();
|
||||||
|
+ rcu_read_unlock();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- read_unlock();
|
||||||
|
+ rcu_read_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -29,15 +30,16 @@
|
||||||
|
{
|
||||||
|
struct el *p;
|
||||||
|
|
||||||
|
- write_lock(&listmutex);
|
||||||
|
+ spin_lock(&listmutex);
|
||||||
|
list_for_each_entry(p, head, lp) {
|
||||||
|
if (p->key == key) {
|
||||||
|
list_del(&p->list);
|
||||||
|
- write_unlock(&listmutex);
|
||||||
|
+ spin_unlock(&listmutex);
|
||||||
|
+ synchronize_rcu();
|
||||||
|
kfree(p);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- write_unlock(&listmutex);
|
||||||
|
+ spin_unlock(&listmutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Or, for those who prefer a side-by-side listing:
|
||||||
|
|
||||||
|
1 struct el { 1 struct el {
|
||||||
|
2 struct list_head list; 2 struct list_head list;
|
||||||
|
3 long key; 3 long key;
|
||||||
|
4 spinlock_t mutex; 4 spinlock_t mutex;
|
||||||
|
5 int data; 5 int data;
|
||||||
|
6 /* Other data fields */ 6 /* Other data fields */
|
||||||
|
7 }; 7 };
|
||||||
|
8 spinlock_t listmutex; 8 spinlock_t listmutex;
|
||||||
|
9 struct el head; 9 struct el head;
|
||||||
|
|
||||||
|
1 int search(long key, int *result) 1 int search(long key, int *result)
|
||||||
|
2 { 2 {
|
||||||
|
3 struct list_head *lp; 3 struct list_head *lp;
|
||||||
|
4 struct el *p; 4 struct el *p;
|
||||||
|
5 5
|
||||||
|
6 read_lock(); 6 rcu_read_lock();
|
||||||
|
7 list_for_each_entry(p, head, lp) { 7 list_for_each_entry_rcu(p, head, lp) {
|
||||||
|
8 if (p->key == key) { 8 if (p->key == key) {
|
||||||
|
9 *result = p->data; 9 *result = p->data;
|
||||||
|
10 read_unlock(); 10 rcu_read_unlock();
|
||||||
|
11 return 1; 11 return 1;
|
||||||
|
12 } 12 }
|
||||||
|
13 } 13 }
|
||||||
|
14 read_unlock(); 14 rcu_read_unlock();
|
||||||
|
15 return 0; 15 return 0;
|
||||||
|
16 } 16 }
|
||||||
|
|
||||||
|
1 int delete(long key) 1 int delete(long key)
|
||||||
|
2 { 2 {
|
||||||
|
3 struct el *p; 3 struct el *p;
|
||||||
|
4 4
|
||||||
|
5 write_lock(&listmutex); 5 spin_lock(&listmutex);
|
||||||
|
6 list_for_each_entry(p, head, lp) { 6 list_for_each_entry(p, head, lp) {
|
||||||
|
7 if (p->key == key) { 7 if (p->key == key) {
|
||||||
|
8 list_del(&p->list); 8 list_del(&p->list);
|
||||||
|
9 write_unlock(&listmutex); 9 spin_unlock(&listmutex);
|
||||||
|
10 synchronize_rcu();
|
||||||
|
10 kfree(p); 11 kfree(p);
|
||||||
|
11 return 1; 12 return 1;
|
||||||
|
12 } 13 }
|
||||||
|
13 } 14 }
|
||||||
|
14 write_unlock(&listmutex); 15 spin_unlock(&listmutex);
|
||||||
|
15 return 0; 16 return 0;
|
||||||
|
16 } 17 }
|
||||||
|
|
||||||
|
Either way, the differences are quite small. Read-side locking moves
|
||||||
|
to rcu_read_lock() and rcu_read_unlock, update-side locking moves from
|
||||||
|
from a reader-writer lock to a simple spinlock, and a synchronize_rcu()
|
||||||
|
precedes the kfree().
|
||||||
|
|
||||||
|
However, there is one potential catch: the read-side and update-side
|
||||||
|
critical sections can now run concurrently. In many cases, this will
|
||||||
|
not be a problem, but it is necessary to check carefully regardless.
|
||||||
|
For example, if multiple independent list updates must be seen as
|
||||||
|
a single atomic update, converting to RCU will require special care.
|
||||||
|
|
||||||
|
Also, the presence of synchronize_rcu() means that the RCU version of
|
||||||
|
delete() can now block. If this is a problem, there is a callback-based
|
||||||
|
mechanism that never blocks, namely call_rcu(), that can be used in
|
||||||
|
place of synchronize_rcu().
|
||||||
|
|
||||||
|
|
||||||
|
7. FULL LIST OF RCU APIs
|
||||||
|
|
||||||
|
The RCU APIs are documented in docbook-format header comments in the
|
||||||
|
Linux-kernel source code, but it helps to have a full list of the
|
||||||
|
APIs, since there does not appear to be a way to categorize them
|
||||||
|
in docbook. Here is the list, by category.
|
||||||
|
|
||||||
|
Markers for RCU read-side critical sections:
|
||||||
|
|
||||||
|
rcu_read_lock
|
||||||
|
rcu_read_unlock
|
||||||
|
rcu_read_lock_bh
|
||||||
|
rcu_read_unlock_bh
|
||||||
|
|
||||||
|
RCU pointer/list traversal:
|
||||||
|
|
||||||
|
rcu_dereference
|
||||||
|
list_for_each_rcu (to be deprecated in favor of
|
||||||
|
list_for_each_entry_rcu)
|
||||||
|
list_for_each_safe_rcu (deprecated, not used)
|
||||||
|
list_for_each_entry_rcu
|
||||||
|
list_for_each_continue_rcu (to be deprecated in favor of new
|
||||||
|
list_for_each_entry_continue_rcu)
|
||||||
|
hlist_for_each_rcu (to be deprecated in favor of
|
||||||
|
hlist_for_each_entry_rcu)
|
||||||
|
hlist_for_each_entry_rcu
|
||||||
|
|
||||||
|
RCU pointer update:
|
||||||
|
|
||||||
|
rcu_assign_pointer
|
||||||
|
list_add_rcu
|
||||||
|
list_add_tail_rcu
|
||||||
|
list_del_rcu
|
||||||
|
list_replace_rcu
|
||||||
|
hlist_del_rcu
|
||||||
|
hlist_add_head_rcu
|
||||||
|
|
||||||
|
RCU grace period:
|
||||||
|
|
||||||
|
synchronize_kernel (deprecated)
|
||||||
|
synchronize_net
|
||||||
|
synchronize_sched
|
||||||
|
synchronize_rcu
|
||||||
|
call_rcu
|
||||||
|
call_rcu_bh
|
||||||
|
|
||||||
|
See the comment headers in the source code (or the docbook generated
|
||||||
|
from them) for more information.
|
||||||
|
|
||||||
|
|
||||||
|
8. ANSWERS TO QUICK QUIZZES
|
||||||
|
|
||||||
|
Quick Quiz #1: Why is this argument naive? How could a deadlock
|
||||||
|
occur when using this algorithm in a real-world Linux
|
||||||
|
kernel? [Referring to the lock-based "toy" RCU
|
||||||
|
algorithm.]
|
||||||
|
|
||||||
|
Answer: Consider the following sequence of events:
|
||||||
|
|
||||||
|
1. CPU 0 acquires some unrelated lock, call it
|
||||||
|
"problematic_lock".
|
||||||
|
|
||||||
|
2. CPU 1 enters synchronize_rcu(), write-acquiring
|
||||||
|
rcu_gp_mutex.
|
||||||
|
|
||||||
|
3. CPU 0 enters rcu_read_lock(), but must wait
|
||||||
|
because CPU 1 holds rcu_gp_mutex.
|
||||||
|
|
||||||
|
4. CPU 1 is interrupted, and the irq handler
|
||||||
|
attempts to acquire problematic_lock.
|
||||||
|
|
||||||
|
The system is now deadlocked.
|
||||||
|
|
||||||
|
One way to avoid this deadlock is to use an approach like
|
||||||
|
that of CONFIG_PREEMPT_RT, where all normal spinlocks
|
||||||
|
become blocking locks, and all irq handlers execute in
|
||||||
|
the context of special tasks. In this case, in step 4
|
||||||
|
above, the irq handler would block, allowing CPU 1 to
|
||||||
|
release rcu_gp_mutex, avoiding the deadlock.
|
||||||
|
|
||||||
|
Even in the absence of deadlock, this RCU implementation
|
||||||
|
allows latency to "bleed" from readers to other
|
||||||
|
readers through synchronize_rcu(). To see this,
|
||||||
|
consider task A in an RCU read-side critical section
|
||||||
|
(thus read-holding rcu_gp_mutex), task B blocked
|
||||||
|
attempting to write-acquire rcu_gp_mutex, and
|
||||||
|
task C blocked in rcu_read_lock() attempting to
|
||||||
|
read_acquire rcu_gp_mutex. Task A's RCU read-side
|
||||||
|
latency is holding up task C, albeit indirectly via
|
||||||
|
task B.
|
||||||
|
|
||||||
|
Realtime RCU implementations therefore use a counter-based
|
||||||
|
approach where tasks in RCU read-side critical sections
|
||||||
|
cannot be blocked by tasks executing synchronize_rcu().
|
||||||
|
|
||||||
|
Quick Quiz #2: Give an example where Classic RCU's read-side
|
||||||
|
overhead is -negative-.
|
||||||
|
|
||||||
|
Answer: Imagine a single-CPU system with a non-CONFIG_PREEMPT
|
||||||
|
kernel where a routing table is used by process-context
|
||||||
|
code, but can be updated by irq-context code (for example,
|
||||||
|
by an "ICMP REDIRECT" packet). The usual way of handling
|
||||||
|
this would be to have the process-context code disable
|
||||||
|
interrupts while searching the routing table. Use of
|
||||||
|
RCU allows such interrupt-disabling to be dispensed with.
|
||||||
|
Thus, without RCU, you pay the cost of disabling interrupts,
|
||||||
|
and with RCU you don't.
|
||||||
|
|
||||||
|
One can argue that the overhead of RCU in this
|
||||||
|
case is negative with respect to the single-CPU
|
||||||
|
interrupt-disabling approach. Others might argue that
|
||||||
|
the overhead of RCU is merely zero, and that replacing
|
||||||
|
the positive overhead of the interrupt-disabling scheme
|
||||||
|
with the zero-overhead RCU scheme does not constitute
|
||||||
|
negative overhead.
|
||||||
|
|
||||||
|
In real life, of course, things are more complex. But
|
||||||
|
even the theoretical possibility of negative overhead for
|
||||||
|
a synchronization primitive is a bit unexpected. ;-)
|
||||||
|
|
||||||
|
Quick Quiz #3: If it is illegal to block in an RCU read-side
|
||||||
|
critical section, what the heck do you do in
|
||||||
|
PREEMPT_RT, where normal spinlocks can block???
|
||||||
|
|
||||||
|
Answer: Just as PREEMPT_RT permits preemption of spinlock
|
||||||
|
critical sections, it permits preemption of RCU
|
||||||
|
read-side critical sections. It also permits
|
||||||
|
spinlocks blocking while in RCU read-side critical
|
||||||
|
sections.
|
||||||
|
|
||||||
|
Why the apparent inconsistency? Because it is it
|
||||||
|
possible to use priority boosting to keep the RCU
|
||||||
|
grace periods short if need be (for example, if running
|
||||||
|
short of memory). In contrast, if blocking waiting
|
||||||
|
for (say) network reception, there is no way to know
|
||||||
|
what should be boosted. Especially given that the
|
||||||
|
process we need to boost might well be a human being
|
||||||
|
who just went out for a pizza or something. And although
|
||||||
|
a computer-operated cattle prod might arouse serious
|
||||||
|
interest, it might also provoke serious objections.
|
||||||
|
Besides, how does the computer know what pizza parlor
|
||||||
|
the human being went to???
|
||||||
|
|
||||||
|
|
||||||
|
ACKNOWLEDGEMENTS
|
||||||
|
|
||||||
|
My thanks to the people who helped make this human-readable, including
|
||||||
|
Jon Walpole, Josh Triplett, Serge Hallyn, and Suzanne Wood.
|
||||||
|
|
||||||
|
|
||||||
|
For more information, see http://www.rdrop.com/users/paulmck/RCU.
|
@ -35,4 +35,4 @@ created. Please use command "cat /proc/acpi/hotkey/polling_method"
|
|||||||
to retrieve it.
|
to retrieve it.
|
||||||
|
|
||||||
Note: Use cmdline "acpi_generic_hotkey" to over-ride
|
Note: Use cmdline "acpi_generic_hotkey" to over-ride
|
||||||
loading any platform specific drivers.
|
platform-specific with generic driver.
|
||||||
|
@ -8,13 +8,15 @@ fi
|
|||||||
n_partitions=${n_partitions:-16}
|
n_partitions=${n_partitions:-16}
|
||||||
dir=$1
|
dir=$1
|
||||||
shelf=$2
|
shelf=$2
|
||||||
|
nslots=16
|
||||||
|
maxslot=`echo $nslots 1 - p | dc`
|
||||||
MAJOR=152
|
MAJOR=152
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
minor=`echo 10 \* $shelf \* $n_partitions | bc`
|
minor=`echo $nslots \* $shelf \* $n_partitions | bc`
|
||||||
endp=`echo $n_partitions - 1 | bc`
|
endp=`echo $n_partitions - 1 | bc`
|
||||||
for slot in `seq 0 9`; do
|
for slot in `seq 0 $maxslot`; do
|
||||||
for part in `seq 0 $endp`; do
|
for part in `seq 0 $endp`; do
|
||||||
name=e$shelf.$slot
|
name=e$shelf.$slot
|
||||||
test "$part" != "0" && name=${name}p$part
|
test "$part" != "0" && name=${name}p$part
|
||||||
|
439
Documentation/applying-patches.txt
Normal file
439
Documentation/applying-patches.txt
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
|
||||||
|
Applying Patches To The Linux Kernel
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
(Written by Jesper Juhl, August 2005)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
A frequently asked question on the Linux Kernel Mailing List is how to apply
|
||||||
|
a patch to the kernel or, more specifically, what base kernel a patch for
|
||||||
|
one of the many trees/branches should be applied to. Hopefully this document
|
||||||
|
will explain this to you.
|
||||||
|
|
||||||
|
In addition to explaining how to apply and revert patches, a brief
|
||||||
|
description of the different kernel trees (and examples of how to apply
|
||||||
|
their specific patches) is also provided.
|
||||||
|
|
||||||
|
|
||||||
|
What is a patch?
|
||||||
|
---
|
||||||
|
A patch is a small text document containing a delta of changes between two
|
||||||
|
different versions of a source tree. Patches are created with the `diff'
|
||||||
|
program.
|
||||||
|
To correctly apply a patch you need to know what base it was generated from
|
||||||
|
and what new version the patch will change the source tree into. These
|
||||||
|
should both be present in the patch file metadata or be possible to deduce
|
||||||
|
from the filename.
|
||||||
|
|
||||||
|
|
||||||
|
How do I apply or revert a patch?
|
||||||
|
---
|
||||||
|
You apply a patch with the `patch' program. The patch program reads a diff
|
||||||
|
(or patch) file and makes the changes to the source tree described in it.
|
||||||
|
|
||||||
|
Patches for the Linux kernel are generated relative to the parent directory
|
||||||
|
holding the kernel source dir.
|
||||||
|
|
||||||
|
This means that paths to files inside the patch file contain the name of the
|
||||||
|
kernel source directories it was generated against (or some other directory
|
||||||
|
names like "a/" and "b/").
|
||||||
|
Since this is unlikely to match the name of the kernel source dir on your
|
||||||
|
local machine (but is often useful info to see what version an otherwise
|
||||||
|
unlabeled patch was generated against) you should change into your kernel
|
||||||
|
source directory and then strip the first element of the path from filenames
|
||||||
|
in the patch file when applying it (the -p1 argument to `patch' does this).
|
||||||
|
|
||||||
|
To revert a previously applied patch, use the -R argument to patch.
|
||||||
|
So, if you applied a patch like this:
|
||||||
|
patch -p1 < ../patch-x.y.z
|
||||||
|
|
||||||
|
You can revert (undo) it like this:
|
||||||
|
patch -R -p1 < ../patch-x.y.z
|
||||||
|
|
||||||
|
|
||||||
|
How do I feed a patch/diff file to `patch'?
|
||||||
|
---
|
||||||
|
This (as usual with Linux and other UNIX like operating systems) can be
|
||||||
|
done in several different ways.
|
||||||
|
In all the examples below I feed the file (in uncompressed form) to patch
|
||||||
|
via stdin using the following syntax:
|
||||||
|
patch -p1 < path/to/patch-x.y.z
|
||||||
|
|
||||||
|
If you just want to be able to follow the examples below and don't want to
|
||||||
|
know of more than one way to use patch, then you can stop reading this
|
||||||
|
section here.
|
||||||
|
|
||||||
|
Patch can also get the name of the file to use via the -i argument, like
|
||||||
|
this:
|
||||||
|
patch -p1 -i path/to/patch-x.y.z
|
||||||
|
|
||||||
|
If your patch file is compressed with gzip or bzip2 and you don't want to
|
||||||
|
uncompress it before applying it, then you can feed it to patch like this
|
||||||
|
instead:
|
||||||
|
zcat path/to/patch-x.y.z.gz | patch -p1
|
||||||
|
bzcat path/to/patch-x.y.z.bz2 | patch -p1
|
||||||
|
|
||||||
|
If you wish to uncompress the patch file by hand first before applying it
|
||||||
|
(what I assume you've done in the examples below), then you simply run
|
||||||
|
gunzip or bunzip2 on the file - like this:
|
||||||
|
gunzip patch-x.y.z.gz
|
||||||
|
bunzip2 patch-x.y.z.bz2
|
||||||
|
|
||||||
|
Which will leave you with a plain text patch-x.y.z file that you can feed to
|
||||||
|
patch via stdin or the -i argument, as you prefer.
|
||||||
|
|
||||||
|
A few other nice arguments for patch are -s which causes patch to be silent
|
||||||
|
except for errors which is nice to prevent errors from scrolling out of the
|
||||||
|
screen too fast, and --dry-run which causes patch to just print a listing of
|
||||||
|
what would happen, but doesn't actually make any changes. Finally --verbose
|
||||||
|
tells patch to print more information about the work being done.
|
||||||
|
|
||||||
|
|
||||||
|
Common errors when patching
|
||||||
|
---
|
||||||
|
When patch applies a patch file it attempts to verify the sanity of the
|
||||||
|
file in different ways.
|
||||||
|
Checking that the file looks like a valid patch file, checking the code
|
||||||
|
around the bits being modified matches the context provided in the patch are
|
||||||
|
just two of the basic sanity checks patch does.
|
||||||
|
|
||||||
|
If patch encounters something that doesn't look quite right it has two
|
||||||
|
options. It can either refuse to apply the changes and abort or it can try
|
||||||
|
to find a way to make the patch apply with a few minor changes.
|
||||||
|
|
||||||
|
One example of something that's not 'quite right' that patch will attempt to
|
||||||
|
fix up is if all the context matches, the lines being changed match, but the
|
||||||
|
line numbers are different. This can happen, for example, if the patch makes
|
||||||
|
a change in the middle of the file but for some reasons a few lines have
|
||||||
|
been added or removed near the beginning of the file. In that case
|
||||||
|
everything looks good it has just moved up or down a bit, and patch will
|
||||||
|
usually adjust the line numbers and apply the patch.
|
||||||
|
|
||||||
|
Whenever patch applies a patch that it had to modify a bit to make it fit
|
||||||
|
it'll tell you about it by saying the patch applied with 'fuzz'.
|
||||||
|
You should be wary of such changes since even though patch probably got it
|
||||||
|
right it doesn't /always/ get it right, and the result will sometimes be
|
||||||
|
wrong.
|
||||||
|
|
||||||
|
When patch encounters a change that it can't fix up with fuzz it rejects it
|
||||||
|
outright and leaves a file with a .rej extension (a reject file). You can
|
||||||
|
read this file to see exactely what change couldn't be applied, so you can
|
||||||
|
go fix it up by hand if you wish.
|
||||||
|
|
||||||
|
If you don't have any third party patches applied to your kernel source, but
|
||||||
|
only patches from kernel.org and you apply the patches in the correct order,
|
||||||
|
and have made no modifications yourself to the source files, then you should
|
||||||
|
never see a fuzz or reject message from patch. If you do see such messages
|
||||||
|
anyway, then there's a high risk that either your local source tree or the
|
||||||
|
patch file is corrupted in some way. In that case you should probably try
|
||||||
|
redownloading the patch and if things are still not OK then you'd be advised
|
||||||
|
to start with a fresh tree downloaded in full from kernel.org.
|
||||||
|
|
||||||
|
Let's look a bit more at some of the messages patch can produce.
|
||||||
|
|
||||||
|
If patch stops and presents a "File to patch:" prompt, then patch could not
|
||||||
|
find a file to be patched. Most likely you forgot to specify -p1 or you are
|
||||||
|
in the wrong directory. Less often, you'll find patches that need to be
|
||||||
|
applied with -p0 instead of -p1 (reading the patch file should reveal if
|
||||||
|
this is the case - if so, then this is an error by the person who created
|
||||||
|
the patch but is not fatal).
|
||||||
|
|
||||||
|
If you get "Hunk #2 succeeded at 1887 with fuzz 2 (offset 7 lines)." or a
|
||||||
|
message similar to that, then it means that patch had to adjust the location
|
||||||
|
of the change (in this example it needed to move 7 lines from where it
|
||||||
|
expected to make the change to make it fit).
|
||||||
|
The resulting file may or may not be OK, depending on the reason the file
|
||||||
|
was different than expected.
|
||||||
|
This often happens if you try to apply a patch that was generated against a
|
||||||
|
different kernel version than the one you are trying to patch.
|
||||||
|
|
||||||
|
If you get a message like "Hunk #3 FAILED at 2387.", then it means that the
|
||||||
|
patch could not be applied correctly and the patch program was unable to
|
||||||
|
fuzz its way through. This will generate a .rej file with the change that
|
||||||
|
caused the patch to fail and also a .orig file showing you the original
|
||||||
|
content that couldn't be changed.
|
||||||
|
|
||||||
|
If you get "Reversed (or previously applied) patch detected! Assume -R? [n]"
|
||||||
|
then patch detected that the change contained in the patch seems to have
|
||||||
|
already been made.
|
||||||
|
If you actually did apply this patch previously and you just re-applied it
|
||||||
|
in error, then just say [n]o and abort this patch. If you applied this patch
|
||||||
|
previously and actually intended to revert it, but forgot to specify -R,
|
||||||
|
then you can say [y]es here to make patch revert it for you.
|
||||||
|
This can also happen if the creator of the patch reversed the source and
|
||||||
|
destination directories when creating the patch, and in that case reverting
|
||||||
|
the patch will in fact apply it.
|
||||||
|
|
||||||
|
A message similar to "patch: **** unexpected end of file in patch" or "patch
|
||||||
|
unexpectedly ends in middle of line" means that patch could make no sense of
|
||||||
|
the file you fed to it. Either your download is broken or you tried to feed
|
||||||
|
patch a compressed patch file without uncompressing it first.
|
||||||
|
|
||||||
|
As I already mentioned above, these errors should never happen if you apply
|
||||||
|
a patch from kernel.org to the correct version of an unmodified source tree.
|
||||||
|
So if you get these errors with kernel.org patches then you should probably
|
||||||
|
assume that either your patch file or your tree is broken and I'd advice you
|
||||||
|
to start over with a fresh download of a full kernel tree and the patch you
|
||||||
|
wish to apply.
|
||||||
|
|
||||||
|
|
||||||
|
Are there any alternatives to `patch'?
|
||||||
|
---
|
||||||
|
Yes there are alternatives. You can use the `interdiff' program
|
||||||
|
(http://cyberelk.net/tim/patchutils/) to generate a patch representing the
|
||||||
|
differences between two patches and then apply the result.
|
||||||
|
This will let you move from something like 2.6.12.2 to 2.6.12.3 in a single
|
||||||
|
step. The -z flag to interdiff will even let you feed it patches in gzip or
|
||||||
|
bzip2 compressed form directly without the use of zcat or bzcat or manual
|
||||||
|
decompression.
|
||||||
|
|
||||||
|
Here's how you'd go from 2.6.12.2 to 2.6.12.3 in a single step:
|
||||||
|
interdiff -z ../patch-2.6.12.2.bz2 ../patch-2.6.12.3.gz | patch -p1
|
||||||
|
|
||||||
|
Although interdiff may save you a step or two you are generally advised to
|
||||||
|
do the additional steps since interdiff can get things wrong in some cases.
|
||||||
|
|
||||||
|
Another alternative is `ketchup', which is a python script for automatic
|
||||||
|
downloading and applying of patches (http://www.selenic.com/ketchup/).
|
||||||
|
|
||||||
|
Other nice tools are diffstat which shows a summary of changes made by a
|
||||||
|
patch, lsdiff which displays a short listing of affected files in a patch
|
||||||
|
file, along with (optionally) the line numbers of the start of each patch
|
||||||
|
and grepdiff which displays a list of the files modified by a patch where
|
||||||
|
the patch contains a given regular expression.
|
||||||
|
|
||||||
|
|
||||||
|
Where can I download the patches?
|
||||||
|
---
|
||||||
|
The patches are available at http://kernel.org/
|
||||||
|
Most recent patches are linked from the front page, but they also have
|
||||||
|
specific homes.
|
||||||
|
|
||||||
|
The 2.6.x.y (-stable) and 2.6.x patches live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
|
||||||
|
|
||||||
|
The -rc patches live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/testing/
|
||||||
|
|
||||||
|
The -git patches live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/snapshots/
|
||||||
|
|
||||||
|
The -mm kernels live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/
|
||||||
|
|
||||||
|
In place of ftp.kernel.org you can use ftp.cc.kernel.org, where cc is a
|
||||||
|
country code. This way you'll be downloading from a mirror site that's most
|
||||||
|
likely geographically closer to you, resulting in faster downloads for you,
|
||||||
|
less bandwidth used globally and less load on the main kernel.org servers -
|
||||||
|
these are good things, do use mirrors when possible.
|
||||||
|
|
||||||
|
|
||||||
|
The 2.6.x kernels
|
||||||
|
---
|
||||||
|
These are the base stable releases released by Linus. The highest numbered
|
||||||
|
release is the most recent.
|
||||||
|
|
||||||
|
If regressions or other serious flaws are found then a -stable fix patch
|
||||||
|
will be released (see below) on top of this base. Once a new 2.6.x base
|
||||||
|
kernel is released, a patch is made available that is a delta between the
|
||||||
|
previous 2.6.x kernel and the new one.
|
||||||
|
|
||||||
|
To apply a patch moving from 2.6.11 to 2.6.12 you'd do the following (note
|
||||||
|
that such patches do *NOT* apply on top of 2.6.x.y kernels but on top of the
|
||||||
|
base 2.6.x kernel - if you need to move from 2.6.x.y to 2.6.x+1 you need to
|
||||||
|
first revert the 2.6.x.y patch).
|
||||||
|
|
||||||
|
Here are some examples:
|
||||||
|
|
||||||
|
# moving from 2.6.11 to 2.6.12
|
||||||
|
$ cd ~/linux-2.6.11 # change to kernel source dir
|
||||||
|
$ patch -p1 < ../patch-2.6.12 # apply the 2.6.12 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.11 linux-2.6.12 # rename source dir
|
||||||
|
|
||||||
|
# moving from 2.6.11.1 to 2.6.12
|
||||||
|
$ cd ~/linux-2.6.11.1 # change to kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.11.1 # revert the 2.6.11.1 patch
|
||||||
|
# source dir is now 2.6.11
|
||||||
|
$ patch -p1 < ../patch-2.6.12 # apply new 2.6.12 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.11.1 inux-2.6.12 # rename source dir
|
||||||
|
|
||||||
|
|
||||||
|
The 2.6.x.y kernels
|
||||||
|
---
|
||||||
|
Kernels with 4 digit versions are -stable kernels. They contain small(ish)
|
||||||
|
critical fixes for security problems or significant regressions discovered
|
||||||
|
in a given 2.6.x kernel.
|
||||||
|
|
||||||
|
This is the recommended branch for users who want the most recent stable
|
||||||
|
kernel and are not interested in helping test development/experimental
|
||||||
|
versions.
|
||||||
|
|
||||||
|
If no 2.6.x.y kernel is available, then the highest numbered 2.6.x kernel is
|
||||||
|
the current stable kernel.
|
||||||
|
|
||||||
|
These patches are not incremental, meaning that for example the 2.6.12.3
|
||||||
|
patch does not apply on top of the 2.6.12.2 kernel source, but rather on top
|
||||||
|
of the base 2.6.12 kernel source.
|
||||||
|
So, in order to apply the 2.6.12.3 patch to your existing 2.6.12.2 kernel
|
||||||
|
source you have to first back out the 2.6.12.2 patch (so you are left with a
|
||||||
|
base 2.6.12 kernel source) and then apply the new 2.6.12.3 patch.
|
||||||
|
|
||||||
|
Here's a small example:
|
||||||
|
|
||||||
|
$ cd ~/linux-2.6.12.2 # change into the kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.12.2 # revert the 2.6.12.2 patch
|
||||||
|
$ patch -p1 < ../patch-2.6.12.3 # apply the new 2.6.12.3 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12.2 linux-2.6.12.3 # rename the kernel source dir
|
||||||
|
|
||||||
|
|
||||||
|
The -rc kernels
|
||||||
|
---
|
||||||
|
These are release-candidate kernels. These are development kernels released
|
||||||
|
by Linus whenever he deems the current git (the kernel's source management
|
||||||
|
tool) tree to be in a reasonably sane state adequate for testing.
|
||||||
|
|
||||||
|
These kernels are not stable and you should expect occasional breakage if
|
||||||
|
you intend to run them. This is however the most stable of the main
|
||||||
|
development branches and is also what will eventually turn into the next
|
||||||
|
stable kernel, so it is important that it be tested by as many people as
|
||||||
|
possible.
|
||||||
|
|
||||||
|
This is a good branch to run for people who want to help out testing
|
||||||
|
development kernels but do not want to run some of the really experimental
|
||||||
|
stuff (such people should see the sections about -git and -mm kernels below).
|
||||||
|
|
||||||
|
The -rc patches are not incremental, they apply to a base 2.6.x kernel, just
|
||||||
|
like the 2.6.x.y patches described above. The kernel version before the -rcN
|
||||||
|
suffix denotes the version of the kernel that this -rc kernel will eventually
|
||||||
|
turn into.
|
||||||
|
So, 2.6.13-rc5 means that this is the fifth release candidate for the 2.6.13
|
||||||
|
kernel and the patch should be applied on top of the 2.6.12 kernel source.
|
||||||
|
|
||||||
|
Here are 3 examples of how to apply these patches:
|
||||||
|
|
||||||
|
# first an example of moving from 2.6.12 to 2.6.13-rc3
|
||||||
|
$ cd ~/linux-2.6.12 # change into the 2.6.12 source dir
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc3 # apply the 2.6.13-rc3 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12 linux-2.6.13-rc3 # rename the source dir
|
||||||
|
|
||||||
|
# now let's move from 2.6.13-rc3 to 2.6.13-rc5
|
||||||
|
$ cd ~/linux-2.6.13-rc3 # change into the 2.6.13-rc3 dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.13-rc3 # revert the 2.6.13-rc3 patch
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc5 # apply the new 2.6.13-rc5 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.13-rc3 linux-2.6.13-rc5 # rename the source dir
|
||||||
|
|
||||||
|
# finally let's try and move from 2.6.12.3 to 2.6.13-rc5
|
||||||
|
$ cd ~/linux-2.6.12.3 # change to the kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.12.3 # revert the 2.6.12.3 patch
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc5 # apply new 2.6.13-rc5 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12.3 linux-2.6.13-rc5 # rename the kernel source dir
|
||||||
|
|
||||||
|
|
||||||
|
The -git kernels
|
||||||
|
---
|
||||||
|
These are daily snapshots of Linus' kernel tree (managed in a git
|
||||||
|
repository, hence the name).
|
||||||
|
|
||||||
|
These patches are usually released daily and represent the current state of
|
||||||
|
Linus' tree. They are more experimental than -rc kernels since they are
|
||||||
|
generated automatically without even a cursory glance to see if they are
|
||||||
|
sane.
|
||||||
|
|
||||||
|
-git patches are not incremental and apply either to a base 2.6.x kernel or
|
||||||
|
a base 2.6.x-rc kernel - you can see which from their name.
|
||||||
|
A patch named 2.6.12-git1 applies to the 2.6.12 kernel source and a patch
|
||||||
|
named 2.6.13-rc3-git2 applies to the source of the 2.6.13-rc3 kernel.
|
||||||
|
|
||||||
|
Here are some examples of how to apply these patches:
|
||||||
|
|
||||||
|
# moving from 2.6.12 to 2.6.12-git1
|
||||||
|
$ cd ~/linux-2.6.12 # change to the kernel source dir
|
||||||
|
$ patch -p1 < ../patch-2.6.12-git1 # apply the 2.6.12-git1 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12 linux-2.6.12-git1 # rename the kernel source dir
|
||||||
|
|
||||||
|
# moving from 2.6.12-git1 to 2.6.13-rc2-git3
|
||||||
|
$ cd ~/linux-2.6.12-git1 # change to the kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.12-git1 # revert the 2.6.12-git1 patch
|
||||||
|
# we now have a 2.6.12 kernel
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc2 # apply the 2.6.13-rc2 patch
|
||||||
|
# the kernel is now 2.6.13-rc2
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc2-git3 # apply the 2.6.13-rc2-git3 patch
|
||||||
|
# the kernel is now 2.6.13-rc2-git3
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12-git1 linux-2.6.13-rc2-git3 # rename source dir
|
||||||
|
|
||||||
|
|
||||||
|
The -mm kernels
|
||||||
|
---
|
||||||
|
These are experimental kernels released by Andrew Morton.
|
||||||
|
|
||||||
|
The -mm tree serves as a sort of proving ground for new features and other
|
||||||
|
experimental patches.
|
||||||
|
Once a patch has proved its worth in -mm for a while Andrew pushes it on to
|
||||||
|
Linus for inclusion in mainline.
|
||||||
|
|
||||||
|
Although it's encouraged that patches flow to Linus via the -mm tree, this
|
||||||
|
is not always enforced.
|
||||||
|
Subsystem maintainers (or individuals) sometimes push their patches directly
|
||||||
|
to Linus, even though (or after) they have been merged and tested in -mm (or
|
||||||
|
sometimes even without prior testing in -mm).
|
||||||
|
|
||||||
|
You should generally strive to get your patches into mainline via -mm to
|
||||||
|
ensure maximum testing.
|
||||||
|
|
||||||
|
This branch is in constant flux and contains many experimental features, a
|
||||||
|
lot of debugging patches not appropriate for mainline etc and is the most
|
||||||
|
experimental of the branches described in this document.
|
||||||
|
|
||||||
|
These kernels are not appropriate for use on systems that are supposed to be
|
||||||
|
stable and they are more risky to run than any of the other branches (make
|
||||||
|
sure you have up-to-date backups - that goes for any experimental kernel but
|
||||||
|
even more so for -mm kernels).
|
||||||
|
|
||||||
|
These kernels in addition to all the other experimental patches they contain
|
||||||
|
usually also contain any changes in the mainline -git kernels available at
|
||||||
|
the time of release.
|
||||||
|
|
||||||
|
Testing of -mm kernels is greatly appreciated since the whole point of the
|
||||||
|
tree is to weed out regressions, crashes, data corruption bugs, build
|
||||||
|
breakage (and any other bug in general) before changes are merged into the
|
||||||
|
more stable mainline Linus tree.
|
||||||
|
But testers of -mm should be aware that breakage in this tree is more common
|
||||||
|
than in any other tree.
|
||||||
|
|
||||||
|
The -mm kernels are not released on a fixed schedule, but usually a few -mm
|
||||||
|
kernels are released in between each -rc kernel (1 to 3 is common).
|
||||||
|
The -mm kernels apply to either a base 2.6.x kernel (when no -rc kernels
|
||||||
|
have been released yet) or to a Linus -rc kernel.
|
||||||
|
|
||||||
|
Here are some examples of applying the -mm patches:
|
||||||
|
|
||||||
|
# moving from 2.6.12 to 2.6.12-mm1
|
||||||
|
$ cd ~/linux-2.6.12 # change to the 2.6.12 source dir
|
||||||
|
$ patch -p1 < ../2.6.12-mm1 # apply the 2.6.12-mm1 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12 linux-2.6.12-mm1 # rename the source appropriately
|
||||||
|
|
||||||
|
# moving from 2.6.12-mm1 to 2.6.13-rc3-mm3
|
||||||
|
$ cd ~/linux-2.6.12-mm1
|
||||||
|
$ patch -p1 -R < ../2.6.12-mm1 # revert the 2.6.12-mm1 patch
|
||||||
|
# we now have a 2.6.12 source
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc3 # apply the 2.6.13-rc3 patch
|
||||||
|
# we now have a 2.6.13-rc3 source
|
||||||
|
$ patch -p1 < ../2.6.13-rc3-mm3 # apply the 2.6.13-rc3-mm3 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3 # rename the source dir
|
||||||
|
|
||||||
|
|
||||||
|
This concludes this list of explanations of the various kernel trees and I
|
||||||
|
hope you are now crystal clear on how to apply the various patches and help
|
||||||
|
testing the kernel.
|
||||||
|
|
194
Documentation/connector/cn_test.c
Normal file
194
Documentation/connector/cn_test.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* cn_test.c
|
||||||
|
*
|
||||||
|
* 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
|
#include "connector.h"
|
||||||
|
|
||||||
|
static struct cb_id cn_test_id = { 0x123, 0x456 };
|
||||||
|
static char cn_test_name[] = "cn_test";
|
||||||
|
static struct sock *nls;
|
||||||
|
static struct timer_list cn_test_timer;
|
||||||
|
|
||||||
|
void cn_test_callback(void *data)
|
||||||
|
{
|
||||||
|
struct cn_msg *msg = (struct cn_msg *)data;
|
||||||
|
|
||||||
|
printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
|
||||||
|
__func__, jiffies, msg->id.idx, msg->id.val,
|
||||||
|
msg->seq, msg->ack, msg->len, (char *)msg->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cn_test_want_notify(void)
|
||||||
|
{
|
||||||
|
struct cn_ctl_msg *ctl;
|
||||||
|
struct cn_notify_req *req;
|
||||||
|
struct cn_msg *msg = NULL;
|
||||||
|
int size, size0;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
struct nlmsghdr *nlh;
|
||||||
|
u32 group = 1;
|
||||||
|
|
||||||
|
size0 = sizeof(*msg) + sizeof(*ctl) + 3 * sizeof(*req);
|
||||||
|
|
||||||
|
size = NLMSG_SPACE(size0);
|
||||||
|
|
||||||
|
skb = alloc_skb(size, GFP_ATOMIC);
|
||||||
|
if (!skb) {
|
||||||
|
printk(KERN_ERR "Failed to allocate new skb with size=%u.\n",
|
||||||
|
size);
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlh = NLMSG_PUT(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh));
|
||||||
|
|
||||||
|
msg = (struct cn_msg *)NLMSG_DATA(nlh);
|
||||||
|
|
||||||
|
memset(msg, 0, size0);
|
||||||
|
|
||||||
|
msg->id.idx = -1;
|
||||||
|
msg->id.val = -1;
|
||||||
|
msg->seq = 0x123;
|
||||||
|
msg->ack = 0x345;
|
||||||
|
msg->len = size0 - sizeof(*msg);
|
||||||
|
|
||||||
|
ctl = (struct cn_ctl_msg *)(msg + 1);
|
||||||
|
|
||||||
|
ctl->idx_notify_num = 1;
|
||||||
|
ctl->val_notify_num = 2;
|
||||||
|
ctl->group = group;
|
||||||
|
ctl->len = msg->len - sizeof(*ctl);
|
||||||
|
|
||||||
|
req = (struct cn_notify_req *)(ctl + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Idx.
|
||||||
|
*/
|
||||||
|
req->first = cn_test_id.idx;
|
||||||
|
req->range = 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Val 0.
|
||||||
|
*/
|
||||||
|
req++;
|
||||||
|
req->first = cn_test_id.val;
|
||||||
|
req->range = 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Val 1.
|
||||||
|
*/
|
||||||
|
req++;
|
||||||
|
req->first = cn_test_id.val + 20;
|
||||||
|
req->range = 10;
|
||||||
|
|
||||||
|
NETLINK_CB(skb).dst_groups = ctl->group;
|
||||||
|
//netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
|
||||||
|
netlink_unicast(nls, skb, 0, 0);
|
||||||
|
|
||||||
|
printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nlmsg_failure:
|
||||||
|
printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
|
||||||
|
kfree_skb(skb);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 cn_test_timer_counter;
|
||||||
|
static void cn_test_timer_func(unsigned long __data)
|
||||||
|
{
|
||||||
|
struct cn_msg *m;
|
||||||
|
char data[32];
|
||||||
|
|
||||||
|
m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
|
||||||
|
if (m) {
|
||||||
|
memset(m, 0, sizeof(*m) + sizeof(data));
|
||||||
|
|
||||||
|
memcpy(&m->id, &cn_test_id, sizeof(m->id));
|
||||||
|
m->seq = cn_test_timer_counter;
|
||||||
|
m->len = sizeof(data);
|
||||||
|
|
||||||
|
m->len =
|
||||||
|
scnprintf(data, sizeof(data), "counter = %u",
|
||||||
|
cn_test_timer_counter) + 1;
|
||||||
|
|
||||||
|
memcpy(m + 1, data, m->len);
|
||||||
|
|
||||||
|
cn_netlink_send(m, 0, gfp_any());
|
||||||
|
kfree(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
cn_test_timer_counter++;
|
||||||
|
|
||||||
|
mod_timer(&cn_test_timer, jiffies + HZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cn_test_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
|
||||||
|
if (err)
|
||||||
|
goto err_out;
|
||||||
|
cn_test_id.val++;
|
||||||
|
err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
|
||||||
|
if (err) {
|
||||||
|
cn_del_callback(&cn_test_id);
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_timer(&cn_test_timer);
|
||||||
|
cn_test_timer.function = cn_test_timer_func;
|
||||||
|
cn_test_timer.expires = jiffies + HZ;
|
||||||
|
cn_test_timer.data = 0;
|
||||||
|
add_timer(&cn_test_timer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
if (nls && nls->sk_socket)
|
||||||
|
sock_release(nls->sk_socket);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cn_test_fini(void)
|
||||||
|
{
|
||||||
|
del_timer_sync(&cn_test_timer);
|
||||||
|
cn_del_callback(&cn_test_id);
|
||||||
|
cn_test_id.val--;
|
||||||
|
cn_del_callback(&cn_test_id);
|
||||||
|
if (nls && nls->sk_socket)
|
||||||
|
sock_release(nls->sk_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(cn_test_init);
|
||||||
|
module_exit(cn_test_fini);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
|
||||||
|
MODULE_DESCRIPTION("Connector's test module");
|
133
Documentation/connector/connector.txt
Normal file
133
Documentation/connector/connector.txt
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*****************************************/
|
||||||
|
Kernel Connector.
|
||||||
|
/*****************************************/
|
||||||
|
|
||||||
|
Kernel connector - new netlink based userspace <-> kernel space easy
|
||||||
|
to use communication module.
|
||||||
|
|
||||||
|
Connector driver adds possibility to connect various agents using
|
||||||
|
netlink based network. One must register callback and
|
||||||
|
identifier. When driver receives special netlink message with
|
||||||
|
appropriate identifier, appropriate callback will be called.
|
||||||
|
|
||||||
|
From the userspace point of view it's quite straightforward:
|
||||||
|
|
||||||
|
socket();
|
||||||
|
bind();
|
||||||
|
send();
|
||||||
|
recv();
|
||||||
|
|
||||||
|
But if kernelspace want to use full power of such connections, driver
|
||||||
|
writer must create special sockets, must know about struct sk_buff
|
||||||
|
handling... Connector allows any kernelspace agents to use netlink
|
||||||
|
based networking for inter-process communication in a significantly
|
||||||
|
easier way:
|
||||||
|
|
||||||
|
int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
|
||||||
|
void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask);
|
||||||
|
|
||||||
|
struct cb_id
|
||||||
|
{
|
||||||
|
__u32 idx;
|
||||||
|
__u32 val;
|
||||||
|
};
|
||||||
|
|
||||||
|
idx and val are unique identifiers which must be registered in
|
||||||
|
connector.h for in-kernel usage. void (*callback) (void *) - is a
|
||||||
|
callback function which will be called when message with above idx.val
|
||||||
|
will be received by connector core. Argument for that function must
|
||||||
|
be dereferenced to struct cn_msg *.
|
||||||
|
|
||||||
|
struct cn_msg
|
||||||
|
{
|
||||||
|
struct cb_id id;
|
||||||
|
|
||||||
|
__u32 seq;
|
||||||
|
__u32 ack;
|
||||||
|
|
||||||
|
__u32 len; /* Length of the following data */
|
||||||
|
__u8 data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************/
|
||||||
|
Connector interfaces.
|
||||||
|
/*****************************************/
|
||||||
|
|
||||||
|
int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
|
||||||
|
|
||||||
|
Registers new callback with connector core.
|
||||||
|
|
||||||
|
struct cb_id *id - unique connector's user identifier.
|
||||||
|
It must be registered in connector.h for legal in-kernel users.
|
||||||
|
char *name - connector's callback symbolic name.
|
||||||
|
void (*callback) (void *) - connector's callback.
|
||||||
|
Argument must be dereferenced to struct cn_msg *.
|
||||||
|
|
||||||
|
void cn_del_callback(struct cb_id *id);
|
||||||
|
|
||||||
|
Unregisters new callback with connector core.
|
||||||
|
|
||||||
|
struct cb_id *id - unique connector's user identifier.
|
||||||
|
|
||||||
|
void cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
|
||||||
|
|
||||||
|
Sends message to the specified groups. It can be safely called from
|
||||||
|
any context, but may silently fail under strong memory pressure.
|
||||||
|
|
||||||
|
struct cn_msg * - message header(with attached data).
|
||||||
|
u32 __group - destination group.
|
||||||
|
If __group is zero, then appropriate group will
|
||||||
|
be searched through all registered connector users,
|
||||||
|
and message will be delivered to the group which was
|
||||||
|
created for user with the same ID as in msg.
|
||||||
|
If __group is not zero, then message will be delivered
|
||||||
|
to the specified group.
|
||||||
|
int gfp_mask - GFP mask.
|
||||||
|
|
||||||
|
Note: When registering new callback user, connector core assigns
|
||||||
|
netlink group to the user which is equal to it's id.idx.
|
||||||
|
|
||||||
|
/*****************************************/
|
||||||
|
Protocol description.
|
||||||
|
/*****************************************/
|
||||||
|
|
||||||
|
Current offers transport layer with fixed header. Recommended
|
||||||
|
protocol which uses such header is following:
|
||||||
|
|
||||||
|
msg->seq and msg->ack are used to determine message genealogy. When
|
||||||
|
someone sends message it puts there locally unique sequence and random
|
||||||
|
acknowledge numbers. Sequence number may be copied into
|
||||||
|
nlmsghdr->nlmsg_seq too.
|
||||||
|
|
||||||
|
Sequence number is incremented with each message to be sent.
|
||||||
|
|
||||||
|
If we expect reply to our message, then sequence number in received
|
||||||
|
message MUST be the same as in original message, and acknowledge
|
||||||
|
number MUST be the same + 1.
|
||||||
|
|
||||||
|
If we receive message and it's sequence number is not equal to one we
|
||||||
|
are expecting, then it is new message. If we receive message and it's
|
||||||
|
sequence number is the same as one we are expecting, but it's
|
||||||
|
acknowledge is not equal acknowledge number in original message + 1,
|
||||||
|
then it is new message.
|
||||||
|
|
||||||
|
Obviously, protocol header contains above id.
|
||||||
|
|
||||||
|
connector allows event notification in the following form: kernel
|
||||||
|
driver or userspace process can ask connector to notify it when
|
||||||
|
selected id's will be turned on or off(registered or unregistered it's
|
||||||
|
callback). It is done by sending special command to connector
|
||||||
|
driver(it also registers itself with id={-1, -1}).
|
||||||
|
|
||||||
|
As example of usage Documentation/connector now contains cn_test.c -
|
||||||
|
testing module which uses connector to request notification and to
|
||||||
|
send messages.
|
||||||
|
|
||||||
|
/*****************************************/
|
||||||
|
Reliability.
|
||||||
|
/*****************************************/
|
||||||
|
|
||||||
|
Netlink itself is not reliable protocol, that means that messages can
|
||||||
|
be lost due to memory pressure or process' receiving queue overflowed,
|
||||||
|
so caller is warned must be prepared. That is why struct cn_msg [main
|
||||||
|
connector's message header] contains u32 seq and u32 ack fields.
|
@ -36,7 +36,7 @@ cpufreq stats provides following statistics (explained in detail below).
|
|||||||
|
|
||||||
All the statistics will be from the time the stats driver has been inserted
|
All the statistics will be from the time the stats driver has been inserted
|
||||||
to the time when a read of a particular statistic is done. Obviously, stats
|
to the time when a read of a particular statistic is done. Obviously, stats
|
||||||
driver will not have any information about the the frequcny transitions before
|
driver will not have any information about the frequency transitions before
|
||||||
the stats driver insertion.
|
the stats driver insertion.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
@ -277,7 +277,7 @@ rewritten to the 'tasks' file of its cpuset. This is done to avoid
|
|||||||
impacting the scheduler code in the kernel with a check for changes
|
impacting the scheduler code in the kernel with a check for changes
|
||||||
in a tasks processor placement.
|
in a tasks processor placement.
|
||||||
|
|
||||||
There is an exception to the above. If hotplug funtionality is used
|
There is an exception to the above. If hotplug functionality is used
|
||||||
to remove all the CPUs that are currently assigned to a cpuset,
|
to remove all the CPUs that are currently assigned to a cpuset,
|
||||||
then the kernel will automatically update the cpus_allowed of all
|
then the kernel will automatically update the cpus_allowed of all
|
||||||
tasks attached to CPUs in that cpuset to allow all CPUs. When memory
|
tasks attached to CPUs in that cpuset to allow all CPUs. When memory
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Below is the orginal README file from the descore.shar package.
|
Below is the original README file from the descore.shar package.
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
des - fast & portable DES encryption & decryption.
|
des - fast & portable DES encryption & decryption.
|
||||||
|
@ -1,55 +1,74 @@
|
|||||||
How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working
|
How to get the Nebula, PCTV and Twinhan DST cards working
|
||||||
=========================================================================================
|
=========================================================
|
||||||
|
|
||||||
1) General information
|
This class of cards has a bt878a as the PCI interface, and
|
||||||
======================
|
require the bttv driver.
|
||||||
|
|
||||||
This class of cards has a bt878a chip as the PCI interface.
|
Please pay close attention to the warning about the bttv module
|
||||||
The different card drivers require the bttv driver to provide the means
|
options below for the DST card.
|
||||||
to access the i2c bus and the gpio pins of the bt8xx chipset.
|
|
||||||
|
|
||||||
2) Compilation rules for Kernel >= 2.6.12
|
1) General informations
|
||||||
=========================================
|
=======================
|
||||||
|
|
||||||
Enable the following options:
|
These drivers require the bttv driver to provide the means to access
|
||||||
|
the i2c bus and the gpio pins of the bt8xx chipset.
|
||||||
|
|
||||||
|
Because of this, you need to enable
|
||||||
"Device drivers" => "Multimedia devices"
|
"Device drivers" => "Multimedia devices"
|
||||||
=> "Video For Linux" => "BT848 Video For Linux"
|
=> "Video For Linux" => "BT848 Video For Linux"
|
||||||
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
|
|
||||||
=> "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
|
|
||||||
|
|
||||||
3) Loading Modules, described by two approaches
|
Furthermore you need to enable
|
||||||
===============================================
|
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
|
||||||
|
=> "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
|
||||||
|
|
||||||
|
2) Loading Modules
|
||||||
|
==================
|
||||||
|
|
||||||
In general you need to load the bttv driver, which will handle the gpio and
|
In general you need to load the bttv driver, which will handle the gpio and
|
||||||
i2c communication for us, plus the common dvb-bt8xx device driver,
|
i2c communication for us, plus the common dvb-bt8xx device driver.
|
||||||
which is called the backend.
|
The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
|
||||||
The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110),
|
TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
|
||||||
TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend.
|
|
||||||
For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt.
|
|
||||||
|
|
||||||
3a) The manual approach
|
3a) Nebula / Pinnacle PCTV
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Loading modules:
|
|
||||||
modprobe bttv
|
|
||||||
modprobe dvb-bt8xx
|
|
||||||
|
|
||||||
Unloading modules:
|
|
||||||
modprobe -r dvb-bt8xx
|
|
||||||
modprobe -r bttv
|
|
||||||
|
|
||||||
3b) The automatic approach
|
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
If not already done by installation, place a line either in
|
$ modprobe bttv (normally bttv is being loaded automatically by kmod)
|
||||||
/etc/modules.conf or in /etc/modprobe.conf containing this text:
|
$ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
|
||||||
alias char-major-81 bttv
|
|
||||||
|
|
||||||
Then place a line in /etc/modules containing this text:
|
|
||||||
dvb-bt8xx
|
|
||||||
|
|
||||||
Reboot your system and have fun!
|
3b) TwinHan and Clones
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
$ modprobe bttv i2c_hw=1 card=0x71
|
||||||
|
$ modprobe dvb-bt8xx
|
||||||
|
$ modprobe dst
|
||||||
|
|
||||||
|
The value 0x71 will override the PCI type detection for dvb-bt8xx,
|
||||||
|
which is necessary for TwinHan cards.
|
||||||
|
|
||||||
|
If you're having an older card (blue color circuit) and card=0x71 locks
|
||||||
|
your machine, try using 0x68, too. If that does not work, ask on the
|
||||||
|
mailing list.
|
||||||
|
|
||||||
|
The DST module takes a couple of useful parameters.
|
||||||
|
|
||||||
|
verbose takes values 0 to 4. These values control the verbosity level,
|
||||||
|
and can be used to debug also.
|
||||||
|
|
||||||
|
verbose=0 means complete disabling of messages
|
||||||
|
1 only error messages are displayed
|
||||||
|
2 notifications are also displayed
|
||||||
|
3 informational messages are also displayed
|
||||||
|
4 debug setting
|
||||||
|
|
||||||
|
dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
|
||||||
|
0x20 means it has a Conditional Access slot.
|
||||||
|
|
||||||
|
The autodected values are determined bythe cards 'response
|
||||||
|
string' which you can see in your logs e.g.
|
||||||
|
|
||||||
|
dst_get_device_id: Recognise [DSTMCI]
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
|
Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
|
||||||
|
@ -23,7 +23,6 @@ This application requires the following to function properly as of now.
|
|||||||
eg: $ szap -c channels.conf -r "TMC" -x
|
eg: $ szap -c channels.conf -r "TMC" -x
|
||||||
|
|
||||||
(b) a channels.conf containing a valid PMT PID
|
(b) a channels.conf containing a valid PMT PID
|
||||||
|
|
||||||
eg: TMC:11996:h:0:27500:278:512:650:321
|
eg: TMC:11996:h:0:27500:278:512:650:321
|
||||||
|
|
||||||
here 278 is a valid PMT PID. the rest of the values are the
|
here 278 is a valid PMT PID. the rest of the values are the
|
||||||
@ -31,13 +30,7 @@ This application requires the following to function properly as of now.
|
|||||||
|
|
||||||
(c) after running a szap, you have to run ca_zap, for the
|
(c) after running a szap, you have to run ca_zap, for the
|
||||||
descrambler to function,
|
descrambler to function,
|
||||||
|
eg: $ ca_zap channels.conf "TMC"
|
||||||
eg: $ ca_zap patched_channels.conf "TMC"
|
|
||||||
|
|
||||||
The patched means a patch to apply to scan, such that scan can
|
|
||||||
generate a channels.conf_with pmt, which has this PMT PID info
|
|
||||||
(NOTE: szap cannot use this channels.conf with the PMT_PID)
|
|
||||||
|
|
||||||
|
|
||||||
(d) Hopeflly Enjoy your favourite subscribed channel as you do with
|
(d) Hopeflly Enjoy your favourite subscribed channel as you do with
|
||||||
a FTA card.
|
a FTA card.
|
||||||
|
14
Documentation/fb/cyblafb/bugs
Normal file
14
Documentation/fb/cyblafb/bugs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Bugs
|
||||||
|
====
|
||||||
|
|
||||||
|
I currently don't know of any bug. Please do send reports to:
|
||||||
|
- linux-fbdev-devel@lists.sourceforge.net
|
||||||
|
- Knut_Petersen@t-online.de.
|
||||||
|
|
||||||
|
|
||||||
|
Untested features
|
||||||
|
=================
|
||||||
|
|
||||||
|
All LCD stuff is untested. If it worked in tridentfb, it should work in
|
||||||
|
cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
|
||||||
|
|
7
Documentation/fb/cyblafb/credits
Normal file
7
Documentation/fb/cyblafb/credits
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Thanks to
|
||||||
|
=========
|
||||||
|
* Alan Hourihane, for writing the X trident driver
|
||||||
|
* Jani Monoses, for writing the tridentfb driver
|
||||||
|
* Antonino A. Daplas, for review of the first published
|
||||||
|
version of cyblafb and some code
|
||||||
|
* Jochen Hein, for testing and a helpfull bug report
|
17
Documentation/fb/cyblafb/documentation
Normal file
17
Documentation/fb/cyblafb/documentation
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Available Documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Apollo PLE 133 Chipset VT8601A North Bridge Datasheet, Rev. 1.82, October 22,
|
||||||
|
2001, available from VIA:
|
||||||
|
|
||||||
|
http://www.viavpsd.com/product/6/15/DS8601A182.pdf
|
||||||
|
|
||||||
|
The datasheet is incomplete, some registers that need to be programmed are not
|
||||||
|
explained at all and important bits are listed as "reserved". But you really
|
||||||
|
need the datasheet to understand the code. "p. xxx" comments refer to page
|
||||||
|
numbers of this document.
|
||||||
|
|
||||||
|
XFree/XOrg drivers are available and of good quality, looking at the code
|
||||||
|
there is a good idea if the datasheet does not provide enough information
|
||||||
|
or if the datasheet seems to be wrong.
|
||||||
|
|
155
Documentation/fb/cyblafb/fb.modes
Normal file
155
Documentation/fb/cyblafb/fb.modes
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#
|
||||||
|
# Sample fb.modes file
|
||||||
|
#
|
||||||
|
# Provides an incomplete list of working modes for
|
||||||
|
# the cyberblade/i1 graphics core.
|
||||||
|
#
|
||||||
|
# The value 4294967256 is used instead of -40. Of course, -40 is not
|
||||||
|
# a really reasonable value, but chip design does not always follow
|
||||||
|
# logic. Believe me, it's ok, and it's the way the BIOS does it.
|
||||||
|
#
|
||||||
|
# fbset requires 4294967256 in fb.modes and -40 as an argument to
|
||||||
|
# the -t parameter. That's also not too reasonable, and it might change
|
||||||
|
# in the future or might even be differt for your current version.
|
||||||
|
#
|
||||||
|
|
||||||
|
mode "640x480-50"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 47619 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-60"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 39682 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-70"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 34013 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-72"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 33068 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-75"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 31746 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-80"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 29761 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-85"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 28011 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-50"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 30303 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-60"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 25252 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-70"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 21645 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-72"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 21043 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-75"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 20202 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-80"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 18939 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-85"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 17825 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-50"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 19054 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-60"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 15880 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-70"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 13610 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-72"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 13232 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-75"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 12703 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-80"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 11910 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-85"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 11209 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-50"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 11114 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-60"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 9262 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-70"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 7939 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-72"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 7719 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-75"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 7410 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-80"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 6946 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-85"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 6538 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
80
Documentation/fb/cyblafb/performance
Normal file
80
Documentation/fb/cyblafb/performance
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
Speed
|
||||||
|
=====
|
||||||
|
|
||||||
|
CyBlaFB is much faster than tridentfb and vesafb. Compare the performance data
|
||||||
|
for mode 1280x1024-[8,16,32]@61 Hz.
|
||||||
|
|
||||||
|
Test 1: Cat a file with 2000 lines of 0 characters.
|
||||||
|
Test 2: Cat a file with 2000 lines of 80 characters.
|
||||||
|
Test 3: Cat a file with 2000 lines of 160 characters.
|
||||||
|
|
||||||
|
All values show system time use in seconds, kernel 2.6.12 was used for
|
||||||
|
the measurements. 2.6.13 is a bit slower, 2.6.14 hopefully will include a
|
||||||
|
patch that speeds up kernel bitblitting a lot ( > 20%).
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | not accelerated |
|
||||||
|
| TRIDENTFB +-----------------+-----------------+-----------------+
|
||||||
|
| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | 4.31 | 4.33 | 6.05 | 12.81 | ---- | ---- |
|
||||||
|
| Test 2 | 67.94 | 5.44 | 123.16 | 14.79 | ---- | ---- |
|
||||||
|
| Test 3 | 131.36 | 6.55 | 240.12 | 16.76 | ---- | ---- |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | | | completely bro- |
|
||||||
|
| | | | ken, monitor |
|
||||||
|
| | | | switches off |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | accelerated |
|
||||||
|
| TRIDENTFB +-----------------+-----------------+-----------------+
|
||||||
|
| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | ---- | ---- | 20.62 | 1.22 | ---- | ---- |
|
||||||
|
| Test 2 | ---- | ---- | 22.61 | 3.19 | ---- | ---- |
|
||||||
|
| Test 3 | ---- | ---- | 24.59 | 5.16 | ---- | ---- |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | broken, writing | broken, ok only | completely bro- |
|
||||||
|
| | to wrong places | if bgcolor is | ken, monitor |
|
||||||
|
| | on screen + bug | black, bug in | switches off |
|
||||||
|
| | in fillrect() | fillrect() | |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | not accelerated |
|
||||||
|
| VESAFB +-----------------+-----------------+-----------------+
|
||||||
|
| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | 4.26 | 3.76 | 5.99 | 7.23 | ---- | ---- |
|
||||||
|
| Test 2 | 65.65 | 4.89 | 120.88 | 9.08 | ---- | ---- |
|
||||||
|
| Test 3 | 126.91 | 5.94 | 235.77 | 11.03 | ---- | ---- |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | vga=0x307 | vga=0x31a | vga=0x31b not |
|
||||||
|
| | fh=80kHz | fh=80kHz | supported by |
|
||||||
|
| | fv=75kHz | fv=75kHz | video BIOS and |
|
||||||
|
| | | | hardware |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | accelerated |
|
||||||
|
| CYBLAFB +-----------------+-----------------+-----------------+
|
||||||
|
| | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | 8.02 | 0.23 | 19.04 | 0.61 | 57.12 | 2.74 |
|
||||||
|
| Test 2 | 8.38 | 0.55 | 19.39 | 0.92 | 57.54 | 3.13 |
|
||||||
|
| Test 3 | 8.73 | 0.86 | 19.74 | 1.24 | 57.95 | 3.51 |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | | | |
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
32
Documentation/fb/cyblafb/todo
Normal file
32
Documentation/fb/cyblafb/todo
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
TODO / Missing features
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Verify LCD stuff "stretch" and "center" options are
|
||||||
|
completely untested ... this code needs to be
|
||||||
|
verified. As I don't have access to such
|
||||||
|
hardware, please contact me if you are
|
||||||
|
willing run some tests.
|
||||||
|
|
||||||
|
Interlaced video modes The reason that interleaved
|
||||||
|
modes are disabled is that I do not know
|
||||||
|
the meaning of the vertical interlace
|
||||||
|
parameter. Also the datasheet mentions a
|
||||||
|
bit d8 of a horizontal interlace parameter,
|
||||||
|
but nowhere the lower 8 bits. Please help
|
||||||
|
if you can.
|
||||||
|
|
||||||
|
low-res double scan modes Who needs it?
|
||||||
|
|
||||||
|
accelerated color blitting Who needs it? The console driver does use color
|
||||||
|
blitting for nothing but drawing the penguine,
|
||||||
|
everything else is done using color expanding
|
||||||
|
blitting of 1bpp character bitmaps.
|
||||||
|
|
||||||
|
xpanning Who needs it?
|
||||||
|
|
||||||
|
ioctls Who needs it?
|
||||||
|
|
||||||
|
TV-out Will be done later
|
||||||
|
|
||||||
|
??? Feel free to contact me if you have any
|
||||||
|
feature requests
|
206
Documentation/fb/cyblafb/usage
Normal file
206
Documentation/fb/cyblafb/usage
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
CyBlaFB is a framebuffer driver for the Cyberblade/i1 graphics core integrated
|
||||||
|
into the VIA Apollo PLE133 (aka vt8601) south bridge. It is developed and
|
||||||
|
tested using a VIA EPIA 5000 board.
|
||||||
|
|
||||||
|
Cyblafb - compiled into the kernel or as a module?
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
You might compile cyblafb either as a module or compile it permanently into the
|
||||||
|
kernel.
|
||||||
|
|
||||||
|
Unless you have a real reason to do so you should not compile both vesafb and
|
||||||
|
cyblafb permanently into the kernel. It's possible and it helps during the
|
||||||
|
developement cycle, but it's useless and will at least block some otherwise
|
||||||
|
usefull memory for ordinary users.
|
||||||
|
|
||||||
|
Selecting Modes
|
||||||
|
===============
|
||||||
|
|
||||||
|
Startup Mode
|
||||||
|
============
|
||||||
|
|
||||||
|
First of all, you might use the "vga=???" boot parameter as it is
|
||||||
|
documented in vesafb.txt and svga.txt. Cyblafb will detect the video
|
||||||
|
mode selected and will use the geometry and timings found by
|
||||||
|
inspecting the hardware registers.
|
||||||
|
|
||||||
|
video=cyblafb vga=0x317
|
||||||
|
|
||||||
|
Alternatively you might use a combination of the mode, ref and bpp
|
||||||
|
parameters. If you compiled the driver into the kernel, add something
|
||||||
|
like this to the kernel command line:
|
||||||
|
|
||||||
|
video=cyblafb:1280x1024,bpp=16,ref=50 ...
|
||||||
|
|
||||||
|
If you compiled the driver as a module, the same mode would be
|
||||||
|
selected by the following command:
|
||||||
|
|
||||||
|
modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
|
||||||
|
|
||||||
|
None of the modes possible to select as startup modes are affected by
|
||||||
|
the problems described at the end of the next subsection.
|
||||||
|
|
||||||
|
Mode changes using fbset
|
||||||
|
========================
|
||||||
|
|
||||||
|
You might use fbset to change the video mode, see "man fbset". Cyblafb
|
||||||
|
generally does assume that you know what you are doing. But it does
|
||||||
|
some checks, especially those that are needed to prevent you from
|
||||||
|
damaging your hardware.
|
||||||
|
|
||||||
|
- only 8, 16, 24 and 32 bpp video modes are accepted
|
||||||
|
- interlaced video modes are not accepted
|
||||||
|
- double scan video modes are not accepted
|
||||||
|
- if a flat panel is found, cyblafb does not allow you
|
||||||
|
to program a resolution higher than the physical
|
||||||
|
resolution of the flat panel monitor
|
||||||
|
- cyblafb does not allow xres to differ from xres_virtual
|
||||||
|
- cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
|
||||||
|
and (currently) 24 bit modes use a doubled vclk internally,
|
||||||
|
the dotclock limit as seen by fbset is 115 MHz for those
|
||||||
|
modes and 230 MHz for 8 and 16 bpp modes.
|
||||||
|
|
||||||
|
Any request that violates the rules given above will be ignored and
|
||||||
|
fbset will return an error.
|
||||||
|
|
||||||
|
If you program a virtual y resolution higher than the hardware limit,
|
||||||
|
cyblafb will silently decrease that value to the highest possible
|
||||||
|
value.
|
||||||
|
|
||||||
|
Attempts to disable acceleration are ignored.
|
||||||
|
|
||||||
|
Some video modes that should work do not work as expected. If you use
|
||||||
|
the standard fb.modes, fbset 640x480-60 will program that mode, but
|
||||||
|
you will see a vertical area, about two characters wide, with only
|
||||||
|
much darker characters than the other characters on the screen.
|
||||||
|
Cyblafb does allow that mode to be set, as it does not violate the
|
||||||
|
official specifications. It would need a lot of code to reliably sort
|
||||||
|
out all invalid modes, playing around with the margin values will
|
||||||
|
give a valid mode quickly. And if cyblafb would detect such an invalid
|
||||||
|
mode, should it silently alter the requested values or should it
|
||||||
|
report an error? Both options have some pros and cons. As stated
|
||||||
|
above, none of the startup modes are affected, and if you set
|
||||||
|
verbosity to 1 or higher, cyblafb will print the fbset command that
|
||||||
|
would be needed to program that mode using fbset.
|
||||||
|
|
||||||
|
|
||||||
|
Other Parameters
|
||||||
|
================
|
||||||
|
|
||||||
|
|
||||||
|
crt don't autodetect, assume monitor connected to
|
||||||
|
standard VGA connector
|
||||||
|
|
||||||
|
fp don't autodetect, assume flat panel display
|
||||||
|
connected to flat panel monitor interface
|
||||||
|
|
||||||
|
nativex inform driver about native x resolution of
|
||||||
|
flat panel monitor connected to special
|
||||||
|
interface (should be autodetected)
|
||||||
|
|
||||||
|
stretch stretch image to adapt low resolution modes to
|
||||||
|
higer resolutions of flat panel monitors
|
||||||
|
connected to special interface
|
||||||
|
|
||||||
|
center center image to adapt low resolution modes to
|
||||||
|
higer resolutions of flat panel monitors
|
||||||
|
connected to special interface
|
||||||
|
|
||||||
|
memsize use if autodetected memsize is wrong ...
|
||||||
|
should never be necessary
|
||||||
|
|
||||||
|
nopcirr disable PCI read retry
|
||||||
|
nopciwr disable PCI write retry
|
||||||
|
nopcirb disable PCI read bursts
|
||||||
|
nopciwb disable PCI write bursts
|
||||||
|
|
||||||
|
bpp bpp for specified modes
|
||||||
|
valid values: 8 || 16 || 24 || 32
|
||||||
|
|
||||||
|
ref refresh rate for specified mode
|
||||||
|
valid values: 50 <= ref <= 85
|
||||||
|
|
||||||
|
mode 640x480 or 800x600 or 1024x768 or 1280x1024
|
||||||
|
if not specified, the startup mode will be detected
|
||||||
|
and used, so you might also use the vga=??? parameter
|
||||||
|
described in vesafb.txt. If you do not specify a mode,
|
||||||
|
bpp and ref parameters are ignored.
|
||||||
|
|
||||||
|
verbosity 0 is the default, increase to at least 2 for every
|
||||||
|
bug report!
|
||||||
|
|
||||||
|
vesafb allows cyblafb to be loaded after vesafb has been
|
||||||
|
loaded. See sections "Module unloading ...".
|
||||||
|
|
||||||
|
|
||||||
|
Development hints
|
||||||
|
=================
|
||||||
|
|
||||||
|
It's much faster do compile a module and to load the new version after
|
||||||
|
unloading the old module than to compile a new kernel and to reboot. So if you
|
||||||
|
try to work on cyblafb, it might be a good idea to use cyblafb as a module.
|
||||||
|
In real life, fast often means dangerous, and that's also the case here. If
|
||||||
|
you introduce a serious bug when cyblafb is compiled into the kernel, the
|
||||||
|
kernel will lock or oops with a high probability before the file system is
|
||||||
|
mounted, and the danger for your data is low. If you load a broken own version
|
||||||
|
of cyblafb on a running system, the danger for the integrity of the file
|
||||||
|
system is much higher as you might need a hard reset afterwards. Decide
|
||||||
|
yourself.
|
||||||
|
|
||||||
|
Module unloading, the vfb method
|
||||||
|
================================
|
||||||
|
|
||||||
|
If you want to unload/reload cyblafb using the virtual framebuffer, you need
|
||||||
|
to enable vfb support in the kernel first. After that, load the modules as
|
||||||
|
shown below:
|
||||||
|
|
||||||
|
modprobe vfb vfb_enable=1
|
||||||
|
modprobe fbcon
|
||||||
|
modprobe cyblafb
|
||||||
|
fbset -fb /dev/fb1 1280x1024-60 -vyres 2662
|
||||||
|
con2fb /dev/fb1 /dev/tty1
|
||||||
|
...
|
||||||
|
|
||||||
|
If you now made some changes to cyblafb and want to reload it, you might do it
|
||||||
|
as show below:
|
||||||
|
|
||||||
|
con2fb /dev/fb0 /dev/tty1
|
||||||
|
...
|
||||||
|
rmmod cyblafb
|
||||||
|
modprobe cyblafb
|
||||||
|
con2fb /dev/fb1 /dev/tty1
|
||||||
|
...
|
||||||
|
|
||||||
|
Of course, you might choose another mode, and most certainly you also want to
|
||||||
|
map some other /dev/tty* to the real framebuffer device. You might also choose
|
||||||
|
to compile fbcon as a kernel module or place it permanently in the kernel.
|
||||||
|
|
||||||
|
I do not know of any way to unload fbcon, and fbcon will prevent the
|
||||||
|
framebuffer device loaded first from unloading. [If there is a way, then
|
||||||
|
please add a description here!]
|
||||||
|
|
||||||
|
Module unloading, the vesafb method
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Configure the kernel:
|
||||||
|
|
||||||
|
<*> Support for frame buffer devices
|
||||||
|
[*] VESA VGA graphics support
|
||||||
|
<M> Cyberblade/i1 support
|
||||||
|
|
||||||
|
Add e.g. "video=vesafb:ypan vga=0x307" to the kernel parameters. The ypan
|
||||||
|
parameter is important, choose any vga parameter you like as long as it is
|
||||||
|
a graphics mode.
|
||||||
|
|
||||||
|
After booting, load cyblafb without any mode and bpp parameter and assign
|
||||||
|
cyblafb to individual ttys using con2fb, e.g.:
|
||||||
|
|
||||||
|
modprobe cyblafb vesafb=1
|
||||||
|
con2fb /dev/fb1 /dev/tty1
|
||||||
|
|
||||||
|
Unloading cyblafb works without problems after you assign vesafb to all
|
||||||
|
ttys again, e.g.:
|
||||||
|
|
||||||
|
con2fb /dev/fb0 /dev/tty1
|
||||||
|
rmmod cyblafb
|
||||||
|
|
85
Documentation/fb/cyblafb/whycyblafb
Normal file
85
Documentation/fb/cyblafb/whycyblafb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
I tried the following framebuffer drivers:
|
||||||
|
|
||||||
|
- TRIDENTFB is full of bugs. Acceleration is broken for Blade3D
|
||||||
|
graphics cores like the cyberblade/i1. It claims to support a great
|
||||||
|
number of devices, but documentation for most of these devices is
|
||||||
|
unfortunately not available. There is _no_ reason to use tridentfb
|
||||||
|
for cyberblade/i1 + CRT users. VESAFB is faster, and the one
|
||||||
|
advantage, mode switching, is broken in tridentfb.
|
||||||
|
|
||||||
|
- VESAFB is used by many distributions as a standard. Vesafb does
|
||||||
|
not support mode switching. VESAFB is a bit faster than the working
|
||||||
|
configurations of TRIDENTFB, but it is still too slow, even if you
|
||||||
|
use ypan.
|
||||||
|
|
||||||
|
- EPIAFB (you'll find it on sourceforge) supports the Cyberblade/i1
|
||||||
|
graphics core, but it still has serious bugs and developement seems
|
||||||
|
to have stopped. This is the one driver with TV-out support. If you
|
||||||
|
do need this feature, try epiafb.
|
||||||
|
|
||||||
|
None of these drivers was a real option for me.
|
||||||
|
|
||||||
|
I believe that is unreasonable to change code that announces to support 20
|
||||||
|
devices if I only have more or less sufficient documentation for exactly one
|
||||||
|
of these. The risk of breaking device foo while fixing device bar is too high.
|
||||||
|
|
||||||
|
So I decided to start CyBlaFB as a stripped down tridentfb.
|
||||||
|
|
||||||
|
All code specific to other Trident chips has been removed. After that there
|
||||||
|
were a lot of cosmetic changes to increase the readability of the code. All
|
||||||
|
register names were changed to those mnemonics used in the datasheet. Function
|
||||||
|
and macro names were changed if they hindered easy understanding of the code.
|
||||||
|
|
||||||
|
After that I debugged the code and implemented some new features. I'll try to
|
||||||
|
give a little summary of the main changes:
|
||||||
|
|
||||||
|
- calculation of vertical and horizontal timings was fixed
|
||||||
|
|
||||||
|
- video signal quality has been improved dramatically
|
||||||
|
|
||||||
|
- acceleration:
|
||||||
|
|
||||||
|
- fillrect and copyarea were fixed and reenabled
|
||||||
|
|
||||||
|
- color expanding imageblit was newly implemented, color
|
||||||
|
imageblit (only used to draw the penguine) still uses the
|
||||||
|
generic code.
|
||||||
|
|
||||||
|
- init of the acceleration engine was improved and moved to a
|
||||||
|
place where it really works ...
|
||||||
|
|
||||||
|
- sync function has a timeout now and tries to reset and
|
||||||
|
reinit the accel engine if necessary
|
||||||
|
|
||||||
|
- fewer slow copyarea calls when doing ypan scrolling by using
|
||||||
|
undocumented bit d21 of screen start address stored in
|
||||||
|
CR2B[5]. BIOS does use it also, so this should be safe.
|
||||||
|
|
||||||
|
- cyblafb rejects any attempt to set modes that would cause vclk
|
||||||
|
values above reasonable 230 MHz. 32bit modes use a clock
|
||||||
|
multiplicator of 2, so fbset does show the correct values for
|
||||||
|
pixclock but not for vclk in this case. The fbset limit is 115 MHz
|
||||||
|
for 32 bpp modes.
|
||||||
|
|
||||||
|
- cyblafb rejects modes known to be broken or unimplemented (all
|
||||||
|
interlaced modes, all doublescan modes for now)
|
||||||
|
|
||||||
|
- cyblafb now works independant of the video mode in effect at startup
|
||||||
|
time (tridentfb does not init all needed registers to reasonable
|
||||||
|
values)
|
||||||
|
|
||||||
|
- switching between video modes does work reliably now
|
||||||
|
|
||||||
|
- the first video mode now is the one selected on startup using the
|
||||||
|
vga=???? mechanism or any of
|
||||||
|
- 640x480, 800x600, 1024x768, 1280x1024
|
||||||
|
- 8, 16, 24 or 32 bpp
|
||||||
|
- refresh between 50 Hz and 85 Hz, 1 Hz steps (1280x1024-32
|
||||||
|
is limited to 63Hz)
|
||||||
|
|
||||||
|
- pci retry and pci burst mode are settable (try to disable if you
|
||||||
|
experience latency problems)
|
||||||
|
|
||||||
|
- built as a module cyblafb might be unloaded and reloaded using
|
||||||
|
the vfb module and con2vt or might be used together with vesafb
|
||||||
|
|
@ -5,6 +5,7 @@ Intel 810/815 Framebuffer driver
|
|||||||
March 17, 2002
|
March 17, 2002
|
||||||
|
|
||||||
First Released: July 2001
|
First Released: July 2001
|
||||||
|
Last Update: September 12, 2005
|
||||||
================================================================
|
================================================================
|
||||||
|
|
||||||
A. Introduction
|
A. Introduction
|
||||||
@ -44,6 +45,8 @@ B. Features
|
|||||||
|
|
||||||
- Hardware Cursor Support
|
- Hardware Cursor Support
|
||||||
|
|
||||||
|
- Supports EDID probing either by DDC/I2C or through the BIOS
|
||||||
|
|
||||||
C. List of available options
|
C. List of available options
|
||||||
|
|
||||||
a. "video=i810fb"
|
a. "video=i810fb"
|
||||||
@ -52,14 +55,17 @@ C. List of available options
|
|||||||
Recommendation: required
|
Recommendation: required
|
||||||
|
|
||||||
b. "xres:<value>"
|
b. "xres:<value>"
|
||||||
select horizontal resolution in pixels
|
select horizontal resolution in pixels. (This parameter will be
|
||||||
|
ignored if 'mode_option' is specified. See 'o' below).
|
||||||
|
|
||||||
Recommendation: user preference
|
Recommendation: user preference
|
||||||
(default = 640)
|
(default = 640)
|
||||||
|
|
||||||
c. "yres:<value>"
|
c. "yres:<value>"
|
||||||
select vertical resolution in scanlines. If Discrete Video Timings
|
select vertical resolution in scanlines. If Discrete Video Timings
|
||||||
is enabled, this will be ignored and computed as 3*xres/4.
|
is enabled, this will be ignored and computed as 3*xres/4. (This
|
||||||
|
parameter will be ignored if 'mode_option' is specified. See 'o'
|
||||||
|
below)
|
||||||
|
|
||||||
Recommendation: user preference
|
Recommendation: user preference
|
||||||
(default = 480)
|
(default = 480)
|
||||||
@ -86,7 +92,8 @@ C. List of available options
|
|||||||
g. "hsync1/hsync2:<value>"
|
g. "hsync1/hsync2:<value>"
|
||||||
select the minimum and maximum Horizontal Sync Frequency of the
|
select the minimum and maximum Horizontal Sync Frequency of the
|
||||||
monitor in KHz. If a using a fixed frequency monitor, hsync1 must
|
monitor in KHz. If a using a fixed frequency monitor, hsync1 must
|
||||||
be equal to hsync2.
|
be equal to hsync2. If EDID probing is successful, these will be
|
||||||
|
ignored and values will be taken from the EDID block.
|
||||||
|
|
||||||
Recommendation: check monitor manual for correct values
|
Recommendation: check monitor manual for correct values
|
||||||
default (29/30)
|
default (29/30)
|
||||||
@ -94,7 +101,8 @@ C. List of available options
|
|||||||
h. "vsync1/vsync2:<value>"
|
h. "vsync1/vsync2:<value>"
|
||||||
select the minimum and maximum Vertical Sync Frequency of the monitor
|
select the minimum and maximum Vertical Sync Frequency of the monitor
|
||||||
in Hz. You can also use this option to lock your monitor's refresh
|
in Hz. You can also use this option to lock your monitor's refresh
|
||||||
rate.
|
rate. If EDID probing is successful, these will be ignored and values
|
||||||
|
will be taken from the EDID block.
|
||||||
|
|
||||||
Recommendation: check monitor manual for correct values
|
Recommendation: check monitor manual for correct values
|
||||||
(default = 60/60)
|
(default = 60/60)
|
||||||
@ -154,7 +162,11 @@ C. List of available options
|
|||||||
|
|
||||||
Recommendation: do not set
|
Recommendation: do not set
|
||||||
(default = not set)
|
(default = not set)
|
||||||
|
o. <xres>x<yres>[-<bpp>][@<refresh>]
|
||||||
|
The driver will now accept specification of boot mode option. If this
|
||||||
|
is specified, the options 'xres' and 'yres' will be ignored. See
|
||||||
|
Documentation/fb/modedb.txt for usage.
|
||||||
|
|
||||||
D. Kernel booting
|
D. Kernel booting
|
||||||
|
|
||||||
Separate each option/option-pair by commas (,) and the option from its value
|
Separate each option/option-pair by commas (,) and the option from its value
|
||||||
@ -176,7 +188,10 @@ will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
|
|||||||
|
|
||||||
IMPORTANT:
|
IMPORTANT:
|
||||||
You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
|
You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
|
||||||
better than 640x480 at 60Hz.
|
better than 640x480 at 60Hz. HOWEVER, if your chipset/display combination
|
||||||
|
supports I2C and has an EDID block, you can safely exclude hsync1, hsync2,
|
||||||
|
vsync1 and vsync2 parameters. These parameters will be taken from the EDID
|
||||||
|
block.
|
||||||
|
|
||||||
E. Module options
|
E. Module options
|
||||||
|
|
||||||
@ -217,32 +232,21 @@ F. Setup
|
|||||||
This is required. The option is under "Character Devices"
|
This is required. The option is under "Character Devices"
|
||||||
|
|
||||||
d. Under "Graphics Support", select "Intel 810/815" either statically
|
d. Under "Graphics Support", select "Intel 810/815" either statically
|
||||||
or as a module. Choose "use VESA GTF for video timings" if you
|
or as a module. Choose "use VESA Generalized Timing Formula" if
|
||||||
need to maximize the capability of your display. To be on the
|
you need to maximize the capability of your display. To be on the
|
||||||
safe side, you can leave this unselected.
|
safe side, you can leave this unselected.
|
||||||
|
|
||||||
e. If you want a framebuffer console, enable it under "Console
|
e. If you want support for DDC/I2C probing (Plug and Play Displays),
|
||||||
|
set 'Enable DDC Support' to 'y'. To make this option appear, set
|
||||||
|
'use VESA Generalized Timing Formula' to 'y'.
|
||||||
|
|
||||||
|
f. If you want a framebuffer console, enable it under "Console
|
||||||
Drivers"
|
Drivers"
|
||||||
|
|
||||||
f. Compile your kernel.
|
g. Compile your kernel.
|
||||||
|
|
||||||
g. Load the driver as described in section D and E.
|
h. Load the driver as described in section D and E.
|
||||||
|
|
||||||
Optional:
|
|
||||||
h. If you are going to run XFree86 with its native drivers, the
|
|
||||||
standard XFree86 4.1.0 and 4.2.0 drivers should work as is.
|
|
||||||
However, there's a bug in the XFree86 i810 drivers. It attempts
|
|
||||||
to use XAA even when switched to the console. This will crash
|
|
||||||
your server. I have a fix at this site:
|
|
||||||
|
|
||||||
http://i810fb.sourceforge.net.
|
|
||||||
|
|
||||||
You can either use the patch, or just replace
|
|
||||||
|
|
||||||
/usr/X11R6/lib/modules/drivers/i810_drv.o
|
|
||||||
|
|
||||||
with the one provided at the website.
|
|
||||||
|
|
||||||
i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
|
i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
|
||||||
patch to see the chipset in action (or inaction :-).
|
patch to see the chipset in action (or inaction :-).
|
||||||
|
|
||||||
|
@ -20,12 +20,83 @@ in a video= option, fbmem considers that to be a global video mode option.
|
|||||||
|
|
||||||
Valid mode specifiers (mode_option argument):
|
Valid mode specifiers (mode_option argument):
|
||||||
|
|
||||||
<xres>x<yres>[-<bpp>][@<refresh>]
|
<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m]
|
||||||
<name>[-<bpp>][@<refresh>]
|
<name>[-<bpp>][@<refresh>]
|
||||||
|
|
||||||
with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string.
|
with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string.
|
||||||
Things between square brackets are optional.
|
Things between square brackets are optional.
|
||||||
|
|
||||||
|
If 'M' is specified in the mode_option argument (after <yres> and before
|
||||||
|
<bpp> and <refresh>, if specified) the timings will be calculated using
|
||||||
|
VESA(TM) Coordinated Video Timings instead of looking up the mode from a table.
|
||||||
|
If 'R' is specified, do a 'reduced blanking' calculation for digital displays.
|
||||||
|
If 'i' is specified, calculate for an interlaced mode. And if 'm' is
|
||||||
|
specified, add margins to the calculation (1.8% of xres rounded down to 8
|
||||||
|
pixels and 1.8% of yres).
|
||||||
|
|
||||||
|
Sample usage: 1024x768M@60m - CVT timing with margins
|
||||||
|
|
||||||
|
***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
|
||||||
|
|
||||||
|
What is the VESA(TM) Coordinated Video Timings (CVT)?
|
||||||
|
|
||||||
|
From the VESA(TM) Website:
|
||||||
|
|
||||||
|
"The purpose of CVT is to provide a method for generating a consistent
|
||||||
|
and coordinated set of standard formats, display refresh rates, and
|
||||||
|
timing specifications for computer display products, both those
|
||||||
|
employing CRTs, and those using other display technologies. The
|
||||||
|
intention of CVT is to give both source and display manufacturers a
|
||||||
|
common set of tools to enable new timings to be developed in a
|
||||||
|
consistent manner that ensures greater compatibility."
|
||||||
|
|
||||||
|
This is the third standard approved by VESA(TM) concerning video timings. The
|
||||||
|
first was the Discrete Video Timings (DVT) which is a collection of
|
||||||
|
pre-defined modes approved by VESA(TM). The second is the Generalized Timing
|
||||||
|
Formula (GTF) which is an algorithm to calculate the timings, given the
|
||||||
|
pixelclock, the horizontal sync frequency, or the vertical refresh rate.
|
||||||
|
|
||||||
|
The GTF is limited by the fact that it is designed mainly for CRT displays.
|
||||||
|
It artificially increases the pixelclock because of its high blanking
|
||||||
|
requirement. This is inappropriate for digital display interface with its high
|
||||||
|
data rate which requires that it conserves the pixelclock as much as possible.
|
||||||
|
Also, GTF does not take into account the aspect ratio of the display.
|
||||||
|
|
||||||
|
The CVT addresses these limitations. If used with CRT's, the formula used
|
||||||
|
is a derivation of GTF with a few modifications. If used with digital
|
||||||
|
displays, the "reduced blanking" calculation can be used.
|
||||||
|
|
||||||
|
From the framebuffer subsystem perspective, new formats need not be added
|
||||||
|
to the global mode database whenever a new mode is released by display
|
||||||
|
manufacturers. Specifying for CVT will work for most, if not all, relatively
|
||||||
|
new CRT displays and probably with most flatpanels, if 'reduced blanking'
|
||||||
|
calculation is specified. (The CVT compatibility of the display can be
|
||||||
|
determined from its EDID. The version 1.3 of the EDID has extra 128-byte
|
||||||
|
blocks where additional timing information is placed. As of this time, there
|
||||||
|
is no support yet in the layer to parse this additional blocks.)
|
||||||
|
|
||||||
|
CVT also introduced a new naming convention (should be seen from dmesg output):
|
||||||
|
|
||||||
|
<pix>M<a>[-R]
|
||||||
|
|
||||||
|
where: pix = total amount of pixels in MB (xres x yres)
|
||||||
|
M = always present
|
||||||
|
a = aspect ratio (3 - 4:3; 4 - 5:4; 9 - 15:9, 16:9; A - 16:10)
|
||||||
|
-R = reduced blanking
|
||||||
|
|
||||||
|
example: .48M3-R - 800x600 with reduced blanking
|
||||||
|
|
||||||
|
Note: VESA(TM) has restrictions on what is a standard CVT timing:
|
||||||
|
|
||||||
|
- aspect ratio can only be one of the above values
|
||||||
|
- acceptable refresh rates are 50, 60, 70 or 85 Hz only
|
||||||
|
- if reduced blanking, the refresh rate must be at 60Hz
|
||||||
|
|
||||||
|
If one of the above are not satisfied, the kernel will print a warning but the
|
||||||
|
timings will still be calculated.
|
||||||
|
|
||||||
|
***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
|
||||||
|
|
||||||
To find a suitable video mode, you just call
|
To find a suitable video mode, you just call
|
||||||
|
|
||||||
int __init fb_find_mode(struct fb_var_screeninfo *var,
|
int __init fb_find_mode(struct fb_var_screeninfo *var,
|
||||||
|
@ -17,23 +17,6 @@ Who: Greg Kroah-Hartman <greg@kroah.com>
|
|||||||
|
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
What: ACPI S4bios support
|
|
||||||
When: May 2005
|
|
||||||
Why: Noone uses it, and it probably does not work, anyway. swsusp is
|
|
||||||
faster, more reliable, and people are actually using it.
|
|
||||||
Who: Pavel Machek <pavel@suse.cz>
|
|
||||||
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
What: PCI Name Database (CONFIG_PCI_NAMES)
|
|
||||||
When: July 2005
|
|
||||||
Why: It bloats the kernel unnecessarily, and is handled by userspace better
|
|
||||||
(pciutils supports it.) Will eliminate the need to try to keep the
|
|
||||||
pci.ids file in sync with the sf.net database all of the time.
|
|
||||||
Who: Greg Kroah-Hartman <gregkh@suse.de>
|
|
||||||
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
What: io_remap_page_range() (macro or function)
|
What: io_remap_page_range() (macro or function)
|
||||||
When: September 2005
|
When: September 2005
|
||||||
Why: Replaced by io_remap_pfn_range() which allows more memory space
|
Why: Replaced by io_remap_pfn_range() which allows more memory space
|
||||||
|
123
Documentation/filesystems/files.txt
Normal file
123
Documentation/filesystems/files.txt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
File management in the Linux kernel
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
This document describes how locking for files (struct file)
|
||||||
|
and file descriptor table (struct files) works.
|
||||||
|
|
||||||
|
Up until 2.6.12, the file descriptor table has been protected
|
||||||
|
with a lock (files->file_lock) and reference count (files->count).
|
||||||
|
->file_lock protected accesses to all the file related fields
|
||||||
|
of the table. ->count was used for sharing the file descriptor
|
||||||
|
table between tasks cloned with CLONE_FILES flag. Typically
|
||||||
|
this would be the case for posix threads. As with the common
|
||||||
|
refcounting model in the kernel, the last task doing
|
||||||
|
a put_files_struct() frees the file descriptor (fd) table.
|
||||||
|
The files (struct file) themselves are protected using
|
||||||
|
reference count (->f_count).
|
||||||
|
|
||||||
|
In the new lock-free model of file descriptor management,
|
||||||
|
the reference counting is similar, but the locking is
|
||||||
|
based on RCU. The file descriptor table contains multiple
|
||||||
|
elements - the fd sets (open_fds and close_on_exec, the
|
||||||
|
array of file pointers, the sizes of the sets and the array
|
||||||
|
etc.). In order for the updates to appear atomic to
|
||||||
|
a lock-free reader, all the elements of the file descriptor
|
||||||
|
table are in a separate structure - struct fdtable.
|
||||||
|
files_struct contains a pointer to struct fdtable through
|
||||||
|
which the actual fd table is accessed. Initially the
|
||||||
|
fdtable is embedded in files_struct itself. On a subsequent
|
||||||
|
expansion of fdtable, a new fdtable structure is allocated
|
||||||
|
and files->fdtab points to the new structure. The fdtable
|
||||||
|
structure is freed with RCU and lock-free readers either
|
||||||
|
see the old fdtable or the new fdtable making the update
|
||||||
|
appear atomic. Here are the locking rules for
|
||||||
|
the fdtable structure -
|
||||||
|
|
||||||
|
1. All references to the fdtable must be done through
|
||||||
|
the files_fdtable() macro :
|
||||||
|
|
||||||
|
struct fdtable *fdt;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
fdt = files_fdtable(files);
|
||||||
|
....
|
||||||
|
if (n <= fdt->max_fds)
|
||||||
|
....
|
||||||
|
...
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
files_fdtable() uses rcu_dereference() macro which takes care of
|
||||||
|
the memory barrier requirements for lock-free dereference.
|
||||||
|
The fdtable pointer must be read within the read-side
|
||||||
|
critical section.
|
||||||
|
|
||||||
|
2. Reading of the fdtable as described above must be protected
|
||||||
|
by rcu_read_lock()/rcu_read_unlock().
|
||||||
|
|
||||||
|
3. For any update to the the fd table, files->file_lock must
|
||||||
|
be held.
|
||||||
|
|
||||||
|
4. To look up the file structure given an fd, a reader
|
||||||
|
must use either fcheck() or fcheck_files() APIs. These
|
||||||
|
take care of barrier requirements due to lock-free lookup.
|
||||||
|
An example :
|
||||||
|
|
||||||
|
struct file *file;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
file = fcheck(fd);
|
||||||
|
if (file) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
....
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
5. Handling of the file structures is special. Since the look-up
|
||||||
|
of the fd (fget()/fget_light()) are lock-free, it is possible
|
||||||
|
that look-up may race with the last put() operation on the
|
||||||
|
file structure. This is avoided using the rcuref APIs
|
||||||
|
on ->f_count :
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
file = fcheck_files(files, fd);
|
||||||
|
if (file) {
|
||||||
|
if (rcuref_inc_lf(&file->f_count))
|
||||||
|
*fput_needed = 1;
|
||||||
|
else
|
||||||
|
/* Didn't get the reference, someone's freed */
|
||||||
|
file = NULL;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
....
|
||||||
|
return file;
|
||||||
|
|
||||||
|
rcuref_inc_lf() detects if refcounts is already zero or
|
||||||
|
goes to zero during increment. If it does, we fail
|
||||||
|
fget()/fget_light().
|
||||||
|
|
||||||
|
6. Since both fdtable and file structures can be looked up
|
||||||
|
lock-free, they must be installed using rcu_assign_pointer()
|
||||||
|
API. If they are looked up lock-free, rcu_dereference()
|
||||||
|
must be used. However it is advisable to use files_fdtable()
|
||||||
|
and fcheck()/fcheck_files() which take care of these issues.
|
||||||
|
|
||||||
|
7. While updating, the fdtable pointer must be looked up while
|
||||||
|
holding files->file_lock. If ->file_lock is dropped, then
|
||||||
|
another thread expand the files thereby creating a new
|
||||||
|
fdtable and making the earlier fdtable pointer stale.
|
||||||
|
For example :
|
||||||
|
|
||||||
|
spin_lock(&files->file_lock);
|
||||||
|
fd = locate_fd(files, file, start);
|
||||||
|
if (fd >= 0) {
|
||||||
|
/* locate_fd() may have expanded fdtable, load the ptr */
|
||||||
|
fdt = files_fdtable(files);
|
||||||
|
FD_SET(fd, fdt->open_fds);
|
||||||
|
FD_CLR(fd, fdt->close_on_exec);
|
||||||
|
spin_unlock(&files->file_lock);
|
||||||
|
.....
|
||||||
|
|
||||||
|
Since locate_fd() can drop ->file_lock (and reacquire ->file_lock),
|
||||||
|
the fdtable pointer (fdt) must be loaded after locate_fd().
|
||||||
|
|
315
Documentation/filesystems/fuse.txt
Normal file
315
Documentation/filesystems/fuse.txt
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
Definitions
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
Userspace filesystem:
|
||||||
|
|
||||||
|
A filesystem in which data and metadata are provided by an ordinary
|
||||||
|
userspace process. The filesystem can be accessed normally through
|
||||||
|
the kernel interface.
|
||||||
|
|
||||||
|
Filesystem daemon:
|
||||||
|
|
||||||
|
The process(es) providing the data and metadata of the filesystem.
|
||||||
|
|
||||||
|
Non-privileged mount (or user mount):
|
||||||
|
|
||||||
|
A userspace filesystem mounted by a non-privileged (non-root) user.
|
||||||
|
The filesystem daemon is running with the privileges of the mounting
|
||||||
|
user. NOTE: this is not the same as mounts allowed with the "user"
|
||||||
|
option in /etc/fstab, which is not discussed here.
|
||||||
|
|
||||||
|
Mount owner:
|
||||||
|
|
||||||
|
The user who does the mounting.
|
||||||
|
|
||||||
|
User:
|
||||||
|
|
||||||
|
The user who is performing filesystem operations.
|
||||||
|
|
||||||
|
What is FUSE?
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
FUSE is a userspace filesystem framework. It consists of a kernel
|
||||||
|
module (fuse.ko), a userspace library (libfuse.*) and a mount utility
|
||||||
|
(fusermount).
|
||||||
|
|
||||||
|
One of the most important features of FUSE is allowing secure,
|
||||||
|
non-privileged mounts. This opens up new possibilities for the use of
|
||||||
|
filesystems. A good example is sshfs: a secure network filesystem
|
||||||
|
using the sftp protocol.
|
||||||
|
|
||||||
|
The userspace library and utilities are available from the FUSE
|
||||||
|
homepage:
|
||||||
|
|
||||||
|
http://fuse.sourceforge.net/
|
||||||
|
|
||||||
|
Mount options
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
'fd=N'
|
||||||
|
|
||||||
|
The file descriptor to use for communication between the userspace
|
||||||
|
filesystem and the kernel. The file descriptor must have been
|
||||||
|
obtained by opening the FUSE device ('/dev/fuse').
|
||||||
|
|
||||||
|
'rootmode=M'
|
||||||
|
|
||||||
|
The file mode of the filesystem's root in octal representation.
|
||||||
|
|
||||||
|
'user_id=N'
|
||||||
|
|
||||||
|
The numeric user id of the mount owner.
|
||||||
|
|
||||||
|
'group_id=N'
|
||||||
|
|
||||||
|
The numeric group id of the mount owner.
|
||||||
|
|
||||||
|
'default_permissions'
|
||||||
|
|
||||||
|
By default FUSE doesn't check file access permissions, the
|
||||||
|
filesystem is free to implement it's access policy or leave it to
|
||||||
|
the underlying file access mechanism (e.g. in case of network
|
||||||
|
filesystems). This option enables permission checking, restricting
|
||||||
|
access based on file mode. This is option is usually useful
|
||||||
|
together with the 'allow_other' mount option.
|
||||||
|
|
||||||
|
'allow_other'
|
||||||
|
|
||||||
|
This option overrides the security measure restricting file access
|
||||||
|
to the user mounting the filesystem. This option is by default only
|
||||||
|
allowed to root, but this restriction can be removed with a
|
||||||
|
(userspace) configuration option.
|
||||||
|
|
||||||
|
'max_read=N'
|
||||||
|
|
||||||
|
With this option the maximum size of read operations can be set.
|
||||||
|
The default is infinite. Note that the size of read requests is
|
||||||
|
limited anyway to 32 pages (which is 128kbyte on i386).
|
||||||
|
|
||||||
|
How do non-privileged mounts work?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Since the mount() system call is a privileged operation, a helper
|
||||||
|
program (fusermount) is needed, which is installed setuid root.
|
||||||
|
|
||||||
|
The implication of providing non-privileged mounts is that the mount
|
||||||
|
owner must not be able to use this capability to compromise the
|
||||||
|
system. Obvious requirements arising from this are:
|
||||||
|
|
||||||
|
A) mount owner should not be able to get elevated privileges with the
|
||||||
|
help of the mounted filesystem
|
||||||
|
|
||||||
|
B) mount owner should not get illegitimate access to information from
|
||||||
|
other users' and the super user's processes
|
||||||
|
|
||||||
|
C) mount owner should not be able to induce undesired behavior in
|
||||||
|
other users' or the super user's processes
|
||||||
|
|
||||||
|
How are requirements fulfilled?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A) The mount owner could gain elevated privileges by either:
|
||||||
|
|
||||||
|
1) creating a filesystem containing a device file, then opening
|
||||||
|
this device
|
||||||
|
|
||||||
|
2) creating a filesystem containing a suid or sgid application,
|
||||||
|
then executing this application
|
||||||
|
|
||||||
|
The solution is not to allow opening device files and ignore
|
||||||
|
setuid and setgid bits when executing programs. To ensure this
|
||||||
|
fusermount always adds "nosuid" and "nodev" to the mount options
|
||||||
|
for non-privileged mounts.
|
||||||
|
|
||||||
|
B) If another user is accessing files or directories in the
|
||||||
|
filesystem, the filesystem daemon serving requests can record the
|
||||||
|
exact sequence and timing of operations performed. This
|
||||||
|
information is otherwise inaccessible to the mount owner, so this
|
||||||
|
counts as an information leak.
|
||||||
|
|
||||||
|
The solution to this problem will be presented in point 2) of C).
|
||||||
|
|
||||||
|
C) There are several ways in which the mount owner can induce
|
||||||
|
undesired behavior in other users' processes, such as:
|
||||||
|
|
||||||
|
1) mounting a filesystem over a file or directory which the mount
|
||||||
|
owner could otherwise not be able to modify (or could only
|
||||||
|
make limited modifications).
|
||||||
|
|
||||||
|
This is solved in fusermount, by checking the access
|
||||||
|
permissions on the mountpoint and only allowing the mount if
|
||||||
|
the mount owner can do unlimited modification (has write
|
||||||
|
access to the mountpoint, and mountpoint is not a "sticky"
|
||||||
|
directory)
|
||||||
|
|
||||||
|
2) Even if 1) is solved the mount owner can change the behavior
|
||||||
|
of other users' processes.
|
||||||
|
|
||||||
|
i) It can slow down or indefinitely delay the execution of a
|
||||||
|
filesystem operation creating a DoS against the user or the
|
||||||
|
whole system. For example a suid application locking a
|
||||||
|
system file, and then accessing a file on the mount owner's
|
||||||
|
filesystem could be stopped, and thus causing the system
|
||||||
|
file to be locked forever.
|
||||||
|
|
||||||
|
ii) It can present files or directories of unlimited length, or
|
||||||
|
directory structures of unlimited depth, possibly causing a
|
||||||
|
system process to eat up diskspace, memory or other
|
||||||
|
resources, again causing DoS.
|
||||||
|
|
||||||
|
The solution to this as well as B) is not to allow processes
|
||||||
|
to access the filesystem, which could otherwise not be
|
||||||
|
monitored or manipulated by the mount owner. Since if the
|
||||||
|
mount owner can ptrace a process, it can do all of the above
|
||||||
|
without using a FUSE mount, the same criteria as used in
|
||||||
|
ptrace can be used to check if a process is allowed to access
|
||||||
|
the filesystem or not.
|
||||||
|
|
||||||
|
Note that the ptrace check is not strictly necessary to
|
||||||
|
prevent B/2/i, it is enough to check if mount owner has enough
|
||||||
|
privilege to send signal to the process accessing the
|
||||||
|
filesystem, since SIGSTOP can be used to get a similar effect.
|
||||||
|
|
||||||
|
I think these limitations are unacceptable?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If a sysadmin trusts the users enough, or can ensure through other
|
||||||
|
measures, that system processes will never enter non-privileged
|
||||||
|
mounts, it can relax the last limitation with a "user_allow_other"
|
||||||
|
config option. If this config option is set, the mounting user can
|
||||||
|
add the "allow_other" mount option which disables the check for other
|
||||||
|
users' processes.
|
||||||
|
|
||||||
|
Kernel - userspace interface
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The following diagram shows how a filesystem operation (in this
|
||||||
|
example unlink) is performed in FUSE.
|
||||||
|
|
||||||
|
NOTE: everything in this description is greatly simplified
|
||||||
|
|
||||||
|
| "rm /mnt/fuse/file" | FUSE filesystem daemon
|
||||||
|
| |
|
||||||
|
| | >sys_read()
|
||||||
|
| | >fuse_dev_read()
|
||||||
|
| | >request_wait()
|
||||||
|
| | [sleep on fc->waitq]
|
||||||
|
| |
|
||||||
|
| >sys_unlink() |
|
||||||
|
| >fuse_unlink() |
|
||||||
|
| [get request from |
|
||||||
|
| fc->unused_list] |
|
||||||
|
| >request_send() |
|
||||||
|
| [queue req on fc->pending] |
|
||||||
|
| [wake up fc->waitq] | [woken up]
|
||||||
|
| >request_wait_answer() |
|
||||||
|
| [sleep on req->waitq] |
|
||||||
|
| | <request_wait()
|
||||||
|
| | [remove req from fc->pending]
|
||||||
|
| | [copy req to read buffer]
|
||||||
|
| | [add req to fc->processing]
|
||||||
|
| | <fuse_dev_read()
|
||||||
|
| | <sys_read()
|
||||||
|
| |
|
||||||
|
| | [perform unlink]
|
||||||
|
| |
|
||||||
|
| | >sys_write()
|
||||||
|
| | >fuse_dev_write()
|
||||||
|
| | [look up req in fc->processing]
|
||||||
|
| | [remove from fc->processing]
|
||||||
|
| | [copy write buffer to req]
|
||||||
|
| [woken up] | [wake up req->waitq]
|
||||||
|
| | <fuse_dev_write()
|
||||||
|
| | <sys_write()
|
||||||
|
| <request_wait_answer() |
|
||||||
|
| <request_send() |
|
||||||
|
| [add request to |
|
||||||
|
| fc->unused_list] |
|
||||||
|
| <fuse_unlink() |
|
||||||
|
| <sys_unlink() |
|
||||||
|
|
||||||
|
There are a couple of ways in which to deadlock a FUSE filesystem.
|
||||||
|
Since we are talking about unprivileged userspace programs,
|
||||||
|
something must be done about these.
|
||||||
|
|
||||||
|
Scenario 1 - Simple deadlock
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
| "rm /mnt/fuse/file" | FUSE filesystem daemon
|
||||||
|
| |
|
||||||
|
| >sys_unlink("/mnt/fuse/file") |
|
||||||
|
| [acquire inode semaphore |
|
||||||
|
| for "file"] |
|
||||||
|
| >fuse_unlink() |
|
||||||
|
| [sleep on req->waitq] |
|
||||||
|
| | <sys_read()
|
||||||
|
| | >sys_unlink("/mnt/fuse/file")
|
||||||
|
| | [acquire inode semaphore
|
||||||
|
| | for "file"]
|
||||||
|
| | *DEADLOCK*
|
||||||
|
|
||||||
|
The solution for this is to allow requests to be interrupted while
|
||||||
|
they are in userspace:
|
||||||
|
|
||||||
|
| [interrupted by signal] |
|
||||||
|
| <fuse_unlink() |
|
||||||
|
| [release semaphore] | [semaphore acquired]
|
||||||
|
| <sys_unlink() |
|
||||||
|
| | >fuse_unlink()
|
||||||
|
| | [queue req on fc->pending]
|
||||||
|
| | [wake up fc->waitq]
|
||||||
|
| | [sleep on req->waitq]
|
||||||
|
|
||||||
|
If the filesystem daemon was single threaded, this will stop here,
|
||||||
|
since there's no other thread to dequeue and execute the request.
|
||||||
|
In this case the solution is to kill the FUSE daemon as well. If
|
||||||
|
there are multiple serving threads, you just have to kill them as
|
||||||
|
long as any remain.
|
||||||
|
|
||||||
|
Moral: a filesystem which deadlocks, can soon find itself dead.
|
||||||
|
|
||||||
|
Scenario 2 - Tricky deadlock
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
This one needs a carefully crafted filesystem. It's a variation on
|
||||||
|
the above, only the call back to the filesystem is not explicit,
|
||||||
|
but is caused by a pagefault.
|
||||||
|
|
||||||
|
| Kamikaze filesystem thread 1 | Kamikaze filesystem thread 2
|
||||||
|
| |
|
||||||
|
| [fd = open("/mnt/fuse/file")] | [request served normally]
|
||||||
|
| [mmap fd to 'addr'] |
|
||||||
|
| [close fd] | [FLUSH triggers 'magic' flag]
|
||||||
|
| [read a byte from addr] |
|
||||||
|
| >do_page_fault() |
|
||||||
|
| [find or create page] |
|
||||||
|
| [lock page] |
|
||||||
|
| >fuse_readpage() |
|
||||||
|
| [queue READ request] |
|
||||||
|
| [sleep on req->waitq] |
|
||||||
|
| | [read request to buffer]
|
||||||
|
| | [create reply header before addr]
|
||||||
|
| | >sys_write(addr - headerlength)
|
||||||
|
| | >fuse_dev_write()
|
||||||
|
| | [look up req in fc->processing]
|
||||||
|
| | [remove from fc->processing]
|
||||||
|
| | [copy write buffer to req]
|
||||||
|
| | >do_page_fault()
|
||||||
|
| | [find or create page]
|
||||||
|
| | [lock page]
|
||||||
|
| | * DEADLOCK *
|
||||||
|
|
||||||
|
Solution is again to let the the request be interrupted (not
|
||||||
|
elaborated further).
|
||||||
|
|
||||||
|
An additional problem is that while the write buffer is being
|
||||||
|
copied to the request, the request must not be interrupted. This
|
||||||
|
is because the destination address of the copy may not be valid
|
||||||
|
after the request is interrupted.
|
||||||
|
|
||||||
|
This is solved with doing the copy atomically, and allowing
|
||||||
|
interruption while the page(s) belonging to the write buffer are
|
||||||
|
faulted with get_user_pages(). The 'req->locked' flag indicates
|
||||||
|
when the copy is taking place, and interruption is delayed until
|
||||||
|
this flag is unset.
|
||||||
|
|
@ -439,6 +439,18 @@ ChangeLog
|
|||||||
|
|
||||||
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
|
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
|
||||||
|
|
||||||
|
2.1.24:
|
||||||
|
- Support journals ($LogFile) which have been modified by chkdsk. This
|
||||||
|
means users can boot into Windows after we marked the volume dirty.
|
||||||
|
The Windows boot will run chkdsk and then reboot. The user can then
|
||||||
|
immediately boot into Linux rather than having to do a full Windows
|
||||||
|
boot first before rebooting into Linux and we will recognize such a
|
||||||
|
journal and empty it as it is clean by definition.
|
||||||
|
- Support journals ($LogFile) with only one restart page as well as
|
||||||
|
journals with two different restart pages. We sanity check both and
|
||||||
|
either use the only sane one or the more recent one of the two in the
|
||||||
|
case that both are valid.
|
||||||
|
- Lots of bug fixes and enhancements across the board.
|
||||||
2.1.23:
|
2.1.23:
|
||||||
- Stamp the user space journal, aka transaction log, aka $UsnJrnl, if
|
- Stamp the user space journal, aka transaction log, aka $UsnJrnl, if
|
||||||
it is present and active thus telling Windows and applications using
|
it is present and active thus telling Windows and applications using
|
||||||
|
@ -1241,16 +1241,38 @@ swap-intensive.
|
|||||||
overcommit_memory
|
overcommit_memory
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
This file contains one value. The following algorithm is used to decide if
|
Controls overcommit of system memory, possibly allowing processes
|
||||||
there's enough memory: if the value of overcommit_memory is positive, then
|
to allocate (but not use) more memory than is actually available.
|
||||||
there's always enough memory. This is a useful feature, since programs often
|
|
||||||
malloc() huge amounts of memory 'just in case', while they only use a small
|
|
||||||
part of it. Leaving this value at 0 will lead to the failure of such a huge
|
|
||||||
malloc(), when in fact the system has enough memory for the program to run.
|
|
||||||
|
|
||||||
On the other hand, enabling this feature can cause you to run out of memory
|
|
||||||
and thrash the system to death, so large and/or important servers will want to
|
0 - Heuristic overcommit handling. Obvious overcommits of
|
||||||
set this value to 0.
|
address space are refused. Used for a typical system. It
|
||||||
|
ensures a seriously wild allocation fails while allowing
|
||||||
|
overcommit to reduce swap usage. root is allowed to
|
||||||
|
allocate slighly more memory in this mode. This is the
|
||||||
|
default.
|
||||||
|
|
||||||
|
1 - Always overcommit. Appropriate for some scientific
|
||||||
|
applications.
|
||||||
|
|
||||||
|
2 - Don't overcommit. The total address space commit
|
||||||
|
for the system is not permitted to exceed swap plus a
|
||||||
|
configurable percentage (default is 50) of physical RAM.
|
||||||
|
Depending on the percentage you use, in most situations
|
||||||
|
this means a process will not be killed while attempting
|
||||||
|
to use already-allocated memory but will receive errors
|
||||||
|
on memory allocation as appropriate.
|
||||||
|
|
||||||
|
overcommit_ratio
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Percentage of physical memory size to include in overcommit calculations
|
||||||
|
(see above.)
|
||||||
|
|
||||||
|
Memory allocation limit = swapspace + physmem * (overcommit_ratio / 100)
|
||||||
|
|
||||||
|
swapspace = total size of all swap areas
|
||||||
|
physmem = size of physical memory in system
|
||||||
|
|
||||||
nr_hugepages and hugetlb_shm_group
|
nr_hugepages and hugetlb_shm_group
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
95
Documentation/filesystems/v9fs.txt
Normal file
95
Documentation/filesystems/v9fs.txt
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
V9FS: 9P2000 for Linux
|
||||||
|
======================
|
||||||
|
|
||||||
|
ABOUT
|
||||||
|
=====
|
||||||
|
|
||||||
|
v9fs is a Unix implementation of the Plan 9 9p remote filesystem protocol.
|
||||||
|
|
||||||
|
This software was originally developed by Ron Minnich <rminnich@lanl.gov>
|
||||||
|
and Maya Gokhale <maya@lanl.gov>. Additional development by Greg Watson
|
||||||
|
<gwatson@lanl.gov> and most recently Eric Van Hensbergen
|
||||||
|
<ericvh@gmail.com> and Latchesar Ionkov <lucho@ionkov.net>.
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
=====
|
||||||
|
|
||||||
|
For remote file server:
|
||||||
|
|
||||||
|
mount -t 9P 10.10.1.2 /mnt/9
|
||||||
|
|
||||||
|
For Plan 9 From User Space applications (http://swtch.com/plan9)
|
||||||
|
|
||||||
|
mount -t 9P `namespace`/acme /mnt/9 -o proto=unix,name=$USER
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
=======
|
||||||
|
|
||||||
|
proto=name select an alternative transport. Valid options are
|
||||||
|
currently:
|
||||||
|
unix - specifying a named pipe mount point
|
||||||
|
tcp - specifying a normal TCP/IP connection
|
||||||
|
fd - used passed file descriptors for connection
|
||||||
|
(see rfdno and wfdno)
|
||||||
|
|
||||||
|
name=name user name to attempt mount as on the remote server. The
|
||||||
|
server may override or ignore this value. Certain user
|
||||||
|
names may require authentication.
|
||||||
|
|
||||||
|
aname=name aname specifies the file tree to access when the server is
|
||||||
|
offering several exported file systems.
|
||||||
|
|
||||||
|
debug=n specifies debug level. The debug level is a bitmask.
|
||||||
|
0x01 = display verbose error messages
|
||||||
|
0x02 = developer debug (DEBUG_CURRENT)
|
||||||
|
0x04 = display 9P trace
|
||||||
|
0x08 = display VFS trace
|
||||||
|
0x10 = display Marshalling debug
|
||||||
|
0x20 = display RPC debug
|
||||||
|
0x40 = display transport debug
|
||||||
|
0x80 = display allocation debug
|
||||||
|
|
||||||
|
rfdno=n the file descriptor for reading with proto=fd
|
||||||
|
|
||||||
|
wfdno=n the file descriptor for writing with proto=fd
|
||||||
|
|
||||||
|
maxdata=n the number of bytes to use for 9P packet payload (msize)
|
||||||
|
|
||||||
|
port=n port to connect to on the remote server
|
||||||
|
|
||||||
|
timeout=n request timeouts (in ms) (default 60000ms)
|
||||||
|
|
||||||
|
noextend force legacy mode (no 9P2000.u semantics)
|
||||||
|
|
||||||
|
uid attempt to mount as a particular uid
|
||||||
|
|
||||||
|
gid attempt to mount with a particular gid
|
||||||
|
|
||||||
|
afid security channel - used by Plan 9 authentication protocols
|
||||||
|
|
||||||
|
nodevmap do not map special files - represent them as normal files.
|
||||||
|
This can be used to share devices/named pipes/sockets between
|
||||||
|
hosts. This functionality will be expanded in later versions.
|
||||||
|
|
||||||
|
RESOURCES
|
||||||
|
=========
|
||||||
|
|
||||||
|
The Linux version of the 9P server, along with some client-side utilities
|
||||||
|
can be found at http://v9fs.sf.net (along with a CVS repository of the
|
||||||
|
development branch of this module). There are user and developer mailing
|
||||||
|
lists here, as well as a bug-tracker.
|
||||||
|
|
||||||
|
For more information on the Plan 9 Operating System check out
|
||||||
|
http://plan9.bell-labs.com/plan9
|
||||||
|
|
||||||
|
For information on Plan 9 from User Space (Plan 9 applications and libraries
|
||||||
|
ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9
|
||||||
|
|
||||||
|
|
||||||
|
STATUS
|
||||||
|
======
|
||||||
|
|
||||||
|
The 2.6 kernel support is working on PPC and x86.
|
||||||
|
|
||||||
|
PLEASE USE THE SOURCEFORGE BUG-TRACKER TO REPORT PROBLEMS.
|
||||||
|
|
@ -1,35 +1,27 @@
|
|||||||
/* -*- auto-fill -*- */
|
|
||||||
|
|
||||||
Overview of the Virtual File System
|
Overview of the Linux Virtual File System
|
||||||
|
|
||||||
Richard Gooch <rgooch@atnf.csiro.au>
|
Original author: Richard Gooch <rgooch@atnf.csiro.au>
|
||||||
|
|
||||||
5-JUL-1999
|
Last updated on August 25, 2005
|
||||||
|
|
||||||
|
Copyright (C) 1999 Richard Gooch
|
||||||
|
Copyright (C) 2005 Pekka Enberg
|
||||||
|
|
||||||
|
This file is released under the GPLv2.
|
||||||
|
|
||||||
|
|
||||||
Conventions used in this document <section>
|
What is it?
|
||||||
=================================
|
|
||||||
|
|
||||||
Each section in this document will have the string "<section>" at the
|
|
||||||
right-hand side of the section title. Each subsection will have
|
|
||||||
"<subsection>" at the right-hand side. These strings are meant to make
|
|
||||||
it easier to search through the document.
|
|
||||||
|
|
||||||
NOTE that the master copy of this document is available online at:
|
|
||||||
http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt
|
|
||||||
|
|
||||||
|
|
||||||
What is it? <section>
|
|
||||||
===========
|
===========
|
||||||
|
|
||||||
The Virtual File System (otherwise known as the Virtual Filesystem
|
The Virtual File System (otherwise known as the Virtual Filesystem
|
||||||
Switch) is the software layer in the kernel that provides the
|
Switch) is the software layer in the kernel that provides the
|
||||||
filesystem interface to userspace programs. It also provides an
|
filesystem interface to userspace programs. It also provides an
|
||||||
abstraction within the kernel which allows different filesystem
|
abstraction within the kernel which allows different filesystem
|
||||||
implementations to co-exist.
|
implementations to coexist.
|
||||||
|
|
||||||
|
|
||||||
A Quick Look At How It Works <section>
|
A Quick Look At How It Works
|
||||||
============================
|
============================
|
||||||
|
|
||||||
In this section I'll briefly describe how things work, before
|
In this section I'll briefly describe how things work, before
|
||||||
@ -38,7 +30,8 @@ when user programs open and manipulate files, and then look from the
|
|||||||
other view which is how a filesystem is supported and subsequently
|
other view which is how a filesystem is supported and subsequently
|
||||||
mounted.
|
mounted.
|
||||||
|
|
||||||
Opening a File <subsection>
|
|
||||||
|
Opening a File
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The VFS implements the open(2), stat(2), chmod(2) and similar system
|
The VFS implements the open(2), stat(2), chmod(2) and similar system
|
||||||
@ -77,7 +70,7 @@ back to userspace.
|
|||||||
|
|
||||||
Opening a file requires another operation: allocation of a file
|
Opening a file requires another operation: allocation of a file
|
||||||
structure (this is the kernel-side implementation of file
|
structure (this is the kernel-side implementation of file
|
||||||
descriptors). The freshly allocated file structure is initialised with
|
descriptors). The freshly allocated file structure is initialized with
|
||||||
a pointer to the dentry and a set of file operation member functions.
|
a pointer to the dentry and a set of file operation member functions.
|
||||||
These are taken from the inode data. The open() file method is then
|
These are taken from the inode data. The open() file method is then
|
||||||
called so the specific filesystem implementation can do it's work. You
|
called so the specific filesystem implementation can do it's work. You
|
||||||
@ -102,7 +95,8 @@ filesystem or driver code at the same time, on different
|
|||||||
processors. You should ensure that access to shared resources is
|
processors. You should ensure that access to shared resources is
|
||||||
protected by appropriate locks.
|
protected by appropriate locks.
|
||||||
|
|
||||||
Registering and Mounting a Filesystem <subsection>
|
|
||||||
|
Registering and Mounting a Filesystem
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
If you want to support a new kind of filesystem in the kernel, all you
|
If you want to support a new kind of filesystem in the kernel, all you
|
||||||
@ -123,17 +117,21 @@ updated to point to the root inode for the new filesystem.
|
|||||||
It's now time to look at things in more detail.
|
It's now time to look at things in more detail.
|
||||||
|
|
||||||
|
|
||||||
struct file_system_type <section>
|
struct file_system_type
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This describes the filesystem. As of kernel 2.1.99, the following
|
This describes the filesystem. As of kernel 2.6.13, the following
|
||||||
members are defined:
|
members are defined:
|
||||||
|
|
||||||
struct file_system_type {
|
struct file_system_type {
|
||||||
const char *name;
|
const char *name;
|
||||||
int fs_flags;
|
int fs_flags;
|
||||||
struct super_block *(*read_super) (struct super_block *, void *, int);
|
struct super_block *(*get_sb) (struct file_system_type *, int,
|
||||||
struct file_system_type * next;
|
const char *, void *);
|
||||||
|
void (*kill_sb) (struct super_block *);
|
||||||
|
struct module *owner;
|
||||||
|
struct file_system_type * next;
|
||||||
|
struct list_head fs_supers;
|
||||||
};
|
};
|
||||||
|
|
||||||
name: the name of the filesystem type, such as "ext2", "iso9660",
|
name: the name of the filesystem type, such as "ext2", "iso9660",
|
||||||
@ -141,51 +139,97 @@ struct file_system_type {
|
|||||||
|
|
||||||
fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.)
|
fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.)
|
||||||
|
|
||||||
read_super: the method to call when a new instance of this
|
get_sb: the method to call when a new instance of this
|
||||||
filesystem should be mounted
|
filesystem should be mounted
|
||||||
|
|
||||||
next: for internal VFS use: you should initialise this to NULL
|
kill_sb: the method to call when an instance of this filesystem
|
||||||
|
should be unmounted
|
||||||
|
|
||||||
The read_super() method has the following arguments:
|
owner: for internal VFS use: you should initialize this to THIS_MODULE in
|
||||||
|
most cases.
|
||||||
|
|
||||||
|
next: for internal VFS use: you should initialize this to NULL
|
||||||
|
|
||||||
|
The get_sb() method has the following arguments:
|
||||||
|
|
||||||
struct super_block *sb: the superblock structure. This is partially
|
struct super_block *sb: the superblock structure. This is partially
|
||||||
initialised by the VFS and the rest must be initialised by the
|
initialized by the VFS and the rest must be initialized by the
|
||||||
read_super() method
|
get_sb() method
|
||||||
|
|
||||||
|
int flags: mount flags
|
||||||
|
|
||||||
|
const char *dev_name: the device name we are mounting.
|
||||||
|
|
||||||
void *data: arbitrary mount options, usually comes as an ASCII
|
void *data: arbitrary mount options, usually comes as an ASCII
|
||||||
string
|
string
|
||||||
|
|
||||||
int silent: whether or not to be silent on error
|
int silent: whether or not to be silent on error
|
||||||
|
|
||||||
The read_super() method must determine if the block device specified
|
The get_sb() method must determine if the block device specified
|
||||||
in the superblock contains a filesystem of the type the method
|
in the superblock contains a filesystem of the type the method
|
||||||
supports. On success the method returns the superblock pointer, on
|
supports. On success the method returns the superblock pointer, on
|
||||||
failure it returns NULL.
|
failure it returns NULL.
|
||||||
|
|
||||||
The most interesting member of the superblock structure that the
|
The most interesting member of the superblock structure that the
|
||||||
read_super() method fills in is the "s_op" field. This is a pointer to
|
get_sb() method fills in is the "s_op" field. This is a pointer to
|
||||||
a "struct super_operations" which describes the next level of the
|
a "struct super_operations" which describes the next level of the
|
||||||
filesystem implementation.
|
filesystem implementation.
|
||||||
|
|
||||||
|
Usually, a filesystem uses generic one of the generic get_sb()
|
||||||
|
implementations and provides a fill_super() method instead. The
|
||||||
|
generic methods are:
|
||||||
|
|
||||||
struct super_operations <section>
|
get_sb_bdev: mount a filesystem residing on a block device
|
||||||
|
|
||||||
|
get_sb_nodev: mount a filesystem that is not backed by a device
|
||||||
|
|
||||||
|
get_sb_single: mount a filesystem which shares the instance between
|
||||||
|
all mounts
|
||||||
|
|
||||||
|
A fill_super() method implementation has the following arguments:
|
||||||
|
|
||||||
|
struct super_block *sb: the superblock structure. The method fill_super()
|
||||||
|
must initialize this properly.
|
||||||
|
|
||||||
|
void *data: arbitrary mount options, usually comes as an ASCII
|
||||||
|
string
|
||||||
|
|
||||||
|
int silent: whether or not to be silent on error
|
||||||
|
|
||||||
|
|
||||||
|
struct super_operations
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This describes how the VFS can manipulate the superblock of your
|
This describes how the VFS can manipulate the superblock of your
|
||||||
filesystem. As of kernel 2.1.99, the following members are defined:
|
filesystem. As of kernel 2.6.13, the following members are defined:
|
||||||
|
|
||||||
struct super_operations {
|
struct super_operations {
|
||||||
void (*read_inode) (struct inode *);
|
struct inode *(*alloc_inode)(struct super_block *sb);
|
||||||
int (*write_inode) (struct inode *, int);
|
void (*destroy_inode)(struct inode *);
|
||||||
void (*put_inode) (struct inode *);
|
|
||||||
void (*drop_inode) (struct inode *);
|
void (*read_inode) (struct inode *);
|
||||||
void (*delete_inode) (struct inode *);
|
|
||||||
int (*notify_change) (struct dentry *, struct iattr *);
|
void (*dirty_inode) (struct inode *);
|
||||||
void (*put_super) (struct super_block *);
|
int (*write_inode) (struct inode *, int);
|
||||||
void (*write_super) (struct super_block *);
|
void (*put_inode) (struct inode *);
|
||||||
int (*statfs) (struct super_block *, struct statfs *, int);
|
void (*drop_inode) (struct inode *);
|
||||||
int (*remount_fs) (struct super_block *, int *, char *);
|
void (*delete_inode) (struct inode *);
|
||||||
void (*clear_inode) (struct inode *);
|
void (*put_super) (struct super_block *);
|
||||||
|
void (*write_super) (struct super_block *);
|
||||||
|
int (*sync_fs)(struct super_block *sb, int wait);
|
||||||
|
void (*write_super_lockfs) (struct super_block *);
|
||||||
|
void (*unlockfs) (struct super_block *);
|
||||||
|
int (*statfs) (struct super_block *, struct kstatfs *);
|
||||||
|
int (*remount_fs) (struct super_block *, int *, char *);
|
||||||
|
void (*clear_inode) (struct inode *);
|
||||||
|
void (*umount_begin) (struct super_block *);
|
||||||
|
|
||||||
|
void (*sync_inodes) (struct super_block *sb,
|
||||||
|
struct writeback_control *wbc);
|
||||||
|
int (*show_options)(struct seq_file *, struct vfsmount *);
|
||||||
|
|
||||||
|
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
|
||||||
|
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
All methods are called without any locks being held, unless otherwise
|
All methods are called without any locks being held, unless otherwise
|
||||||
@ -193,43 +237,62 @@ noted. This means that most methods can block safely. All methods are
|
|||||||
only called from a process context (i.e. not from an interrupt handler
|
only called from a process context (i.e. not from an interrupt handler
|
||||||
or bottom half).
|
or bottom half).
|
||||||
|
|
||||||
|
alloc_inode: this method is called by inode_alloc() to allocate memory
|
||||||
|
for struct inode and initialize it.
|
||||||
|
|
||||||
|
destroy_inode: this method is called by destroy_inode() to release
|
||||||
|
resources allocated for struct inode.
|
||||||
|
|
||||||
read_inode: this method is called to read a specific inode from the
|
read_inode: this method is called to read a specific inode from the
|
||||||
mounted filesystem. The "i_ino" member in the "struct inode"
|
mounted filesystem. The i_ino member in the struct inode is
|
||||||
will be initialised by the VFS to indicate which inode to
|
initialized by the VFS to indicate which inode to read. Other
|
||||||
read. Other members are filled in by this method
|
members are filled in by this method.
|
||||||
|
|
||||||
|
You can set this to NULL and use iget5_locked() instead of iget()
|
||||||
|
to read inodes. This is necessary for filesystems for which the
|
||||||
|
inode number is not sufficient to identify an inode.
|
||||||
|
|
||||||
|
dirty_inode: this method is called by the VFS to mark an inode dirty.
|
||||||
|
|
||||||
write_inode: this method is called when the VFS needs to write an
|
write_inode: this method is called when the VFS needs to write an
|
||||||
inode to disc. The second parameter indicates whether the write
|
inode to disc. The second parameter indicates whether the write
|
||||||
should be synchronous or not, not all filesystems check this flag.
|
should be synchronous or not, not all filesystems check this flag.
|
||||||
|
|
||||||
put_inode: called when the VFS inode is removed from the inode
|
put_inode: called when the VFS inode is removed from the inode
|
||||||
cache. This method is optional
|
cache.
|
||||||
|
|
||||||
drop_inode: called when the last access to the inode is dropped,
|
drop_inode: called when the last access to the inode is dropped,
|
||||||
with the inode_lock spinlock held.
|
with the inode_lock spinlock held.
|
||||||
|
|
||||||
This method should be either NULL (normal unix filesystem
|
This method should be either NULL (normal UNIX filesystem
|
||||||
semantics) or "generic_delete_inode" (for filesystems that do not
|
semantics) or "generic_delete_inode" (for filesystems that do not
|
||||||
want to cache inodes - causing "delete_inode" to always be
|
want to cache inodes - causing "delete_inode" to always be
|
||||||
called regardless of the value of i_nlink)
|
called regardless of the value of i_nlink)
|
||||||
|
|
||||||
The "generic_delete_inode()" behaviour is equivalent to the
|
The "generic_delete_inode()" behavior is equivalent to the
|
||||||
old practice of using "force_delete" in the put_inode() case,
|
old practice of using "force_delete" in the put_inode() case,
|
||||||
but does not have the races that the "force_delete()" approach
|
but does not have the races that the "force_delete()" approach
|
||||||
had.
|
had.
|
||||||
|
|
||||||
delete_inode: called when the VFS wants to delete an inode
|
delete_inode: called when the VFS wants to delete an inode
|
||||||
|
|
||||||
notify_change: called when VFS inode attributes are changed. If this
|
|
||||||
is NULL the VFS falls back to the write_inode() method. This
|
|
||||||
is called with the kernel lock held
|
|
||||||
|
|
||||||
put_super: called when the VFS wishes to free the superblock
|
put_super: called when the VFS wishes to free the superblock
|
||||||
(i.e. unmount). This is called with the superblock lock held
|
(i.e. unmount). This is called with the superblock lock held
|
||||||
|
|
||||||
write_super: called when the VFS superblock needs to be written to
|
write_super: called when the VFS superblock needs to be written to
|
||||||
disc. This method is optional
|
disc. This method is optional
|
||||||
|
|
||||||
|
sync_fs: called when VFS is writing out all dirty data associated with
|
||||||
|
a superblock. The second parameter indicates whether the method
|
||||||
|
should wait until the write out has been completed. Optional.
|
||||||
|
|
||||||
|
write_super_lockfs: called when VFS is locking a filesystem and forcing
|
||||||
|
it into a consistent state. This function is currently used by the
|
||||||
|
Logical Volume Manager (LVM).
|
||||||
|
|
||||||
|
unlockfs: called when VFS is unlocking a filesystem and making it writable
|
||||||
|
again.
|
||||||
|
|
||||||
statfs: called when the VFS needs to get filesystem statistics. This
|
statfs: called when the VFS needs to get filesystem statistics. This
|
||||||
is called with the kernel lock held
|
is called with the kernel lock held
|
||||||
|
|
||||||
@ -238,21 +301,31 @@ or bottom half).
|
|||||||
|
|
||||||
clear_inode: called then the VFS clears the inode. Optional
|
clear_inode: called then the VFS clears the inode. Optional
|
||||||
|
|
||||||
|
umount_begin: called when the VFS is unmounting a filesystem.
|
||||||
|
|
||||||
|
sync_inodes: called when the VFS is writing out dirty data associated with
|
||||||
|
a superblock.
|
||||||
|
|
||||||
|
show_options: called by the VFS to show mount options for /proc/<pid>/mounts.
|
||||||
|
|
||||||
|
quota_read: called by the VFS to read from filesystem quota file.
|
||||||
|
|
||||||
|
quota_write: called by the VFS to write to filesystem quota file.
|
||||||
|
|
||||||
The read_inode() method is responsible for filling in the "i_op"
|
The read_inode() method is responsible for filling in the "i_op"
|
||||||
field. This is a pointer to a "struct inode_operations" which
|
field. This is a pointer to a "struct inode_operations" which
|
||||||
describes the methods that can be performed on individual inodes.
|
describes the methods that can be performed on individual inodes.
|
||||||
|
|
||||||
|
|
||||||
struct inode_operations <section>
|
struct inode_operations
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This describes how the VFS can manipulate an inode in your
|
This describes how the VFS can manipulate an inode in your
|
||||||
filesystem. As of kernel 2.1.99, the following members are defined:
|
filesystem. As of kernel 2.6.13, the following members are defined:
|
||||||
|
|
||||||
struct inode_operations {
|
struct inode_operations {
|
||||||
struct file_operations * default_file_ops;
|
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
|
||||||
int (*create) (struct inode *,struct dentry *,int);
|
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
|
||||||
int (*lookup) (struct inode *,struct dentry *);
|
|
||||||
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
||||||
int (*unlink) (struct inode *,struct dentry *);
|
int (*unlink) (struct inode *,struct dentry *);
|
||||||
int (*symlink) (struct inode *,struct dentry *,const char *);
|
int (*symlink) (struct inode *,struct dentry *,const char *);
|
||||||
@ -261,25 +334,22 @@ struct inode_operations {
|
|||||||
int (*mknod) (struct inode *,struct dentry *,int,dev_t);
|
int (*mknod) (struct inode *,struct dentry *,int,dev_t);
|
||||||
int (*rename) (struct inode *, struct dentry *,
|
int (*rename) (struct inode *, struct dentry *,
|
||||||
struct inode *, struct dentry *);
|
struct inode *, struct dentry *);
|
||||||
int (*readlink) (struct dentry *, char *,int);
|
int (*readlink) (struct dentry *, char __user *,int);
|
||||||
struct dentry * (*follow_link) (struct dentry *, struct dentry *);
|
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||||
int (*readpage) (struct file *, struct page *);
|
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||||
int (*writepage) (struct page *page, struct writeback_control *wbc);
|
|
||||||
int (*bmap) (struct inode *,int);
|
|
||||||
void (*truncate) (struct inode *);
|
void (*truncate) (struct inode *);
|
||||||
int (*permission) (struct inode *, int);
|
int (*permission) (struct inode *, int, struct nameidata *);
|
||||||
int (*smap) (struct inode *,int);
|
int (*setattr) (struct dentry *, struct iattr *);
|
||||||
int (*updatepage) (struct file *, struct page *, const char *,
|
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
|
||||||
unsigned long, unsigned int, int);
|
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
|
||||||
int (*revalidate) (struct dentry *);
|
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
|
||||||
|
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||||
|
int (*removexattr) (struct dentry *, const char *);
|
||||||
};
|
};
|
||||||
|
|
||||||
Again, all methods are called without any locks being held, unless
|
Again, all methods are called without any locks being held, unless
|
||||||
otherwise noted.
|
otherwise noted.
|
||||||
|
|
||||||
default_file_ops: this is a pointer to a "struct file_operations"
|
|
||||||
which describes how to open and then manipulate open files
|
|
||||||
|
|
||||||
create: called by the open(2) and creat(2) system calls. Only
|
create: called by the open(2) and creat(2) system calls. Only
|
||||||
required if you want to support regular files. The dentry you
|
required if you want to support regular files. The dentry you
|
||||||
get should not have an inode (i.e. it should be a negative
|
get should not have an inode (i.e. it should be a negative
|
||||||
@ -328,31 +398,143 @@ otherwise noted.
|
|||||||
you want to support reading symbolic links
|
you want to support reading symbolic links
|
||||||
|
|
||||||
follow_link: called by the VFS to follow a symbolic link to the
|
follow_link: called by the VFS to follow a symbolic link to the
|
||||||
inode it points to. Only required if you want to support
|
inode it points to. Only required if you want to support
|
||||||
symbolic links
|
symbolic links. This function returns a void pointer cookie
|
||||||
|
that is passed to put_link().
|
||||||
|
|
||||||
|
put_link: called by the VFS to release resources allocated by
|
||||||
|
follow_link(). The cookie returned by follow_link() is passed to
|
||||||
|
to this function as the last parameter. It is used by filesystems
|
||||||
|
such as NFS where page cache is not stable (i.e. page that was
|
||||||
|
installed when the symbolic link walk started might not be in the
|
||||||
|
page cache at the end of the walk).
|
||||||
|
|
||||||
|
truncate: called by the VFS to change the size of a file. The i_size
|
||||||
|
field of the inode is set to the desired size by the VFS before
|
||||||
|
this function is called. This function is called by the truncate(2)
|
||||||
|
system call and related functionality.
|
||||||
|
|
||||||
|
permission: called by the VFS to check for access rights on a POSIX-like
|
||||||
|
filesystem.
|
||||||
|
|
||||||
|
setattr: called by the VFS to set attributes for a file. This function is
|
||||||
|
called by chmod(2) and related system calls.
|
||||||
|
|
||||||
|
getattr: called by the VFS to get attributes of a file. This function is
|
||||||
|
called by stat(2) and related system calls.
|
||||||
|
|
||||||
|
setxattr: called by the VFS to set an extended attribute for a file.
|
||||||
|
Extended attribute is a name:value pair associated with an inode. This
|
||||||
|
function is called by setxattr(2) system call.
|
||||||
|
|
||||||
|
getxattr: called by the VFS to retrieve the value of an extended attribute
|
||||||
|
name. This function is called by getxattr(2) function call.
|
||||||
|
|
||||||
|
listxattr: called by the VFS to list all extended attributes for a given
|
||||||
|
file. This function is called by listxattr(2) system call.
|
||||||
|
|
||||||
|
removexattr: called by the VFS to remove an extended attribute from a file.
|
||||||
|
This function is called by removexattr(2) system call.
|
||||||
|
|
||||||
|
|
||||||
struct file_operations <section>
|
struct address_space_operations
|
||||||
|
===============================
|
||||||
|
|
||||||
|
This describes how the VFS can manipulate mapping of a file to page cache in
|
||||||
|
your filesystem. As of kernel 2.6.13, the following members are defined:
|
||||||
|
|
||||||
|
struct address_space_operations {
|
||||||
|
int (*writepage)(struct page *page, struct writeback_control *wbc);
|
||||||
|
int (*readpage)(struct file *, struct page *);
|
||||||
|
int (*sync_page)(struct page *);
|
||||||
|
int (*writepages)(struct address_space *, struct writeback_control *);
|
||||||
|
int (*set_page_dirty)(struct page *page);
|
||||||
|
int (*readpages)(struct file *filp, struct address_space *mapping,
|
||||||
|
struct list_head *pages, unsigned nr_pages);
|
||||||
|
int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
|
||||||
|
int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
|
||||||
|
sector_t (*bmap)(struct address_space *, sector_t);
|
||||||
|
int (*invalidatepage) (struct page *, unsigned long);
|
||||||
|
int (*releasepage) (struct page *, int);
|
||||||
|
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
|
||||||
|
loff_t offset, unsigned long nr_segs);
|
||||||
|
struct page* (*get_xip_page)(struct address_space *, sector_t,
|
||||||
|
int);
|
||||||
|
};
|
||||||
|
|
||||||
|
writepage: called by the VM write a dirty page to backing store.
|
||||||
|
|
||||||
|
readpage: called by the VM to read a page from backing store.
|
||||||
|
|
||||||
|
sync_page: called by the VM to notify the backing store to perform all
|
||||||
|
queued I/O operations for a page. I/O operations for other pages
|
||||||
|
associated with this address_space object may also be performed.
|
||||||
|
|
||||||
|
writepages: called by the VM to write out pages associated with the
|
||||||
|
address_space object.
|
||||||
|
|
||||||
|
set_page_dirty: called by the VM to set a page dirty.
|
||||||
|
|
||||||
|
readpages: called by the VM to read pages associated with the address_space
|
||||||
|
object.
|
||||||
|
|
||||||
|
prepare_write: called by the generic write path in VM to set up a write
|
||||||
|
request for a page.
|
||||||
|
|
||||||
|
commit_write: called by the generic write path in VM to write page to
|
||||||
|
its backing store.
|
||||||
|
|
||||||
|
bmap: called by the VFS to map a logical block offset within object to
|
||||||
|
physical block number. This method is use by for the legacy FIBMAP
|
||||||
|
ioctl. Other uses are discouraged.
|
||||||
|
|
||||||
|
invalidatepage: called by the VM on truncate to disassociate a page from its
|
||||||
|
address_space mapping.
|
||||||
|
|
||||||
|
releasepage: called by the VFS to release filesystem specific metadata from
|
||||||
|
a page.
|
||||||
|
|
||||||
|
direct_IO: called by the VM for direct I/O writes and reads.
|
||||||
|
|
||||||
|
get_xip_page: called by the VM to translate a block number to a page.
|
||||||
|
The page is valid until the corresponding filesystem is unmounted.
|
||||||
|
Filesystems that want to use execute-in-place (XIP) need to implement
|
||||||
|
it. An example implementation can be found in fs/ext2/xip.c.
|
||||||
|
|
||||||
|
|
||||||
|
struct file_operations
|
||||||
======================
|
======================
|
||||||
|
|
||||||
This describes how the VFS can manipulate an open file. As of kernel
|
This describes how the VFS can manipulate an open file. As of kernel
|
||||||
2.1.99, the following members are defined:
|
2.6.13, the following members are defined:
|
||||||
|
|
||||||
struct file_operations {
|
struct file_operations {
|
||||||
loff_t (*llseek) (struct file *, loff_t, int);
|
loff_t (*llseek) (struct file *, loff_t, int);
|
||||||
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
|
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
||||||
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
|
ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
|
||||||
|
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
||||||
|
ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
|
||||||
int (*readdir) (struct file *, void *, filldir_t);
|
int (*readdir) (struct file *, void *, filldir_t);
|
||||||
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
||||||
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
|
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
|
||||||
|
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
||||||
|
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
|
||||||
int (*mmap) (struct file *, struct vm_area_struct *);
|
int (*mmap) (struct file *, struct vm_area_struct *);
|
||||||
int (*open) (struct inode *, struct file *);
|
int (*open) (struct inode *, struct file *);
|
||||||
|
int (*flush) (struct file *);
|
||||||
int (*release) (struct inode *, struct file *);
|
int (*release) (struct inode *, struct file *);
|
||||||
int (*fsync) (struct file *, struct dentry *);
|
int (*fsync) (struct file *, struct dentry *, int datasync);
|
||||||
int (*fasync) (struct file *, int);
|
int (*aio_fsync) (struct kiocb *, int datasync);
|
||||||
int (*check_media_change) (kdev_t dev);
|
int (*fasync) (int, struct file *, int);
|
||||||
int (*revalidate) (kdev_t dev);
|
|
||||||
int (*lock) (struct file *, int, struct file_lock *);
|
int (*lock) (struct file *, int, struct file_lock *);
|
||||||
|
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
|
||||||
|
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
|
||||||
|
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
|
||||||
|
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
|
||||||
|
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
|
||||||
|
int (*check_flags)(int);
|
||||||
|
int (*dir_notify)(struct file *filp, unsigned long arg);
|
||||||
|
int (*flock) (struct file *, int, struct file_lock *);
|
||||||
};
|
};
|
||||||
|
|
||||||
Again, all methods are called without any locks being held, unless
|
Again, all methods are called without any locks being held, unless
|
||||||
@ -362,8 +544,12 @@ otherwise noted.
|
|||||||
|
|
||||||
read: called by read(2) and related system calls
|
read: called by read(2) and related system calls
|
||||||
|
|
||||||
|
aio_read: called by io_submit(2) and other asynchronous I/O operations
|
||||||
|
|
||||||
write: called by write(2) and related system calls
|
write: called by write(2) and related system calls
|
||||||
|
|
||||||
|
aio_write: called by io_submit(2) and other asynchronous I/O operations
|
||||||
|
|
||||||
readdir: called when the VFS needs to read the directory contents
|
readdir: called when the VFS needs to read the directory contents
|
||||||
|
|
||||||
poll: called by the VFS when a process wants to check if there is
|
poll: called by the VFS when a process wants to check if there is
|
||||||
@ -372,18 +558,25 @@ otherwise noted.
|
|||||||
|
|
||||||
ioctl: called by the ioctl(2) system call
|
ioctl: called by the ioctl(2) system call
|
||||||
|
|
||||||
|
unlocked_ioctl: called by the ioctl(2) system call. Filesystems that do not
|
||||||
|
require the BKL should use this method instead of the ioctl() above.
|
||||||
|
|
||||||
|
compat_ioctl: called by the ioctl(2) system call when 32 bit system calls
|
||||||
|
are used on 64 bit kernels.
|
||||||
|
|
||||||
mmap: called by the mmap(2) system call
|
mmap: called by the mmap(2) system call
|
||||||
|
|
||||||
open: called by the VFS when an inode should be opened. When the VFS
|
open: called by the VFS when an inode should be opened. When the VFS
|
||||||
opens a file, it creates a new "struct file" and initialises
|
opens a file, it creates a new "struct file". It then calls the
|
||||||
the "f_op" file operations member with the "default_file_ops"
|
open method for the newly allocated file structure. You might
|
||||||
field in the inode structure. It then calls the open method
|
think that the open method really belongs in
|
||||||
for the newly allocated file structure. You might think that
|
"struct inode_operations", and you may be right. I think it's
|
||||||
the open method really belongs in "struct inode_operations",
|
done the way it is because it makes filesystems simpler to
|
||||||
and you may be right. I think it's done the way it is because
|
implement. The open() method is a good place to initialize the
|
||||||
it makes filesystems simpler to implement. The open() method
|
"private_data" member in the file structure if you want to point
|
||||||
is a good place to initialise the "private_data" member in the
|
to a device structure
|
||||||
file structure if you want to point to a device structure
|
|
||||||
|
flush: called by the close(2) system call to flush a file
|
||||||
|
|
||||||
release: called when the last reference to an open file is closed
|
release: called when the last reference to an open file is closed
|
||||||
|
|
||||||
@ -392,6 +585,23 @@ otherwise noted.
|
|||||||
fasync: called by the fcntl(2) system call when asynchronous
|
fasync: called by the fcntl(2) system call when asynchronous
|
||||||
(non-blocking) mode is enabled for a file
|
(non-blocking) mode is enabled for a file
|
||||||
|
|
||||||
|
lock: called by the fcntl(2) system call for F_GETLK, F_SETLK, and F_SETLKW
|
||||||
|
commands
|
||||||
|
|
||||||
|
readv: called by the readv(2) system call
|
||||||
|
|
||||||
|
writev: called by the writev(2) system call
|
||||||
|
|
||||||
|
sendfile: called by the sendfile(2) system call
|
||||||
|
|
||||||
|
get_unmapped_area: called by the mmap(2) system call
|
||||||
|
|
||||||
|
check_flags: called by the fcntl(2) system call for F_SETFL command
|
||||||
|
|
||||||
|
dir_notify: called by the fcntl(2) system call for F_NOTIFY command
|
||||||
|
|
||||||
|
flock: called by the flock(2) system call
|
||||||
|
|
||||||
Note that the file operations are implemented by the specific
|
Note that the file operations are implemented by the specific
|
||||||
filesystem in which the inode resides. When opening a device node
|
filesystem in which the inode resides. When opening a device node
|
||||||
(character or block special) most filesystems will call special
|
(character or block special) most filesystems will call special
|
||||||
@ -400,29 +610,28 @@ driver information. These support routines replace the filesystem file
|
|||||||
operations with those for the device driver, and then proceed to call
|
operations with those for the device driver, and then proceed to call
|
||||||
the new open() method for the file. This is how opening a device file
|
the new open() method for the file. This is how opening a device file
|
||||||
in the filesystem eventually ends up calling the device driver open()
|
in the filesystem eventually ends up calling the device driver open()
|
||||||
method. Note the devfs (the Device FileSystem) has a more direct path
|
method.
|
||||||
from device node to device driver (this is an unofficial kernel
|
|
||||||
patch).
|
|
||||||
|
|
||||||
|
|
||||||
Directory Entry Cache (dcache) <section>
|
Directory Entry Cache (dcache)
|
||||||
------------------------------
|
==============================
|
||||||
|
|
||||||
|
|
||||||
struct dentry_operations
|
struct dentry_operations
|
||||||
========================
|
------------------------
|
||||||
|
|
||||||
This describes how a filesystem can overload the standard dentry
|
This describes how a filesystem can overload the standard dentry
|
||||||
operations. Dentries and the dcache are the domain of the VFS and the
|
operations. Dentries and the dcache are the domain of the VFS and the
|
||||||
individual filesystem implementations. Device drivers have no business
|
individual filesystem implementations. Device drivers have no business
|
||||||
here. These methods may be set to NULL, as they are either optional or
|
here. These methods may be set to NULL, as they are either optional or
|
||||||
the VFS uses a default. As of kernel 2.1.99, the following members are
|
the VFS uses a default. As of kernel 2.6.13, the following members are
|
||||||
defined:
|
defined:
|
||||||
|
|
||||||
struct dentry_operations {
|
struct dentry_operations {
|
||||||
int (*d_revalidate)(struct dentry *);
|
int (*d_revalidate)(struct dentry *, struct nameidata *);
|
||||||
int (*d_hash) (struct dentry *, struct qstr *);
|
int (*d_hash) (struct dentry *, struct qstr *);
|
||||||
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
|
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
|
||||||
void (*d_delete)(struct dentry *);
|
int (*d_delete)(struct dentry *);
|
||||||
void (*d_release)(struct dentry *);
|
void (*d_release)(struct dentry *);
|
||||||
void (*d_iput)(struct dentry *, struct inode *);
|
void (*d_iput)(struct dentry *, struct inode *);
|
||||||
};
|
};
|
||||||
@ -451,6 +660,7 @@ Each dentry has a pointer to its parent dentry, as well as a hash list
|
|||||||
of child dentries. Child dentries are basically like files in a
|
of child dentries. Child dentries are basically like files in a
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
|
|
||||||
Directory Entry Cache APIs
|
Directory Entry Cache APIs
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
@ -471,7 +681,7 @@ manipulate dentries:
|
|||||||
"d_delete" method is called
|
"d_delete" method is called
|
||||||
|
|
||||||
d_drop: this unhashes a dentry from its parents hash list. A
|
d_drop: this unhashes a dentry from its parents hash list. A
|
||||||
subsequent call to dput() will dellocate the dentry if its
|
subsequent call to dput() will deallocate the dentry if its
|
||||||
usage count drops to 0
|
usage count drops to 0
|
||||||
|
|
||||||
d_delete: delete a dentry. If there are no other open references to
|
d_delete: delete a dentry. If there are no other open references to
|
||||||
@ -507,16 +717,16 @@ up by walking the tree starting with the first component
|
|||||||
of the pathname and using that dentry along with the next
|
of the pathname and using that dentry along with the next
|
||||||
component to look up the next level and so on. Since it
|
component to look up the next level and so on. Since it
|
||||||
is a frequent operation for workloads like multiuser
|
is a frequent operation for workloads like multiuser
|
||||||
environments and webservers, it is important to optimize
|
environments and web servers, it is important to optimize
|
||||||
this path.
|
this path.
|
||||||
|
|
||||||
Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus
|
Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus
|
||||||
in every component during path look-up. Since 2.5.10 onwards,
|
in every component during path look-up. Since 2.5.10 onwards,
|
||||||
fastwalk algorithm changed this by holding the dcache_lock
|
fast-walk algorithm changed this by holding the dcache_lock
|
||||||
at the beginning and walking as many cached path component
|
at the beginning and walking as many cached path component
|
||||||
dentries as possible. This signficantly decreases the number
|
dentries as possible. This significantly decreases the number
|
||||||
of acquisition of dcache_lock. However it also increases the
|
of acquisition of dcache_lock. However it also increases the
|
||||||
lock hold time signficantly and affects performance in large
|
lock hold time significantly and affects performance in large
|
||||||
SMP machines. Since 2.5.62 kernel, dcache has been using
|
SMP machines. Since 2.5.62 kernel, dcache has been using
|
||||||
a new locking model that uses RCU to make dcache look-up
|
a new locking model that uses RCU to make dcache look-up
|
||||||
lock-free.
|
lock-free.
|
||||||
@ -527,7 +737,7 @@ protected the hash chain, d_child, d_alias, d_lru lists as well
|
|||||||
as d_inode and several other things like mount look-up. RCU-based
|
as d_inode and several other things like mount look-up. RCU-based
|
||||||
changes affect only the way the hash chain is protected. For everything
|
changes affect only the way the hash chain is protected. For everything
|
||||||
else the dcache_lock must be taken for both traversing as well as
|
else the dcache_lock must be taken for both traversing as well as
|
||||||
updating. The hash chain updations too take the dcache_lock.
|
updating. The hash chain updates too take the dcache_lock.
|
||||||
The significant change is the way d_lookup traverses the hash chain,
|
The significant change is the way d_lookup traverses the hash chain,
|
||||||
it doesn't acquire the dcache_lock for this and rely on RCU to
|
it doesn't acquire the dcache_lock for this and rely on RCU to
|
||||||
ensure that the dentry has not been *freed*.
|
ensure that the dentry has not been *freed*.
|
||||||
@ -535,14 +745,15 @@ ensure that the dentry has not been *freed*.
|
|||||||
|
|
||||||
Dcache locking details
|
Dcache locking details
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
For many multi-user workloads, open() and stat() on files are
|
For many multi-user workloads, open() and stat() on files are
|
||||||
very frequently occurring operations. Both involve walking
|
very frequently occurring operations. Both involve walking
|
||||||
of path names to find the dentry corresponding to the
|
of path names to find the dentry corresponding to the
|
||||||
concerned file. In 2.4 kernel, dcache_lock was held
|
concerned file. In 2.4 kernel, dcache_lock was held
|
||||||
during look-up of each path component. Contention and
|
during look-up of each path component. Contention and
|
||||||
cacheline bouncing of this global lock caused significant
|
cache-line bouncing of this global lock caused significant
|
||||||
scalability problems. With the introduction of RCU
|
scalability problems. With the introduction of RCU
|
||||||
in linux kernel, this was worked around by making
|
in Linux kernel, this was worked around by making
|
||||||
the look-up of path components during path walking lock-free.
|
the look-up of path components during path walking lock-free.
|
||||||
|
|
||||||
|
|
||||||
@ -562,7 +773,7 @@ Some of the important changes are :
|
|||||||
2. Insertion of a dentry into the hash table is done using
|
2. Insertion of a dentry into the hash table is done using
|
||||||
hlist_add_head_rcu() which take care of ordering the writes -
|
hlist_add_head_rcu() which take care of ordering the writes -
|
||||||
the writes to the dentry must be visible before the dentry
|
the writes to the dentry must be visible before the dentry
|
||||||
is inserted. This works in conjuction with hlist_for_each_rcu()
|
is inserted. This works in conjunction with hlist_for_each_rcu()
|
||||||
while walking the hash chain. The only requirement is that
|
while walking the hash chain. The only requirement is that
|
||||||
all initialization to the dentry must be done before hlist_add_head_rcu()
|
all initialization to the dentry must be done before hlist_add_head_rcu()
|
||||||
since we don't have dcache_lock protection while traversing
|
since we don't have dcache_lock protection while traversing
|
||||||
@ -584,7 +795,7 @@ Some of the important changes are :
|
|||||||
the same. In some sense, dcache_rcu path walking looks like
|
the same. In some sense, dcache_rcu path walking looks like
|
||||||
the pre-2.5.10 version.
|
the pre-2.5.10 version.
|
||||||
|
|
||||||
5. All dentry hash chain updations must take the dcache_lock as well as
|
5. All dentry hash chain updates must take the dcache_lock as well as
|
||||||
the per-dentry lock in that order. dput() does this to ensure
|
the per-dentry lock in that order. dput() does this to ensure
|
||||||
that a dentry that has just been looked up in another CPU
|
that a dentry that has just been looked up in another CPU
|
||||||
doesn't get deleted before dget() can be done on it.
|
doesn't get deleted before dget() can be done on it.
|
||||||
@ -640,10 +851,10 @@ handled as described below :
|
|||||||
Since we redo the d_parent check and compare name while holding
|
Since we redo the d_parent check and compare name while holding
|
||||||
d_lock, lock-free look-up will not race against d_move().
|
d_lock, lock-free look-up will not race against d_move().
|
||||||
|
|
||||||
4. There can be a theoritical race when a dentry keeps coming back
|
4. There can be a theoretical race when a dentry keeps coming back
|
||||||
to original bucket due to double moves. Due to this look-up may
|
to original bucket due to double moves. Due to this look-up may
|
||||||
consider that it has never moved and can end up in a infinite loop.
|
consider that it has never moved and can end up in a infinite loop.
|
||||||
But this is not any worse that theoritical livelocks we already
|
But this is not any worse that theoretical livelocks we already
|
||||||
have in the kernel.
|
have in the kernel.
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,14 +32,14 @@ static void sample_firmware_load(char *firmware, int size)
|
|||||||
u8 buf[size+1];
|
u8 buf[size+1];
|
||||||
memcpy(buf, firmware, size);
|
memcpy(buf, firmware, size);
|
||||||
buf[size] = '\0';
|
buf[size] = '\0';
|
||||||
printk("firmware_sample_driver: firmware: %s\n", buf);
|
printk(KERN_INFO "firmware_sample_driver: firmware: %s\n", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sample_probe_default(void)
|
static void sample_probe_default(void)
|
||||||
{
|
{
|
||||||
/* uses the default method to get the firmware */
|
/* uses the default method to get the firmware */
|
||||||
const struct firmware *fw_entry;
|
const struct firmware *fw_entry;
|
||||||
printk("firmware_sample_driver: a ghost device got inserted :)\n");
|
printk(KERN_INFO "firmware_sample_driver: a ghost device got inserted :)\n");
|
||||||
|
|
||||||
if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0)
|
if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0)
|
||||||
{
|
{
|
||||||
@ -61,7 +61,7 @@ static void sample_probe_specific(void)
|
|||||||
|
|
||||||
/* NOTE: This currently doesn't work */
|
/* NOTE: This currently doesn't work */
|
||||||
|
|
||||||
printk("firmware_sample_driver: a ghost device got inserted :)\n");
|
printk(KERN_INFO "firmware_sample_driver: a ghost device got inserted :)\n");
|
||||||
|
|
||||||
if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0)
|
if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0)
|
||||||
{
|
{
|
||||||
@ -83,7 +83,7 @@ static void sample_probe_async_cont(const struct firmware *fw, void *context)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("firmware_sample_driver: device pointer \"%s\"\n",
|
printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n",
|
||||||
(char *)context);
|
(char *)context);
|
||||||
sample_firmware_load(fw->data, fw->size);
|
sample_firmware_load(fw->data, fw->size);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
IBM ThinkPad ACPI Extras Driver
|
IBM ThinkPad ACPI Extras Driver
|
||||||
|
|
||||||
Version 0.8
|
Version 0.12
|
||||||
8 November 2004
|
17 August 2005
|
||||||
|
|
||||||
Borislav Deianov <borislav@users.sf.net>
|
Borislav Deianov <borislav@users.sf.net>
|
||||||
http://ibm-acpi.sf.net/
|
http://ibm-acpi.sf.net/
|
||||||
|
|
||||||
|
|
||||||
This is a Linux ACPI driver for the IBM ThinkPad laptops. It aims to
|
This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports
|
||||||
support various features of these laptops which are accessible through
|
various features of these laptops which are accessible through the
|
||||||
the ACPI framework but not otherwise supported by the generic Linux
|
ACPI framework but not otherwise supported by the generic Linux ACPI
|
||||||
ACPI drivers.
|
drivers.
|
||||||
|
|
||||||
|
|
||||||
Status
|
Status
|
||||||
@ -25,9 +25,14 @@ detailed description):
|
|||||||
- ThinkLight on and off
|
- ThinkLight on and off
|
||||||
- limited docking and undocking
|
- limited docking and undocking
|
||||||
- UltraBay eject
|
- UltraBay eject
|
||||||
- Experimental: CMOS control
|
- CMOS control
|
||||||
- Experimental: LED control
|
- LED control
|
||||||
- Experimental: ACPI sounds
|
- ACPI sounds
|
||||||
|
- temperature sensors
|
||||||
|
- Experimental: embedded controller register dump
|
||||||
|
- Experimental: LCD brightness control
|
||||||
|
- Experimental: volume control
|
||||||
|
- Experimental: fan speed, fan enable/disable
|
||||||
|
|
||||||
A compatibility table by model and feature is maintained on the web
|
A compatibility table by model and feature is maintained on the web
|
||||||
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
||||||
@ -91,12 +96,12 @@ driver is still in the alpha stage, the exact proc file format and
|
|||||||
commands supported by the various features is guaranteed to change
|
commands supported by the various features is guaranteed to change
|
||||||
frequently.
|
frequently.
|
||||||
|
|
||||||
Driver Version -- /proc/acpi/ibm/driver
|
Driver version -- /proc/acpi/ibm/driver
|
||||||
--------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
The driver name and version. No commands can be written to this file.
|
The driver name and version. No commands can be written to this file.
|
||||||
|
|
||||||
Hot Keys -- /proc/acpi/ibm/hotkey
|
Hot keys -- /proc/acpi/ibm/hotkey
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
Without this driver, only the Fn-F4 key (sleep button) generates an
|
Without this driver, only the Fn-F4 key (sleep button) generates an
|
||||||
@ -188,7 +193,7 @@ and, on the X40, video corruption. By disabling automatic switching,
|
|||||||
the flickering or video corruption can be avoided.
|
the flickering or video corruption can be avoided.
|
||||||
|
|
||||||
The video_switch command cycles through the available video outputs
|
The video_switch command cycles through the available video outputs
|
||||||
(it sumulates the behavior of Fn-F7).
|
(it simulates the behavior of Fn-F7).
|
||||||
|
|
||||||
Video expansion can be toggled through this feature. This controls
|
Video expansion can be toggled through this feature. This controls
|
||||||
whether the display is expanded to fill the entire LCD screen when a
|
whether the display is expanded to fill the entire LCD screen when a
|
||||||
@ -201,6 +206,12 @@ Fn-F7 from working. This also disables the video output switching
|
|||||||
features of this driver, as it uses the same ACPI methods as
|
features of this driver, as it uses the same ACPI methods as
|
||||||
Fn-F7. Video switching on the console should still work.
|
Fn-F7. Video switching on the console should still work.
|
||||||
|
|
||||||
|
UPDATE: There's now a patch for the X.org Radeon driver which
|
||||||
|
addresses this issue. Some people are reporting success with the patch
|
||||||
|
while others are still having problems. For more information:
|
||||||
|
|
||||||
|
https://bugs.freedesktop.org/show_bug.cgi?id=2000
|
||||||
|
|
||||||
ThinkLight control -- /proc/acpi/ibm/light
|
ThinkLight control -- /proc/acpi/ibm/light
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
@ -211,7 +222,7 @@ models which do not make the status available will show it as
|
|||||||
echo on > /proc/acpi/ibm/light
|
echo on > /proc/acpi/ibm/light
|
||||||
echo off > /proc/acpi/ibm/light
|
echo off > /proc/acpi/ibm/light
|
||||||
|
|
||||||
Docking / Undocking -- /proc/acpi/ibm/dock
|
Docking / undocking -- /proc/acpi/ibm/dock
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
Docking and undocking (e.g. with the X4 UltraBase) requires some
|
Docking and undocking (e.g. with the X4 UltraBase) requires some
|
||||||
@ -228,11 +239,15 @@ NOTE: These events will only be generated if the laptop was docked
|
|||||||
when originally booted. This is due to the current lack of support for
|
when originally booted. This is due to the current lack of support for
|
||||||
hot plugging of devices in the Linux ACPI framework. If the laptop was
|
hot plugging of devices in the Linux ACPI framework. If the laptop was
|
||||||
booted while not in the dock, the following message is shown in the
|
booted while not in the dock, the following message is shown in the
|
||||||
logs: "ibm_acpi: dock device not present". No dock-related events are
|
logs:
|
||||||
generated but the dock and undock commands described below still
|
|
||||||
work. They can be executed manually or triggered by Fn key
|
Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present
|
||||||
combinations (see the example acpid configuration files included in
|
|
||||||
the driver tarball package available on the web site).
|
In this case, no dock-related events are generated but the dock and
|
||||||
|
undock commands described below still work. They can be executed
|
||||||
|
manually or triggered by Fn key combinations (see the example acpid
|
||||||
|
configuration files included in the driver tarball package available
|
||||||
|
on the web site).
|
||||||
|
|
||||||
When the eject request button on the dock is pressed, the first event
|
When the eject request button on the dock is pressed, the first event
|
||||||
above is generated. The handler for this event should issue the
|
above is generated. The handler for this event should issue the
|
||||||
@ -267,7 +282,7 @@ the only docking stations currently supported are the X-series
|
|||||||
UltraBase docks and "dumb" port replicators like the Mini Dock (the
|
UltraBase docks and "dumb" port replicators like the Mini Dock (the
|
||||||
latter don't need any ACPI support, actually).
|
latter don't need any ACPI support, actually).
|
||||||
|
|
||||||
UltraBay Eject -- /proc/acpi/ibm/bay
|
UltraBay eject -- /proc/acpi/ibm/bay
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
Inserting or ejecting an UltraBay device requires some actions to be
|
Inserting or ejecting an UltraBay device requires some actions to be
|
||||||
@ -284,8 +299,11 @@ when the laptop was originally booted (on the X series, the UltraBay
|
|||||||
is in the dock, so it may not be present if the laptop was undocked).
|
is in the dock, so it may not be present if the laptop was undocked).
|
||||||
This is due to the current lack of support for hot plugging of devices
|
This is due to the current lack of support for hot plugging of devices
|
||||||
in the Linux ACPI framework. If the laptop was booted without the
|
in the Linux ACPI framework. If the laptop was booted without the
|
||||||
UltraBay, the following message is shown in the logs: "ibm_acpi: bay
|
UltraBay, the following message is shown in the logs:
|
||||||
device not present". No bay-related events are generated but the eject
|
|
||||||
|
Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present
|
||||||
|
|
||||||
|
In this case, no bay-related events are generated but the eject
|
||||||
command described below still works. It can be executed manually or
|
command described below still works. It can be executed manually or
|
||||||
triggered by a hot key combination.
|
triggered by a hot key combination.
|
||||||
|
|
||||||
@ -306,22 +324,33 @@ necessary to enable the UltraBay device (e.g. call idectl).
|
|||||||
The contents of the /proc/acpi/ibm/bay file shows the current status
|
The contents of the /proc/acpi/ibm/bay file shows the current status
|
||||||
of the UltraBay, as provided by the ACPI framework.
|
of the UltraBay, as provided by the ACPI framework.
|
||||||
|
|
||||||
Experimental Features
|
EXPERIMENTAL warm eject support on the 600e/x, A22p and A3x (To use
|
||||||
---------------------
|
this feature, you need to supply the experimental=1 parameter when
|
||||||
|
loading the module):
|
||||||
|
|
||||||
The following features are marked experimental because using them
|
These models do not have a button near the UltraBay device to request
|
||||||
involves guessing the correct values of some parameters. Guessing
|
a hot eject but rather require the laptop to be put to sleep
|
||||||
incorrectly may have undesirable effects like crashing your
|
(suspend-to-ram) before the bay device is ejected or inserted).
|
||||||
ThinkPad. USE THESE WITH CAUTION! To activate them, you'll need to
|
The sequence of steps to eject the device is as follows:
|
||||||
supply the experimental=1 parameter when loading the module.
|
|
||||||
|
|
||||||
Experimental: CMOS control - /proc/acpi/ibm/cmos
|
echo eject > /proc/acpi/ibm/bay
|
||||||
------------------------------------------------
|
put the ThinkPad to sleep
|
||||||
|
remove the drive
|
||||||
|
resume from sleep
|
||||||
|
cat /proc/acpi/ibm/bay should show that the drive was removed
|
||||||
|
|
||||||
|
On the A3x, both the UltraBay 2000 and UltraBay Plus devices are
|
||||||
|
supported. Use "eject2" instead of "eject" for the second bay.
|
||||||
|
|
||||||
|
Note: the UltraBay eject support on the 600e/x, A22p and A3x is
|
||||||
|
EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
|
||||||
|
|
||||||
|
CMOS control -- /proc/acpi/ibm/cmos
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
This feature is used internally by the ACPI firmware to control the
|
This feature is used internally by the ACPI firmware to control the
|
||||||
ThinkLight on most newer ThinkPad models. It appears that it can also
|
ThinkLight on most newer ThinkPad models. It may also control LCD
|
||||||
control LCD brightness, sounds volume and more, but only on some
|
brightness, sounds volume and more, but only on some models.
|
||||||
models.
|
|
||||||
|
|
||||||
The commands are non-negative integer numbers:
|
The commands are non-negative integer numbers:
|
||||||
|
|
||||||
@ -330,10 +359,9 @@ The commands are non-negative integer numbers:
|
|||||||
echo 2 >/proc/acpi/ibm/cmos
|
echo 2 >/proc/acpi/ibm/cmos
|
||||||
...
|
...
|
||||||
|
|
||||||
The range of numbers which are used internally by various models is 0
|
The range of valid numbers is 0 to 21, but not all have an effect and
|
||||||
to 21, but it's possible that numbers outside this range have
|
the behavior varies from model to model. Here is the behavior on the
|
||||||
interesting behavior. Here is the behavior on the X40 (tpb is the
|
X40 (tpb is the ThinkPad Buttons utility):
|
||||||
ThinkPad Buttons utility):
|
|
||||||
|
|
||||||
0 - no effect but tpb reports "Volume down"
|
0 - no effect but tpb reports "Volume down"
|
||||||
1 - no effect but tpb reports "Volume up"
|
1 - no effect but tpb reports "Volume up"
|
||||||
@ -346,26 +374,18 @@ ThinkPad Buttons utility):
|
|||||||
13 - ThinkLight off
|
13 - ThinkLight off
|
||||||
14 - no effect but tpb reports ThinkLight status change
|
14 - no effect but tpb reports ThinkLight status change
|
||||||
|
|
||||||
If you try this feature, please send me a report similar to the
|
LED control -- /proc/acpi/ibm/led
|
||||||
above. On models which allow control of LCD brightness or sound
|
---------------------------------
|
||||||
volume, I'd like to provide this functionality in an user-friendly
|
|
||||||
way, but first I need a way to identify the models which this is
|
|
||||||
possible.
|
|
||||||
|
|
||||||
Experimental: LED control - /proc/acpi/ibm/LED
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
Some of the LED indicators can be controlled through this feature. The
|
Some of the LED indicators can be controlled through this feature. The
|
||||||
available commands are:
|
available commands are:
|
||||||
|
|
||||||
echo <led number> on >/proc/acpi/ibm/led
|
echo '<led number> on' >/proc/acpi/ibm/led
|
||||||
echo <led number> off >/proc/acpi/ibm/led
|
echo '<led number> off' >/proc/acpi/ibm/led
|
||||||
echo <led number> blink >/proc/acpi/ibm/led
|
echo '<led number> blink' >/proc/acpi/ibm/led
|
||||||
|
|
||||||
The <led number> parameter is a non-negative integer. The range of LED
|
The <led number> range is 0 to 7. The set of LEDs that can be
|
||||||
numbers used internally by various models is 0 to 7 but it's possible
|
controlled varies from model to model. Here is the mapping on the X40:
|
||||||
that numbers outside this range are also valid. Here is the mapping on
|
|
||||||
the X40:
|
|
||||||
|
|
||||||
0 - power
|
0 - power
|
||||||
1 - battery (orange)
|
1 - battery (orange)
|
||||||
@ -376,49 +396,224 @@ the X40:
|
|||||||
|
|
||||||
All of the above can be turned on and off and can be made to blink.
|
All of the above can be turned on and off and can be made to blink.
|
||||||
|
|
||||||
If you try this feature, please send me a report similar to the
|
ACPI sounds -- /proc/acpi/ibm/beep
|
||||||
above. I'd like to provide this functionality in an user-friendly way,
|
----------------------------------
|
||||||
but first I need to identify the which numbers correspond to which
|
|
||||||
LEDs on various models.
|
|
||||||
|
|
||||||
Experimental: ACPI sounds - /proc/acpi/ibm/beep
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
The BEEP method is used internally by the ACPI firmware to provide
|
The BEEP method is used internally by the ACPI firmware to provide
|
||||||
audible alerts in various situtation. This feature allows the same
|
audible alerts in various situations. This feature allows the same
|
||||||
sounds to be triggered manually.
|
sounds to be triggered manually.
|
||||||
|
|
||||||
The commands are non-negative integer numbers:
|
The commands are non-negative integer numbers:
|
||||||
|
|
||||||
echo 0 >/proc/acpi/ibm/beep
|
echo <number> >/proc/acpi/ibm/beep
|
||||||
echo 1 >/proc/acpi/ibm/beep
|
|
||||||
echo 2 >/proc/acpi/ibm/beep
|
|
||||||
...
|
|
||||||
|
|
||||||
The range of numbers which are used internally by various models is 0
|
The valid <number> range is 0 to 17. Not all numbers trigger sounds
|
||||||
to 17, but it's possible that numbers outside this range are also
|
and the sounds vary from model to model. Here is the behavior on the
|
||||||
valid. Here is the behavior on the X40:
|
X40:
|
||||||
|
|
||||||
2 - two beeps, pause, third beep
|
0 - stop a sound in progress (but use 17 to stop 16)
|
||||||
|
2 - two beeps, pause, third beep ("low battery")
|
||||||
3 - single beep
|
3 - single beep
|
||||||
4 - "unable"
|
4 - high, followed by low-pitched beep ("unable")
|
||||||
5 - single beep
|
5 - single beep
|
||||||
6 - "AC/DC"
|
6 - very high, followed by high-pitched beep ("AC/DC")
|
||||||
7 - high-pitched beep
|
7 - high-pitched beep
|
||||||
9 - three short beeps
|
9 - three short beeps
|
||||||
10 - very long beep
|
10 - very long beep
|
||||||
12 - low-pitched beep
|
12 - low-pitched beep
|
||||||
|
15 - three high-pitched beeps repeating constantly, stop with 0
|
||||||
|
16 - one medium-pitched beep repeating constantly, stop with 17
|
||||||
|
17 - stop 16
|
||||||
|
|
||||||
(I've only been able to identify a couple of them).
|
Temperature sensors -- /proc/acpi/ibm/thermal
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
If you try this feature, please send me a report similar to the
|
Most ThinkPads include six or more separate temperature sensors but
|
||||||
above. I'd like to provide this functionality in an user-friendly way,
|
only expose the CPU temperature through the standard ACPI methods.
|
||||||
but first I need to identify the which numbers correspond to which
|
This feature shows readings from up to eight different sensors. Some
|
||||||
sounds on various models.
|
readings may not be valid, e.g. may show large negative values. For
|
||||||
|
example, on the X40, a typical output may be:
|
||||||
|
|
||||||
|
temperatures: 42 42 45 41 36 -128 33 -128
|
||||||
|
|
||||||
|
Thomas Gruber took his R51 apart and traced all six active sensors in
|
||||||
|
his laptop (the location of sensors may vary on other models):
|
||||||
|
|
||||||
|
1: CPU
|
||||||
|
2: Mini PCI Module
|
||||||
|
3: HDD
|
||||||
|
4: GPU
|
||||||
|
5: Battery
|
||||||
|
6: N/A
|
||||||
|
7: Battery
|
||||||
|
8: N/A
|
||||||
|
|
||||||
|
No commands can be written to this file.
|
||||||
|
|
||||||
|
EXPERIMENTAL: Embedded controller reigster dump -- /proc/acpi/ibm/ecdump
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This feature is marked EXPERIMENTAL because the implementation
|
||||||
|
directly accesses hardware registers and may not work as expected. USE
|
||||||
|
WITH CAUTION! To use this feature, you need to supply the
|
||||||
|
experimental=1 parameter when loading the module.
|
||||||
|
|
||||||
|
This feature dumps the values of 256 embedded controller
|
||||||
|
registers. Values which have changed since the last time the registers
|
||||||
|
were dumped are marked with a star:
|
||||||
|
|
||||||
|
[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
|
||||||
|
EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
|
||||||
|
EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
|
||||||
|
EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
|
||||||
|
EC 0x20: 00 00 00 00 00 00 00 00 00 00 00 03 43 00 00 80
|
||||||
|
EC 0x30: 01 07 1a 00 30 04 00 00 *85 00 00 10 00 50 00 00
|
||||||
|
EC 0x40: 00 00 00 00 00 00 14 01 00 04 00 00 00 00 00 00
|
||||||
|
EC 0x50: 00 c0 02 0d 00 01 01 02 02 03 03 03 03 *bc *02 *bc
|
||||||
|
EC 0x60: *02 *bc *02 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0x70: 00 00 00 00 00 12 30 40 *24 *26 *2c *27 *20 80 *1f 80
|
||||||
|
EC 0x80: 00 00 00 06 *37 *0e 03 00 00 00 0e 07 00 00 00 00
|
||||||
|
EC 0x90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xa0: *ff 09 ff 09 ff ff *64 00 *00 *00 *a2 41 *ff *ff *e0 00
|
||||||
|
EC 0xb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xd0: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xe0: 00 00 00 00 00 00 00 00 11 20 49 04 24 06 55 03
|
||||||
|
EC 0xf0: 31 55 48 54 35 38 57 57 08 2f 45 73 07 65 6c 1a
|
||||||
|
|
||||||
|
This feature can be used to determine the register holding the fan
|
||||||
|
speed on some models. To do that, do the following:
|
||||||
|
|
||||||
|
- make sure the battery is fully charged
|
||||||
|
- make sure the fan is running
|
||||||
|
- run 'cat /proc/acpi/ibm/ecdump' several times, once per second or so
|
||||||
|
|
||||||
|
The first step makes sure various charging-related values don't
|
||||||
|
vary. The second ensures that the fan-related values do vary, since
|
||||||
|
the fan speed fluctuates a bit. The third will (hopefully) mark the
|
||||||
|
fan register with a star:
|
||||||
|
|
||||||
|
[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
|
||||||
|
EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
|
||||||
|
EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
|
||||||
|
EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
|
||||||
|
EC 0x20: 00 00 00 00 00 00 00 00 00 00 00 03 43 00 00 80
|
||||||
|
EC 0x30: 01 07 1a 00 30 04 00 00 85 00 00 10 00 50 00 00
|
||||||
|
EC 0x40: 00 00 00 00 00 00 14 01 00 04 00 00 00 00 00 00
|
||||||
|
EC 0x50: 00 c0 02 0d 00 01 01 02 02 03 03 03 03 bc 02 bc
|
||||||
|
EC 0x60: 02 bc 02 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0x70: 00 00 00 00 00 12 30 40 24 27 2c 27 21 80 1f 80
|
||||||
|
EC 0x80: 00 00 00 06 *be 0d 03 00 00 00 0e 07 00 00 00 00
|
||||||
|
EC 0x90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xa0: ff 09 ff 09 ff ff 64 00 00 00 a2 41 ff ff e0 00
|
||||||
|
EC 0xb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xd0: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
EC 0xe0: 00 00 00 00 00 00 00 00 11 20 49 04 24 06 55 03
|
||||||
|
EC 0xf0: 31 55 48 54 35 38 57 57 08 2f 45 73 07 65 6c 1a
|
||||||
|
|
||||||
|
Another set of values that varies often is the temperature
|
||||||
|
readings. Since temperatures don't change vary fast, you can take
|
||||||
|
several quick dumps to eliminate them.
|
||||||
|
|
||||||
|
You can use a similar method to figure out the meaning of other
|
||||||
|
embedded controller registers - e.g. make sure nothing else changes
|
||||||
|
except the charging or discharging battery to determine which
|
||||||
|
registers contain the current battery capacity, etc. If you experiment
|
||||||
|
with this, do send me your results (including some complete dumps with
|
||||||
|
a description of the conditions when they were taken.)
|
||||||
|
|
||||||
|
EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
This feature is marked EXPERIMENTAL because the implementation
|
||||||
|
directly accesses hardware registers and may not work as expected. USE
|
||||||
|
WITH CAUTION! To use this feature, you need to supply the
|
||||||
|
experimental=1 parameter when loading the module.
|
||||||
|
|
||||||
|
This feature allows software control of the LCD brightness on ThinkPad
|
||||||
|
models which don't have a hardware brightness slider. The available
|
||||||
|
commands are:
|
||||||
|
|
||||||
|
echo up >/proc/acpi/ibm/brightness
|
||||||
|
echo down >/proc/acpi/ibm/brightness
|
||||||
|
echo 'level <level>' >/proc/acpi/ibm/brightness
|
||||||
|
|
||||||
|
The <level> number range is 0 to 7, although not all of them may be
|
||||||
|
distinct. The current brightness level is shown in the file.
|
||||||
|
|
||||||
|
EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
This feature is marked EXPERIMENTAL because the implementation
|
||||||
|
directly accesses hardware registers and may not work as expected. USE
|
||||||
|
WITH CAUTION! To use this feature, you need to supply the
|
||||||
|
experimental=1 parameter when loading the module.
|
||||||
|
|
||||||
|
This feature allows volume control on ThinkPad models which don't have
|
||||||
|
a hardware volume knob. The available commands are:
|
||||||
|
|
||||||
|
echo up >/proc/acpi/ibm/volume
|
||||||
|
echo down >/proc/acpi/ibm/volume
|
||||||
|
echo mute >/proc/acpi/ibm/volume
|
||||||
|
echo 'level <level>' >/proc/acpi/ibm/volume
|
||||||
|
|
||||||
|
The <level> number range is 0 to 15 although not all of them may be
|
||||||
|
distinct. The unmute the volume after the mute command, use either the
|
||||||
|
up or down command (the level command will not unmute the volume).
|
||||||
|
The current volume level and mute state is shown in the file.
|
||||||
|
|
||||||
|
EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
This feature is marked EXPERIMENTAL because the implementation
|
||||||
|
directly accesses hardware registers and may not work as expected. USE
|
||||||
|
WITH CAUTION! To use this feature, you need to supply the
|
||||||
|
experimental=1 parameter when loading the module.
|
||||||
|
|
||||||
|
This feature attempts to show the current fan speed. The speed is read
|
||||||
|
directly from the hardware registers of the embedded controller. This
|
||||||
|
is known to work on later R, T and X series ThinkPads but may show a
|
||||||
|
bogus value on other models.
|
||||||
|
|
||||||
|
The fan may be enabled or disabled with the following commands:
|
||||||
|
|
||||||
|
echo enable >/proc/acpi/ibm/fan
|
||||||
|
echo disable >/proc/acpi/ibm/fan
|
||||||
|
|
||||||
|
WARNING WARNING WARNING: do not leave the fan disabled unless you are
|
||||||
|
monitoring the temperature sensor readings and you are ready to enable
|
||||||
|
it if necessary to avoid overheating.
|
||||||
|
|
||||||
|
The fan only runs if it's enabled *and* the various temperature
|
||||||
|
sensors which control it read high enough. On the X40, this seems to
|
||||||
|
depend on the CPU and HDD temperatures. Specifically, the fan is
|
||||||
|
turned on when either the CPU temperature climbs to 56 degrees or the
|
||||||
|
HDD temperature climbs to 46 degrees. The fan is turned off when the
|
||||||
|
CPU temperature drops to 49 degrees and the HDD temperature drops to
|
||||||
|
41 degrees. These thresholds cannot currently be controlled.
|
||||||
|
|
||||||
|
On the X31 and X40 (and ONLY on those models), the fan speed can be
|
||||||
|
controlled to a certain degree. Once the fan is running, it can be
|
||||||
|
forced to run faster or slower with the following command:
|
||||||
|
|
||||||
|
echo 'speed <speed>' > /proc/acpi/ibm/thermal
|
||||||
|
|
||||||
|
The sustainable range of fan speeds on the X40 appears to be from
|
||||||
|
about 3700 to about 7350. Values outside this range either do not have
|
||||||
|
any effect or the fan speed eventually settles somewhere in that
|
||||||
|
range. The fan cannot be stopped or started with this command.
|
||||||
|
|
||||||
|
On the 570, temperature readings are not available through this
|
||||||
|
feature and the fan control works a little differently. The fan speed
|
||||||
|
is reported in levels from 0 (off) to 7 (max) and can be controlled
|
||||||
|
with the following command:
|
||||||
|
|
||||||
|
echo 'level <level>' > /proc/acpi/ibm/thermal
|
||||||
|
|
||||||
|
|
||||||
Multiple Command, Module Parameters
|
Multiple Commands, Module Parameters
|
||||||
-----------------------------------
|
------------------------------------
|
||||||
|
|
||||||
Multiple commands can be written to the proc files in one shot by
|
Multiple commands can be written to the proc files in one shot by
|
||||||
separating them with commas, for example:
|
separating them with commas, for example:
|
||||||
@ -451,24 +646,19 @@ scripts (included with ibm-acpi for completeness):
|
|||||||
/usr/local/sbin/laptop_mode -- from the Linux kernel source
|
/usr/local/sbin/laptop_mode -- from the Linux kernel source
|
||||||
distribution, see Documentation/laptop-mode.txt
|
distribution, see Documentation/laptop-mode.txt
|
||||||
/sbin/service -- comes with Redhat/Fedora distributions
|
/sbin/service -- comes with Redhat/Fedora distributions
|
||||||
|
/usr/sbin/hibernate -- from the Software Suspend 2 distribution,
|
||||||
|
see http://softwaresuspend.berlios.de/
|
||||||
|
|
||||||
Toan T Nguyen <ntt@control.uchicago.edu> has written a SuSE powersave
|
Toan T Nguyen <ntt@physics.ucla.edu> notes that Suse uses the
|
||||||
script for the X20, included in config/usr/sbin/ibm_hotkeys_X20
|
powersave program to suspend ('powersave --suspend-to-ram') or
|
||||||
|
hibernate ('powersave --suspend-to-disk'). This means that the
|
||||||
|
hibernate script is not needed on that distribution.
|
||||||
|
|
||||||
Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
|
Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
|
||||||
handler script for the X31. You can get the latest version from
|
handler script for the X31. You can get the latest version from
|
||||||
http://dev.gentoo.org/~brix/files/x31.sh
|
http://dev.gentoo.org/~brix/files/x31.sh
|
||||||
|
|
||||||
David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
|
David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
|
||||||
script which works on Debian systems, included in
|
script which works on Debian systems. This scripts has now been
|
||||||
configs/etc/acpi/actions/blank-debian.sh
|
extended to also work on Fedora systems and included as the default
|
||||||
|
blank.sh in the distribution.
|
||||||
|
|
||||||
TODO
|
|
||||||
----
|
|
||||||
|
|
||||||
I'd like to implement the following features but haven't yet found the
|
|
||||||
time and/or I don't yet know how to implement them:
|
|
||||||
|
|
||||||
- UltraBay floppy drive support
|
|
||||||
|
|
||||||
|
84
Documentation/input/appletouch.txt
Normal file
84
Documentation/input/appletouch.txt
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
Apple Touchpad Driver (appletouch)
|
||||||
|
----------------------------------
|
||||||
|
Copyright (C) 2005 Stelian Pop <stelian@popies.net>
|
||||||
|
|
||||||
|
appletouch is a Linux kernel driver for the USB touchpad found on post
|
||||||
|
February 2005 Apple Alu Powerbooks.
|
||||||
|
|
||||||
|
This driver is derived from Johannes Berg's appletrackpad driver[1], but it has
|
||||||
|
been improved in some areas:
|
||||||
|
* appletouch is a full kernel driver, no userspace program is necessary
|
||||||
|
* appletouch can be interfaced with the synaptics X11 driver, in order
|
||||||
|
to have touchpad acceleration, scrolling, etc.
|
||||||
|
|
||||||
|
Credits go to Johannes Berg for reverse-engineering the touchpad protocol,
|
||||||
|
Frank Arnold for further improvements, and Alex Harper for some additional
|
||||||
|
information about the inner workings of the touchpad sensors.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
------
|
||||||
|
|
||||||
|
In order to use the touchpad in the basic mode, compile the driver and load
|
||||||
|
the module. A new input device will be detected and you will be able to read
|
||||||
|
the mouse data from /dev/input/mice (using gpm, or X11).
|
||||||
|
|
||||||
|
In X11, you can configure the touchpad to use the synaptics X11 driver, which
|
||||||
|
will give additional functionalities, like acceleration, scrolling, 2 finger
|
||||||
|
tap for middle button mouse emulation, 3 finger tap for right button mouse
|
||||||
|
emulation, etc. In order to do this, make sure you're using a recent version of
|
||||||
|
the synaptics driver (tested with 0.14.2, available from [2]), and configure a
|
||||||
|
new input device in your X11 configuration file (take a look below for an
|
||||||
|
example). For additional configuration, see the synaptics driver documentation.
|
||||||
|
|
||||||
|
Section "InputDevice"
|
||||||
|
Identifier "Synaptics Touchpad"
|
||||||
|
Driver "synaptics"
|
||||||
|
Option "SendCoreEvents" "true"
|
||||||
|
Option "Device" "/dev/input/mice"
|
||||||
|
Option "Protocol" "auto-dev"
|
||||||
|
Option "LeftEdge" "0"
|
||||||
|
Option "RightEdge" "850"
|
||||||
|
Option "TopEdge" "0"
|
||||||
|
Option "BottomEdge" "645"
|
||||||
|
Option "MinSpeed" "0.4"
|
||||||
|
Option "MaxSpeed" "1"
|
||||||
|
Option "AccelFactor" "0.02"
|
||||||
|
Option "FingerLow" "0"
|
||||||
|
Option "FingerHigh" "30"
|
||||||
|
Option "MaxTapMove" "20"
|
||||||
|
Option "MaxTapTime" "100"
|
||||||
|
Option "HorizScrollDelta" "0"
|
||||||
|
Option "VertScrollDelta" "30"
|
||||||
|
Option "SHMConfig" "on"
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "ServerLayout"
|
||||||
|
...
|
||||||
|
InputDevice "Mouse"
|
||||||
|
InputDevice "Synaptics Touchpad"
|
||||||
|
...
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Fuzz problems:
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The touchpad sensors are very sensitive to heat, and will generate a lot of
|
||||||
|
noise when the temperature changes. This is especially true when you power-on
|
||||||
|
the laptop for the first time.
|
||||||
|
|
||||||
|
The appletouch driver tries to handle this noise and auto adapt itself, but it
|
||||||
|
is not perfect. If finger movements are not recognized anymore, try reloading
|
||||||
|
the driver.
|
||||||
|
|
||||||
|
You can activate debugging using the 'debug' module parameter. A value of 0
|
||||||
|
deactivates any debugging, 1 activates tracing of invalid samples, 2 activates
|
||||||
|
full tracing (each sample is being traced):
|
||||||
|
modprobe appletouch debug=1
|
||||||
|
or
|
||||||
|
echo "1" > /sys/module/appletouch/parameters/debug
|
||||||
|
|
||||||
|
Links:
|
||||||
|
------
|
||||||
|
|
||||||
|
[1]: http://johannes.sipsolutions.net/PowerBook/touchpad/
|
||||||
|
[2]: http://web.telia.com/~u89404340/touchpad/index.html
|
203
Documentation/input/yealink.txt
Normal file
203
Documentation/input/yealink.txt
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
Driver documentation for yealink usb-p1k phones
|
||||||
|
|
||||||
|
0. Status
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
The p1k is a relatively cheap usb 1.1 phone with:
|
||||||
|
- keyboard full support, yealink.ko / input event API
|
||||||
|
- LCD full support, yealink.ko / sysfs API
|
||||||
|
- LED full support, yealink.ko / sysfs API
|
||||||
|
- dialtone full support, yealink.ko / sysfs API
|
||||||
|
- ringtone full support, yealink.ko / sysfs API
|
||||||
|
- audio playback full support, snd_usb_audio.ko / alsa API
|
||||||
|
- audio record full support, snd_usb_audio.ko / alsa API
|
||||||
|
|
||||||
|
For vendor documentation see http://www.yealink.com
|
||||||
|
|
||||||
|
|
||||||
|
1. Compilation (stand alone version)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Currently only kernel 2.6.x.y versions are supported.
|
||||||
|
In order to build the yealink.ko module do:
|
||||||
|
|
||||||
|
make
|
||||||
|
|
||||||
|
If you encounter problems please check if in the MAKE_OPTS variable in
|
||||||
|
the Makefile is pointing to the location where your kernel sources
|
||||||
|
are located, default /usr/src/linux.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2. keyboard features
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
The current mapping in the kernel is provided by the map_p1k_to_key
|
||||||
|
function:
|
||||||
|
|
||||||
|
Physical USB-P1K button layout input events
|
||||||
|
|
||||||
|
|
||||||
|
up up
|
||||||
|
IN OUT left, right
|
||||||
|
down down
|
||||||
|
|
||||||
|
pickup C hangup enter, backspace, escape
|
||||||
|
1 2 3 1, 2, 3
|
||||||
|
4 5 6 4, 5, 6,
|
||||||
|
7 8 9 7, 8, 9,
|
||||||
|
* 0 # *, 0, #,
|
||||||
|
|
||||||
|
The "up" and "down" keys, are symbolised by arrows on the button.
|
||||||
|
The "pickup" and "hangup" keys are symbolised by a green and red phone
|
||||||
|
on the button.
|
||||||
|
|
||||||
|
|
||||||
|
3. LCD features
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The LCD is divided and organised as a 3 line display:
|
||||||
|
|
||||||
|
|[] [][] [][] [][] in |[][]
|
||||||
|
|[] M [][] D [][] : [][] out |[][]
|
||||||
|
store
|
||||||
|
|
||||||
|
NEW REP SU MO TU WE TH FR SA
|
||||||
|
|
||||||
|
[] [] [] [] [] [] [] [] [] [] [] []
|
||||||
|
[] [] [] [] [] [] [] [] [] [] [] []
|
||||||
|
|
||||||
|
|
||||||
|
Line 1 Format (see below) : 18.e8.M8.88...188
|
||||||
|
Icon names : M D : IN OUT STORE
|
||||||
|
Line 2 Format : .........
|
||||||
|
Icon name : NEW REP SU MO TU WE TH FR SA
|
||||||
|
Line 3 Format : 888888888888
|
||||||
|
|
||||||
|
|
||||||
|
Format description:
|
||||||
|
From a user space perspective the world is seperated in "digits" and "icons".
|
||||||
|
A digit can have a character set, an icon can only be ON or OFF.
|
||||||
|
|
||||||
|
Format specifier
|
||||||
|
'8' : Generic 7 segment digit with individual addressable segments
|
||||||
|
|
||||||
|
Reduced capabillity 7 segm digit, when segments are hard wired together.
|
||||||
|
'1' : 2 segments digit only able to produce a 1.
|
||||||
|
'e' : Most significant day of the month digit,
|
||||||
|
able to produce at least 1 2 3.
|
||||||
|
'M' : Most significant minute digit,
|
||||||
|
able to produce at least 0 1 2 3 4 5.
|
||||||
|
|
||||||
|
Icons or pictograms:
|
||||||
|
'.' : For example like AM, PM, SU, a 'dot' .. or other single segment
|
||||||
|
elements.
|
||||||
|
|
||||||
|
|
||||||
|
4. Driver usage
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
For userland the following interfaces are available using the sysfs interface:
|
||||||
|
/sys/.../
|
||||||
|
line1 Read/Write, lcd line1
|
||||||
|
line2 Read/Write, lcd line2
|
||||||
|
line3 Read/Write, lcd line3
|
||||||
|
|
||||||
|
get_icons Read, returns a set of available icons.
|
||||||
|
hide_icon Write, hide the element by writing the icon name.
|
||||||
|
show_icon Write, display the element by writing the icon name.
|
||||||
|
|
||||||
|
map_seg7 Read/Write, the 7 segments char set, common for all
|
||||||
|
yealink phones. (see map_to_7segment.h)
|
||||||
|
|
||||||
|
ringtone Write, upload binary representation of a ringtone,
|
||||||
|
see yealink.c. status EXPERIMENTAL due to potential
|
||||||
|
races between async. and sync usb calls.
|
||||||
|
|
||||||
|
|
||||||
|
4.1 lineX
|
||||||
|
~~~~~~~~~
|
||||||
|
Reading /sys/../lineX will return the format string with its current value:
|
||||||
|
|
||||||
|
Example:
|
||||||
|
cat ./line3
|
||||||
|
888888888888
|
||||||
|
Linux Rocks!
|
||||||
|
|
||||||
|
Writing to /sys/../lineX will set the coresponding LCD line.
|
||||||
|
- Excess characters are ignored.
|
||||||
|
- If less characters are written than allowed, the remaining digits are
|
||||||
|
unchanged.
|
||||||
|
- The tab '\t'and '\n' char does not overwrite the original content.
|
||||||
|
- Writing a space to an icon will always hide its content.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
date +"%m.%e.%k:%M" | sed 's/^0/ /' > ./line1
|
||||||
|
|
||||||
|
Will update the LCD with the current date & time.
|
||||||
|
|
||||||
|
|
||||||
|
4.2 get_icons
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
Reading will return all available icon names and its current settings:
|
||||||
|
|
||||||
|
cat ./get_icons
|
||||||
|
on M
|
||||||
|
on D
|
||||||
|
on :
|
||||||
|
IN
|
||||||
|
OUT
|
||||||
|
STORE
|
||||||
|
NEW
|
||||||
|
REP
|
||||||
|
SU
|
||||||
|
MO
|
||||||
|
TU
|
||||||
|
WE
|
||||||
|
TH
|
||||||
|
FR
|
||||||
|
SA
|
||||||
|
LED
|
||||||
|
DIALTONE
|
||||||
|
RINGTONE
|
||||||
|
|
||||||
|
|
||||||
|
4.3 show/hide icons
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
Writing to these files will update the state of the icon.
|
||||||
|
Only one icon at a time can be updated.
|
||||||
|
|
||||||
|
If an icon is also on a ./lineX the corresponding value is
|
||||||
|
updated with the first letter of the icon.
|
||||||
|
|
||||||
|
Example - light up the store icon:
|
||||||
|
echo -n "STORE" > ./show_icon
|
||||||
|
|
||||||
|
cat ./line1
|
||||||
|
18.e8.M8.88...188
|
||||||
|
S
|
||||||
|
|
||||||
|
Example - sound the ringtone for 10 seconds:
|
||||||
|
echo -n RINGTONE > /sys/..../show_icon
|
||||||
|
sleep 10
|
||||||
|
echo -n RINGTONE > /sys/..../hide_icon
|
||||||
|
|
||||||
|
|
||||||
|
5. Sound features
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
Sound is supported by the ALSA driver: snd_usb_audio
|
||||||
|
|
||||||
|
One 16-bit channel with sample and playback rates of 8000 Hz is the practical
|
||||||
|
limit of the device.
|
||||||
|
|
||||||
|
Example - recording test:
|
||||||
|
arecord -v -d 10 -r 8000 -f S16_LE -t wav foobar.wav
|
||||||
|
|
||||||
|
Example - playback test:
|
||||||
|
aplay foobar.wav
|
||||||
|
|
||||||
|
|
||||||
|
6. Credits & Acknowledgments
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
- Olivier Vandorpe, for starting the usbb2k-api project doing much of
|
||||||
|
the reverse engineering.
|
||||||
|
- Martin Diehl, for pointing out how to handle USB memory allocation.
|
||||||
|
- Dmitry Torokhov, for the numerous code reviews and suggestions.
|
||||||
|
|
@ -878,7 +878,7 @@ DVD_READ_STRUCT Read structure
|
|||||||
|
|
||||||
error returns:
|
error returns:
|
||||||
EINVAL physical.layer_num exceeds number of layers
|
EINVAL physical.layer_num exceeds number of layers
|
||||||
EIO Recieved invalid response from drive
|
EIO Received invalid response from drive
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ This document describes the Linux kernel Makefiles.
|
|||||||
|
|
||||||
=== 6 Architecture Makefiles
|
=== 6 Architecture Makefiles
|
||||||
--- 6.1 Set variables to tweak the build to the architecture
|
--- 6.1 Set variables to tweak the build to the architecture
|
||||||
--- 6.2 Add prerequisites to prepare:
|
--- 6.2 Add prerequisites to archprepare:
|
||||||
--- 6.3 List directories to visit when descending
|
--- 6.3 List directories to visit when descending
|
||||||
--- 6.4 Architecture specific boot images
|
--- 6.4 Architecture specific boot images
|
||||||
--- 6.5 Building non-kbuild targets
|
--- 6.5 Building non-kbuild targets
|
||||||
@ -734,18 +734,18 @@ When kbuild executes the following steps are followed (roughly):
|
|||||||
for loadable kernel modules.
|
for loadable kernel modules.
|
||||||
|
|
||||||
|
|
||||||
--- 6.2 Add prerequisites to prepare:
|
--- 6.2 Add prerequisites to archprepare:
|
||||||
|
|
||||||
The prepare: rule is used to list prerequisites that needs to be
|
The archprepare: rule is used to list prerequisites that needs to be
|
||||||
built before starting to descend down in the subdirectories.
|
built before starting to descend down in the subdirectories.
|
||||||
This is usual header files containing assembler constants.
|
This is usual header files containing assembler constants.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
#arch/s390/Makefile
|
#arch/arm/Makefile
|
||||||
prepare: include/asm-$(ARCH)/offsets.h
|
archprepare: maketools
|
||||||
|
|
||||||
In this example the file include/asm-$(ARCH)/offsets.h will
|
In this example the file target maketools will be processed
|
||||||
be built before descending down in the subdirectories.
|
before descending down in the subdirectories.
|
||||||
See also chapter XXX-TODO that describe how kbuild supports
|
See also chapter XXX-TODO that describe how kbuild supports
|
||||||
generating offset header files.
|
generating offset header files.
|
||||||
|
|
||||||
|
@ -39,8 +39,7 @@ SETUP
|
|||||||
and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch
|
and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch
|
||||||
and after that build the source.
|
and after that build the source.
|
||||||
|
|
||||||
2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel
|
2) Download and build the appropriate (2.6.13-rc1 onwards) vanilla kernel.
|
||||||
patchset and apply it to the vanilla kernel tree.
|
|
||||||
|
|
||||||
Two kernels need to be built in order to get this feature working.
|
Two kernels need to be built in order to get this feature working.
|
||||||
|
|
||||||
@ -84,15 +83,16 @@ SETUP
|
|||||||
|
|
||||||
4) Load the second kernel to be booted using:
|
4) Load the second kernel to be booted using:
|
||||||
|
|
||||||
kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev>
|
kexec -p <second-kernel> --args-linux --elf32-core-headers
|
||||||
init 1 irqpoll"
|
--append="root=<root-dev> init 1 irqpoll"
|
||||||
|
|
||||||
Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work,
|
Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work,
|
||||||
as of now.
|
as of now.
|
||||||
ii) By default ELF headers are stored in ELF32 format (for i386). This
|
ii) By default ELF headers are stored in ELF64 format. Option
|
||||||
is sufficient to represent the physical memory up to 4GB. To store
|
--elf32-core-headers forces generation of ELF32 headers. gdb can
|
||||||
headers in ELF64 format, specifiy "--elf64-core-headers" on the
|
not open ELF64 headers on 32 bit systems. So creating ELF32
|
||||||
kexec command line additionally.
|
headers can come handy for users who have got non-PAE systems and
|
||||||
|
hence have memory less than 4GB.
|
||||||
iii) Specify "irqpoll" as command line parameter. This reduces driver
|
iii) Specify "irqpoll" as command line parameter. This reduces driver
|
||||||
initialization failures in second kernel due to shared interrupts.
|
initialization failures in second kernel due to shared interrupts.
|
||||||
|
|
||||||
|
@ -164,6 +164,15 @@ running once the system is up.
|
|||||||
over-ride platform specific driver.
|
over-ride platform specific driver.
|
||||||
See also Documentation/acpi-hotkey.txt.
|
See also Documentation/acpi-hotkey.txt.
|
||||||
|
|
||||||
|
enable_timer_pin_1 [i386,x86-64]
|
||||||
|
Enable PIN 1 of APIC timer
|
||||||
|
Can be useful to work around chipset bugs (in particular on some ATI chipsets)
|
||||||
|
The kernel tries to set a reasonable default.
|
||||||
|
|
||||||
|
disable_timer_pin_1 [i386,x86-64]
|
||||||
|
Disable PIN 1 of APIC timer
|
||||||
|
Can be useful to work around chipset bugs.
|
||||||
|
|
||||||
ad1816= [HW,OSS]
|
ad1816= [HW,OSS]
|
||||||
Format: <io>,<irq>,<dma>,<dma2>
|
Format: <io>,<irq>,<dma>,<dma2>
|
||||||
See also Documentation/sound/oss/AD1816.
|
See also Documentation/sound/oss/AD1816.
|
||||||
@ -549,6 +558,7 @@ running once the system is up.
|
|||||||
keyboard and can not control its state
|
keyboard and can not control its state
|
||||||
(Don't attempt to blink the leds)
|
(Don't attempt to blink the leds)
|
||||||
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
|
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
|
||||||
|
i8042.nokbd [HW] Don't check/create keyboard port
|
||||||
i8042.nomux [HW] Don't check presence of an active multiplexing
|
i8042.nomux [HW] Don't check presence of an active multiplexing
|
||||||
controller
|
controller
|
||||||
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
|
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
|
||||||
|
@ -30,7 +30,7 @@ other program after you have done the following:
|
|||||||
Read the file 'binfmt_misc.txt' in this directory to know
|
Read the file 'binfmt_misc.txt' in this directory to know
|
||||||
more about the configuration process.
|
more about the configuration process.
|
||||||
|
|
||||||
3) Add the following enries to /etc/rc.local or similar script
|
3) Add the following entries to /etc/rc.local or similar script
|
||||||
to be run at system startup:
|
to be run at system startup:
|
||||||
|
|
||||||
# Insert BINFMT_MISC module into the kernel
|
# Insert BINFMT_MISC module into the kernel
|
||||||
|
@ -1241,7 +1241,7 @@ traffic while still maintaining carrier on.
|
|||||||
|
|
||||||
If running SNMP agents, the bonding driver should be loaded
|
If running SNMP agents, the bonding driver should be loaded
|
||||||
before any network drivers participating in a bond. This requirement
|
before any network drivers participating in a bond. This requirement
|
||||||
is due to the the interface index (ipAdEntIfIndex) being associated to
|
is due to the interface index (ipAdEntIfIndex) being associated to
|
||||||
the first interface found with a given IP address. That is, there is
|
the first interface found with a given IP address. That is, there is
|
||||||
only one ipAdEntIfIndex for each IP address. For example, if eth0 and
|
only one ipAdEntIfIndex for each IP address. For example, if eth0 and
|
||||||
eth1 are slaves of bond0 and the driver for eth0 is loaded before the
|
eth1 are slaves of bond0 and the driver for eth0 is loaded before the
|
||||||
@ -1937,7 +1937,7 @@ switches currently available support 802.3ad.
|
|||||||
If not explicitly configured (with ifconfig or ip link), the
|
If not explicitly configured (with ifconfig or ip link), the
|
||||||
MAC address of the bonding device is taken from its first slave
|
MAC address of the bonding device is taken from its first slave
|
||||||
device. This MAC address is then passed to all following slaves and
|
device. This MAC address is then passed to all following slaves and
|
||||||
remains persistent (even if the the first slave is removed) until the
|
remains persistent (even if the first slave is removed) until the
|
||||||
bonding device is brought down or reconfigured.
|
bonding device is brought down or reconfigured.
|
||||||
|
|
||||||
If you wish to change the MAC address, you can set it with
|
If you wish to change the MAC address, you can set it with
|
||||||
|
@ -355,7 +355,7 @@ REVISION HISTORY
|
|||||||
There is no functional difference between the two packages
|
There is no functional difference between the two packages
|
||||||
|
|
||||||
2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE.
|
2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE.
|
||||||
o Fixed a memeory leak for X25API
|
o Fixed a memory leak for X25API
|
||||||
o Updated the X25API code for 2.2.X kernels.
|
o Updated the X25API code for 2.2.X kernels.
|
||||||
o Improved NEM handling.
|
o Improved NEM handling.
|
||||||
|
|
||||||
@ -514,7 +514,7 @@ beta2-2.2.0 Jan 8 2001
|
|||||||
o Patches for 2.4.0 kernel
|
o Patches for 2.4.0 kernel
|
||||||
o Patches for 2.2.18 kernel
|
o Patches for 2.2.18 kernel
|
||||||
o Minor updates to PPP and CHLDC drivers.
|
o Minor updates to PPP and CHLDC drivers.
|
||||||
Note: No functinal difference.
|
Note: No functional difference.
|
||||||
|
|
||||||
beta3-2.2.9 Jan 10 2001
|
beta3-2.2.9 Jan 10 2001
|
||||||
o I missed the 2.2.18 kernel patches in beta2-2.2.0
|
o I missed the 2.2.18 kernel patches in beta2-2.2.0
|
||||||
|
@ -84,7 +84,7 @@ Each entry consists of:
|
|||||||
|
|
||||||
Most drivers don't need to use the driver_data field. Best practice
|
Most drivers don't need to use the driver_data field. Best practice
|
||||||
for use of driver_data is to use it as an index into a static list of
|
for use of driver_data is to use it as an index into a static list of
|
||||||
equivalant device types, not to use it as a pointer.
|
equivalent device types, not to use it as a pointer.
|
||||||
|
|
||||||
Have a table entry {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID}
|
Have a table entry {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID}
|
||||||
to have probe() called for every PCI device known to the system.
|
to have probe() called for every PCI device known to the system.
|
||||||
|
@ -134,7 +134,7 @@ pci_get_device_by_addr() will find the pci device associated
|
|||||||
with that address (if any).
|
with that address (if any).
|
||||||
|
|
||||||
The default include/asm-ppc64/io.h macros readb(), inb(), insb(),
|
The default include/asm-ppc64/io.h macros readb(), inb(), insb(),
|
||||||
etc. include a check to see if the the i/o read returned all-0xff's.
|
etc. include a check to see if the i/o read returned all-0xff's.
|
||||||
If so, these make a call to eeh_dn_check_failure(), which in turn
|
If so, these make a call to eeh_dn_check_failure(), which in turn
|
||||||
asks the firmware if the all-ff's value is the sign of a true EEH
|
asks the firmware if the all-ff's value is the sign of a true EEH
|
||||||
error. If it is not, processing continues as normal. The grand
|
error. If it is not, processing continues as normal. The grand
|
||||||
|
@ -468,7 +468,7 @@ The hex_ascii view shows the data field in hex and ascii representation
|
|||||||
The raw view returns a bytestream as the debug areas are stored in memory.
|
The raw view returns a bytestream as the debug areas are stored in memory.
|
||||||
|
|
||||||
The sprintf view formats the debug entries in the same way as the sprintf
|
The sprintf view formats the debug entries in the same way as the sprintf
|
||||||
function would do. The sprintf event/expection fuctions write to the
|
function would do. The sprintf event/expection functions write to the
|
||||||
debug entry a pointer to the format string (size = sizeof(long))
|
debug entry a pointer to the format string (size = sizeof(long))
|
||||||
and for each vararg a long value. So e.g. for a debug entry with a format
|
and for each vararg a long value. So e.g. for a debug entry with a format
|
||||||
string plus two varargs one would need to allocate a (3 * sizeof(long))
|
string plus two varargs one would need to allocate a (3 * sizeof(long))
|
||||||
|
@ -60,6 +60,8 @@ scsi.txt
|
|||||||
- short blurb on using SCSI support as a module.
|
- short blurb on using SCSI support as a module.
|
||||||
scsi_mid_low_api.txt
|
scsi_mid_low_api.txt
|
||||||
- info on API between SCSI layer and low level drivers
|
- info on API between SCSI layer and low level drivers
|
||||||
|
scsi_eh.txt
|
||||||
|
- info on SCSI midlayer error handling infrastructure
|
||||||
st.txt
|
st.txt
|
||||||
- info on scsi tape driver
|
- info on scsi tape driver
|
||||||
sym53c500_cs.txt
|
sym53c500_cs.txt
|
||||||
|
@ -344,7 +344,7 @@
|
|||||||
/proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
|
/proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
|
||||||
|
|
||||||
This table is quite informative for interested users. It shows the load
|
This table is quite informative for interested users. It shows the load
|
||||||
of commands on the subsystem and wether you are running the bypassed
|
of commands on the subsystem and whether you are running the bypassed
|
||||||
(software) or integrated (hardware) SCSI-command set (see below). The
|
(software) or integrated (hardware) SCSI-command set (see below). The
|
||||||
amount of accesses is shown. Read, write, modeselect is shown separately
|
amount of accesses is shown. Read, write, modeselect is shown separately
|
||||||
in order to help debugging problems with CD-ROMs or tapedrives.
|
in order to help debugging problems with CD-ROMs or tapedrives.
|
||||||
|
479
Documentation/scsi/scsi_eh.txt
Normal file
479
Documentation/scsi/scsi_eh.txt
Normal file
@ -0,0 +1,479 @@
|
|||||||
|
|
||||||
|
SCSI EH
|
||||||
|
======================================
|
||||||
|
|
||||||
|
This document describes SCSI midlayer error handling infrastructure.
|
||||||
|
Please refer to Documentation/scsi/scsi_mid_low_api.txt for more
|
||||||
|
information regarding SCSI midlayer.
|
||||||
|
|
||||||
|
TABLE OF CONTENTS
|
||||||
|
|
||||||
|
[1] How SCSI commands travel through the midlayer and to EH
|
||||||
|
[1-1] struct scsi_cmnd
|
||||||
|
[1-2] How do scmd's get completed?
|
||||||
|
[1-2-1] Completing a scmd w/ scsi_done
|
||||||
|
[1-2-2] Completing a scmd w/ timeout
|
||||||
|
[1-3] How EH takes over
|
||||||
|
[2] How SCSI EH works
|
||||||
|
[2-1] EH through fine-grained callbacks
|
||||||
|
[2-1-1] Overview
|
||||||
|
[2-1-2] Flow of scmds through EH
|
||||||
|
[2-1-3] Flow of control
|
||||||
|
[2-2] EH through hostt->eh_strategy_handler()
|
||||||
|
[2-2-1] Pre hostt->eh_strategy_handler() SCSI midlayer conditions
|
||||||
|
[2-2-2] Post hostt->eh_strategy_handler() SCSI midlayer conditions
|
||||||
|
[2-2-3] Things to consider
|
||||||
|
|
||||||
|
|
||||||
|
[1] How SCSI commands travel through the midlayer and to EH
|
||||||
|
|
||||||
|
[1-1] struct scsi_cmnd
|
||||||
|
|
||||||
|
Each SCSI command is represented with struct scsi_cmnd (== scmd). A
|
||||||
|
scmd has two list_head's to link itself into lists. The two are
|
||||||
|
scmd->list and scmd->eh_entry. The former is used for free list or
|
||||||
|
per-device allocated scmd list and not of much interest to this EH
|
||||||
|
discussion. The latter is used for completion and EH lists and unless
|
||||||
|
otherwise stated scmds are always linked using scmd->eh_entry in this
|
||||||
|
discussion.
|
||||||
|
|
||||||
|
|
||||||
|
[1-2] How do scmd's get completed?
|
||||||
|
|
||||||
|
Once LLDD gets hold of a scmd, either the LLDD will complete the
|
||||||
|
command by calling scsi_done callback passed from midlayer when
|
||||||
|
invoking hostt->queuecommand() or SCSI midlayer will time it out.
|
||||||
|
|
||||||
|
|
||||||
|
[1-2-1] Completing a scmd w/ scsi_done
|
||||||
|
|
||||||
|
For all non-EH commands, scsi_done() is the completion callback. It
|
||||||
|
does the following.
|
||||||
|
|
||||||
|
1. Delete timeout timer. If it fails, it means that timeout timer
|
||||||
|
has expired and is going to finish the command. Just return.
|
||||||
|
|
||||||
|
2. Link scmd to per-cpu scsi_done_q using scmd->en_entry
|
||||||
|
|
||||||
|
3. Raise SCSI_SOFTIRQ
|
||||||
|
|
||||||
|
SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to
|
||||||
|
determine what to do with the command. scsi_decide_disposition()
|
||||||
|
looks at the scmd->result value and sense data to determine what to do
|
||||||
|
with the command.
|
||||||
|
|
||||||
|
- SUCCESS
|
||||||
|
scsi_finish_command() is invoked for the command. The
|
||||||
|
function does some maintenance choirs and notify completion by
|
||||||
|
calling scmd->done() callback, which, for fs requests, would
|
||||||
|
be HLD completion callback - sd:sd_rw_intr, sr:rw_intr,
|
||||||
|
st:st_intr.
|
||||||
|
|
||||||
|
- NEEDS_RETRY
|
||||||
|
- ADD_TO_MLQUEUE
|
||||||
|
scmd is requeued to blk queue.
|
||||||
|
|
||||||
|
- otherwise
|
||||||
|
scsi_eh_scmd_add(scmd, 0) is invoked for the command. See
|
||||||
|
[1-3] for details of this funciton.
|
||||||
|
|
||||||
|
|
||||||
|
[1-2-2] Completing a scmd w/ timeout
|
||||||
|
|
||||||
|
The timeout handler is scsi_times_out(). When a timeout occurs, this
|
||||||
|
function
|
||||||
|
|
||||||
|
1. invokes optional hostt->eh_timedout() callback. Return value can
|
||||||
|
be one of
|
||||||
|
|
||||||
|
- EH_HANDLED
|
||||||
|
This indicates that eh_timedout() dealt with the timeout. The
|
||||||
|
scmd is passed to __scsi_done() and thus linked into per-cpu
|
||||||
|
scsi_done_q. Normal command completion described in [1-2-1]
|
||||||
|
follows.
|
||||||
|
|
||||||
|
- EH_RESET_TIMER
|
||||||
|
This indicates that more time is required to finish the
|
||||||
|
command. Timer is restarted. This action is counted as a
|
||||||
|
retry and only allowed scmd->allowed + 1(!) times. Once the
|
||||||
|
limit is reached, action for EH_NOT_HANDLED is taken instead.
|
||||||
|
|
||||||
|
*NOTE* This action is racy as the LLDD could finish the scmd
|
||||||
|
after the timeout has expired but before it's added back. In
|
||||||
|
such cases, scsi_done() would think that timeout has occurred
|
||||||
|
and return without doing anything. We lose completion and the
|
||||||
|
command will time out again.
|
||||||
|
|
||||||
|
- EH_NOT_HANDLED
|
||||||
|
This is the same as when eh_timedout() callback doesn't exist.
|
||||||
|
Step #2 is taken.
|
||||||
|
|
||||||
|
2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the
|
||||||
|
command. See [1-3] for more information.
|
||||||
|
|
||||||
|
|
||||||
|
[1-3] How EH takes over
|
||||||
|
|
||||||
|
scmds enter EH via scsi_eh_scmd_add(), which does the following.
|
||||||
|
|
||||||
|
1. Turns on scmd->eh_eflags as requested. It's 0 for error
|
||||||
|
completions and SCSI_EH_CANCEL_CMD for timeouts.
|
||||||
|
|
||||||
|
2. Links scmd->eh_entry to shost->eh_cmd_q
|
||||||
|
|
||||||
|
3. Sets SHOST_RECOVERY bit in shost->shost_state
|
||||||
|
|
||||||
|
4. Increments shost->host_failed
|
||||||
|
|
||||||
|
5. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed
|
||||||
|
|
||||||
|
As can be seen above, once any scmd is added to shost->eh_cmd_q,
|
||||||
|
SHOST_RECOVERY shost_state bit is turned on. This prevents any new
|
||||||
|
scmd to be issued from blk queue to the host; eventually, all scmds on
|
||||||
|
the host either complete normally, fail and get added to eh_cmd_q, or
|
||||||
|
time out and get added to shost->eh_cmd_q.
|
||||||
|
|
||||||
|
If all scmds either complete or fail, the number of in-flight scmds
|
||||||
|
becomes equal to the number of failed scmds - i.e. shost->host_busy ==
|
||||||
|
shost->host_failed. This wakes up SCSI EH thread. So, once woken up,
|
||||||
|
SCSI EH thread can expect that all in-flight commands have failed and
|
||||||
|
are linked on shost->eh_cmd_q.
|
||||||
|
|
||||||
|
Note that this does not mean lower layers are quiescent. If a LLDD
|
||||||
|
completed a scmd with error status, the LLDD and lower layers are
|
||||||
|
assumed to forget about the scmd at that point. However, if a scmd
|
||||||
|
has timed out, unless hostt->eh_timedout() made lower layers forget
|
||||||
|
about the scmd, which currently no LLDD does, the command is still
|
||||||
|
active as long as lower layers are concerned and completion could
|
||||||
|
occur at any time. Of course, all such completions are ignored as the
|
||||||
|
timer has already expired.
|
||||||
|
|
||||||
|
We'll talk about how SCSI EH takes actions to abort - make LLDD
|
||||||
|
forget about - timed out scmds later.
|
||||||
|
|
||||||
|
|
||||||
|
[2] How SCSI EH works
|
||||||
|
|
||||||
|
LLDD's can implement SCSI EH actions in one of the following two
|
||||||
|
ways.
|
||||||
|
|
||||||
|
- Fine-grained EH callbacks
|
||||||
|
LLDD can implement fine-grained EH callbacks and let SCSI
|
||||||
|
midlayer drive error handling and call appropriate callbacks.
|
||||||
|
This will be dicussed further in [2-1].
|
||||||
|
|
||||||
|
- eh_strategy_handler() callback
|
||||||
|
This is one big callback which should perform whole error
|
||||||
|
handling. As such, it should do all choirs SCSI midlayer
|
||||||
|
performs during recovery. This will be discussed in [2-2].
|
||||||
|
|
||||||
|
Once recovery is complete, SCSI EH resumes normal operation by
|
||||||
|
calling scsi_restart_operations(), which
|
||||||
|
|
||||||
|
1. Checks if door locking is needed and locks door.
|
||||||
|
|
||||||
|
2. Clears SHOST_RECOVERY shost_state bit
|
||||||
|
|
||||||
|
3. Wakes up waiters on shost->host_wait. This occurs if someone
|
||||||
|
calls scsi_block_when_processing_errors() on the host.
|
||||||
|
(*QUESTION* why is it needed? All operations will be blocked
|
||||||
|
anyway after it reaches blk queue.)
|
||||||
|
|
||||||
|
4. Kicks queues in all devices on the host in the asses
|
||||||
|
|
||||||
|
|
||||||
|
[2-1] EH through fine-grained callbacks
|
||||||
|
|
||||||
|
[2-1-1] Overview
|
||||||
|
|
||||||
|
If eh_strategy_handler() is not present, SCSI midlayer takes charge
|
||||||
|
of driving error handling. EH's goals are two - make LLDD, host and
|
||||||
|
device forget about timed out scmds and make them ready for new
|
||||||
|
commands. A scmd is said to be recovered if the scmd is forgotten by
|
||||||
|
lower layers and lower layers are ready to process or fail the scmd
|
||||||
|
again.
|
||||||
|
|
||||||
|
To achieve these goals, EH performs recovery actions with increasing
|
||||||
|
severity. Some actions are performed by issueing SCSI commands and
|
||||||
|
others are performed by invoking one of the following fine-grained
|
||||||
|
hostt EH callbacks. Callbacks may be omitted and omitted ones are
|
||||||
|
considered to fail always.
|
||||||
|
|
||||||
|
int (* eh_abort_handler)(struct scsi_cmnd *);
|
||||||
|
int (* eh_device_reset_handler)(struct scsi_cmnd *);
|
||||||
|
int (* eh_bus_reset_handler)(struct scsi_cmnd *);
|
||||||
|
int (* eh_host_reset_handler)(struct scsi_cmnd *);
|
||||||
|
|
||||||
|
Higher-severity actions are taken only when lower-severity actions
|
||||||
|
cannot recover some of failed scmds. Also, note that failure of the
|
||||||
|
highest-severity action means EH failure and results in offlining of
|
||||||
|
all unrecovered devices.
|
||||||
|
|
||||||
|
During recovery, the following rules are followed
|
||||||
|
|
||||||
|
- Recovery actions are performed on failed scmds on the to do list,
|
||||||
|
eh_work_q. If a recovery action succeeds for a scmd, recovered
|
||||||
|
scmds are removed from eh_work_q.
|
||||||
|
|
||||||
|
Note that single recovery action on a scmd can recover multiple
|
||||||
|
scmds. e.g. resetting a device recovers all failed scmds on the
|
||||||
|
device.
|
||||||
|
|
||||||
|
- Higher severity actions are taken iff eh_work_q is not empty after
|
||||||
|
lower severity actions are complete.
|
||||||
|
|
||||||
|
- EH reuses failed scmds to issue commands for recovery. For
|
||||||
|
timed-out scmds, SCSI EH ensures that LLDD forgets about a scmd
|
||||||
|
before reusing it for EH commands.
|
||||||
|
|
||||||
|
When a scmd is recovered, the scmd is moved from eh_work_q to EH
|
||||||
|
local eh_done_q using scsi_eh_finish_cmd(). After all scmds are
|
||||||
|
recovered (eh_work_q is empty), scsi_eh_flush_done_q() is invoked to
|
||||||
|
either retry or error-finish (notify upper layer of failure) recovered
|
||||||
|
scmds.
|
||||||
|
|
||||||
|
scmds are retried iff its sdev is still online (not offlined during
|
||||||
|
EH), REQ_FAILFAST is not set and ++scmd->retries is less than
|
||||||
|
scmd->allowed.
|
||||||
|
|
||||||
|
|
||||||
|
[2-1-2] Flow of scmds through EH
|
||||||
|
|
||||||
|
1. Error completion / time out
|
||||||
|
ACTION: scsi_eh_scmd_add() is invoked for scmd
|
||||||
|
- set scmd->eh_eflags
|
||||||
|
- add scmd to shost->eh_cmd_q
|
||||||
|
- set SHOST_RECOVERY
|
||||||
|
- shost->host_failed++
|
||||||
|
LOCKING: shost->host_lock
|
||||||
|
|
||||||
|
2. EH starts
|
||||||
|
ACTION: move all scmds to EH's local eh_work_q. shost->eh_cmd_q
|
||||||
|
is cleared.
|
||||||
|
LOCKING: shost->host_lock (not strictly necessary, just for
|
||||||
|
consistency)
|
||||||
|
|
||||||
|
3. scmd recovered
|
||||||
|
ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd
|
||||||
|
- shost->host_failed--
|
||||||
|
- clear scmd->eh_eflags
|
||||||
|
- scsi_setup_cmd_retry()
|
||||||
|
- move from local eh_work_q to local eh_done_q
|
||||||
|
LOCKING: none
|
||||||
|
|
||||||
|
4. EH completes
|
||||||
|
ACTION: scsi_eh_flush_done_q() retries scmds or notifies upper
|
||||||
|
layer of failure.
|
||||||
|
- scmd is removed from eh_done_q and scmd->eh_entry is cleared
|
||||||
|
- if retry is necessary, scmd is requeued using
|
||||||
|
scsi_queue_insert()
|
||||||
|
- otherwise, scsi_finish_command() is invoked for scmd
|
||||||
|
LOCKING: queue or finish function performs appropriate locking
|
||||||
|
|
||||||
|
|
||||||
|
[2-1-3] Flow of control
|
||||||
|
|
||||||
|
EH through fine-grained callbacks start from scsi_unjam_host().
|
||||||
|
|
||||||
|
<<scsi_unjam_host>>
|
||||||
|
|
||||||
|
1. Lock shost->host_lock, splice_init shost->eh_cmd_q into local
|
||||||
|
eh_work_q and unlock host_lock. Note that shost->eh_cmd_q is
|
||||||
|
cleared by this action.
|
||||||
|
|
||||||
|
2. Invoke scsi_eh_get_sense.
|
||||||
|
|
||||||
|
<<scsi_eh_get_sense>>
|
||||||
|
|
||||||
|
This action is taken for each error-completed
|
||||||
|
(!SCSI_EH_CANCEL_CMD) commands without valid sense data. Most
|
||||||
|
SCSI transports/LLDDs automatically acquire sense data on
|
||||||
|
command failures (autosense). Autosense is recommended for
|
||||||
|
performance reasons and as sense information could get out of
|
||||||
|
sync inbetween occurrence of CHECK CONDITION and this action.
|
||||||
|
|
||||||
|
Note that if autosense is not supported, scmd->sense_buffer
|
||||||
|
contains invalid sense data when error-completing the scmd
|
||||||
|
with scsi_done(). scsi_decide_disposition() always returns
|
||||||
|
FAILED in such cases thus invoking SCSI EH. When the scmd
|
||||||
|
reaches here, sense data is acquired and
|
||||||
|
scsi_decide_disposition() is called again.
|
||||||
|
|
||||||
|
1. Invoke scsi_request_sense() which issues REQUEST_SENSE
|
||||||
|
command. If fails, no action. Note that taking no action
|
||||||
|
causes higher-severity recovery to be taken for the scmd.
|
||||||
|
|
||||||
|
2. Invoke scsi_decide_disposition() on the scmd
|
||||||
|
|
||||||
|
- SUCCESS
|
||||||
|
scmd->retries is set to scmd->allowed preventing
|
||||||
|
scsi_eh_flush_done_q() from retrying the scmd and
|
||||||
|
scsi_eh_finish_cmd() is invoked.
|
||||||
|
|
||||||
|
- NEEDS_RETRY
|
||||||
|
scsi_eh_finish_cmd() invoked
|
||||||
|
|
||||||
|
- otherwise
|
||||||
|
No action.
|
||||||
|
|
||||||
|
3. If !list_empty(&eh_work_q), invoke scsi_eh_abort_cmds().
|
||||||
|
|
||||||
|
<<scsi_eh_abort_cmds>>
|
||||||
|
|
||||||
|
This action is taken for each timed out command.
|
||||||
|
hostt->eh_abort_handler() is invoked for each scmd. The
|
||||||
|
handler returns SUCCESS if it has succeeded to make LLDD and
|
||||||
|
all related hardware forget about the scmd.
|
||||||
|
|
||||||
|
If a timedout scmd is successfully aborted and the sdev is
|
||||||
|
either offline or ready, scsi_eh_finish_cmd() is invoked for
|
||||||
|
the scmd. Otherwise, the scmd is left in eh_work_q for
|
||||||
|
higher-severity actions.
|
||||||
|
|
||||||
|
Note that both offline and ready status mean that the sdev is
|
||||||
|
ready to process new scmds, where processing also implies
|
||||||
|
immediate failing; thus, if a sdev is in one of the two
|
||||||
|
states, no further recovery action is needed.
|
||||||
|
|
||||||
|
Device readiness is tested using scsi_eh_tur() which issues
|
||||||
|
TEST_UNIT_READY command. Note that the scmd must have been
|
||||||
|
aborted successfully before reusing it for TEST_UNIT_READY.
|
||||||
|
|
||||||
|
4. If !list_empty(&eh_work_q), invoke scsi_eh_ready_devs()
|
||||||
|
|
||||||
|
<<scsi_eh_ready_devs>>
|
||||||
|
|
||||||
|
This function takes four increasingly more severe measures to
|
||||||
|
make failed sdevs ready for new commands.
|
||||||
|
|
||||||
|
1. Invoke scsi_eh_stu()
|
||||||
|
|
||||||
|
<<scsi_eh_stu>>
|
||||||
|
|
||||||
|
For each sdev which has failed scmds with valid sense data
|
||||||
|
of which scsi_check_sense()'s verdict is FAILED,
|
||||||
|
START_STOP_UNIT command is issued w/ start=1. Note that
|
||||||
|
as we explicitly choose error-completed scmds, it is known
|
||||||
|
that lower layers have forgotten about the scmd and we can
|
||||||
|
reuse it for STU.
|
||||||
|
|
||||||
|
If STU succeeds and the sdev is either offline or ready,
|
||||||
|
all failed scmds on the sdev are EH-finished with
|
||||||
|
scsi_eh_finish_cmd().
|
||||||
|
|
||||||
|
*NOTE* If hostt->eh_abort_handler() isn't implemented or
|
||||||
|
failed, we may still have timed out scmds at this point
|
||||||
|
and STU doesn't make lower layers forget about those
|
||||||
|
scmds. Yet, this function EH-finish all scmds on the sdev
|
||||||
|
if STU succeeds leaving lower layers in an inconsistent
|
||||||
|
state. It seems that STU action should be taken only when
|
||||||
|
a sdev has no timed out scmd.
|
||||||
|
|
||||||
|
2. If !list_empty(&eh_work_q), invoke scsi_eh_bus_device_reset().
|
||||||
|
|
||||||
|
<<scsi_eh_bus_device_reset>>
|
||||||
|
|
||||||
|
This action is very similar to scsi_eh_stu() except that,
|
||||||
|
instead of issuing STU, hostt->eh_device_reset_handler()
|
||||||
|
is used. Also, as we're not issuing SCSI commands and
|
||||||
|
resetting clears all scmds on the sdev, there is no need
|
||||||
|
to choose error-completed scmds.
|
||||||
|
|
||||||
|
3. If !list_empty(&eh_work_q), invoke scsi_eh_bus_reset()
|
||||||
|
|
||||||
|
<<scsi_eh_bus_reset>>
|
||||||
|
|
||||||
|
hostt->eh_bus_reset_handler() is invoked for each channel
|
||||||
|
with failed scmds. If bus reset succeeds, all failed
|
||||||
|
scmds on all ready or offline sdevs on the channel are
|
||||||
|
EH-finished.
|
||||||
|
|
||||||
|
4. If !list_empty(&eh_work_q), invoke scsi_eh_host_reset()
|
||||||
|
|
||||||
|
<<scsi_eh_host_reset>>
|
||||||
|
|
||||||
|
This is the last resort. hostt->eh_host_reset_handler()
|
||||||
|
is invoked. If host reset succeeds, all failed scmds on
|
||||||
|
all ready or offline sdevs on the host are EH-finished.
|
||||||
|
|
||||||
|
5. If !list_empty(&eh_work_q), invoke scsi_eh_offline_sdevs()
|
||||||
|
|
||||||
|
<<scsi_eh_offline_sdevs>>
|
||||||
|
|
||||||
|
Take all sdevs which still have unrecovered scmds offline
|
||||||
|
and EH-finish the scmds.
|
||||||
|
|
||||||
|
5. Invoke scsi_eh_flush_done_q().
|
||||||
|
|
||||||
|
<<scsi_eh_flush_done_q>>
|
||||||
|
|
||||||
|
At this point all scmds are recovered (or given up) and
|
||||||
|
put on eh_done_q by scsi_eh_finish_cmd(). This function
|
||||||
|
flushes eh_done_q by either retrying or notifying upper
|
||||||
|
layer of failure of the scmds.
|
||||||
|
|
||||||
|
|
||||||
|
[2-2] EH through hostt->eh_strategy_handler()
|
||||||
|
|
||||||
|
hostt->eh_strategy_handler() is invoked in the place of
|
||||||
|
scsi_unjam_host() and it is responsible for whole recovery process.
|
||||||
|
On completion, the handler should have made lower layers forget about
|
||||||
|
all failed scmds and either ready for new commands or offline. Also,
|
||||||
|
it should perform SCSI EH maintenance choirs to maintain integrity of
|
||||||
|
SCSI midlayer. IOW, of the steps described in [2-1-2], all steps
|
||||||
|
except for #1 must be implemented by eh_strategy_handler().
|
||||||
|
|
||||||
|
|
||||||
|
[2-2-1] Pre hostt->eh_strategy_handler() SCSI midlayer conditions
|
||||||
|
|
||||||
|
The following conditions are true on entry to the handler.
|
||||||
|
|
||||||
|
- Each failed scmd's eh_flags field is set appropriately.
|
||||||
|
|
||||||
|
- Each failed scmd is linked on scmd->eh_cmd_q by scmd->eh_entry.
|
||||||
|
|
||||||
|
- SHOST_RECOVERY is set.
|
||||||
|
|
||||||
|
- shost->host_failed == shost->host_busy
|
||||||
|
|
||||||
|
|
||||||
|
[2-2-2] Post hostt->eh_strategy_handler() SCSI midlayer conditions
|
||||||
|
|
||||||
|
The following conditions must be true on exit from the handler.
|
||||||
|
|
||||||
|
- shost->host_failed is zero.
|
||||||
|
|
||||||
|
- Each scmd's eh_eflags field is cleared.
|
||||||
|
|
||||||
|
- Each scmd is in such a state that scsi_setup_cmd_retry() on the
|
||||||
|
scmd doesn't make any difference.
|
||||||
|
|
||||||
|
- shost->eh_cmd_q is cleared.
|
||||||
|
|
||||||
|
- Each scmd->eh_entry is cleared.
|
||||||
|
|
||||||
|
- Either scsi_queue_insert() or scsi_finish_command() is called on
|
||||||
|
each scmd. Note that the handler is free to use scmd->retries and
|
||||||
|
->allowed to limit the number of retries.
|
||||||
|
|
||||||
|
|
||||||
|
[2-2-3] Things to consider
|
||||||
|
|
||||||
|
- Know that timed out scmds are still active on lower layers. Make
|
||||||
|
lower layers forget about them before doing anything else with
|
||||||
|
those scmds.
|
||||||
|
|
||||||
|
- For consistency, when accessing/modifying shost data structure,
|
||||||
|
grab shost->host_lock.
|
||||||
|
|
||||||
|
- On completion, each failed sdev must have forgotten about all
|
||||||
|
active scmds.
|
||||||
|
|
||||||
|
- On completion, each failed sdev must be ready for new commands or
|
||||||
|
offline.
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
Tejun Heo
|
||||||
|
htejun@gmail.com
|
||||||
|
11th September 2005
|
@ -1459,7 +1459,7 @@ devices where %i is sound card number from zero to seven.
|
|||||||
To auto-load an ALSA driver for OSS services, define the string
|
To auto-load an ALSA driver for OSS services, define the string
|
||||||
'sound-slot-%i' where %i means the slot number for OSS, which
|
'sound-slot-%i' where %i means the slot number for OSS, which
|
||||||
corresponds to the card index of ALSA. Usually, define this
|
corresponds to the card index of ALSA. Usually, define this
|
||||||
as the the same card module.
|
as the same card module.
|
||||||
|
|
||||||
An example configuration for a single emu10k1 card is like below:
|
An example configuration for a single emu10k1 card is like below:
|
||||||
----- /etc/modprobe.conf
|
----- /etc/modprobe.conf
|
||||||
|
@ -57,7 +57,7 @@ With BK, you can just get it from
|
|||||||
|
|
||||||
and DaveJ has tar-balls at
|
and DaveJ has tar-balls at
|
||||||
|
|
||||||
http://www.codemonkey.org.uk/projects/bitkeeper/sparse/
|
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
|
||||||
|
|
||||||
|
|
||||||
Once you have it, just do
|
Once you have it, just do
|
||||||
|
@ -171,7 +171,7 @@ the header 'include/linux/sysrq.h', this will define everything else you need.
|
|||||||
Next, you must create a sysrq_key_op struct, and populate it with A) the key
|
Next, you must create a sysrq_key_op struct, and populate it with A) the key
|
||||||
handler function you will use, B) a help_msg string, that will print when SysRQ
|
handler function you will use, B) a help_msg string, that will print when SysRQ
|
||||||
prints help, and C) an action_msg string, that will print right before your
|
prints help, and C) an action_msg string, that will print right before your
|
||||||
handler is called. Your handler must conform to the protoype in 'sysrq.h'.
|
handler is called. Your handler must conform to the prototype in 'sysrq.h'.
|
||||||
|
|
||||||
After the sysrq_key_op is created, you can call the macro
|
After the sysrq_key_op is created, you can call the macro
|
||||||
register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in
|
register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in
|
||||||
|
@ -2176,7 +2176,7 @@
|
|||||||
If you want to access files on the host machine from inside UML, you
|
If you want to access files on the host machine from inside UML, you
|
||||||
can treat it as a separate machine and either nfs mount directories
|
can treat it as a separate machine and either nfs mount directories
|
||||||
from the host or copy files into the virtual machine with scp or rcp.
|
from the host or copy files into the virtual machine with scp or rcp.
|
||||||
However, since UML is running on the the host, it can access those
|
However, since UML is running on the host, it can access those
|
||||||
files just like any other process and make them available inside the
|
files just like any other process and make them available inside the
|
||||||
virtual machine without needing to use the network.
|
virtual machine without needing to use the network.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ License along with this program; if not, write to the Free
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
MA 02111-1307 USA.
|
MA 02111-1307 USA.
|
||||||
|
|
||||||
This document and the the gadget serial driver itself are
|
This document and the gadget serial driver itself are
|
||||||
Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
|
Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
|
||||||
|
|
||||||
If you have questions, problems, or suggestions for this driver
|
If you have questions, problems, or suggestions for this driver
|
||||||
|
@ -20,7 +20,7 @@ the /proc/bus/usb/BBB/DDD files.
|
|||||||
|
|
||||||
to /etc/fstab. This will mount usbfs at each reboot.
|
to /etc/fstab. This will mount usbfs at each reboot.
|
||||||
You can then issue `cat /proc/bus/usb/devices` to extract
|
You can then issue `cat /proc/bus/usb/devices` to extract
|
||||||
USB device information, and user mode drivers can use usbfs
|
USB device information, and user mode drivers can use usbfs
|
||||||
to interact with USB devices.
|
to interact with USB devices.
|
||||||
|
|
||||||
There are a number of mount options supported by usbfs.
|
There are a number of mount options supported by usbfs.
|
||||||
@ -32,7 +32,7 @@ the /proc/bus/usb/BBB/DDD files.
|
|||||||
still see references to the older "usbdevfs" name.
|
still see references to the older "usbdevfs" name.
|
||||||
|
|
||||||
For more information on mounting the usbfs file system, see the
|
For more information on mounting the usbfs file system, see the
|
||||||
"USB Device Filesystem" section of the USB Guide. The latest copy
|
"USB Device Filesystem" section of the USB Guide. The latest copy
|
||||||
of the USB Guide can be found at http://www.linux-usb.org/
|
of the USB Guide can be found at http://www.linux-usb.org/
|
||||||
|
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
|
|||||||
are the only transfers that reserve bandwidth. Control and bulk
|
are the only transfers that reserve bandwidth. Control and bulk
|
||||||
transfers use all other bandwidth, including reserved bandwidth that
|
transfers use all other bandwidth, including reserved bandwidth that
|
||||||
is not used for transfers (such as for short packets).
|
is not used for transfers (such as for short packets).
|
||||||
|
|
||||||
The percentage is how much of the "reserved" bandwidth is scheduled by
|
The percentage is how much of the "reserved" bandwidth is scheduled by
|
||||||
those transfers. For a low or full speed bus (loosely, "USB 1.1"),
|
those transfers. For a low or full speed bus (loosely, "USB 1.1"),
|
||||||
90% of the bus bandwidth is reserved. For a high speed bus (loosely,
|
90% of the bus bandwidth is reserved. For a high speed bus (loosely,
|
||||||
@ -197,7 +197,7 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
|
|||||||
| | |__NumberOfInterfaces
|
| | |__NumberOfInterfaces
|
||||||
| |__ "*" indicates the active configuration (others are " ")
|
| |__ "*" indicates the active configuration (others are " ")
|
||||||
|__Config info tag
|
|__Config info tag
|
||||||
|
|
||||||
USB devices may have multiple configurations, each of which act
|
USB devices may have multiple configurations, each of which act
|
||||||
rather differently. For example, a bus-powered configuration
|
rather differently. For example, a bus-powered configuration
|
||||||
might be much less capable than one that is self-powered. Only
|
might be much less capable than one that is self-powered. Only
|
||||||
@ -228,7 +228,7 @@ I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
|
|||||||
For example, default settings may not use more than a small
|
For example, default settings may not use more than a small
|
||||||
amount of periodic bandwidth. To use significant fractions
|
amount of periodic bandwidth. To use significant fractions
|
||||||
of bus bandwidth, drivers must select a non-default altsetting.
|
of bus bandwidth, drivers must select a non-default altsetting.
|
||||||
|
|
||||||
Only one setting for an interface may be active at a time, and
|
Only one setting for an interface may be active at a time, and
|
||||||
only one driver may bind to an interface at a time. Most devices
|
only one driver may bind to an interface at a time. Most devices
|
||||||
have only one alternate setting per interface.
|
have only one alternate setting per interface.
|
||||||
@ -297,18 +297,21 @@ S: SerialNumber=dce0
|
|||||||
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
|
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
|
||||||
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
|
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
|
||||||
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
|
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
|
||||||
|
|
||||||
T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
|
T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
|
||||||
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
||||||
P: Vendor=0451 ProdID=1446 Rev= 1.00
|
P: Vendor=0451 ProdID=1446 Rev= 1.00
|
||||||
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
|
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
|
||||||
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
|
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
|
||||||
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
|
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
|
||||||
|
|
||||||
T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
|
T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
|
||||||
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
||||||
P: Vendor=04b4 ProdID=0001 Rev= 0.00
|
P: Vendor=04b4 ProdID=0001 Rev= 0.00
|
||||||
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
|
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
|
||||||
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
|
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
|
||||||
E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
|
E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
|
||||||
|
|
||||||
T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
|
T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
|
||||||
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
||||||
P: Vendor=0565 ProdID=0001 Rev= 1.08
|
P: Vendor=0565 ProdID=0001 Rev= 1.08
|
||||||
|
@ -126,10 +126,12 @@ card=124 - AverMedia AverTV DVB-T 761
|
|||||||
card=125 - MATRIX Vision Sigma-SQ
|
card=125 - MATRIX Vision Sigma-SQ
|
||||||
card=126 - MATRIX Vision Sigma-SLC
|
card=126 - MATRIX Vision Sigma-SLC
|
||||||
card=127 - APAC Viewcomp 878(AMAX)
|
card=127 - APAC Viewcomp 878(AMAX)
|
||||||
card=128 - DVICO FusionHDTV DVB-T Lite
|
card=128 - DViCO FusionHDTV DVB-T Lite
|
||||||
card=129 - V-Gear MyVCD
|
card=129 - V-Gear MyVCD
|
||||||
card=130 - Super TV Tuner
|
card=130 - Super TV Tuner
|
||||||
card=131 - Tibet Systems 'Progress DVR' CS16
|
card=131 - Tibet Systems 'Progress DVR' CS16
|
||||||
card=132 - Kodicom 4400R (master)
|
card=132 - Kodicom 4400R (master)
|
||||||
card=133 - Kodicom 4400R (slave)
|
card=133 - Kodicom 4400R (slave)
|
||||||
card=134 - Adlink RTV24
|
card=134 - Adlink RTV24
|
||||||
|
card=135 - DViCO FusionHDTV 5 Lite
|
||||||
|
card=136 - Acorp Y878F
|
||||||
|
@ -62,3 +62,6 @@
|
|||||||
61 -> Philips TOUGH DVB-T reference design [1131:2004]
|
61 -> Philips TOUGH DVB-T reference design [1131:2004]
|
||||||
62 -> Compro VideoMate TV Gold+II
|
62 -> Compro VideoMate TV Gold+II
|
||||||
63 -> Kworld Xpert TV PVR7134
|
63 -> Kworld Xpert TV PVR7134
|
||||||
|
64 -> FlyTV mini Asus Digimatrix [1043:0210,1043:0210]
|
||||||
|
65 -> V-Stream Studio TV Terminator
|
||||||
|
66 -> Yuan TUN-900 (saa7135)
|
||||||
|
@ -64,3 +64,4 @@ tuner=62 - Philips TEA5767HN FM Radio
|
|||||||
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
|
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
|
||||||
tuner=64 - LG TDVS-H062F/TUA6034
|
tuner=64 - LG TDVS-H062F/TUA6034
|
||||||
tuner=65 - Ymec TVF66T5-B/DFF
|
tuner=65 - Ymec TVF66T5-B/DFF
|
||||||
|
tuner=66 - LG NTSC (TALN mini series)
|
||||||
|
@ -222,7 +222,7 @@ was introduced in 1991, is used in the DC10 old
|
|||||||
can generate: PAL , NTSC , SECAM
|
can generate: PAL , NTSC , SECAM
|
||||||
|
|
||||||
The adv717x, should be able to produce PAL N. But you find nothing PAL N
|
The adv717x, should be able to produce PAL N. But you find nothing PAL N
|
||||||
specific in the the registers. Seem that you have to reuse a other standard
|
specific in the registers. Seem that you have to reuse a other standard
|
||||||
to generate PAL N, maybe it would work if you use the PAL M settings.
|
to generate PAL N, maybe it would work if you use the PAL M settings.
|
||||||
|
|
||||||
==========================
|
==========================
|
||||||
|
@ -11,6 +11,11 @@ Machine check
|
|||||||
If your BIOS doesn't do that it's a good idea to enable though
|
If your BIOS doesn't do that it's a good idea to enable though
|
||||||
to make sure you log even machine check events that result
|
to make sure you log even machine check events that result
|
||||||
in a reboot.
|
in a reboot.
|
||||||
|
mce=tolerancelevel (number)
|
||||||
|
0: always panic, 1: panic if deadlock possible,
|
||||||
|
2: try to avoid panic, 3: never panic or exit (for testing)
|
||||||
|
default is 1
|
||||||
|
Can be also set using sysfs which is preferable.
|
||||||
|
|
||||||
nomce (for compatibility with i386): same as mce=off
|
nomce (for compatibility with i386): same as mce=off
|
||||||
|
|
||||||
|
49
Kbuild
Normal file
49
Kbuild
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#
|
||||||
|
# Kbuild for top-level directory of the kernel
|
||||||
|
# This file takes care of the following:
|
||||||
|
# 1) Generate asm-offsets.h
|
||||||
|
|
||||||
|
#####
|
||||||
|
# 1) Generate asm-offsets.h
|
||||||
|
#
|
||||||
|
|
||||||
|
offsets-file := include/asm-$(ARCH)/asm-offsets.h
|
||||||
|
|
||||||
|
always := $(offsets-file)
|
||||||
|
targets := $(offsets-file)
|
||||||
|
targets += arch/$(ARCH)/kernel/asm-offsets.s
|
||||||
|
|
||||||
|
# Default sed regexp - multiline due to syntax constraints
|
||||||
|
define sed-y
|
||||||
|
"/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
|
||||||
|
endef
|
||||||
|
# Override default regexp for specific architectures
|
||||||
|
sed-$(CONFIG_MIPS) := "/^@@@/s///p"
|
||||||
|
|
||||||
|
quiet_cmd_offsets = GEN $@
|
||||||
|
define cmd_offsets
|
||||||
|
mkdir -p $(dir $@); \
|
||||||
|
cat $< | \
|
||||||
|
(set -e; \
|
||||||
|
echo "#ifndef __ASM_OFFSETS_H__"; \
|
||||||
|
echo "#define __ASM_OFFSETS_H__"; \
|
||||||
|
echo "/*"; \
|
||||||
|
echo " * DO NOT MODIFY."; \
|
||||||
|
echo " *"; \
|
||||||
|
echo " * This file was generated by $(srctree)/Kbuild"; \
|
||||||
|
echo " *"; \
|
||||||
|
echo " */"; \
|
||||||
|
echo ""; \
|
||||||
|
sed -ne $(sed-y); \
|
||||||
|
echo ""; \
|
||||||
|
echo "#endif" ) > $@
|
||||||
|
endef
|
||||||
|
|
||||||
|
# We use internal kbuild rules to avoid the "is up to date" message from make
|
||||||
|
arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE
|
||||||
|
$(Q)mkdir -p $(dir $@)
|
||||||
|
$(call if_changed_dep,cc_s_c)
|
||||||
|
|
||||||
|
$(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild
|
||||||
|
$(call cmd,offsets)
|
||||||
|
|
44
MAINTAINERS
44
MAINTAINERS
@ -116,6 +116,12 @@ M: ajk@iehk.rwth-aachen.de
|
|||||||
L: linux-hams@vger.kernel.org
|
L: linux-hams@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
YEALINK PHONE DRIVER
|
||||||
|
P: Henk Vergonet
|
||||||
|
M: Henk.Vergonet@gmail.com
|
||||||
|
L: usbb2k-api-dev@nongnu.org
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
8139CP 10/100 FAST ETHERNET DRIVER
|
8139CP 10/100 FAST ETHERNET DRIVER
|
||||||
P: Jeff Garzik
|
P: Jeff Garzik
|
||||||
M: jgarzik@pobox.com
|
M: jgarzik@pobox.com
|
||||||
@ -620,6 +626,12 @@ M: rmk@arm.linux.org.uk
|
|||||||
W: http://www.arm.linux.org.uk/
|
W: http://www.arm.linux.org.uk/
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
CYBLAFB FRAMEBUFFER DRIVER
|
||||||
|
P: Knut Petersen
|
||||||
|
M: Knut_Petersen@t-online.de
|
||||||
|
L: linux-fbdev-devel@lists.sourceforge.net
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
CYCLADES 2X SYNC CARD DRIVER
|
CYCLADES 2X SYNC CARD DRIVER
|
||||||
P: Arnaldo Carvalho de Melo
|
P: Arnaldo Carvalho de Melo
|
||||||
M: acme@conectiva.com.br
|
M: acme@conectiva.com.br
|
||||||
@ -919,6 +931,13 @@ L: linux-tape@vger.kernel.org
|
|||||||
W: http://sourceforge.net/projects/ftape
|
W: http://sourceforge.net/projects/ftape
|
||||||
S: Orphan
|
S: Orphan
|
||||||
|
|
||||||
|
FUSE: FILESYSTEM IN USERSPACE
|
||||||
|
P: Miklos Szeredi
|
||||||
|
M: miklos@szeredi.hu
|
||||||
|
L: fuse-devel@lists.sourceforge.net
|
||||||
|
W: http://fuse.sourceforge.net/
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
|
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
|
||||||
P: Rik Faith
|
P: Rik Faith
|
||||||
M: faith@cs.unc.edu
|
M: faith@cs.unc.edu
|
||||||
@ -945,6 +964,13 @@ L: lm-sensors@lm-sensors.org
|
|||||||
W: http://www.lm-sensors.nu/
|
W: http://www.lm-sensors.nu/
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
|
||||||
|
P: Robert Love
|
||||||
|
M: rlove@rlove.org
|
||||||
|
M: linux-kernel@vger.kernel.org
|
||||||
|
W: http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
HARMONY SOUND DRIVER
|
HARMONY SOUND DRIVER
|
||||||
P: Kyle McMartin
|
P: Kyle McMartin
|
||||||
M: kyle@parisc-linux.org
|
M: kyle@parisc-linux.org
|
||||||
@ -1813,13 +1839,6 @@ M: hch@infradead.org
|
|||||||
L: linux-abi-devel@lists.sourceforge.net
|
L: linux-abi-devel@lists.sourceforge.net
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
PCI ID DATABASE
|
|
||||||
P: Martin Mares
|
|
||||||
M: mj@ucw.cz
|
|
||||||
L: pciids-devel@lists.sourceforge.net
|
|
||||||
W: http://pciids.sourceforge.net/
|
|
||||||
S: Maintained
|
|
||||||
|
|
||||||
PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES)
|
PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES)
|
||||||
P: Thomas Sailer
|
P: Thomas Sailer
|
||||||
M: sailer@ife.ee.ethz.ch
|
M: sailer@ife.ee.ethz.ch
|
||||||
@ -2685,6 +2704,17 @@ L: rio500-users@lists.sourceforge.net
|
|||||||
W: http://rio500.sourceforge.net
|
W: http://rio500.sourceforge.net
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
V9FS FILE SYSTEM
|
||||||
|
P: Eric Van Hensbergen
|
||||||
|
M: ericvh@gmail.com
|
||||||
|
P: Ron Minnich
|
||||||
|
M: rminnich@lanl.gov
|
||||||
|
P: Latchesar Ionkov
|
||||||
|
M: lucho@ionkov.net
|
||||||
|
L: v9fs-developer@lists.sourceforge.net
|
||||||
|
W: http://v9fs.sf.net
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
VIDEO FOR LINUX
|
VIDEO FOR LINUX
|
||||||
P: Mauro Carvalho Chehab
|
P: Mauro Carvalho Chehab
|
||||||
M: mchehab@brturbo.com.br
|
M: mchehab@brturbo.com.br
|
||||||
|
84
Makefile
84
Makefile
@ -1,7 +1,7 @@
|
|||||||
VERSION = 2
|
VERSION = 2
|
||||||
PATCHLEVEL = 6
|
PATCHLEVEL = 6
|
||||||
SUBLEVEL = 13
|
SUBLEVEL = 14
|
||||||
EXTRAVERSION =
|
EXTRAVERSION =-rc1
|
||||||
NAME=Affluent Albatross
|
NAME=Affluent Albatross
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
@ -334,7 +334,7 @@ KALLSYMS = scripts/kallsyms
|
|||||||
PERL = perl
|
PERL = perl
|
||||||
CHECK = sparse
|
CHECK = sparse
|
||||||
|
|
||||||
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__
|
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ $(CF)
|
||||||
MODFLAGS = -DMODULE
|
MODFLAGS = -DMODULE
|
||||||
CFLAGS_MODULE = $(MODFLAGS)
|
CFLAGS_MODULE = $(MODFLAGS)
|
||||||
AFLAGS_MODULE = $(MODFLAGS)
|
AFLAGS_MODULE = $(MODFLAGS)
|
||||||
@ -382,6 +382,9 @@ RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CV
|
|||||||
scripts_basic:
|
scripts_basic:
|
||||||
$(Q)$(MAKE) $(build)=scripts/basic
|
$(Q)$(MAKE) $(build)=scripts/basic
|
||||||
|
|
||||||
|
# To avoid any implicit rule to kick in, define an empty command.
|
||||||
|
scripts/basic/%: scripts_basic ;
|
||||||
|
|
||||||
.PHONY: outputmakefile
|
.PHONY: outputmakefile
|
||||||
# outputmakefile generate a Makefile to be placed in output directory, if
|
# outputmakefile generate a Makefile to be placed in output directory, if
|
||||||
# using a seperate output directory. This allows convinient use
|
# using a seperate output directory. This allows convinient use
|
||||||
@ -444,9 +447,8 @@ ifeq ($(config-targets),1)
|
|||||||
include $(srctree)/arch/$(ARCH)/Makefile
|
include $(srctree)/arch/$(ARCH)/Makefile
|
||||||
export KBUILD_DEFCONFIG
|
export KBUILD_DEFCONFIG
|
||||||
|
|
||||||
config: scripts_basic outputmakefile FORCE
|
config %config: scripts_basic outputmakefile FORCE
|
||||||
$(Q)$(MAKE) $(build)=scripts/kconfig $@
|
$(Q)mkdir -p include/linux
|
||||||
%config: scripts_basic outputmakefile FORCE
|
|
||||||
$(Q)$(MAKE) $(build)=scripts/kconfig $@
|
$(Q)$(MAKE) $(build)=scripts/kconfig $@
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -489,6 +491,7 @@ include .config
|
|||||||
# If .config is newer than include/linux/autoconf.h, someone tinkered
|
# If .config is newer than include/linux/autoconf.h, someone tinkered
|
||||||
# with it and forgot to run make oldconfig
|
# with it and forgot to run make oldconfig
|
||||||
include/linux/autoconf.h: .config
|
include/linux/autoconf.h: .config
|
||||||
|
$(Q)mkdir -p include/linux
|
||||||
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
|
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
|
||||||
else
|
else
|
||||||
# Dummy target needed, because used as prerequisite
|
# Dummy target needed, because used as prerequisite
|
||||||
@ -641,8 +644,13 @@ quiet_cmd_vmlinux__ ?= LD $@
|
|||||||
# Generate new vmlinux version
|
# Generate new vmlinux version
|
||||||
quiet_cmd_vmlinux_version = GEN .version
|
quiet_cmd_vmlinux_version = GEN .version
|
||||||
cmd_vmlinux_version = set -e; \
|
cmd_vmlinux_version = set -e; \
|
||||||
. $(srctree)/scripts/mkversion > .tmp_version; \
|
if [ ! -r .version ]; then \
|
||||||
mv -f .tmp_version .version; \
|
rm -f .version; \
|
||||||
|
echo 1 >.version; \
|
||||||
|
else \
|
||||||
|
mv .version .old_version; \
|
||||||
|
expr 0$$(cat .old_version) + 1 >.version; \
|
||||||
|
fi; \
|
||||||
$(MAKE) $(build)=init
|
$(MAKE) $(build)=init
|
||||||
|
|
||||||
# Generate System.map
|
# Generate System.map
|
||||||
@ -756,6 +764,7 @@ endif # ifdef CONFIG_KALLSYMS
|
|||||||
# vmlinux image - including updated kernel symbols
|
# vmlinux image - including updated kernel symbols
|
||||||
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
|
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
|
||||||
$(call if_changed_rule,vmlinux__)
|
$(call if_changed_rule,vmlinux__)
|
||||||
|
$(Q)rm -f .old_version
|
||||||
|
|
||||||
# The actual objects are generated when descending,
|
# The actual objects are generated when descending,
|
||||||
# make sure no implicit rule kicks in
|
# make sure no implicit rule kicks in
|
||||||
@ -768,22 +777,27 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
|
|||||||
# Error messages still appears in the original language
|
# Error messages still appears in the original language
|
||||||
|
|
||||||
.PHONY: $(vmlinux-dirs)
|
.PHONY: $(vmlinux-dirs)
|
||||||
$(vmlinux-dirs): prepare-all scripts
|
$(vmlinux-dirs): prepare scripts
|
||||||
$(Q)$(MAKE) $(build)=$@
|
$(Q)$(MAKE) $(build)=$@
|
||||||
|
|
||||||
# Things we need to do before we recursively start building the kernel
|
# Things we need to do before we recursively start building the kernel
|
||||||
# or the modules are listed in "prepare-all".
|
# or the modules are listed in "prepare".
|
||||||
# A multi level approach is used. prepare1 is updated first, then prepare0.
|
# A multi level approach is used. prepareN is processed before prepareN-1.
|
||||||
# prepare-all is the collection point for the prepare targets.
|
# archprepare is used in arch Makefiles and when processed asm symlink,
|
||||||
|
# version.h and scripts_basic is processed / created.
|
||||||
|
|
||||||
.PHONY: prepare-all prepare prepare0 prepare1 prepare2
|
# Listed in dependency order
|
||||||
|
.PHONY: prepare archprepare prepare0 prepare1 prepare2 prepare3
|
||||||
|
|
||||||
# prepare2 is used to check if we are building in a separate output directory,
|
# prepare-all is deprecated, use prepare as valid replacement
|
||||||
|
.PHONY: prepare-all
|
||||||
|
|
||||||
|
# prepare3 is used to check if we are building in a separate output directory,
|
||||||
# and if so do:
|
# and if so do:
|
||||||
# 1) Check that make has not been executed in the kernel src $(srctree)
|
# 1) Check that make has not been executed in the kernel src $(srctree)
|
||||||
# 2) Create the include2 directory, used for the second asm symlink
|
# 2) Create the include2 directory, used for the second asm symlink
|
||||||
|
|
||||||
prepare2:
|
prepare3:
|
||||||
ifneq ($(KBUILD_SRC),)
|
ifneq ($(KBUILD_SRC),)
|
||||||
@echo ' Using $(srctree) as source for kernel'
|
@echo ' Using $(srctree) as source for kernel'
|
||||||
$(Q)if [ -f $(srctree)/.config ]; then \
|
$(Q)if [ -f $(srctree)/.config ]; then \
|
||||||
@ -795,18 +809,23 @@ ifneq ($(KBUILD_SRC),)
|
|||||||
$(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm
|
$(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# prepare1 creates a makefile if using a separate output directory
|
# prepare2 creates a makefile if using a separate output directory
|
||||||
prepare1: prepare2 outputmakefile
|
prepare2: prepare3 outputmakefile
|
||||||
|
|
||||||
prepare0: prepare1 include/linux/version.h include/asm \
|
prepare1: prepare2 include/linux/version.h include/asm \
|
||||||
include/config/MARKER
|
include/config/MARKER
|
||||||
ifneq ($(KBUILD_MODULES),)
|
ifneq ($(KBUILD_MODULES),)
|
||||||
$(Q)rm -rf $(MODVERDIR)
|
$(Q)rm -rf $(MODVERDIR)
|
||||||
$(Q)mkdir -p $(MODVERDIR)
|
$(Q)mkdir -p $(MODVERDIR)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
archprepare: prepare1 scripts_basic
|
||||||
|
|
||||||
|
prepare0: archprepare FORCE
|
||||||
|
$(Q)$(MAKE) $(build)=.
|
||||||
|
|
||||||
# All the preparing..
|
# All the preparing..
|
||||||
prepare-all: prepare0 prepare
|
prepare prepare-all: prepare0
|
||||||
|
|
||||||
# Leave this as default for preprocessing vmlinux.lds.S, which is now
|
# Leave this as default for preprocessing vmlinux.lds.S, which is now
|
||||||
# done in arch/$(ARCH)/kernel/Makefile
|
# done in arch/$(ARCH)/kernel/Makefile
|
||||||
@ -845,7 +864,7 @@ include/asm:
|
|||||||
|
|
||||||
# Split autoconf.h into include/linux/config/*
|
# Split autoconf.h into include/linux/config/*
|
||||||
|
|
||||||
include/config/MARKER: include/linux/autoconf.h
|
include/config/MARKER: scripts/basic/split-include include/linux/autoconf.h
|
||||||
@echo ' SPLIT include/linux/autoconf.h -> include/config/*'
|
@echo ' SPLIT include/linux/autoconf.h -> include/config/*'
|
||||||
@scripts/basic/split-include include/linux/autoconf.h include/config
|
@scripts/basic/split-include include/linux/autoconf.h include/config
|
||||||
@touch $@
|
@touch $@
|
||||||
@ -897,7 +916,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
|
|||||||
|
|
||||||
# Target to prepare building external modules
|
# Target to prepare building external modules
|
||||||
.PHONY: modules_prepare
|
.PHONY: modules_prepare
|
||||||
modules_prepare: prepare-all scripts
|
modules_prepare: prepare scripts
|
||||||
|
|
||||||
# Target to install modules
|
# Target to install modules
|
||||||
.PHONY: modules_install
|
.PHONY: modules_install
|
||||||
@ -949,26 +968,6 @@ modules modules_install: FORCE
|
|||||||
|
|
||||||
endif # CONFIG_MODULES
|
endif # CONFIG_MODULES
|
||||||
|
|
||||||
# Generate asm-offsets.h
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
define filechk_gen-asm-offsets
|
|
||||||
(set -e; \
|
|
||||||
echo "#ifndef __ASM_OFFSETS_H__"; \
|
|
||||||
echo "#define __ASM_OFFSETS_H__"; \
|
|
||||||
echo "/*"; \
|
|
||||||
echo " * DO NOT MODIFY."; \
|
|
||||||
echo " *"; \
|
|
||||||
echo " * This file was generated by arch/$(ARCH)/Makefile"; \
|
|
||||||
echo " *"; \
|
|
||||||
echo " */"; \
|
|
||||||
echo ""; \
|
|
||||||
sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \
|
|
||||||
echo ""; \
|
|
||||||
echo "#endif" )
|
|
||||||
endef
|
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Cleaning is done on three levels.
|
# Cleaning is done on three levels.
|
||||||
# make clean Delete most generated files
|
# make clean Delete most generated files
|
||||||
@ -991,7 +990,7 @@ MRPROPER_FILES += .config .config.old include/asm .version \
|
|||||||
#
|
#
|
||||||
clean: rm-dirs := $(CLEAN_DIRS)
|
clean: rm-dirs := $(CLEAN_DIRS)
|
||||||
clean: rm-files := $(CLEAN_FILES)
|
clean: rm-files := $(CLEAN_FILES)
|
||||||
clean-dirs := $(addprefix _clean_,$(vmlinux-alldirs))
|
clean-dirs := $(addprefix _clean_,$(srctree) $(vmlinux-alldirs))
|
||||||
|
|
||||||
.PHONY: $(clean-dirs) clean archclean
|
.PHONY: $(clean-dirs) clean archclean
|
||||||
$(clean-dirs):
|
$(clean-dirs):
|
||||||
@ -1070,6 +1069,7 @@ help:
|
|||||||
@echo ' rpm - Build a kernel as an RPM package'
|
@echo ' rpm - Build a kernel as an RPM package'
|
||||||
@echo ' tags/TAGS - Generate tags file for editors'
|
@echo ' tags/TAGS - Generate tags file for editors'
|
||||||
@echo ' cscope - Generate cscope index'
|
@echo ' cscope - Generate cscope index'
|
||||||
|
@echo ' kernelrelease - Output the release version string'
|
||||||
@echo ''
|
@echo ''
|
||||||
@echo 'Static analysers'
|
@echo 'Static analysers'
|
||||||
@echo ' buildcheck - List dangling references to vmlinux discarded sections'
|
@echo ' buildcheck - List dangling references to vmlinux discarded sections'
|
||||||
|
@ -9,7 +9,7 @@ screen please read "Documentation/oops-tracing.txt" before posting your
|
|||||||
bug report. This explains what you should do with the "Oops" information
|
bug report. This explains what you should do with the "Oops" information
|
||||||
to make it useful to the recipient.
|
to make it useful to the recipient.
|
||||||
|
|
||||||
Send the output the maintainer of the kernel area that seems to
|
Send the output to the maintainer of the kernel area that seems to
|
||||||
be involved with the problem. Don't worry too much about getting the
|
be involved with the problem. Don't worry too much about getting the
|
||||||
wrong person. If you are unsure send it to the person responsible for the
|
wrong person. If you are unsure send it to the person responsible for the
|
||||||
code relevant to what you were doing. If it occurs repeatably try and
|
code relevant to what you were doing. If it occurs repeatably try and
|
||||||
@ -18,15 +18,15 @@ The list of maintainers is in the MAINTAINERS file in this directory.
|
|||||||
|
|
||||||
If it is a security bug, please copy the Security Contact listed
|
If it is a security bug, please copy the Security Contact listed
|
||||||
in the MAINTAINERS file. They can help coordinate bugfix and disclosure.
|
in the MAINTAINERS file. They can help coordinate bugfix and disclosure.
|
||||||
See Documentation/SecurityBugs for more infomation.
|
See Documentation/SecurityBugs for more information.
|
||||||
|
|
||||||
If you are totally stumped as to whom to send the report, send it to
|
If you are totally stumped as to whom to send the report, send it to
|
||||||
linux-kernel@vger.kernel.org. (For more information on the linux-kernel
|
linux-kernel@vger.kernel.org. (For more information on the linux-kernel
|
||||||
mailing list see http://www.tux.org/lkml/).
|
mailing list see http://www.tux.org/lkml/).
|
||||||
|
|
||||||
This is a suggested format for a bug report sent to the Linux kernel mailing
|
This is a suggested format for a bug report sent to the Linux kernel mailing
|
||||||
list. Having a standardized bug report form makes it easier for you not to
|
list. Having a standardized bug report form makes it easier for you not to
|
||||||
overlook things, and easier for the developers to find the pieces of
|
overlook things, and easier for the developers to find the pieces of
|
||||||
information they're really interested in. Don't feel you have to follow it.
|
information they're really interested in. Don't feel you have to follow it.
|
||||||
|
|
||||||
First run the ver_linux script included as scripts/ver_linux, which
|
First run the ver_linux script included as scripts/ver_linux, which
|
||||||
@ -35,9 +35,9 @@ the command "sh scripts/ver_linux".
|
|||||||
|
|
||||||
Use that information to fill in all fields of the bug report form, and
|
Use that information to fill in all fields of the bug report form, and
|
||||||
post it to the mailing list with a subject of "PROBLEM: <one line
|
post it to the mailing list with a subject of "PROBLEM: <one line
|
||||||
summary from [1.]>" for easy identification by the developers
|
summary from [1.]>" for easy identification by the developers.
|
||||||
|
|
||||||
[1.] One line summary of the problem:
|
[1.] One line summary of the problem:
|
||||||
[2.] Full description of the problem/report:
|
[2.] Full description of the problem/report:
|
||||||
[3.] Keywords (i.e., modules, networking, kernel):
|
[3.] Keywords (i.e., modules, networking, kernel):
|
||||||
[4.] Kernel version (from /proc/version):
|
[4.] Kernel version (from /proc/version):
|
||||||
|
@ -108,20 +108,9 @@ $(boot)/vmlinux.gz: vmlinux
|
|||||||
bootimage bootpfile bootpzfile: vmlinux
|
bootimage bootpfile bootpzfile: vmlinux
|
||||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||||
|
|
||||||
|
|
||||||
prepare: include/asm-$(ARCH)/asm_offsets.h
|
|
||||||
|
|
||||||
arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
|
|
||||||
include/config/MARKER
|
|
||||||
|
|
||||||
include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
|
|
||||||
$(call filechk,gen-asm-offsets)
|
|
||||||
|
|
||||||
archclean:
|
archclean:
|
||||||
$(Q)$(MAKE) $(clean)=$(boot)
|
$(Q)$(MAKE) $(clean)=$(boot)
|
||||||
|
|
||||||
CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h
|
|
||||||
|
|
||||||
define archhelp
|
define archhelp
|
||||||
echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)'
|
echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)'
|
||||||
echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)'
|
echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)'
|
||||||
|
@ -185,15 +185,6 @@ EXPORT_SYMBOL(smp_num_cpus);
|
|||||||
EXPORT_SYMBOL(smp_call_function);
|
EXPORT_SYMBOL(smp_call_function);
|
||||||
EXPORT_SYMBOL(smp_call_function_on_cpu);
|
EXPORT_SYMBOL(smp_call_function_on_cpu);
|
||||||
EXPORT_SYMBOL(_atomic_dec_and_lock);
|
EXPORT_SYMBOL(_atomic_dec_and_lock);
|
||||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
||||||
EXPORT_SYMBOL(_raw_spin_unlock);
|
|
||||||
EXPORT_SYMBOL(debug_spin_lock);
|
|
||||||
EXPORT_SYMBOL(debug_spin_trylock);
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_DEBUG_RWLOCK
|
|
||||||
EXPORT_SYMBOL(_raw_write_lock);
|
|
||||||
EXPORT_SYMBOL(_raw_read_lock);
|
|
||||||
#endif
|
|
||||||
EXPORT_SYMBOL(cpu_present_mask);
|
EXPORT_SYMBOL(cpu_present_mask);
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/pal.h>
|
#include <asm/pal.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.globl swapper_pg_dir
|
.globl swapper_pg_dir
|
||||||
.globl _stext
|
.globl _stext
|
||||||
|
@ -47,7 +47,7 @@ module_free(struct module *mod, void *module_region)
|
|||||||
|
|
||||||
struct got_entry {
|
struct got_entry {
|
||||||
struct got_entry *next;
|
struct got_entry *next;
|
||||||
Elf64_Addr r_offset;
|
Elf64_Sxword r_addend;
|
||||||
int got_offset;
|
int got_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,14 +57,14 @@ process_reloc_for_got(Elf64_Rela *rela,
|
|||||||
{
|
{
|
||||||
unsigned long r_sym = ELF64_R_SYM (rela->r_info);
|
unsigned long r_sym = ELF64_R_SYM (rela->r_info);
|
||||||
unsigned long r_type = ELF64_R_TYPE (rela->r_info);
|
unsigned long r_type = ELF64_R_TYPE (rela->r_info);
|
||||||
Elf64_Addr r_offset = rela->r_offset;
|
Elf64_Sxword r_addend = rela->r_addend;
|
||||||
struct got_entry *g;
|
struct got_entry *g;
|
||||||
|
|
||||||
if (r_type != R_ALPHA_LITERAL)
|
if (r_type != R_ALPHA_LITERAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (g = chains + r_sym; g ; g = g->next)
|
for (g = chains + r_sym; g ; g = g->next)
|
||||||
if (g->r_offset == r_offset) {
|
if (g->r_addend == r_addend) {
|
||||||
if (g->got_offset == 0) {
|
if (g->got_offset == 0) {
|
||||||
g->got_offset = *poffset;
|
g->got_offset = *poffset;
|
||||||
*poffset += 8;
|
*poffset += 8;
|
||||||
@ -74,7 +74,7 @@ process_reloc_for_got(Elf64_Rela *rela,
|
|||||||
|
|
||||||
g = kmalloc (sizeof (*g), GFP_KERNEL);
|
g = kmalloc (sizeof (*g), GFP_KERNEL);
|
||||||
g->next = chains[r_sym].next;
|
g->next = chains[r_sym].next;
|
||||||
g->r_offset = r_offset;
|
g->r_addend = r_addend;
|
||||||
g->got_offset = *poffset;
|
g->got_offset = *poffset;
|
||||||
*poffset += 8;
|
*poffset += 8;
|
||||||
chains[r_sym].next = g;
|
chains[r_sym].next = g;
|
||||||
|
@ -974,6 +974,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
|
|||||||
size_t size;
|
size_t size;
|
||||||
long timeout;
|
long timeout;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
struct fdtable *fdt;
|
||||||
|
|
||||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||||
if (tvp) {
|
if (tvp) {
|
||||||
@ -995,7 +996,8 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n < 0 || n > current->files->max_fdset)
|
fdt = files_fdtable(current->files);
|
||||||
|
if (n < 0 || n > fdt->max_fdset)
|
||||||
goto out_nofds;
|
goto out_nofds;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1152,8 +1154,7 @@ osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remai
|
|||||||
|
|
||||||
ticks = timeval_to_jiffies(&tmp);
|
ticks = timeval_to_jiffies(&tmp);
|
||||||
|
|
||||||
current->state = TASK_INTERRUPTIBLE;
|
ticks = schedule_timeout_interruptible(ticks);
|
||||||
ticks = schedule_timeout(ticks);
|
|
||||||
|
|
||||||
if (remain) {
|
if (remain) {
|
||||||
jiffies_to_timeval(ticks, &tmp);
|
jiffies_to_timeval(ticks, &tmp);
|
||||||
|
@ -989,175 +989,3 @@ flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
|
|||||||
|
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
||||||
void
|
|
||||||
_raw_spin_unlock(spinlock_t * lock)
|
|
||||||
{
|
|
||||||
mb();
|
|
||||||
lock->lock = 0;
|
|
||||||
|
|
||||||
lock->on_cpu = -1;
|
|
||||||
lock->previous = NULL;
|
|
||||||
lock->task = NULL;
|
|
||||||
lock->base_file = "none";
|
|
||||||
lock->line_no = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
|
|
||||||
{
|
|
||||||
long tmp;
|
|
||||||
long stuck;
|
|
||||||
void *inline_pc = __builtin_return_address(0);
|
|
||||||
unsigned long started = jiffies;
|
|
||||||
int printed = 0;
|
|
||||||
int cpu = smp_processor_id();
|
|
||||||
|
|
||||||
stuck = 1L << 30;
|
|
||||||
try_again:
|
|
||||||
|
|
||||||
/* Use sub-sections to put the actual loop at the end
|
|
||||||
of this object file's text section so as to perfect
|
|
||||||
branch prediction. */
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1: ldl_l %0,%1\n"
|
|
||||||
" subq %2,1,%2\n"
|
|
||||||
" blbs %0,2f\n"
|
|
||||||
" or %0,1,%0\n"
|
|
||||||
" stl_c %0,%1\n"
|
|
||||||
" beq %0,3f\n"
|
|
||||||
"4: mb\n"
|
|
||||||
".subsection 2\n"
|
|
||||||
"2: ldl %0,%1\n"
|
|
||||||
" subq %2,1,%2\n"
|
|
||||||
"3: blt %2,4b\n"
|
|
||||||
" blbs %0,2b\n"
|
|
||||||
" br 1b\n"
|
|
||||||
".previous"
|
|
||||||
: "=r" (tmp), "=m" (lock->lock), "=r" (stuck)
|
|
||||||
: "m" (lock->lock), "2" (stuck) : "memory");
|
|
||||||
|
|
||||||
if (stuck < 0) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"%s:%d spinlock stuck in %s at %p(%d)"
|
|
||||||
" owner %s at %p(%d) %s:%d\n",
|
|
||||||
base_file, line_no,
|
|
||||||
current->comm, inline_pc, cpu,
|
|
||||||
lock->task->comm, lock->previous,
|
|
||||||
lock->on_cpu, lock->base_file, lock->line_no);
|
|
||||||
stuck = 1L << 36;
|
|
||||||
printed = 1;
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exiting. Got the lock. */
|
|
||||||
lock->on_cpu = cpu;
|
|
||||||
lock->previous = inline_pc;
|
|
||||||
lock->task = current;
|
|
||||||
lock->base_file = base_file;
|
|
||||||
lock->line_no = line_no;
|
|
||||||
|
|
||||||
if (printed) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n",
|
|
||||||
base_file, line_no, current->comm, inline_pc,
|
|
||||||
cpu, jiffies - started);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
if ((ret = !test_and_set_bit(0, lock))) {
|
|
||||||
lock->on_cpu = smp_processor_id();
|
|
||||||
lock->previous = __builtin_return_address(0);
|
|
||||||
lock->task = current;
|
|
||||||
} else {
|
|
||||||
lock->base_file = base_file;
|
|
||||||
lock->line_no = line_no;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_DEBUG_SPINLOCK */
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_RWLOCK
|
|
||||||
void _raw_write_lock(rwlock_t * lock)
|
|
||||||
{
|
|
||||||
long regx, regy;
|
|
||||||
int stuck_lock, stuck_reader;
|
|
||||||
void *inline_pc = __builtin_return_address(0);
|
|
||||||
|
|
||||||
try_again:
|
|
||||||
|
|
||||||
stuck_lock = 1<<30;
|
|
||||||
stuck_reader = 1<<30;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1: ldl_l %1,%0\n"
|
|
||||||
" blbs %1,6f\n"
|
|
||||||
" blt %1,8f\n"
|
|
||||||
" mov 1,%1\n"
|
|
||||||
" stl_c %1,%0\n"
|
|
||||||
" beq %1,6f\n"
|
|
||||||
"4: mb\n"
|
|
||||||
".subsection 2\n"
|
|
||||||
"6: blt %3,4b # debug\n"
|
|
||||||
" subl %3,1,%3 # debug\n"
|
|
||||||
" ldl %1,%0\n"
|
|
||||||
" blbs %1,6b\n"
|
|
||||||
"8: blt %4,4b # debug\n"
|
|
||||||
" subl %4,1,%4 # debug\n"
|
|
||||||
" ldl %1,%0\n"
|
|
||||||
" blt %1,8b\n"
|
|
||||||
" br 1b\n"
|
|
||||||
".previous"
|
|
||||||
: "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (regy),
|
|
||||||
"=&r" (stuck_lock), "=&r" (stuck_reader)
|
|
||||||
: "m" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory");
|
|
||||||
|
|
||||||
if (stuck_lock < 0) {
|
|
||||||
printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
if (stuck_reader < 0) {
|
|
||||||
printk(KERN_WARNING "write_lock stuck on readers at %p\n",
|
|
||||||
inline_pc);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _raw_read_lock(rwlock_t * lock)
|
|
||||||
{
|
|
||||||
long regx;
|
|
||||||
int stuck_lock;
|
|
||||||
void *inline_pc = __builtin_return_address(0);
|
|
||||||
|
|
||||||
try_again:
|
|
||||||
|
|
||||||
stuck_lock = 1<<30;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1: ldl_l %1,%0;"
|
|
||||||
" blbs %1,6f;"
|
|
||||||
" subl %1,2,%1;"
|
|
||||||
" stl_c %1,%0;"
|
|
||||||
" beq %1,6f;"
|
|
||||||
"4: mb\n"
|
|
||||||
".subsection 2\n"
|
|
||||||
"6: ldl %1,%0;"
|
|
||||||
" blt %2,4b # debug\n"
|
|
||||||
" subl %2,1,%2 # debug\n"
|
|
||||||
" blbs %1,6b;"
|
|
||||||
" br 1b\n"
|
|
||||||
".previous"
|
|
||||||
: "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (stuck_lock)
|
|
||||||
: "m" (*(volatile int *)lock), "2" (stuck_lock) : "memory");
|
|
||||||
|
|
||||||
if (stuck_lock < 0) {
|
|
||||||
printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_DEBUG_RWLOCK */
|
|
||||||
|
@ -373,12 +373,11 @@ marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
|
|||||||
irq += 0x80; /* offset for lsi */
|
irq += 0x80; /* offset for lsi */
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
printk("PCI:%d:%d:%d (hose %d) [%s] is using MSI\n",
|
printk("PCI:%d:%d:%d (hose %d) is using MSI\n",
|
||||||
dev->bus->number,
|
dev->bus->number,
|
||||||
PCI_SLOT(dev->devfn),
|
PCI_SLOT(dev->devfn),
|
||||||
PCI_FUNC(dev->devfn),
|
PCI_FUNC(dev->devfn),
|
||||||
hose->index,
|
hose->index);
|
||||||
pci_pretty_name (dev));
|
|
||||||
printk(" %d message(s) from 0x%04x\n",
|
printk(" %d message(s) from 0x%04x\n",
|
||||||
1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
|
1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
|
||||||
msg_dat);
|
msg_dat);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Verify that we have not overflowed the stack. Oops if we have.
|
* Verify that we have not overflowed the stack. Oops if we have.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.set noat
|
.set noat
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* uninitialized local variables in the act.
|
* uninitialized local variables in the act.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.set noat
|
.set noat
|
||||||
|
@ -326,8 +326,8 @@ config SMP
|
|||||||
processor machines. On a single processor machine, the kernel will
|
processor machines. On a single processor machine, the kernel will
|
||||||
run faster if you say N here.
|
run faster if you say N here.
|
||||||
|
|
||||||
See also the <file:Documentation/smp.tex>,
|
See also the <file:Documentation/smp.txt>,
|
||||||
<file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
|
<file:Documentation/i386/IO-APIC.txt>,
|
||||||
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
|
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
|
||||||
<http://www.linuxdoc.org/docs.html#howto>.
|
<http://www.linuxdoc.org/docs.html#howto>.
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ config DEBUG_LL
|
|||||||
bool "Kernel low-level debugging functions"
|
bool "Kernel low-level debugging functions"
|
||||||
depends on DEBUG_KERNEL
|
depends on DEBUG_KERNEL
|
||||||
help
|
help
|
||||||
Say Y here to include definitions of printascii, printchar, printhex
|
Say Y here to include definitions of printascii, printch, printhex
|
||||||
in the kernel. This is helpful if you are debugging code that
|
in the kernel. This is helpful if you are debugging code that
|
||||||
executes before the console is initialized.
|
executes before the console is initialized.
|
||||||
|
|
||||||
|
@ -175,10 +175,10 @@ else
|
|||||||
endif
|
endif
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
prepare: maketools include/asm-arm/.arch
|
archprepare: maketools include/asm-arm/.arch
|
||||||
|
|
||||||
.PHONY: maketools FORCE
|
.PHONY: maketools FORCE
|
||||||
maketools: include/asm-arm/constants.h include/linux/version.h FORCE
|
maketools: include/linux/version.h FORCE
|
||||||
$(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
|
$(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
|
||||||
|
|
||||||
# Convert bzImage to zImage
|
# Convert bzImage to zImage
|
||||||
@ -190,7 +190,7 @@ zImage Image xipImage bootpImage uImage: vmlinux
|
|||||||
zinstall install: vmlinux
|
zinstall install: vmlinux
|
||||||
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
||||||
|
|
||||||
CLEAN_FILES += include/asm-arm/constants.h* include/asm-arm/mach-types.h \
|
CLEAN_FILES += include/asm-arm/mach-types.h \
|
||||||
include/asm-arm/arch include/asm-arm/.arch
|
include/asm-arm/arch include/asm-arm/.arch
|
||||||
|
|
||||||
# We use MRPROPER_FILES and CLEAN_FILES now
|
# We use MRPROPER_FILES and CLEAN_FILES now
|
||||||
@ -201,11 +201,6 @@ archclean:
|
|||||||
bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage
|
bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage
|
||||||
i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
||||||
|
|
||||||
arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
|
|
||||||
include/asm-arm/.arch
|
|
||||||
|
|
||||||
include/asm-$(ARCH)/constants.h: arch/$(ARCH)/kernel/asm-offsets.s
|
|
||||||
$(call filechk,gen-asm-offsets)
|
|
||||||
|
|
||||||
define archhelp
|
define archhelp
|
||||||
echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
|
echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
|
||||||
|
@ -541,6 +541,103 @@ locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
|
struct locomo_save_data {
|
||||||
|
u16 LCM_GPO;
|
||||||
|
u16 LCM_SPICT;
|
||||||
|
u16 LCM_GPE;
|
||||||
|
u16 LCM_ASD;
|
||||||
|
u16 LCM_SPIMD;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int locomo_suspend(struct device *dev, u32 pm_message_t, u32 level)
|
||||||
|
{
|
||||||
|
struct locomo *lchip = dev_get_drvdata(dev);
|
||||||
|
struct locomo_save_data *save;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (level != SUSPEND_DISABLE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL);
|
||||||
|
if (!save)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dev->power.saved_state = (void *) save;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&lchip->lock, flags);
|
||||||
|
|
||||||
|
save->LCM_GPO = locomo_readl(lchip->base + LOCOMO_GPO); /* GPIO */
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_GPO);
|
||||||
|
save->LCM_SPICT = locomo_readl(lchip->base + LOCOMO_SPICT); /* SPI */
|
||||||
|
locomo_writel(0x40, lchip->base + LOCOMO_SPICT);
|
||||||
|
save->LCM_GPE = locomo_readl(lchip->base + LOCOMO_GPE); /* GPIO */
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_GPE);
|
||||||
|
save->LCM_ASD = locomo_readl(lchip->base + LOCOMO_ASD); /* ADSTART */
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_ASD);
|
||||||
|
save->LCM_SPIMD = locomo_readl(lchip->base + LOCOMO_SPIMD); /* SPI */
|
||||||
|
locomo_writel(0x3C14, lchip->base + LOCOMO_SPIMD);
|
||||||
|
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_PAIF);
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_DAC);
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC);
|
||||||
|
|
||||||
|
if ( (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88) )
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_C32K); /* CLK32 off */
|
||||||
|
else
|
||||||
|
/* 18MHz already enabled, so no wait */
|
||||||
|
locomo_writel(0xc1, lchip->base + LOCOMO_C32K); /* CLK32 on */
|
||||||
|
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_TADC); /* 18MHz clock off*/
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC); /* 22MHz/24MHz clock off */
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); /* FL */
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&lchip->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int locomo_resume(struct device *dev, u32 level)
|
||||||
|
{
|
||||||
|
struct locomo *lchip = dev_get_drvdata(dev);
|
||||||
|
struct locomo_save_data *save;
|
||||||
|
unsigned long r;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (level != RESUME_ENABLE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
save = (struct locomo_save_data *) dev->power.saved_state;
|
||||||
|
if (!save)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&lchip->lock, flags);
|
||||||
|
|
||||||
|
locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO);
|
||||||
|
locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPICT);
|
||||||
|
locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE);
|
||||||
|
locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD);
|
||||||
|
locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPIMD);
|
||||||
|
|
||||||
|
locomo_writel(0x00, lchip->base + LOCOMO_C32K);
|
||||||
|
locomo_writel(0x90, lchip->base + LOCOMO_TADC);
|
||||||
|
|
||||||
|
locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC);
|
||||||
|
r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
|
||||||
|
r &= 0xFEFF;
|
||||||
|
locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
|
||||||
|
locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&lchip->lock, flags);
|
||||||
|
|
||||||
|
dev->power.saved_state = NULL;
|
||||||
|
kfree(save);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* locomo_probe - probe for a single LoCoMo chip.
|
* locomo_probe - probe for a single LoCoMo chip.
|
||||||
* @phys_addr: physical address of device.
|
* @phys_addr: physical address of device.
|
||||||
@ -707,6 +804,10 @@ static struct device_driver locomo_device_driver = {
|
|||||||
.bus = &platform_bus_type,
|
.bus = &platform_bus_type,
|
||||||
.probe = locomo_probe,
|
.probe = locomo_probe,
|
||||||
.remove = locomo_remove,
|
.remove = locomo_remove,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.suspend = locomo_suspend,
|
||||||
|
.resume = locomo_resume,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -91,7 +91,7 @@ EXPORT_SYMBOL(read_scoop_reg);
|
|||||||
EXPORT_SYMBOL(write_scoop_reg);
|
EXPORT_SYMBOL(write_scoop_reg);
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level)
|
static int scoop_suspend(struct device *dev, pm_message_t state, uint32_t level)
|
||||||
{
|
{
|
||||||
if (level == SUSPEND_POWER_DOWN) {
|
if (level == SUSPEND_POWER_DOWN) {
|
||||||
struct scoop_dev *sdev = dev_get_drvdata(dev);
|
struct scoop_dev *sdev = dev_get_drvdata(dev);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated make config: don't edit
|
# Automatically generated make config: don't edit
|
||||||
# Linux kernel version: 2.6.12-git4
|
# Linux kernel version: 2.6.13-git8
|
||||||
# Wed Jun 22 15:56:42 2005
|
# Thu Sep 8 19:24:02 2005
|
||||||
#
|
#
|
||||||
CONFIG_ARM=y
|
CONFIG_ARM=y
|
||||||
CONFIG_MMU=y
|
CONFIG_MMU=y
|
||||||
@ -22,6 +22,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
|
|||||||
# General setup
|
# General setup
|
||||||
#
|
#
|
||||||
CONFIG_LOCALVERSION=""
|
CONFIG_LOCALVERSION=""
|
||||||
|
CONFIG_LOCALVERSION_AUTO=y
|
||||||
CONFIG_SWAP=y
|
CONFIG_SWAP=y
|
||||||
CONFIG_SYSVIPC=y
|
CONFIG_SYSVIPC=y
|
||||||
# CONFIG_POSIX_MQUEUE is not set
|
# CONFIG_POSIX_MQUEUE is not set
|
||||||
@ -31,6 +32,7 @@ CONFIG_SYSCTL=y
|
|||||||
# CONFIG_HOTPLUG is not set
|
# CONFIG_HOTPLUG is not set
|
||||||
CONFIG_KOBJECT_UEVENT=y
|
CONFIG_KOBJECT_UEVENT=y
|
||||||
# CONFIG_IKCONFIG is not set
|
# CONFIG_IKCONFIG is not set
|
||||||
|
CONFIG_INITRAMFS_SOURCE=""
|
||||||
# CONFIG_EMBEDDED is not set
|
# CONFIG_EMBEDDED is not set
|
||||||
CONFIG_KALLSYMS=y
|
CONFIG_KALLSYMS=y
|
||||||
# CONFIG_KALLSYMS_ALL is not set
|
# CONFIG_KALLSYMS_ALL is not set
|
||||||
@ -88,7 +90,9 @@ CONFIG_ARCH_S3C2410=y
|
|||||||
#
|
#
|
||||||
# S3C24XX Implementations
|
# S3C24XX Implementations
|
||||||
#
|
#
|
||||||
|
CONFIG_MACH_ANUBIS=y
|
||||||
CONFIG_ARCH_BAST=y
|
CONFIG_ARCH_BAST=y
|
||||||
|
CONFIG_BAST_PC104_IRQ=y
|
||||||
CONFIG_ARCH_H1940=y
|
CONFIG_ARCH_H1940=y
|
||||||
CONFIG_MACH_N30=y
|
CONFIG_MACH_N30=y
|
||||||
CONFIG_ARCH_SMDK2410=y
|
CONFIG_ARCH_SMDK2410=y
|
||||||
@ -112,6 +116,7 @@ CONFIG_S3C2410_DMA=y
|
|||||||
# CONFIG_S3C2410_DMA_DEBUG is not set
|
# CONFIG_S3C2410_DMA_DEBUG is not set
|
||||||
# CONFIG_S3C2410_PM_DEBUG is not set
|
# CONFIG_S3C2410_PM_DEBUG is not set
|
||||||
# CONFIG_S3C2410_PM_CHECK is not set
|
# CONFIG_S3C2410_PM_CHECK is not set
|
||||||
|
CONFIG_PM_SIMTEC=y
|
||||||
CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
|
CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -149,7 +154,15 @@ CONFIG_ISA_DMA_API=y
|
|||||||
#
|
#
|
||||||
# CONFIG_SMP is not set
|
# CONFIG_SMP is not set
|
||||||
# CONFIG_PREEMPT is not set
|
# CONFIG_PREEMPT is not set
|
||||||
# CONFIG_DISCONTIGMEM is not set
|
# CONFIG_NO_IDLE_HZ is not set
|
||||||
|
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
|
||||||
|
CONFIG_SELECT_MEMORY_MODEL=y
|
||||||
|
CONFIG_FLATMEM_MANUAL=y
|
||||||
|
# CONFIG_DISCONTIGMEM_MANUAL is not set
|
||||||
|
# CONFIG_SPARSEMEM_MANUAL is not set
|
||||||
|
CONFIG_FLATMEM=y
|
||||||
|
CONFIG_FLAT_NODE_MEM_MAP=y
|
||||||
|
# CONFIG_SPARSEMEM_STATIC is not set
|
||||||
CONFIG_ALIGNMENT_TRAP=y
|
CONFIG_ALIGNMENT_TRAP=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -185,6 +198,74 @@ CONFIG_BINFMT_AOUT=y
|
|||||||
CONFIG_PM=y
|
CONFIG_PM=y
|
||||||
CONFIG_APM=y
|
CONFIG_APM=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Networking
|
||||||
|
#
|
||||||
|
CONFIG_NET=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Networking options
|
||||||
|
#
|
||||||
|
# CONFIG_PACKET is not set
|
||||||
|
CONFIG_UNIX=y
|
||||||
|
# CONFIG_NET_KEY is not set
|
||||||
|
CONFIG_INET=y
|
||||||
|
# CONFIG_IP_MULTICAST is not set
|
||||||
|
# CONFIG_IP_ADVANCED_ROUTER is not set
|
||||||
|
CONFIG_IP_FIB_HASH=y
|
||||||
|
CONFIG_IP_PNP=y
|
||||||
|
# CONFIG_IP_PNP_DHCP is not set
|
||||||
|
CONFIG_IP_PNP_BOOTP=y
|
||||||
|
# CONFIG_IP_PNP_RARP is not set
|
||||||
|
# CONFIG_NET_IPIP is not set
|
||||||
|
# CONFIG_NET_IPGRE is not set
|
||||||
|
# CONFIG_ARPD is not set
|
||||||
|
# CONFIG_SYN_COOKIES is not set
|
||||||
|
# CONFIG_INET_AH is not set
|
||||||
|
# CONFIG_INET_ESP is not set
|
||||||
|
# CONFIG_INET_IPCOMP is not set
|
||||||
|
# CONFIG_INET_TUNNEL is not set
|
||||||
|
CONFIG_INET_DIAG=y
|
||||||
|
CONFIG_INET_TCP_DIAG=y
|
||||||
|
# CONFIG_TCP_CONG_ADVANCED is not set
|
||||||
|
CONFIG_TCP_CONG_BIC=y
|
||||||
|
# CONFIG_IPV6 is not set
|
||||||
|
# CONFIG_NETFILTER is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# DCCP Configuration (EXPERIMENTAL)
|
||||||
|
#
|
||||||
|
# CONFIG_IP_DCCP is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# SCTP Configuration (EXPERIMENTAL)
|
||||||
|
#
|
||||||
|
# CONFIG_IP_SCTP is not set
|
||||||
|
# CONFIG_ATM is not set
|
||||||
|
# CONFIG_BRIDGE is not set
|
||||||
|
# CONFIG_VLAN_8021Q is not set
|
||||||
|
# CONFIG_DECNET is not set
|
||||||
|
# CONFIG_LLC2 is not set
|
||||||
|
# CONFIG_IPX is not set
|
||||||
|
# CONFIG_ATALK is not set
|
||||||
|
# CONFIG_X25 is not set
|
||||||
|
# CONFIG_LAPB is not set
|
||||||
|
# CONFIG_NET_DIVERT is not set
|
||||||
|
# CONFIG_ECONET is not set
|
||||||
|
# CONFIG_WAN_ROUTER is not set
|
||||||
|
# CONFIG_NET_SCHED is not set
|
||||||
|
# CONFIG_NET_CLS_ROUTE is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# Network testing
|
||||||
|
#
|
||||||
|
# CONFIG_NET_PKTGEN is not set
|
||||||
|
# CONFIG_NETFILTER_NETLINK is not set
|
||||||
|
# CONFIG_HAMRADIO is not set
|
||||||
|
# CONFIG_IRDA is not set
|
||||||
|
# CONFIG_BT is not set
|
||||||
|
# CONFIG_IEEE80211 is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Device Drivers
|
# Device Drivers
|
||||||
#
|
#
|
||||||
@ -258,6 +339,7 @@ CONFIG_MTD_ROM=y
|
|||||||
# CONFIG_MTD_IMPA7 is not set
|
# CONFIG_MTD_IMPA7 is not set
|
||||||
CONFIG_MTD_BAST=y
|
CONFIG_MTD_BAST=y
|
||||||
CONFIG_MTD_BAST_MAXSIZE=4
|
CONFIG_MTD_BAST_MAXSIZE=4
|
||||||
|
# CONFIG_MTD_PLATRAM is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Self-contained MTD device drivers
|
# Self-contained MTD device drivers
|
||||||
@ -312,7 +394,6 @@ CONFIG_BLK_DEV_RAM=y
|
|||||||
CONFIG_BLK_DEV_RAM_COUNT=16
|
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||||
CONFIG_BLK_DEV_INITRD=y
|
CONFIG_BLK_DEV_INITRD=y
|
||||||
CONFIG_INITRAMFS_SOURCE=""
|
|
||||||
# CONFIG_CDROM_PKTCDVD is not set
|
# CONFIG_CDROM_PKTCDVD is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -354,6 +435,7 @@ CONFIG_BLK_DEV_IDE_BAST=y
|
|||||||
#
|
#
|
||||||
# SCSI device support
|
# SCSI device support
|
||||||
#
|
#
|
||||||
|
# CONFIG_RAID_ATTRS is not set
|
||||||
# CONFIG_SCSI is not set
|
# CONFIG_SCSI is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -376,76 +458,19 @@ CONFIG_BLK_DEV_IDE_BAST=y
|
|||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# Networking support
|
# Network device support
|
||||||
#
|
#
|
||||||
CONFIG_NET=y
|
|
||||||
|
|
||||||
#
|
|
||||||
# Networking options
|
|
||||||
#
|
|
||||||
# CONFIG_PACKET is not set
|
|
||||||
CONFIG_UNIX=y
|
|
||||||
# CONFIG_NET_KEY is not set
|
|
||||||
CONFIG_INET=y
|
|
||||||
CONFIG_IP_FIB_HASH=y
|
|
||||||
# CONFIG_IP_FIB_TRIE is not set
|
|
||||||
# CONFIG_IP_MULTICAST is not set
|
|
||||||
# CONFIG_IP_ADVANCED_ROUTER is not set
|
|
||||||
CONFIG_IP_PNP=y
|
|
||||||
# CONFIG_IP_PNP_DHCP is not set
|
|
||||||
CONFIG_IP_PNP_BOOTP=y
|
|
||||||
# CONFIG_IP_PNP_RARP is not set
|
|
||||||
# CONFIG_NET_IPIP is not set
|
|
||||||
# CONFIG_NET_IPGRE is not set
|
|
||||||
# CONFIG_ARPD is not set
|
|
||||||
# CONFIG_SYN_COOKIES is not set
|
|
||||||
# CONFIG_INET_AH is not set
|
|
||||||
# CONFIG_INET_ESP is not set
|
|
||||||
# CONFIG_INET_IPCOMP is not set
|
|
||||||
# CONFIG_INET_TUNNEL is not set
|
|
||||||
CONFIG_IP_TCPDIAG=y
|
|
||||||
# CONFIG_IP_TCPDIAG_IPV6 is not set
|
|
||||||
# CONFIG_IPV6 is not set
|
|
||||||
# CONFIG_NETFILTER is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# SCTP Configuration (EXPERIMENTAL)
|
|
||||||
#
|
|
||||||
# CONFIG_IP_SCTP is not set
|
|
||||||
# CONFIG_ATM is not set
|
|
||||||
# CONFIG_BRIDGE is not set
|
|
||||||
# CONFIG_VLAN_8021Q is not set
|
|
||||||
# CONFIG_DECNET is not set
|
|
||||||
# CONFIG_LLC2 is not set
|
|
||||||
# CONFIG_IPX is not set
|
|
||||||
# CONFIG_ATALK is not set
|
|
||||||
# CONFIG_X25 is not set
|
|
||||||
# CONFIG_LAPB is not set
|
|
||||||
# CONFIG_NET_DIVERT is not set
|
|
||||||
# CONFIG_ECONET is not set
|
|
||||||
# CONFIG_WAN_ROUTER is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# QoS and/or fair queueing
|
|
||||||
#
|
|
||||||
# CONFIG_NET_SCHED is not set
|
|
||||||
# CONFIG_NET_CLS_ROUTE is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# Network testing
|
|
||||||
#
|
|
||||||
# CONFIG_NET_PKTGEN is not set
|
|
||||||
# CONFIG_NETPOLL is not set
|
|
||||||
# CONFIG_NET_POLL_CONTROLLER is not set
|
|
||||||
# CONFIG_HAMRADIO is not set
|
|
||||||
# CONFIG_IRDA is not set
|
|
||||||
# CONFIG_BT is not set
|
|
||||||
CONFIG_NETDEVICES=y
|
CONFIG_NETDEVICES=y
|
||||||
# CONFIG_DUMMY is not set
|
# CONFIG_DUMMY is not set
|
||||||
# CONFIG_BONDING is not set
|
# CONFIG_BONDING is not set
|
||||||
# CONFIG_EQUALIZER is not set
|
# CONFIG_EQUALIZER is not set
|
||||||
# CONFIG_TUN is not set
|
# CONFIG_TUN is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# PHY device support
|
||||||
|
#
|
||||||
|
# CONFIG_PHYLIB is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ethernet (10 or 100Mbit)
|
# Ethernet (10 or 100Mbit)
|
||||||
#
|
#
|
||||||
@ -480,6 +505,8 @@ CONFIG_DM9000=m
|
|||||||
# CONFIG_SLIP is not set
|
# CONFIG_SLIP is not set
|
||||||
# CONFIG_SHAPER is not set
|
# CONFIG_SHAPER is not set
|
||||||
# CONFIG_NETCONSOLE is not set
|
# CONFIG_NETCONSOLE is not set
|
||||||
|
# CONFIG_NETPOLL is not set
|
||||||
|
# CONFIG_NET_POLL_CONTROLLER is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# ISDN subsystem
|
# ISDN subsystem
|
||||||
@ -562,7 +589,6 @@ CONFIG_SERIAL_8250_EXTENDED=y
|
|||||||
CONFIG_SERIAL_8250_MANY_PORTS=y
|
CONFIG_SERIAL_8250_MANY_PORTS=y
|
||||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||||
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
|
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
|
||||||
# CONFIG_SERIAL_8250_MULTIPORT is not set
|
|
||||||
# CONFIG_SERIAL_8250_RSA is not set
|
# CONFIG_SERIAL_8250_RSA is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -605,7 +631,6 @@ CONFIG_S3C2410_RTC=y
|
|||||||
#
|
#
|
||||||
# Ftape, the floppy tape device driver
|
# Ftape, the floppy tape device driver
|
||||||
#
|
#
|
||||||
# CONFIG_DRM is not set
|
|
||||||
# CONFIG_RAW_DRIVER is not set
|
# CONFIG_RAW_DRIVER is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -628,7 +653,7 @@ CONFIG_I2C_ALGOBIT=m
|
|||||||
#
|
#
|
||||||
# I2C Hardware Bus support
|
# I2C Hardware Bus support
|
||||||
#
|
#
|
||||||
# CONFIG_I2C_ISA is not set
|
CONFIG_I2C_ISA=m
|
||||||
# CONFIG_I2C_PARPORT is not set
|
# CONFIG_I2C_PARPORT is not set
|
||||||
# CONFIG_I2C_PARPORT_LIGHT is not set
|
# CONFIG_I2C_PARPORT_LIGHT is not set
|
||||||
CONFIG_I2C_S3C2410=y
|
CONFIG_I2C_S3C2410=y
|
||||||
@ -636,14 +661,33 @@ CONFIG_I2C_S3C2410=y
|
|||||||
# CONFIG_I2C_PCA_ISA is not set
|
# CONFIG_I2C_PCA_ISA is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Hardware Sensors Chip support
|
# Miscellaneous I2C Chip support
|
||||||
#
|
#
|
||||||
CONFIG_I2C_SENSOR=m
|
# CONFIG_SENSORS_DS1337 is not set
|
||||||
|
# CONFIG_SENSORS_DS1374 is not set
|
||||||
|
CONFIG_SENSORS_EEPROM=m
|
||||||
|
# CONFIG_SENSORS_PCF8574 is not set
|
||||||
|
# CONFIG_SENSORS_PCA9539 is not set
|
||||||
|
# CONFIG_SENSORS_PCF8591 is not set
|
||||||
|
# CONFIG_SENSORS_RTC8564 is not set
|
||||||
|
# CONFIG_SENSORS_MAX6875 is not set
|
||||||
|
# CONFIG_I2C_DEBUG_CORE is not set
|
||||||
|
# CONFIG_I2C_DEBUG_ALGO is not set
|
||||||
|
# CONFIG_I2C_DEBUG_BUS is not set
|
||||||
|
# CONFIG_I2C_DEBUG_CHIP is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# Hardware Monitoring support
|
||||||
|
#
|
||||||
|
CONFIG_HWMON=y
|
||||||
|
CONFIG_HWMON_VID=m
|
||||||
# CONFIG_SENSORS_ADM1021 is not set
|
# CONFIG_SENSORS_ADM1021 is not set
|
||||||
# CONFIG_SENSORS_ADM1025 is not set
|
# CONFIG_SENSORS_ADM1025 is not set
|
||||||
# CONFIG_SENSORS_ADM1026 is not set
|
# CONFIG_SENSORS_ADM1026 is not set
|
||||||
# CONFIG_SENSORS_ADM1031 is not set
|
# CONFIG_SENSORS_ADM1031 is not set
|
||||||
|
# CONFIG_SENSORS_ADM9240 is not set
|
||||||
# CONFIG_SENSORS_ASB100 is not set
|
# CONFIG_SENSORS_ASB100 is not set
|
||||||
|
# CONFIG_SENSORS_ATXP1 is not set
|
||||||
# CONFIG_SENSORS_DS1621 is not set
|
# CONFIG_SENSORS_DS1621 is not set
|
||||||
# CONFIG_SENSORS_FSCHER is not set
|
# CONFIG_SENSORS_FSCHER is not set
|
||||||
# CONFIG_SENSORS_FSCPOS is not set
|
# CONFIG_SENSORS_FSCPOS is not set
|
||||||
@ -662,29 +706,23 @@ CONFIG_SENSORS_LM85=m
|
|||||||
# CONFIG_SENSORS_LM92 is not set
|
# CONFIG_SENSORS_LM92 is not set
|
||||||
# CONFIG_SENSORS_MAX1619 is not set
|
# CONFIG_SENSORS_MAX1619 is not set
|
||||||
# CONFIG_SENSORS_PC87360 is not set
|
# CONFIG_SENSORS_PC87360 is not set
|
||||||
# CONFIG_SENSORS_SMSC47B397 is not set
|
|
||||||
# CONFIG_SENSORS_SMSC47M1 is not set
|
# CONFIG_SENSORS_SMSC47M1 is not set
|
||||||
|
# CONFIG_SENSORS_SMSC47B397 is not set
|
||||||
# CONFIG_SENSORS_W83781D is not set
|
# CONFIG_SENSORS_W83781D is not set
|
||||||
|
# CONFIG_SENSORS_W83792D is not set
|
||||||
# CONFIG_SENSORS_W83L785TS is not set
|
# CONFIG_SENSORS_W83L785TS is not set
|
||||||
# CONFIG_SENSORS_W83627HF is not set
|
# CONFIG_SENSORS_W83627HF is not set
|
||||||
|
# CONFIG_SENSORS_W83627EHF is not set
|
||||||
#
|
# CONFIG_HWMON_DEBUG_CHIP is not set
|
||||||
# Other I2C Chip support
|
|
||||||
#
|
|
||||||
# CONFIG_SENSORS_DS1337 is not set
|
|
||||||
CONFIG_SENSORS_EEPROM=m
|
|
||||||
# CONFIG_SENSORS_PCF8574 is not set
|
|
||||||
# CONFIG_SENSORS_PCF8591 is not set
|
|
||||||
# CONFIG_SENSORS_RTC8564 is not set
|
|
||||||
# CONFIG_I2C_DEBUG_CORE is not set
|
|
||||||
# CONFIG_I2C_DEBUG_ALGO is not set
|
|
||||||
# CONFIG_I2C_DEBUG_BUS is not set
|
|
||||||
# CONFIG_I2C_DEBUG_CHIP is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Misc devices
|
# Misc devices
|
||||||
#
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Multimedia Capabilities Port drivers
|
||||||
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# Multimedia devices
|
# Multimedia devices
|
||||||
#
|
#
|
||||||
@ -731,7 +769,7 @@ CONFIG_DUMMY_CONSOLE=y
|
|||||||
# USB support
|
# USB support
|
||||||
#
|
#
|
||||||
CONFIG_USB_ARCH_HAS_HCD=y
|
CONFIG_USB_ARCH_HAS_HCD=y
|
||||||
# CONFIG_USB_ARCH_HAS_OHCI is not set
|
CONFIG_USB_ARCH_HAS_OHCI=y
|
||||||
# CONFIG_USB is not set
|
# CONFIG_USB is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -749,6 +787,7 @@ CONFIG_USB_ARCH_HAS_HCD=y
|
|||||||
#
|
#
|
||||||
CONFIG_EXT2_FS=y
|
CONFIG_EXT2_FS=y
|
||||||
# CONFIG_EXT2_FS_XATTR is not set
|
# CONFIG_EXT2_FS_XATTR is not set
|
||||||
|
# CONFIG_EXT2_FS_XIP is not set
|
||||||
CONFIG_EXT3_FS=y
|
CONFIG_EXT3_FS=y
|
||||||
CONFIG_EXT3_FS_XATTR=y
|
CONFIG_EXT3_FS_XATTR=y
|
||||||
# CONFIG_EXT3_FS_POSIX_ACL is not set
|
# CONFIG_EXT3_FS_POSIX_ACL is not set
|
||||||
@ -758,6 +797,7 @@ CONFIG_JBD=y
|
|||||||
CONFIG_FS_MBCACHE=y
|
CONFIG_FS_MBCACHE=y
|
||||||
# CONFIG_REISERFS_FS is not set
|
# CONFIG_REISERFS_FS is not set
|
||||||
# CONFIG_JFS_FS is not set
|
# CONFIG_JFS_FS is not set
|
||||||
|
# CONFIG_FS_POSIX_ACL is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# XFS support
|
# XFS support
|
||||||
@ -765,6 +805,7 @@ CONFIG_FS_MBCACHE=y
|
|||||||
# CONFIG_XFS_FS is not set
|
# CONFIG_XFS_FS is not set
|
||||||
# CONFIG_MINIX_FS is not set
|
# CONFIG_MINIX_FS is not set
|
||||||
CONFIG_ROMFS_FS=y
|
CONFIG_ROMFS_FS=y
|
||||||
|
CONFIG_INOTIFY=y
|
||||||
# CONFIG_QUOTA is not set
|
# CONFIG_QUOTA is not set
|
||||||
CONFIG_DNOTIFY=y
|
CONFIG_DNOTIFY=y
|
||||||
# CONFIG_AUTOFS_FS is not set
|
# CONFIG_AUTOFS_FS is not set
|
||||||
@ -791,11 +832,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
|
|||||||
#
|
#
|
||||||
CONFIG_PROC_FS=y
|
CONFIG_PROC_FS=y
|
||||||
CONFIG_SYSFS=y
|
CONFIG_SYSFS=y
|
||||||
# CONFIG_DEVPTS_FS_XATTR is not set
|
|
||||||
# CONFIG_TMPFS is not set
|
# CONFIG_TMPFS is not set
|
||||||
# CONFIG_HUGETLBFS is not set
|
# CONFIG_HUGETLBFS is not set
|
||||||
# CONFIG_HUGETLB_PAGE is not set
|
# CONFIG_HUGETLB_PAGE is not set
|
||||||
CONFIG_RAMFS=y
|
CONFIG_RAMFS=y
|
||||||
|
# CONFIG_RELAYFS_FS is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Miscellaneous filesystems
|
# Miscellaneous filesystems
|
||||||
@ -812,8 +853,7 @@ CONFIG_JFFS_FS_VERBOSE=0
|
|||||||
# CONFIG_JFFS_PROC_FS is not set
|
# CONFIG_JFFS_PROC_FS is not set
|
||||||
CONFIG_JFFS2_FS=y
|
CONFIG_JFFS2_FS=y
|
||||||
CONFIG_JFFS2_FS_DEBUG=0
|
CONFIG_JFFS2_FS_DEBUG=0
|
||||||
# CONFIG_JFFS2_FS_NAND is not set
|
CONFIG_JFFS2_FS_WRITEBUFFER=y
|
||||||
# CONFIG_JFFS2_FS_NOR_ECC is not set
|
|
||||||
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
|
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
|
||||||
CONFIG_JFFS2_ZLIB=y
|
CONFIG_JFFS2_ZLIB=y
|
||||||
CONFIG_JFFS2_RTIME=y
|
CONFIG_JFFS2_RTIME=y
|
||||||
@ -835,6 +875,7 @@ CONFIG_NFS_FS=y
|
|||||||
# CONFIG_NFSD is not set
|
# CONFIG_NFSD is not set
|
||||||
CONFIG_ROOT_NFS=y
|
CONFIG_ROOT_NFS=y
|
||||||
CONFIG_LOCKD=y
|
CONFIG_LOCKD=y
|
||||||
|
CONFIG_NFS_COMMON=y
|
||||||
CONFIG_SUNRPC=y
|
CONFIG_SUNRPC=y
|
||||||
# CONFIG_RPCSEC_GSS_KRB5 is not set
|
# CONFIG_RPCSEC_GSS_KRB5 is not set
|
||||||
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
||||||
@ -920,6 +961,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
|
|||||||
CONFIG_DEBUG_KERNEL=y
|
CONFIG_DEBUG_KERNEL=y
|
||||||
# CONFIG_MAGIC_SYSRQ is not set
|
# CONFIG_MAGIC_SYSRQ is not set
|
||||||
CONFIG_LOG_BUF_SHIFT=16
|
CONFIG_LOG_BUF_SHIFT=16
|
||||||
|
CONFIG_DETECT_SOFTLOCKUP=y
|
||||||
# CONFIG_SCHEDSTATS is not set
|
# CONFIG_SCHEDSTATS is not set
|
||||||
# CONFIG_DEBUG_SLAB is not set
|
# CONFIG_DEBUG_SLAB is not set
|
||||||
# CONFIG_DEBUG_SPINLOCK is not set
|
# CONFIG_DEBUG_SPINLOCK is not set
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* This file is included twice in entry-common.S
|
* This file is included twice in entry-common.S
|
||||||
*/
|
*/
|
||||||
#ifndef NR_syscalls
|
#ifndef NR_syscalls
|
||||||
#define NR_syscalls 320
|
#define NR_syscalls 328
|
||||||
#else
|
#else
|
||||||
|
|
||||||
__syscall_start:
|
__syscall_start:
|
||||||
@ -333,6 +333,9 @@ __syscall_start:
|
|||||||
.long sys_inotify_init
|
.long sys_inotify_init
|
||||||
.long sys_inotify_add_watch
|
.long sys_inotify_add_watch
|
||||||
.long sys_inotify_rm_watch
|
.long sys_inotify_rm_watch
|
||||||
|
.long sys_mbind_wrapper
|
||||||
|
/* 320 */ .long sys_get_mempolicy
|
||||||
|
.long sys_set_mempolicy
|
||||||
__syscall_end:
|
__syscall_end:
|
||||||
|
|
||||||
.rept NR_syscalls - (__syscall_end - __syscall_start) / 4
|
.rept NR_syscalls - (__syscall_end - __syscall_start) / 4
|
||||||
|
@ -269,6 +269,10 @@ sys_arm_fadvise64_64_wrapper:
|
|||||||
str r5, [sp, #4] @ push r5 to stack
|
str r5, [sp, #4] @ push r5 to stack
|
||||||
b sys_arm_fadvise64_64
|
b sys_arm_fadvise64_64
|
||||||
|
|
||||||
|
sys_mbind_wrapper:
|
||||||
|
str r5, [sp, #4]
|
||||||
|
b sys_mbind
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: off_4k (r5) is always units of 4K. If we can't do the requested
|
* Note: off_4k (r5) is always units of 4K. If we can't do the requested
|
||||||
* offset, we return EINVAL.
|
* offset, we return EINVAL.
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
#define MMX_WR0 (0x00)
|
#define MMX_WR0 (0x00)
|
||||||
#define MMX_WR1 (0x08)
|
#define MMX_WR1 (0x08)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
|
#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* Note that ADDR_LIMIT is either 0 or 0xc0000000.
|
* Note that ADDR_LIMIT is either 0 or 0xc0000000.
|
||||||
* Note also that it is intended that __get_user_bad is not global.
|
* Note also that it is intended that __get_user_bad is not global.
|
||||||
*/
|
*/
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* Note that ADDR_LIMIT is either 0 or 0xc0000000
|
* Note that ADDR_LIMIT is either 0 or 0xc0000000
|
||||||
* Note also that it is intended that __put_user_bad is not global.
|
* Note also that it is intended that __put_user_bad is not global.
|
||||||
*/
|
*/
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
|
|||||||
|
|
||||||
static struct platform_device serial_device = {
|
static struct platform_device serial_device = {
|
||||||
.name = "serial8250",
|
.name = "serial8250",
|
||||||
.id = 0,
|
.id = PLAT8250_DEV_PLATFORM,
|
||||||
.dev = {
|
.dev = {
|
||||||
.platform_data = serial_platform_data,
|
.platform_data = serial_platform_data,
|
||||||
},
|
},
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user