forked from Minki/linux
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
This commit is contained in:
commit
334d0dd8b6
5
CREDITS
5
CREDITS
@ -1745,8 +1745,9 @@ S: D-64295
|
||||
S: Germany
|
||||
|
||||
N: Andi Kleen
|
||||
E: ak@muc.de
|
||||
D: network hacker, syncookies
|
||||
E: andi@firstfloor.org
|
||||
U: http://www.halobates.de
|
||||
D: network, x86, NUMA, various hacks
|
||||
S: Schwalbenstr. 96
|
||||
S: 85551 Ottobrunn
|
||||
S: Germany
|
||||
|
@ -41,7 +41,7 @@ psdocs: $(PS)
|
||||
PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
|
||||
pdfdocs: $(PDF)
|
||||
|
||||
HTML := $(patsubst %.xml, %.html, $(BOOKS))
|
||||
HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
|
||||
htmldocs: $(HTML)
|
||||
|
||||
MAN := $(patsubst %.xml, %.9, $(BOOKS))
|
||||
@ -152,6 +152,7 @@ quiet_cmd_db2man = MAN $@
|
||||
@(which xmlto > /dev/null 2>&1) || \
|
||||
(echo "*** You need to install xmlto ***"; \
|
||||
exit 1)
|
||||
$(Q)mkdir -p $(obj)/man
|
||||
$(call cmd,db2man)
|
||||
@touch $@
|
||||
|
||||
@ -212,11 +213,7 @@ clean-files := $(DOCBOOKS) \
|
||||
$(patsubst %.xml, %.9, $(DOCBOOKS)) \
|
||||
$(C-procfs-example)
|
||||
|
||||
clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS))
|
||||
|
||||
#man put files in man subdir - traverse down
|
||||
subdir- := man/
|
||||
|
||||
clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
|
||||
|
||||
# Declare the contents of the .PHONY variable as phony. We keep that
|
||||
# information in a variable se we can use it in if_changed and friends.
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Rules are put in Documentation/DocBook
|
||||
|
||||
clean-files := *.9.gz *.sgml manpage.links manpage.refs
|
11
Documentation/blackfin/00-INDEX
Normal file
11
Documentation/blackfin/00-INDEX
Normal file
@ -0,0 +1,11 @@
|
||||
00-INDEX
|
||||
- This file
|
||||
|
||||
cache-lock.txt
|
||||
- HOWTO for blackfin cache locking.
|
||||
|
||||
cachefeatures.txt
|
||||
- Supported cache features.
|
||||
|
||||
Filesystems
|
||||
- Requirements for mounting the root file system.
|
169
Documentation/blackfin/Filesystems
Normal file
169
Documentation/blackfin/Filesystems
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* File: Documentation/blackfin/Filesystems
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Rev: $Id: Filesystems 2384 2006-11-01 04:12:43Z magicyang $
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
*/
|
||||
|
||||
How to mount the root file system in uClinux/Blackfin
|
||||
-----------------------------------------------------
|
||||
|
||||
1 Mounting EXT3 File system.
|
||||
------------------------
|
||||
|
||||
Creating an EXT3 File system for uClinux/Blackfin:
|
||||
|
||||
|
||||
Please follow the steps to form the EXT3 File system and mount the same as root
|
||||
file system.
|
||||
|
||||
a Make an ext3 file system as large as you want the final root file
|
||||
system.
|
||||
|
||||
mkfs.ext3 /dev/ram0 <your-rootfs-size-in-1k-blocks>
|
||||
|
||||
b Mount this Empty file system on a free directory as:
|
||||
|
||||
mount -t ext3 /dev/ram0 ./test
|
||||
where ./test is the empty directory.
|
||||
|
||||
c Copy your root fs directory that you have so carefully made over.
|
||||
|
||||
cp -af /tmp/my_final_rootfs_files/* ./test
|
||||
|
||||
(For ex: cp -af uClinux-dist/romfs/* ./test)
|
||||
|
||||
d If you have done everything right till now you should be able to see
|
||||
the required "root" dir's (that's etc, root, bin, lib, sbin...)
|
||||
|
||||
e Now unmount the file system
|
||||
|
||||
umount ./test
|
||||
|
||||
f Create the root file system image.
|
||||
|
||||
dd if=/dev/ram0 bs=1k count=<your-rootfs-size-in-1k-blocks> \
|
||||
> ext3fs.img
|
||||
|
||||
|
||||
Now you have to tell the kernel that will be mounting this file system as
|
||||
rootfs.
|
||||
So do a make menuconfig under kernel and select the Ext3 journaling file system
|
||||
support under File system --> submenu.
|
||||
|
||||
|
||||
2. Mounting EXT2 File system.
|
||||
-------------------------
|
||||
|
||||
By default the ext2 file system image will be created if you invoke make from
|
||||
the top uClinux-dist directory.
|
||||
|
||||
|
||||
3. Mounting CRAMFS File System
|
||||
----------------------------
|
||||
|
||||
To create a CRAMFS file system image execute the command
|
||||
|
||||
mkfs.cramfs ./test cramfs.img
|
||||
|
||||
where ./test is the target directory.
|
||||
|
||||
|
||||
4. Mounting ROMFS File System
|
||||
--------------------------
|
||||
|
||||
To create a ROMFS file system image execute the command
|
||||
|
||||
genromfs -v -V "ROMdisk" -f romfs.img -d ./test
|
||||
|
||||
where ./test is the target directory
|
||||
|
||||
|
||||
5. Mounting the JFFS2 Filesystem
|
||||
-----------------------------
|
||||
|
||||
To create a compressed JFFS filesystem (JFFS2), please execute the command
|
||||
|
||||
mkfs.jffs2 -d ./test -o jffs2.img
|
||||
|
||||
where ./test is the target directory.
|
||||
|
||||
However, please make sure the following is in your kernel config.
|
||||
|
||||
/*
|
||||
* RAM/ROM/Flash chip drivers
|
||||
*/
|
||||
#define CONFIG_MTD_CFI 1
|
||||
#define CONFIG_MTD_ROM 1
|
||||
/*
|
||||
* Mapping drivers for chip access
|
||||
*/
|
||||
#define CONFIG_MTD_COMPLEX_MAPPINGS 1
|
||||
#define CONFIG_MTD_BF533 1
|
||||
#undef CONFIG_MTD_UCLINUX
|
||||
|
||||
Through the u-boot boot loader, use the jffs2.img in the corresponding
|
||||
partition made in linux-2.6.x/drivers/mtd/maps/bf533_flash.c.
|
||||
|
||||
NOTE - Currently the Flash driver is available only for EZKIT. Watch out for a
|
||||
STAMP driver soon.
|
||||
|
||||
|
||||
6. Mounting the NFS File system
|
||||
-----------------------------
|
||||
|
||||
For mounting the NFS please do the following in the kernel config.
|
||||
|
||||
In Networking Support --> Networking options --> TCP/IP networking -->
|
||||
IP: kernel level autoconfiguration
|
||||
|
||||
Enable BOOTP Support.
|
||||
|
||||
In Kernel hacking --> Compiled-in kernel boot parameter add the following
|
||||
|
||||
root=/dev/nfs rw ip=bootp
|
||||
|
||||
In File system --> Network File system, Enable
|
||||
|
||||
NFS file system support --> NFSv3 client support
|
||||
Root File system on NFS
|
||||
|
||||
in uClibc menuconfig, do the following
|
||||
In Networking Support
|
||||
enable Remote Procedure Call (RPC) support
|
||||
Full RPC Support
|
||||
|
||||
On the Host side, ensure that /etc/dhcpd.conf looks something like this
|
||||
|
||||
ddns-update-style ad-hoc;
|
||||
allow bootp;
|
||||
subnet 10.100.4.0 netmask 255.255.255.0 {
|
||||
default-lease-time 122209600;
|
||||
max-lease-time 31557600;
|
||||
group {
|
||||
host bf533 {
|
||||
hardware ethernet 00:CF:52:49:C3:01;
|
||||
fixed-address 10.100.4.50;
|
||||
option root-path "/home/nfsmount";
|
||||
}
|
||||
}
|
||||
|
||||
ensure that /etc/exports looks something like this
|
||||
/home/nfsmount *(rw,no_root_squash,no_all_squash)
|
||||
|
||||
run the following commands as root (may differ depending on your
|
||||
distribution) :
|
||||
- service nfs start
|
||||
- service portmap start
|
||||
- service dhcpd start
|
||||
- /usr/sbin/exportfs
|
48
Documentation/blackfin/cache-lock.txt
Normal file
48
Documentation/blackfin/cache-lock.txt
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* File: Documentation/blackfin/cache-lock.txt
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Rev: $Id: cache-lock.txt 2384 2006-11-01 04:12:43Z magicyang $
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
*/
|
||||
|
||||
How to lock your code in cache in uClinux/blackfin
|
||||
--------------------------------------------------
|
||||
|
||||
There are only a few steps required to lock your code into the cache.
|
||||
Currently you can lock the code by Way.
|
||||
|
||||
Below are the interface provided for locking the cache.
|
||||
|
||||
|
||||
1. cache_grab_lock(int Ways);
|
||||
|
||||
This function grab the lock for locking your code into the cache specified
|
||||
by Ways.
|
||||
|
||||
|
||||
2. cache_lock(int Ways);
|
||||
|
||||
This function should be called after your critical code has been executed.
|
||||
Once the critical code exits, the code is now loaded into the cache. This
|
||||
function locks the code into the cache.
|
||||
|
||||
|
||||
So, the example sequence will be:
|
||||
|
||||
cache_grab_lock(WAY0_L); /* Grab the lock */
|
||||
|
||||
critical_code(); /* Execute the code of interest */
|
||||
|
||||
cache_lock(WAY0_L); /* Lock the cache */
|
||||
|
||||
Where WAY0_L signifies WAY0 locking.
|
65
Documentation/blackfin/cachefeatures.txt
Normal file
65
Documentation/blackfin/cachefeatures.txt
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* File: Documentation/blackfin/cachefeatures.txt
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Rev: $Id: cachefeatures.txt 2384 2006-11-01 04:12:43Z magicyang $
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
*/
|
||||
|
||||
- Instruction and Data cache initialization.
|
||||
icache_init();
|
||||
dcache_init();
|
||||
|
||||
- Instruction and Data cache Invalidation Routines, when flushing the
|
||||
same is not required.
|
||||
_icache_invalidate();
|
||||
_dcache_invalidate();
|
||||
|
||||
Also, for invalidating the entire instruction and data cache, the below
|
||||
routines are provided (another method for invalidation, refer page no 267 and 287 of
|
||||
ADSP-BF533 Hardware Reference manual)
|
||||
|
||||
invalidate_entire_dcache();
|
||||
invalidate_entire_icache();
|
||||
|
||||
-External Flushing of Instruction and data cache routines.
|
||||
|
||||
flush_instruction_cache();
|
||||
flush_data_cache();
|
||||
|
||||
- Internal Flushing of Instruction and Data Cache.
|
||||
|
||||
icplb_flush();
|
||||
dcplb_flush();
|
||||
|
||||
- Locking the cache.
|
||||
|
||||
cache_grab_lock();
|
||||
cache_lock();
|
||||
|
||||
Please refer linux-2.6.x/Documentation/blackfin/cache-lock.txt for how to
|
||||
lock the cache.
|
||||
|
||||
Locking the cache is optional feature.
|
||||
|
||||
- Miscellaneous cache functions.
|
||||
|
||||
flush_cache_all();
|
||||
flush_cache_mm();
|
||||
invalidate_dcache_range();
|
||||
flush_dcache_range();
|
||||
flush_dcache_page();
|
||||
flush_cache_range();
|
||||
flush_cache_page();
|
||||
invalidate_dcache_range();
|
||||
flush_page_to_ram();
|
||||
|
@ -55,8 +55,8 @@ aic7*seq.h*
|
||||
aicasm
|
||||
aicdb.h*
|
||||
asm
|
||||
asm-offsets.*
|
||||
asm_offsets.*
|
||||
asm-offsets.h
|
||||
asm_offsets.h
|
||||
autoconf.h*
|
||||
bbootsect
|
||||
bin2c
|
||||
|
@ -182,7 +182,7 @@ For example, you can do something like the following.
|
||||
|
||||
...
|
||||
|
||||
devres_close_group(dev, my_midlayer_something);
|
||||
devres_close_group(dev, my_midlayer_create_something);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -117,13 +117,6 @@ Who: Adrian Bunk <bunk@stusta.de>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: pci_module_init(driver)
|
||||
When: January 2007
|
||||
Why: Is replaced by pci_register_driver(pci_driver).
|
||||
Who: Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@suse.de>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: Usage of invalid timevals in setitimer
|
||||
When: March 2007
|
||||
Why: POSIX requires to validate timevals in the setitimer call. This
|
||||
@ -190,18 +183,10 @@ Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: i2c_adapter.dev
|
||||
i2c_adapter.list
|
||||
What: i2c_adapter.list
|
||||
When: July 2007
|
||||
Why: Superfluous, given i2c_adapter.class_dev:
|
||||
* The "dev" was a stand-in for the physical device node that legacy
|
||||
drivers would not have; but now it's almost always present. Any
|
||||
remaining legacy drivers must upgrade (they now trigger warnings).
|
||||
* The "list" duplicates class device children.
|
||||
The delay in removing this is so upgraded lm_sensors and libsensors
|
||||
can get deployed. (Removal causes minor changes in the sysfs layout,
|
||||
notably the location of the adapter type name and parenting the i2c
|
||||
client hardware directly from their controller.)
|
||||
Why: Superfluous, this list duplicates the one maintained by the driver
|
||||
core.
|
||||
Who: Jean Delvare <khali@linux-fr.org>,
|
||||
David Brownell <dbrownell@users.sourceforge.net>
|
||||
|
||||
@ -314,3 +299,27 @@ Why: Code was merged, then submitter immediately disappeared leaving
|
||||
Who: David S. Miller <davem@davemloft.net>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer)
|
||||
When: December 2007
|
||||
Why: These functions are a leftover from 2.4 times. They have several
|
||||
problems:
|
||||
- Duplication of checks that are done in the device driver's
|
||||
interrupt handler
|
||||
- common I/O layer can't do device specific error recovery
|
||||
- device driver can't be notified for conditions happening during
|
||||
execution of the function
|
||||
Device drivers should issue the read device characteristics and read
|
||||
configuration data ccws and do the appropriate error handling
|
||||
themselves.
|
||||
Who: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
|
||||
When: September 2007
|
||||
Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific
|
||||
I2C-over-GPIO drivers.
|
||||
Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
@ -122,21 +122,22 @@ subdirectory has the entries listed in Table 1-1.
|
||||
|
||||
Table 1-1: Process specific entries in /proc
|
||||
..............................................................................
|
||||
File Content
|
||||
cmdline Command line arguments
|
||||
cpu Current and last cpu in which it was executed (2.4)(smp)
|
||||
cwd Link to the current working directory
|
||||
environ Values of environment variables
|
||||
exe Link to the executable of this process
|
||||
fd Directory, which contains all file descriptors
|
||||
maps Memory maps to executables and library files (2.4)
|
||||
mem Memory held by this process
|
||||
root Link to the root directory of this process
|
||||
stat Process status
|
||||
statm Process memory status information
|
||||
status Process status in human readable form
|
||||
wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan
|
||||
smaps Extension based on maps, presenting the rss size for each mapped file
|
||||
File Content
|
||||
clear_refs Clears page referenced bits shown in smaps output
|
||||
cmdline Command line arguments
|
||||
cpu Current and last cpu in which it was executed (2.4)(smp)
|
||||
cwd Link to the current working directory
|
||||
environ Values of environment variables
|
||||
exe Link to the executable of this process
|
||||
fd Directory, which contains all file descriptors
|
||||
maps Memory maps to executables and library files (2.4)
|
||||
mem Memory held by this process
|
||||
root Link to the root directory of this process
|
||||
stat Process status
|
||||
statm Process memory status information
|
||||
status Process status in human readable form
|
||||
wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan
|
||||
smaps Extension based on maps, the rss size for each mapped file
|
||||
..............................................................................
|
||||
|
||||
For example, to get the status information of a process, all you have to do is
|
||||
|
@ -9,6 +9,8 @@ Supported adapters:
|
||||
* nForce4 MCP-04 10de:0034
|
||||
* nForce4 MCP51 10de:0264
|
||||
* nForce4 MCP55 10de:0368
|
||||
* nForce4 MCP61 10de:03EB
|
||||
* nForce4 MCP65 10de:0446
|
||||
|
||||
Datasheet: not publicly available, but seems to be similar to the
|
||||
AMD-8111 SMBus 2.0 adapter.
|
||||
|
@ -1,4 +1,4 @@
|
||||
Revision 6, 2005-11-20
|
||||
Revision 7, 2007-04-19
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
Greg KH <greg@kroah.com>
|
||||
|
||||
@ -20,6 +20,10 @@ yours for best results.
|
||||
|
||||
Technical changes:
|
||||
|
||||
* [Driver type] Any driver that was relying on i2c-isa has to be
|
||||
converted to a proper isa, platform or pci driver. This is not
|
||||
covered by this guide.
|
||||
|
||||
* [Includes] Get rid of "version.h" and <linux/i2c-proc.h>.
|
||||
Includes typically look like that:
|
||||
#include <linux/module.h>
|
||||
@ -27,12 +31,10 @@ Technical changes:
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-isa.h> /* for ISA drivers */
|
||||
#include <linux/hwmon.h> /* for hardware monitoring drivers */
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/hwmon-vid.h> /* if you need VRM support */
|
||||
#include <linux/err.h> /* for class registration */
|
||||
#include <asm/io.h> /* if you have I/O operations */
|
||||
Please respect this inclusion order. Some extra headers may be
|
||||
required for a given driver (e.g. "lm75.h").
|
||||
|
||||
@ -69,20 +71,16 @@ Technical changes:
|
||||
sensors mailing list <lm-sensors@lm-sensors.org> by providing a
|
||||
patch to the Documentation/hwmon/sysfs-interface file.
|
||||
|
||||
* [Attach] For I2C drivers, the attach function should make sure
|
||||
that the adapter's class has I2C_CLASS_HWMON (or whatever class is
|
||||
suitable for your driver), using the following construct:
|
||||
* [Attach] The attach function should make sure that the adapter's
|
||||
class has I2C_CLASS_HWMON (or whatever class is suitable for your
|
||||
driver), using the following construct:
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
return 0;
|
||||
ISA-only drivers of course don't need this.
|
||||
Call i2c_probe() instead of i2c_detect().
|
||||
|
||||
* [Detect] As mentioned earlier, the flags parameter is gone.
|
||||
The type_name and client_name strings are replaced by a single
|
||||
name string, which will be filled with a lowercase, short string.
|
||||
In i2c-only drivers, drop the i2c_is_isa_adapter check, it's
|
||||
useless. Same for isa-only drivers, as the test would always be
|
||||
true. Only hybrid drivers (which are quite rare) still need it.
|
||||
The labels used for error paths are reduced to the number needed.
|
||||
It is advised that the labels are given descriptive names such as
|
||||
exit and exit_free. Don't forget to properly set err before
|
||||
|
@ -4,17 +4,23 @@ I2C and SMBus
|
||||
=============
|
||||
|
||||
I2C (pronounce: I squared C) is a protocol developed by Philips. It is a
|
||||
slow two-wire protocol (10-400 kHz), but it suffices for many types of
|
||||
devices.
|
||||
slow two-wire protocol (variable speed, up to 400 kHz), with a high speed
|
||||
extension (3.4 MHz). It provides an inexpensive bus for connecting many
|
||||
types of devices with infrequent or low bandwidth communications needs.
|
||||
I2C is widely used with embedded systems. Some systems use variants that
|
||||
don't meet branding requirements, and so are not advertised as being I2C.
|
||||
|
||||
SMBus (System Management Bus) is a subset of the I2C protocol. Many
|
||||
modern mainboards have a System Management Bus. There are a lot of
|
||||
devices which can be connected to a SMBus; the most notable are modern
|
||||
memory chips with EEPROM memories and chips for hardware monitoring.
|
||||
SMBus (System Management Bus) is based on the I2C protocol, and is mostly
|
||||
a subset of I2C protocols and signaling. Many I2C devices will work on an
|
||||
SMBus, but some SMBus protocols add semantics beyond what is required to
|
||||
achieve I2C branding. Modern PC mainboards rely on SMBus. The most common
|
||||
devices connected through SMBus are RAM modules configured using I2C EEPROMs,
|
||||
and hardware monitoring chips.
|
||||
|
||||
Because the SMBus is just a special case of the generalized I2C bus, we
|
||||
can simulate the SMBus protocol on plain I2C busses. The reverse is
|
||||
regretfully impossible.
|
||||
Because the SMBus is mostly a subset of the generalized I2C bus, we can
|
||||
use its protocols on many I2C systems. However, there are systems that don't
|
||||
meet both SMBus and I2C electrical constraints; and others which can't
|
||||
implement all the common SMBus protocol semantics or messages.
|
||||
|
||||
|
||||
Terminology
|
||||
@ -29,6 +35,7 @@ When we talk about I2C, we use the following terms:
|
||||
An Algorithm driver contains general code that can be used for a whole class
|
||||
of I2C adapters. Each specific adapter driver depends on one algorithm
|
||||
driver.
|
||||
|
||||
A Driver driver (yes, this sounds ridiculous, sorry) contains the general
|
||||
code to access some type of device. Each detected device gets its own
|
||||
data in the Client structure. Usually, Driver and Client are more closely
|
||||
@ -40,6 +47,10 @@ a separate Adapter and Algorithm driver), and drivers for your I2C devices
|
||||
in this package. See the lm_sensors project http://www.lm-sensors.nu
|
||||
for device drivers.
|
||||
|
||||
At this time, Linux only operates I2C (or SMBus) in master mode; you can't
|
||||
use these APIs to make a Linux system behave as a slave/device, either to
|
||||
speak a custom protocol or to emulate some other device.
|
||||
|
||||
|
||||
Included Bus Drivers
|
||||
====================
|
||||
|
@ -1,5 +1,5 @@
|
||||
This is a small guide for those who want to write kernel drivers for I2C
|
||||
or SMBus devices.
|
||||
or SMBus devices, using Linux as the protocol host/master (not slave).
|
||||
|
||||
To set up a driver, you need to do several things. Some are optional, and
|
||||
some things can be done slightly or completely different. Use this as a
|
||||
@ -29,8 +29,16 @@ static struct i2c_driver foo_driver = {
|
||||
.driver = {
|
||||
.name = "foo",
|
||||
},
|
||||
|
||||
/* iff driver uses driver model ("new style") binding model: */
|
||||
.probe = foo_probe,
|
||||
.remove = foo_remove,
|
||||
|
||||
/* else, driver uses "legacy" binding model: */
|
||||
.attach_adapter = foo_attach_adapter,
|
||||
.detach_client = foo_detach_client,
|
||||
|
||||
/* these may be used regardless of the driver binding model */
|
||||
.shutdown = foo_shutdown, /* optional */
|
||||
.suspend = foo_suspend, /* optional */
|
||||
.resume = foo_resume, /* optional */
|
||||
@ -40,7 +48,8 @@ static struct i2c_driver foo_driver = {
|
||||
The name field is the driver name, and must not contain spaces. It
|
||||
should match the module name (if the driver can be compiled as a module),
|
||||
although you can use MODULE_ALIAS (passing "foo" in this example) to add
|
||||
another name for the module.
|
||||
another name for the module. If the driver name doesn't match the module
|
||||
name, the module won't be automatically loaded (hotplug/coldplug).
|
||||
|
||||
All other fields are for call-back functions which will be explained
|
||||
below.
|
||||
@ -65,16 +74,13 @@ An example structure is below.
|
||||
|
||||
struct foo_data {
|
||||
struct i2c_client client;
|
||||
struct semaphore lock; /* For ISA access in `sensors' drivers. */
|
||||
int sysctl_id; /* To keep the /proc directory entry for
|
||||
`sensors' drivers. */
|
||||
enum chips type; /* To keep the chips type for `sensors' drivers. */
|
||||
|
||||
/* Because the i2c bus is slow, it is often useful to cache the read
|
||||
information of a chip for some time (for example, 1 or 2 seconds).
|
||||
It depends of course on the device whether this is really worthwhile
|
||||
or even sensible. */
|
||||
struct semaphore update_lock; /* When we are reading lots of information,
|
||||
struct mutex update_lock; /* When we are reading lots of information,
|
||||
another process should not update the
|
||||
below information */
|
||||
char valid; /* != 0 if the following fields are valid. */
|
||||
@ -95,8 +101,7 @@ some obscure clients). But we need generic reading and writing routines.
|
||||
I have found it useful to define foo_read and foo_write function for this.
|
||||
For some cases, it will be easier to call the i2c functions directly,
|
||||
but many chips have some kind of register-value idea that can easily
|
||||
be encapsulated. Also, some chips have both ISA and I2C interfaces, and
|
||||
it useful to abstract from this (only for `sensors' drivers).
|
||||
be encapsulated.
|
||||
|
||||
The below functions are simple examples, and should not be copied
|
||||
literally.
|
||||
@ -119,28 +124,101 @@ literally.
|
||||
return i2c_smbus_write_word_data(client,reg,value);
|
||||
}
|
||||
|
||||
For sensors code, you may have to cope with ISA registers too. Something
|
||||
like the below often works. Note the locking!
|
||||
|
||||
int foo_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int res;
|
||||
if (i2c_is_isa_client(client)) {
|
||||
down(&(((struct foo_data *) (client->data)) -> lock));
|
||||
outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET);
|
||||
res = inb_p(client->addr + FOO_DATA_REG_OFFSET);
|
||||
up(&(((struct foo_data *) (client->data)) -> lock));
|
||||
return res;
|
||||
} else
|
||||
return i2c_smbus_read_byte_data(client,reg);
|
||||
}
|
||||
|
||||
Writing is done the same way.
|
||||
|
||||
|
||||
Probing and attaching
|
||||
=====================
|
||||
|
||||
The Linux I2C stack was originally written to support access to hardware
|
||||
monitoring chips on PC motherboards, and thus it embeds some assumptions
|
||||
that are more appropriate to SMBus (and PCs) than to I2C. One of these
|
||||
assumptions is that most adapters and devices drivers support the SMBUS_QUICK
|
||||
protocol to probe device presence. Another is that devices and their drivers
|
||||
can be sufficiently configured using only such probe primitives.
|
||||
|
||||
As Linux and its I2C stack became more widely used in embedded systems
|
||||
and complex components such as DVB adapters, those assumptions became more
|
||||
problematic. Drivers for I2C devices that issue interrupts need more (and
|
||||
different) configuration information, as do drivers handling chip variants
|
||||
that can't be distinguished by protocol probing, or which need some board
|
||||
specific information to operate correctly.
|
||||
|
||||
Accordingly, the I2C stack now has two models for associating I2C devices
|
||||
with their drivers: the original "legacy" model, and a newer one that's
|
||||
fully compatible with the Linux 2.6 driver model. These models do not mix,
|
||||
since the "legacy" model requires drivers to create "i2c_client" device
|
||||
objects after SMBus style probing, while the Linux driver model expects
|
||||
drivers to be given such device objects in their probe() routines.
|
||||
|
||||
|
||||
Standard Driver Model Binding ("New Style")
|
||||
-------------------------------------------
|
||||
|
||||
System infrastructure, typically board-specific initialization code or
|
||||
boot firmware, reports what I2C devices exist. For example, there may be
|
||||
a table, in the kernel or from the boot loader, identifying I2C devices
|
||||
and linking them to board-specific configuration information about IRQs
|
||||
and other wiring artifacts, chip type, and so on. That could be used to
|
||||
create i2c_client objects for each I2C device.
|
||||
|
||||
I2C device drivers using this binding model work just like any other
|
||||
kind of driver in Linux: they provide a probe() method to bind to
|
||||
those devices, and a remove() method to unbind.
|
||||
|
||||
static int foo_probe(struct i2c_client *client);
|
||||
static int foo_remove(struct i2c_client *client);
|
||||
|
||||
Remember that the i2c_driver does not create those client handles. The
|
||||
handle may be used during foo_probe(). If foo_probe() reports success
|
||||
(zero not a negative status code) it may save the handle and use it until
|
||||
foo_remove() returns. That binding model is used by most Linux drivers.
|
||||
|
||||
Drivers match devices when i2c_client.driver_name and the driver name are
|
||||
the same; this approach is used in several other busses that don't have
|
||||
device typing support in the hardware. The driver and module name should
|
||||
match, so hotplug/coldplug mechanisms will modprobe the driver.
|
||||
|
||||
|
||||
Device Creation (Standard driver model)
|
||||
---------------------------------------
|
||||
|
||||
If you know for a fact that an I2C device is connected to a given I2C bus,
|
||||
you can instantiate that device by simply filling an i2c_board_info
|
||||
structure with the device address and driver name, and calling
|
||||
i2c_new_device(). This will create the device, then the driver core will
|
||||
take care of finding the right driver and will call its probe() method.
|
||||
If a driver supports different device types, you can specify the type you
|
||||
want using the type field. You can also specify an IRQ and platform data
|
||||
if needed.
|
||||
|
||||
Sometimes you know that a device is connected to a given I2C bus, but you
|
||||
don't know the exact address it uses. This happens on TV adapters for
|
||||
example, where the same driver supports dozens of slightly different
|
||||
models, and I2C device addresses change from one model to the next. In
|
||||
that case, you can use the i2c_new_probed_device() variant, which is
|
||||
similar to i2c_new_device(), except that it takes an additional list of
|
||||
possible I2C addresses to probe. A device is created for the first
|
||||
responsive address in the list. If you expect more than one device to be
|
||||
present in the address range, simply call i2c_new_probed_device() that
|
||||
many times.
|
||||
|
||||
The call to i2c_new_device() or i2c_new_probed_device() typically happens
|
||||
in the I2C bus driver. You may want to save the returned i2c_client
|
||||
reference for later use.
|
||||
|
||||
|
||||
Device Deletion (Standard driver model)
|
||||
---------------------------------------
|
||||
|
||||
Each I2C device which has been created using i2c_new_device() or
|
||||
i2c_new_probed_device() can be unregistered by calling
|
||||
i2c_unregister_device(). If you don't call it explicitly, it will be
|
||||
called automatically before the underlying I2C bus itself is removed, as a
|
||||
device can't survive its parent in the device driver model.
|
||||
|
||||
|
||||
Legacy Driver Binding Model
|
||||
---------------------------
|
||||
|
||||
Most i2c devices can be present on several i2c addresses; for some this
|
||||
is determined in hardware (by soldering some chip pins to Vcc or Ground),
|
||||
for others this can be changed in software (by writing to specific client
|
||||
@ -157,13 +235,9 @@ detection algorithm.
|
||||
You do not have to use this parameter interface; but don't try to use
|
||||
function i2c_probe() if you don't.
|
||||
|
||||
NOTE: If you want to write a `sensors' driver, the interface is slightly
|
||||
different! See below.
|
||||
|
||||
|
||||
|
||||
Probing classes
|
||||
---------------
|
||||
Probing classes (Legacy model)
|
||||
------------------------------
|
||||
|
||||
All parameters are given as lists of unsigned 16-bit integers. Lists are
|
||||
terminated by I2C_CLIENT_END.
|
||||
@ -210,8 +284,8 @@ Note that you *have* to call the defined variable `normal_i2c',
|
||||
without any prefix!
|
||||
|
||||
|
||||
Attaching to an adapter
|
||||
-----------------------
|
||||
Attaching to an adapter (Legacy model)
|
||||
--------------------------------------
|
||||
|
||||
Whenever a new adapter is inserted, or for all adapters if the driver is
|
||||
being registered, the callback attach_adapter() is called. Now is the
|
||||
@ -237,17 +311,13 @@ them (unless a `force' parameter was used). In addition, addresses that
|
||||
are already in use (by some other registered client) are skipped.
|
||||
|
||||
|
||||
The detect client function
|
||||
--------------------------
|
||||
The detect client function (Legacy model)
|
||||
-----------------------------------------
|
||||
|
||||
The detect client function is called by i2c_probe. The `kind' parameter
|
||||
contains -1 for a probed detection, 0 for a forced detection, or a positive
|
||||
number for a forced detection with a chip type forced.
|
||||
|
||||
Below, some things are only needed if this is a `sensors' driver. Those
|
||||
parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
|
||||
markers.
|
||||
|
||||
Returning an error different from -ENODEV in a detect function will cause
|
||||
the detection to stop: other addresses and adapters won't be scanned.
|
||||
This should only be done on fatal or internal errors, such as a memory
|
||||
@ -256,64 +326,20 @@ shortage or i2c_attach_client failing.
|
||||
For now, you can ignore the `flags' parameter. It is there for future use.
|
||||
|
||||
int foo_detect_client(struct i2c_adapter *adapter, int address,
|
||||
unsigned short flags, int kind)
|
||||
int kind)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct foo_data *data;
|
||||
const char *client_name = ""; /* For non-`sensors' drivers, put the real
|
||||
name here! */
|
||||
const char *name = "";
|
||||
|
||||
/* Let's see whether this adapter can support what we need.
|
||||
Please substitute the things you need here!
|
||||
For `sensors' drivers, add `! is_isa &&' to the if statement */
|
||||
Please substitute the things you need here! */
|
||||
if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
goto ERROR0;
|
||||
|
||||
/* SENSORS ONLY START */
|
||||
const char *type_name = "";
|
||||
int is_isa = i2c_is_isa_adapter(adapter);
|
||||
|
||||
/* Do this only if the chip can additionally be found on the ISA bus
|
||||
(hybrid chip). */
|
||||
|
||||
if (is_isa) {
|
||||
|
||||
/* Discard immediately if this ISA range is already used */
|
||||
/* FIXME: never use check_region(), only request_region() */
|
||||
if (check_region(address,FOO_EXTENT))
|
||||
goto ERROR0;
|
||||
|
||||
/* Probe whether there is anything on this address.
|
||||
Some example code is below, but you will have to adapt this
|
||||
for your own driver */
|
||||
|
||||
if (kind < 0) /* Only if no force parameter was used */ {
|
||||
/* We may need long timeouts at least for some chips. */
|
||||
#define REALLY_SLOW_IO
|
||||
i = inb_p(address + 1);
|
||||
if (inb_p(address + 2) != i)
|
||||
goto ERROR0;
|
||||
if (inb_p(address + 3) != i)
|
||||
goto ERROR0;
|
||||
if (inb_p(address + 7) != i)
|
||||
goto ERROR0;
|
||||
#undef REALLY_SLOW_IO
|
||||
|
||||
/* Let's just hope nothing breaks here */
|
||||
i = inb_p(address + 5) & 0x7f;
|
||||
outb_p(~i & 0x7f,address+5);
|
||||
if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
|
||||
outb_p(i,address+5);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SENSORS ONLY END */
|
||||
|
||||
/* OK. For now, we presume we have a valid client. We now create the
|
||||
client structure, even though we cannot fill it completely yet.
|
||||
But it allows us to access several i2c functions safely */
|
||||
@ -323,13 +349,12 @@ For now, you can ignore the `flags' parameter. It is there for future use.
|
||||
goto ERROR0;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &foo_driver;
|
||||
new_client->flags = 0;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &foo_driver;
|
||||
|
||||
/* Now, we do the remaining detection. If no `force' parameter is used. */
|
||||
|
||||
@ -337,19 +362,17 @@ For now, you can ignore the `flags' parameter. It is there for future use.
|
||||
parameter was used. */
|
||||
if (kind < 0) {
|
||||
/* The below is of course bogus */
|
||||
if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
|
||||
if (foo_read(client, FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
|
||||
goto ERROR1;
|
||||
}
|
||||
|
||||
/* SENSORS ONLY START */
|
||||
|
||||
/* Next, specific detection. This is especially important for `sensors'
|
||||
devices. */
|
||||
|
||||
/* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter
|
||||
was used. */
|
||||
if (kind <= 0) {
|
||||
i = foo_read(new_client,FOO_REG_CHIPTYPE);
|
||||
i = foo_read(client, FOO_REG_CHIPTYPE);
|
||||
if (i == FOO_TYPE_1)
|
||||
kind = chip1; /* As defined in the enum */
|
||||
else if (i == FOO_TYPE_2)
|
||||
@ -363,63 +386,31 @@ For now, you can ignore the `flags' parameter. It is there for future use.
|
||||
|
||||
/* Now set the type and chip names */
|
||||
if (kind == chip1) {
|
||||
type_name = "chip1"; /* For /proc entry */
|
||||
client_name = "CHIP 1";
|
||||
name = "chip1";
|
||||
} else if (kind == chip2) {
|
||||
type_name = "chip2"; /* For /proc entry */
|
||||
client_name = "CHIP 2";
|
||||
name = "chip2";
|
||||
}
|
||||
|
||||
/* Reserve the ISA region */
|
||||
if (is_isa)
|
||||
request_region(address,FOO_EXTENT,type_name);
|
||||
|
||||
/* SENSORS ONLY END */
|
||||
|
||||
/* Fill in the remaining client fields. */
|
||||
strcpy(new_client->name,client_name);
|
||||
|
||||
/* SENSORS ONLY BEGIN */
|
||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
||||
data->type = kind;
|
||||
/* SENSORS ONLY END */
|
||||
|
||||
data->valid = 0; /* Only if you use this field */
|
||||
init_MUTEX(&data->update_lock); /* Only if you use this field */
|
||||
mutex_init(&data->update_lock); /* Only if you use this field */
|
||||
|
||||
/* Any other initializations in data must be done here too. */
|
||||
|
||||
/* Tell the i2c layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto ERROR3;
|
||||
|
||||
/* SENSORS ONLY BEGIN */
|
||||
/* Register a new directory entry with module sensors. See below for
|
||||
the `template' structure. */
|
||||
if ((i = i2c_register_entry(new_client, type_name,
|
||||
foo_dir_table_template,THIS_MODULE)) < 0) {
|
||||
err = i;
|
||||
goto ERROR4;
|
||||
}
|
||||
data->sysctl_id = i;
|
||||
|
||||
/* SENSORS ONLY END */
|
||||
|
||||
/* This function can write default values to the client registers, if
|
||||
needed. */
|
||||
foo_init_client(new_client);
|
||||
foo_init_client(client);
|
||||
|
||||
/* Tell the i2c layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto ERROR1;
|
||||
|
||||
return 0;
|
||||
|
||||
/* OK, this is not exactly good programming practice, usually. But it is
|
||||
very code-efficient in this case. */
|
||||
|
||||
ERROR4:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR3:
|
||||
ERROR2:
|
||||
/* SENSORS ONLY START */
|
||||
if (is_isa)
|
||||
release_region(address,FOO_EXTENT);
|
||||
/* SENSORS ONLY END */
|
||||
ERROR1:
|
||||
kfree(data);
|
||||
ERROR0:
|
||||
@ -427,8 +418,8 @@ For now, you can ignore the `flags' parameter. It is there for future use.
|
||||
}
|
||||
|
||||
|
||||
Removing the client
|
||||
===================
|
||||
Removing the client (Legacy model)
|
||||
==================================
|
||||
|
||||
The detach_client call back function is called when a client should be
|
||||
removed. It may actually fail, but only when panicking. This code is
|
||||
@ -436,22 +427,12 @@ much simpler than the attachment code, fortunately!
|
||||
|
||||
int foo_detach_client(struct i2c_client *client)
|
||||
{
|
||||
int err,i;
|
||||
|
||||
/* SENSORS ONLY START */
|
||||
/* Deregister with the `i2c-proc' module. */
|
||||
i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
|
||||
/* SENSORS ONLY END */
|
||||
int err;
|
||||
|
||||
/* Try to detach the client from i2c space */
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
/* HYBRID SENSORS CHIP ONLY START */
|
||||
if i2c_is_isa_client(client)
|
||||
release_region(client->addr,LM78_EXTENT);
|
||||
/* HYBRID SENSORS CHIP ONLY END */
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
@ -464,45 +445,34 @@ When the kernel is booted, or when your foo driver module is inserted,
|
||||
you have to do some initializing. Fortunately, just attaching (registering)
|
||||
the driver module is usually enough.
|
||||
|
||||
/* Keep track of how far we got in the initialization process. If several
|
||||
things have to initialized, and we fail halfway, only those things
|
||||
have to be cleaned up! */
|
||||
static int __initdata foo_initialized = 0;
|
||||
|
||||
static int __init foo_init(void)
|
||||
{
|
||||
int res;
|
||||
printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE);
|
||||
|
||||
if ((res = i2c_add_driver(&foo_driver))) {
|
||||
printk("foo: Driver registration failed, module not inserted.\n");
|
||||
foo_cleanup();
|
||||
return res;
|
||||
}
|
||||
foo_initialized ++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo_cleanup(void)
|
||||
static void __exit foo_cleanup(void)
|
||||
{
|
||||
if (foo_initialized == 1) {
|
||||
if ((res = i2c_del_driver(&foo_driver))) {
|
||||
printk("foo: Driver registration failed, module not removed.\n");
|
||||
return;
|
||||
}
|
||||
foo_initialized --;
|
||||
}
|
||||
i2c_del_driver(&foo_driver);
|
||||
}
|
||||
|
||||
/* Substitute your own name and email address */
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
|
||||
MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
|
||||
|
||||
/* a few non-GPL license types are also allowed */
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(foo_init);
|
||||
module_exit(foo_cleanup);
|
||||
|
||||
Note that some functions are marked by `__init', and some data structures
|
||||
by `__init_data'. Hose functions and structures can be removed after
|
||||
by `__initdata'. These functions and structures can be removed after
|
||||
kernel booting (or module loading) is completed.
|
||||
|
||||
|
||||
@ -632,110 +602,7 @@ General purpose routines
|
||||
Below all general purpose routines are listed, that were not mentioned
|
||||
before.
|
||||
|
||||
/* This call returns a unique low identifier for each registered adapter,
|
||||
* or -1 if the adapter was not registered.
|
||||
/* This call returns a unique low identifier for each registered adapter.
|
||||
*/
|
||||
extern int i2c_adapter_id(struct i2c_adapter *adap);
|
||||
|
||||
|
||||
The sensors sysctl/proc interface
|
||||
=================================
|
||||
|
||||
This section only applies if you write `sensors' drivers.
|
||||
|
||||
Each sensors driver creates a directory in /proc/sys/dev/sensors for each
|
||||
registered client. The directory is called something like foo-i2c-4-65.
|
||||
The sensors module helps you to do this as easily as possible.
|
||||
|
||||
The template
|
||||
------------
|
||||
|
||||
You will need to define a ctl_table template. This template will automatically
|
||||
be copied to a newly allocated structure and filled in where necessary when
|
||||
you call sensors_register_entry.
|
||||
|
||||
First, I will give an example definition.
|
||||
static ctl_table foo_dir_table_template[] = {
|
||||
{ FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real,
|
||||
&i2c_sysctl_real,NULL,&foo_func },
|
||||
{ FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real,
|
||||
&i2c_sysctl_real,NULL,&foo_func },
|
||||
{ FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real,
|
||||
&i2c_sysctl_real,NULL,&foo_data },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
In the above example, three entries are defined. They can either be
|
||||
accessed through the /proc interface, in the /proc/sys/dev/sensors/*
|
||||
directories, as files named func1, func2 and data, or alternatively
|
||||
through the sysctl interface, in the appropriate table, with identifiers
|
||||
FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA.
|
||||
|
||||
The third, sixth and ninth parameters should always be NULL, and the
|
||||
fourth should always be 0. The fifth is the mode of the /proc file;
|
||||
0644 is safe, as the file will be owned by root:root.
|
||||
|
||||
The seventh and eighth parameters should be &i2c_proc_real and
|
||||
&i2c_sysctl_real if you want to export lists of reals (scaled
|
||||
integers). You can also use your own function for them, as usual.
|
||||
Finally, the last parameter is the call-back to gather the data
|
||||
(see below) if you use the *_proc_real functions.
|
||||
|
||||
|
||||
Gathering the data
|
||||
------------------
|
||||
|
||||
The call back functions (foo_func and foo_data in the above example)
|
||||
can be called in several ways; the operation parameter determines
|
||||
what should be done:
|
||||
|
||||
* If operation == SENSORS_PROC_REAL_INFO, you must return the
|
||||
magnitude (scaling) in nrels_mag;
|
||||
* If operation == SENSORS_PROC_REAL_READ, you must read information
|
||||
from the chip and return it in results. The number of integers
|
||||
to display should be put in nrels_mag;
|
||||
* If operation == SENSORS_PROC_REAL_WRITE, you must write the
|
||||
supplied information to the chip. nrels_mag will contain the number
|
||||
of integers, results the integers themselves.
|
||||
|
||||
The *_proc_real functions will display the elements as reals for the
|
||||
/proc interface. If you set the magnitude to 2, and supply 345 for
|
||||
SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would
|
||||
write 45.6 to the /proc file, it would be returned as 4560 for
|
||||
SENSORS_PROC_REAL_WRITE. A magnitude may even be negative!
|
||||
|
||||
An example function:
|
||||
|
||||
/* FOO_FROM_REG and FOO_TO_REG translate between scaled values and
|
||||
register values. Note the use of the read cache. */
|
||||
void foo_in(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct foo_data *data = client->data;
|
||||
int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 2;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
/* Update the readings cache (if necessary) */
|
||||
foo_update_client(client);
|
||||
/* Get the readings from the cache */
|
||||
results[0] = FOO_FROM_REG(data->foo_func_base[nr]);
|
||||
results[1] = FOO_FROM_REG(data->foo_func_more[nr]);
|
||||
results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]);
|
||||
*nrels_mag = 2;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
if (*nrels_mag >= 1) {
|
||||
/* Update the cache */
|
||||
data->foo_base[nr] = FOO_TO_REG(results[0]);
|
||||
/* Update the chip */
|
||||
foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]);
|
||||
}
|
||||
if (*nrels_mag >= 2) {
|
||||
/* Update the cache */
|
||||
data->foo_more[nr] = FOO_TO_REG(results[1]);
|
||||
/* Update the chip */
|
||||
foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
----------------------------
|
||||
|
||||
H. Peter Anvin <hpa@zytor.com>
|
||||
Last update 2007-01-26
|
||||
Last update 2007-03-06
|
||||
|
||||
On the i386 platform, the Linux kernel uses a rather complicated boot
|
||||
convention. This has evolved partially due to historical aspects, as
|
||||
@ -35,9 +35,13 @@ Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible
|
||||
initrd address available to the bootloader.
|
||||
|
||||
Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes.
|
||||
|
||||
Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable.
|
||||
Introduce relocatable_kernel and kernel_alignment fields.
|
||||
|
||||
Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of
|
||||
the boot command line
|
||||
|
||||
|
||||
**** MEMORY LAYOUT
|
||||
|
||||
@ -133,6 +137,8 @@ Offset Proto Name Meaning
|
||||
022C/4 2.03+ initrd_addr_max Highest legal initrd address
|
||||
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
|
||||
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
|
||||
0235/3 N/A pad2 Unused
|
||||
0238/4 2.06+ cmdline_size Maximum size of the kernel command line
|
||||
|
||||
(1) For backwards compatibility, if the setup_sects field contains 0, the
|
||||
real value is 4.
|
||||
@ -233,6 +239,12 @@ filled out, however:
|
||||
if your ramdisk is exactly 131072 bytes long and this field is
|
||||
0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
|
||||
|
||||
cmdline_size:
|
||||
The maximum size of the command line without the terminating
|
||||
zero. This means that the command line can contain at most
|
||||
cmdline_size characters. With protocol version 2.05 and
|
||||
earlier, the maximum size was 255.
|
||||
|
||||
|
||||
**** THE KERNEL COMMAND LINE
|
||||
|
||||
@ -241,11 +253,10 @@ loader to communicate with the kernel. Some of its options are also
|
||||
relevant to the boot loader itself, see "special command line options"
|
||||
below.
|
||||
|
||||
The kernel command line is a null-terminated string currently up to
|
||||
255 characters long, plus the final null. A string that is too long
|
||||
will be automatically truncated by the kernel, a boot loader may allow
|
||||
a longer command line to be passed to permit future kernels to extend
|
||||
this limit.
|
||||
The kernel command line is a null-terminated string. The maximum
|
||||
length can be retrieved from the field cmdline_size. Before protocol
|
||||
version 2.06, the maximum was 255 characters. A string that is too
|
||||
long will be automatically truncated by the kernel.
|
||||
|
||||
If the boot protocol version is 2.02 or later, the address of the
|
||||
kernel command line is given by the header field cmd_line_ptr (see
|
||||
|
247
Documentation/ia64/aliasing-test.c
Normal file
247
Documentation/ia64/aliasing-test.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Exercise /dev/mem mmap cases that have been troublesome in the past
|
||||
*
|
||||
* (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int sum;
|
||||
|
||||
int map_mem(char *path, off_t offset, size_t length, int touch)
|
||||
{
|
||||
int fd, rc;
|
||||
void *addr;
|
||||
int *c;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd == -1) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
|
||||
if (addr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
if (touch) {
|
||||
c = (int *) addr;
|
||||
while (c < (int *) (offset + length))
|
||||
sum += *c++;
|
||||
}
|
||||
|
||||
rc = munmap(addr, length);
|
||||
if (rc == -1) {
|
||||
perror("munmap");
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
char *name, *path2;
|
||||
int i, n, r, rc, result = 0;
|
||||
struct stat buf;
|
||||
|
||||
n = scandir(path, &namelist, 0, alphasort);
|
||||
if (n < 0) {
|
||||
perror("scandir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
name = namelist[i]->d_name;
|
||||
|
||||
if (fnmatch(".", name, 0) == 0)
|
||||
goto skip;
|
||||
if (fnmatch("..", name, 0) == 0)
|
||||
goto skip;
|
||||
|
||||
path2 = malloc(strlen(path) + strlen(name) + 3);
|
||||
strcpy(path2, path);
|
||||
strcat(path2, "/");
|
||||
strcat(path2, name);
|
||||
|
||||
if (fnmatch(file, name, 0) == 0) {
|
||||
rc = map_mem(path2, offset, length, touch);
|
||||
if (rc == 0)
|
||||
fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
|
||||
else if (rc > 0)
|
||||
fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
|
||||
else {
|
||||
fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
r = lstat(path2, &buf);
|
||||
if (r == 0 && S_ISDIR(buf.st_mode)) {
|
||||
rc = scan_sysfs(path2, file, offset, length, touch);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
result |= rc;
|
||||
free(path2);
|
||||
|
||||
skip:
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
return rc;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
|
||||
int read_rom(char *path)
|
||||
{
|
||||
int fd, rc;
|
||||
size_t size = 0;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd == -1) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = write(fd, "1", 2);
|
||||
if (rc <= 0) {
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = read(fd, buf, sizeof(buf));
|
||||
if (rc > 0)
|
||||
size += rc;
|
||||
} while (rc > 0);
|
||||
|
||||
close(fd);
|
||||
return size;
|
||||
}
|
||||
|
||||
int scan_rom(char *path, char *file)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
char *name, *path2;
|
||||
int i, n, r, rc, result = 0;
|
||||
struct stat buf;
|
||||
|
||||
n = scandir(path, &namelist, 0, alphasort);
|
||||
if (n < 0) {
|
||||
perror("scandir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
name = namelist[i]->d_name;
|
||||
|
||||
if (fnmatch(".", name, 0) == 0)
|
||||
goto skip;
|
||||
if (fnmatch("..", name, 0) == 0)
|
||||
goto skip;
|
||||
|
||||
path2 = malloc(strlen(path) + strlen(name) + 3);
|
||||
strcpy(path2, path);
|
||||
strcat(path2, "/");
|
||||
strcat(path2, name);
|
||||
|
||||
if (fnmatch(file, name, 0) == 0) {
|
||||
rc = read_rom(path2);
|
||||
|
||||
/*
|
||||
* It's OK if the ROM is unreadable. Maybe there
|
||||
* is no ROM, or some other error ocurred. The
|
||||
* important thing is that no MCA happened.
|
||||
*/
|
||||
if (rc > 0)
|
||||
fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc);
|
||||
else {
|
||||
fprintf(stderr, "PASS: %s not readable\n", path2);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
r = lstat(path2, &buf);
|
||||
if (r == 0 && S_ISDIR(buf.st_mode)) {
|
||||
rc = scan_rom(path2, file);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
result |= rc;
|
||||
free(path2);
|
||||
|
||||
skip:
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
return rc;
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
|
||||
|
||||
/*
|
||||
* It's not safe to blindly read the VGA frame buffer. If you know
|
||||
* how to poke the card the right way, it should respond, but it's
|
||||
* not safe in general. Many machines, e.g., Intel chipsets, cover
|
||||
* up a non-responding card by just returning -1, but others will
|
||||
* report the failure as a machine check.
|
||||
*/
|
||||
if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
|
||||
|
||||
if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
|
||||
|
||||
/*
|
||||
* Often you can map all the individual pieces above (0-0xA0000,
|
||||
* 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
|
||||
* thing at once. This is because the individual pieces use different
|
||||
* attributes, and there's no single attribute supported over the
|
||||
* whole region.
|
||||
*/
|
||||
rc = map_mem("/dev/mem", 0, 1024*1024, 0);
|
||||
if (rc == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
|
||||
else if (rc > 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
|
||||
|
||||
scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
|
||||
scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
|
||||
scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
|
||||
scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
|
||||
|
||||
scan_rom("/sys/devices", "rom");
|
||||
}
|
@ -112,16 +112,6 @@ POTENTIAL ATTRIBUTE ALIASING CASES
|
||||
|
||||
The /dev/mem mmap constraints apply.
|
||||
|
||||
However, since this is for mapping legacy MMIO space, WB access
|
||||
does not make sense. This matters on machines without legacy
|
||||
VGA support: these machines may have WB memory for the entire
|
||||
first megabyte (or even the entire first granule).
|
||||
|
||||
On these machines, we could mmap legacy_mem as WB, which would
|
||||
be safe in terms of attribute aliasing, but X has no way of
|
||||
knowing that it is accessing regular memory, not a frame buffer,
|
||||
so the kernel should fail the mmap rather than doing it with WB.
|
||||
|
||||
read/write of /dev/mem
|
||||
|
||||
This uses copy_from_user(), which implicitly uses a kernel
|
||||
@ -138,14 +128,20 @@ POTENTIAL ATTRIBUTE ALIASING CASES
|
||||
|
||||
ioremap()
|
||||
|
||||
This returns a kernel identity mapping for use inside the
|
||||
kernel.
|
||||
This returns a mapping for use inside the kernel.
|
||||
|
||||
If the region is in kern_memmap, we should use the attribute
|
||||
specified there. Otherwise, if the EFI memory map reports that
|
||||
the entire granule supports WB, we should use that (granules
|
||||
that are partially reserved or occupied by firmware do not appear
|
||||
in kern_memmap). Otherwise, we should use a UC mapping.
|
||||
specified there.
|
||||
|
||||
If the EFI memory map reports that the entire granule supports
|
||||
WB, we should use that (granules that are partially reserved
|
||||
or occupied by firmware do not appear in kern_memmap).
|
||||
|
||||
If the granule contains non-WB memory, but we can cover the
|
||||
region safely with kernel page table mappings, we can use
|
||||
ioremap_page_range() as most other architectures do.
|
||||
|
||||
Failing all of the above, we have to fall back to a UC mapping.
|
||||
|
||||
PAST PROBLEM CASES
|
||||
|
||||
@ -158,7 +154,7 @@ PAST PROBLEM CASES
|
||||
succeed. It may create either WB or UC user mappings, depending
|
||||
on whether the region is in kern_memmap or the EFI memory map.
|
||||
|
||||
mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
|
||||
mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
|
||||
|
||||
See https://bugzilla.novell.com/show_bug.cgi?id=140858.
|
||||
|
||||
@ -171,28 +167,25 @@ PAST PROBLEM CASES
|
||||
so it is safe to use WB mappings.
|
||||
|
||||
The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
|
||||
which will use a granule-sized UC mapping covering 0-0xFFFFF. This
|
||||
granule covers some WB-only memory, but since UC is non-speculative,
|
||||
the processor will never generate an uncacheable reference to the
|
||||
WB-only areas unless the driver explicitly touches them.
|
||||
which uses a granule-sized UC mapping. This granule will cover some
|
||||
WB-only memory, but since UC is non-speculative, the processor will
|
||||
never generate an uncacheable reference to the WB-only areas unless
|
||||
the driver explicitly touches them.
|
||||
|
||||
mmap of 0x0-0xFFFFF legacy_mem by "X"
|
||||
|
||||
If the EFI memory map reports this entire range as WB, there
|
||||
is no VGA MMIO hole, and the mmap should fail or be done with
|
||||
a WB mapping.
|
||||
If the EFI memory map reports that the entire range supports the
|
||||
same attributes, we can allow the mmap (and we will prefer WB if
|
||||
supported, as is the case with HP sx[12]000 machines with VGA
|
||||
disabled).
|
||||
|
||||
There's no easy way for X to determine whether the 0xA0000-0xBFFFF
|
||||
region is a frame buffer or just memory, so I think it's best to
|
||||
just fail this mmap request rather than using a WB mapping. As
|
||||
far as I know, there's no need to map legacy_mem with WB
|
||||
mappings.
|
||||
If EFI reports the range as partly WB and partly UC (as on sx[12]000
|
||||
machines with VGA enabled), we must fail the mmap because there's no
|
||||
safe attribute to use.
|
||||
|
||||
Otherwise, a UC mapping of the entire region is probably safe.
|
||||
The VGA hole means the region will not be in kern_memmap. The
|
||||
HP sx1000 chipset doesn't support UC access to the memory surrounding
|
||||
the VGA hole, but X doesn't need that area anyway and should not
|
||||
reference it.
|
||||
If EFI reports some of the range but not all (as on Intel firmware
|
||||
that doesn't report the VGA frame buffer at all), we should fail the
|
||||
mmap and force the user to map just the specific region of interest.
|
||||
|
||||
mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
|
||||
|
||||
@ -202,6 +195,16 @@ PAST PROBLEM CASES
|
||||
This is a special case of the previous case, and the mmap should
|
||||
fail for the same reason as above.
|
||||
|
||||
read of /sys/devices/.../rom
|
||||
|
||||
For VGA devices, this may cause an ioremap() of 0xC0000. This
|
||||
used to be done with a UC mapping, because the VGA frame buffer
|
||||
at 0xA0000 prevents use of a WB granule. The UC mapping causes
|
||||
an MCA on HP sx[12]000 chipsets.
|
||||
|
||||
We should use WB page table mappings to avoid covering the VGA
|
||||
frame buffer.
|
||||
|
||||
NOTES
|
||||
|
||||
[1] SDM rev 2.2, vol 2, sec 4.4.1.
|
||||
|
1068
Documentation/ia64/err_inject.txt
Normal file
1068
Documentation/ia64/err_inject.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -249,7 +249,7 @@ following files:
|
||||
--> filename: Makefile
|
||||
KERNELDIR := /lib/modules/`uname -r`/build
|
||||
all::
|
||||
$(MAKE) -C $KERNELDIR M=`pwd` $@
|
||||
$(MAKE) -C $(KERNELDIR) M=`pwd` $@
|
||||
|
||||
# Module specific targets
|
||||
genbin:
|
||||
|
@ -64,6 +64,7 @@ parameter is applicable:
|
||||
GENERIC_TIME The generic timeofday code is enabled.
|
||||
NFS Appropriate NFS support is enabled.
|
||||
OSS OSS sound support is enabled.
|
||||
PV_OPS A paravirtualized kernel
|
||||
PARIDE The ParIDE subsystem is enabled.
|
||||
PARISC The PA-RISC architecture is enabled.
|
||||
PCI PCI bus support is enabled.
|
||||
@ -695,8 +696,15 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed
|
||||
See Documentation/ide.txt.
|
||||
|
||||
idle= [HW]
|
||||
Format: idle=poll or idle=halt
|
||||
idle= [X86]
|
||||
Format: idle=poll or idle=mwait
|
||||
Poll forces a polling idle loop that can slightly improves the performance
|
||||
of waking up a idle CPU, but will use a lot of power and make the system
|
||||
run hot. Not recommended.
|
||||
idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose
|
||||
to not use it because it doesn't save as much power as a normal idle
|
||||
loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
|
||||
as idle=poll.
|
||||
|
||||
ignore_loglevel [KNL]
|
||||
Ignore loglevel setting - this will print /all/
|
||||
@ -1157,6 +1165,11 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
|
||||
nomce [IA-32] Machine Check Exception
|
||||
|
||||
noreplace-paravirt [IA-32,PV_OPS] Don't patch paravirt_ops
|
||||
|
||||
noreplace-smp [IA-32,SMP] Don't replace SMP instructions
|
||||
with UP alternatives
|
||||
|
||||
noresidual [PPC] Don't use residual data on PReP machines.
|
||||
|
||||
noresume [SWSUSP] Disables resume and restores original swap
|
||||
@ -1562,6 +1575,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
smart2= [HW]
|
||||
Format: <io1>[,<io2>[,...,<io8>]]
|
||||
|
||||
smp-alt-once [IA-32,SMP] On a hotplug CPU system, only
|
||||
attempt to substitute SMP alternatives once at boot.
|
||||
|
||||
snd-ad1816a= [HW,ALSA]
|
||||
|
||||
snd-ad1848= [HW,ALSA]
|
||||
@ -1820,6 +1836,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
[USBHID] The interval which mice are to be polled at.
|
||||
|
||||
vdso= [IA-32,SH]
|
||||
vdso=2: enable compat VDSO (default with COMPAT_VDSO)
|
||||
vdso=1: enable VDSO (default)
|
||||
vdso=0: disable VDSO mapping
|
||||
|
||||
|
@ -124,10 +124,6 @@ initialization with a pointer to a structure describing the driver
|
||||
|
||||
err_handler See Documentation/pci-error-recovery.txt
|
||||
|
||||
multithread_probe Enable multi-threaded probe/scan. Driver must
|
||||
provide its own locking/syncronization for init
|
||||
operations if this is enabled.
|
||||
|
||||
|
||||
The ID table is an array of struct pci_device_id entries ending with an
|
||||
all-zero entry. Each entry consists of:
|
||||
@ -163,9 +159,9 @@ echo "vendor device subvendor subdevice class class_mask driver_data" > \
|
||||
/sys/bus/pci/drivers/{driver}/new_id
|
||||
|
||||
All fields are passed in as hexadecimal values (no leading 0x).
|
||||
Users need pass only as many fields as necessary:
|
||||
o vendor, device, subvendor, and subdevice fields default
|
||||
to PCI_ANY_ID (FFFFFFFF),
|
||||
The vendor and device fields are mandatory, the others are optional. Users
|
||||
need pass only as many optional fields as necessary:
|
||||
o subvendor and subdevice fields default to PCI_ANY_ID (FFFFFFFF)
|
||||
o class and classmask fields default to 0
|
||||
o driver_data defaults to 0UL.
|
||||
|
||||
@ -549,8 +545,6 @@ pci_find_slot() Find pci_dev corresponding to given bus and
|
||||
pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3)
|
||||
pci_find_capability() Find specified capability in device's capability
|
||||
list.
|
||||
pci_module_init() Inline helper function for ensuring correct
|
||||
pci_driver initialization and error handling.
|
||||
pci_resource_start() Returns bus start address for a given PCI region
|
||||
pci_resource_end() Returns bus end address for a given PCI region
|
||||
pci_resource_len() Returns the byte length of a PCI region
|
||||
|
30
Documentation/pcmcia/driver.txt
Normal file
30
Documentation/pcmcia/driver.txt
Normal file
@ -0,0 +1,30 @@
|
||||
PCMCIA Driver
|
||||
-------------
|
||||
|
||||
|
||||
sysfs
|
||||
-----
|
||||
|
||||
New PCMCIA IDs may be added to a device driver pcmcia_device_id table at
|
||||
runtime as shown below:
|
||||
|
||||
echo "match_flags manf_id card_id func_id function device_no \
|
||||
prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \
|
||||
/sys/bus/pcmcia/drivers/{driver}/new_id
|
||||
|
||||
All fields are passed in as hexadecimal values (no leading 0x).
|
||||
The meaning is described in the PCMCIA specification, the match_flags is
|
||||
a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants
|
||||
defined in include/linux/mod_devicetable.h.
|
||||
|
||||
Once added, the driver probe routine will be invoked for any unclaimed
|
||||
PCMCIA device listed in its (newly updated) pcmcia_device_id list.
|
||||
|
||||
A common use-case is to add a new device according to the manufacturer ID
|
||||
and the card ID (form the manf_id and card_id file in the device tree).
|
||||
For this, just use:
|
||||
|
||||
echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \
|
||||
/sys/bus/pcmcia/drivers/{driver}/new_id
|
||||
|
||||
after loading the driver.
|
@ -34,8 +34,12 @@ for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then,
|
||||
we are able to look in the log messages and work out, for example, which code
|
||||
is being slow and which device drivers are misbehaving.
|
||||
|
||||
Reading from this file will display what the mode is currently set
|
||||
to. Writing to this file will accept one of
|
||||
Reading from this file will display all supported modes and the currently
|
||||
selected one in brackets, for example
|
||||
|
||||
[shutdown] reboot test testproc
|
||||
|
||||
Writing to this file will accept one of
|
||||
|
||||
'platform' (only if the platform supports it)
|
||||
'shutdown'
|
||||
|
@ -203,7 +203,7 @@ resume
|
||||
|
||||
Usage:
|
||||
|
||||
if (dev->driver && dev->driver->suspend)
|
||||
if (dev->driver && dev->driver->resume)
|
||||
dev->driver->resume(dev)
|
||||
|
||||
The resume callback may be called from any power state, and is always meant to
|
||||
|
@ -37,7 +37,11 @@ Supported Cards/Chipsets
|
||||
9005:0286:9005:029d Adaptec 2420SA (Intruder HP release)
|
||||
9005:0286:9005:02ac Adaptec 1800 (Typhoon44)
|
||||
9005:0285:9005:02b5 Adaptec 5445 (Voodoo44)
|
||||
9005:0285:15d9:02b5 SMC AOC-USAS-S4i
|
||||
9005:0285:15d9:02c9 SMC AOC-USAS-S4iR
|
||||
9005:0285:9005:02b6 Adaptec 5805 (Voodoo80)
|
||||
9005:0285:15d9:02b6 SMC AOC-USAS-S8i
|
||||
9005:0285:15d9:02ca SMC AOC-USAS-S8iR
|
||||
9005:0285:9005:02b7 Adaptec 5085 (Voodoo08)
|
||||
9005:0285:9005:02bb Adaptec 3405 (Marauder40LP)
|
||||
9005:0285:9005:02bc Adaptec 3805 (Marauder80LP)
|
||||
@ -93,6 +97,9 @@ Supported Cards/Chipsets
|
||||
9005:0286:9005:02ae (Aurora Lite ARK)
|
||||
9005:0285:9005:02b0 (Sunrise Lake ARK)
|
||||
9005:0285:9005:02b1 Adaptec (Voodoo 8 internal 8 external)
|
||||
9005:0285:108e:7aac SUN STK RAID REM (Voodoo44 Coyote)
|
||||
9005:0285:108e:0286 SUN SG-XPCIESAS-R-IN (Cougar)
|
||||
9005:0285:108e:0287 SUN SG-XPCIESAS-R-EX (Prometheus)
|
||||
|
||||
People
|
||||
-------------------------
|
||||
|
@ -562,11 +562,6 @@ if only one has a flaw for some SCSI feature, you can disable the
|
||||
support by the driver of this feature at linux start-up and enable
|
||||
this feature after boot-up only for devices that support it safely.
|
||||
|
||||
CONFIG_SCSI_NCR53C8XX_PROFILE_SUPPORT (default answer: n)
|
||||
This option must be set for profiling information to be gathered
|
||||
and printed out through the proc file system. This features may
|
||||
impact performances.
|
||||
|
||||
CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n)
|
||||
Answer "y" if you suspect your mother board to not allow memory mapped I/O.
|
||||
May slow down performance a little. This option is required by
|
||||
|
32
Documentation/sh/clk.txt
Normal file
32
Documentation/sh/clk.txt
Normal file
@ -0,0 +1,32 @@
|
||||
Clock framework on SuperH architecture
|
||||
|
||||
The framework on SH extends existing API by the function clk_set_rate_ex,
|
||||
which prototype is as follows:
|
||||
|
||||
clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id)
|
||||
|
||||
The algo_id parameter is used to specify algorithm used to recalculate clocks,
|
||||
adjanced to clock, specified as first argument. It is assumed that algo_id==0
|
||||
means no changes to adjanced clock
|
||||
|
||||
Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method,
|
||||
if it is present in ops structure. The method should set the clock rate and adjust
|
||||
all needed clocks according to the passed algo_id.
|
||||
Exact values for algo_id are machine-dependend. For the sh7722, the following
|
||||
values are defined:
|
||||
|
||||
NO_CHANGE = 0,
|
||||
IUS_N1_N1, /* I:U = N:1, U:Sh = N:1 */
|
||||
IUS_322, /* I:U:Sh = 3:2:2 */
|
||||
IUS_522, /* I:U:Sh = 5:2:2 */
|
||||
IUS_N11, /* I:U:Sh = N:1:1 */
|
||||
SB_N1, /* Sh:B = N:1 */
|
||||
SB3_N1, /* Sh:B3 = N:1 */
|
||||
SB3_32, /* Sh:B3 = 3:2 */
|
||||
SB3_43, /* Sh:B3 = 4:3 */
|
||||
SB3_54, /* Sh:B3 = 5:4 */
|
||||
BP_N1, /* B:P = N:1 */
|
||||
IP_N1 /* I:P = N:1 */
|
||||
|
||||
Each of these constants means relation between clocks that can be set via the FRQCR
|
||||
register
|
@ -62,7 +62,7 @@ static struct resource pxa_spi_nssp_resources[] = {
|
||||
|
||||
static struct pxa2xx_spi_master pxa_nssp_master_info = {
|
||||
.ssp_type = PXA25x_NSSP, /* Type of SSP */
|
||||
.clock_enable = CKEN9_NSSP, /* NSSP Peripheral clock */
|
||||
.clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */
|
||||
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
|
||||
.enable_dma = 1, /* Enables NSSP DMA */
|
||||
};
|
||||
|
@ -197,11 +197,22 @@ and may not be fast.
|
||||
|
||||
panic_on_oom
|
||||
|
||||
This enables or disables panic on out-of-memory feature. If this is set to 1,
|
||||
the kernel panics when out-of-memory happens. If this is set to 0, the kernel
|
||||
will kill some rogue process, called oom_killer. Usually, oom_killer can kill
|
||||
rogue processes and system will survive. If you want to panic the system
|
||||
rather than killing rogue processes, set this to 1.
|
||||
This enables or disables panic on out-of-memory feature.
|
||||
|
||||
If this is set to 0, the kernel will kill some rogue process,
|
||||
called oom_killer. Usually, oom_killer can kill rogue processes and
|
||||
system will survive.
|
||||
|
||||
If this is set to 1, the kernel panics when out-of-memory happens.
|
||||
However, if a process limits using nodes by mempolicy/cpusets,
|
||||
and those nodes become memory exhaustion status, one process
|
||||
may be killed by oom-killer. No panic occurs in this case.
|
||||
Because other nodes' memory may be free. This means system total status
|
||||
may be not fatal yet.
|
||||
|
||||
If this is set to 2, the kernel panics compulsorily even on the
|
||||
above-mentioned.
|
||||
|
||||
The default value is 0.
|
||||
|
||||
1 and 2 are for failover of clustering. Please select either
|
||||
according to your policy of failover.
|
||||
|
@ -1,6 +1,6 @@
|
||||
Linux Magic System Request Key Hacks
|
||||
Documentation for sysrq.c
|
||||
Last update: 2007-JAN-06
|
||||
Last update: 2007-MAR-14
|
||||
|
||||
* What is the magic SysRq key?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -75,7 +75,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
|
||||
|
||||
'f' - Will call oom_kill to kill a memory hog process.
|
||||
|
||||
'g' - Used by kgdb on ppc platforms.
|
||||
'g' - Used by kgdb on ppc and sh platforms.
|
||||
|
||||
'h' - Will display help (actually any other key than those listed
|
||||
above will display help. but 'h' is easy to remember :-)
|
||||
|
@ -42,7 +42,7 @@ ConnectTech WhiteHEAT 4 port converter
|
||||
http://www.connecttech.com
|
||||
|
||||
For any questions or problems with this driver, please contact
|
||||
Stuart MacDonald at stuartm@connecttech.com
|
||||
Connect Tech's Support Department at support@connecttech.com
|
||||
|
||||
|
||||
HandSpring Visor, Palm USB, and Clié USB driver
|
||||
|
943
Documentation/vm/slabinfo.c
Normal file
943
Documentation/vm/slabinfo.c
Normal file
@ -0,0 +1,943 @@
|
||||
/*
|
||||
* Slabinfo: Tool to get reports about slabs
|
||||
*
|
||||
* (C) 2007 sgi, Christoph Lameter <clameter@sgi.com>
|
||||
*
|
||||
* Compile by:
|
||||
*
|
||||
* gcc -o slabinfo slabinfo.c
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <getopt.h>
|
||||
#include <regex.h>
|
||||
|
||||
#define MAX_SLABS 500
|
||||
#define MAX_ALIASES 500
|
||||
#define MAX_NODES 1024
|
||||
|
||||
struct slabinfo {
|
||||
char *name;
|
||||
int alias;
|
||||
int refs;
|
||||
int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
|
||||
int hwcache_align, object_size, objs_per_slab;
|
||||
int sanity_checks, slab_size, store_user, trace;
|
||||
int order, poison, reclaim_account, red_zone;
|
||||
unsigned long partial, objects, slabs;
|
||||
int numa[MAX_NODES];
|
||||
int numa_partial[MAX_NODES];
|
||||
} slabinfo[MAX_SLABS];
|
||||
|
||||
struct aliasinfo {
|
||||
char *name;
|
||||
char *ref;
|
||||
struct slabinfo *slab;
|
||||
} aliasinfo[MAX_ALIASES];
|
||||
|
||||
int slabs = 0;
|
||||
int aliases = 0;
|
||||
int alias_targets = 0;
|
||||
int highest_node = 0;
|
||||
|
||||
char buffer[4096];
|
||||
|
||||
int show_alias = 0;
|
||||
int show_slab = 0;
|
||||
int skip_zero = 1;
|
||||
int show_numa = 0;
|
||||
int show_track = 0;
|
||||
int show_first_alias = 0;
|
||||
int validate = 0;
|
||||
int shrink = 0;
|
||||
int show_inverted = 0;
|
||||
int show_single_ref = 0;
|
||||
int show_totals = 0;
|
||||
int sort_size = 0;
|
||||
|
||||
int page_size;
|
||||
|
||||
regex_t pattern;
|
||||
|
||||
void fatal(const char *x, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, x);
|
||||
vfprintf(stderr, x, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("slabinfo [-ahnpvtsz] [slab-regexp]\n"
|
||||
"-a|--aliases Show aliases\n"
|
||||
"-h|--help Show usage information\n"
|
||||
"-n|--numa Show NUMA information\n"
|
||||
"-s|--shrink Shrink slabs\n"
|
||||
"-v|--validate Validate slabs\n"
|
||||
"-t|--tracking Show alloc/free information\n"
|
||||
"-T|--Totals Show summary information\n"
|
||||
"-l|--slabs Show slabs\n"
|
||||
"-S|--Size Sort by size\n"
|
||||
"-z|--zero Include empty slabs\n"
|
||||
"-f|--first-alias Show first alias\n"
|
||||
"-i|--inverted Inverted list\n"
|
||||
"-1|--1ref Single reference\n"
|
||||
);
|
||||
}
|
||||
|
||||
unsigned long read_obj(char *name)
|
||||
{
|
||||
FILE *f = fopen(name, "r");
|
||||
|
||||
if (!f)
|
||||
buffer[0] = 0;
|
||||
else {
|
||||
if (!fgets(buffer,sizeof(buffer), f))
|
||||
buffer[0] = 0;
|
||||
fclose(f);
|
||||
if (buffer[strlen(buffer)] == '\n')
|
||||
buffer[strlen(buffer)] = 0;
|
||||
}
|
||||
return strlen(buffer);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the contents of an attribute
|
||||
*/
|
||||
unsigned long get_obj(char *name)
|
||||
{
|
||||
if (!read_obj(name))
|
||||
return 0;
|
||||
|
||||
return atol(buffer);
|
||||
}
|
||||
|
||||
unsigned long get_obj_and_str(char *name, char **x)
|
||||
{
|
||||
unsigned long result = 0;
|
||||
char *p;
|
||||
|
||||
*x = NULL;
|
||||
|
||||
if (!read_obj(name)) {
|
||||
x = NULL;
|
||||
return 0;
|
||||
}
|
||||
result = strtoul(buffer, &p, 10);
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
if (*p)
|
||||
*x = strdup(p);
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_obj(struct slabinfo *s, char *name, int n)
|
||||
{
|
||||
char x[100];
|
||||
|
||||
sprintf(x, "%s/%s", s->name, name);
|
||||
|
||||
FILE *f = fopen(x, "w");
|
||||
|
||||
if (!f)
|
||||
fatal("Cannot write to %s\n", x);
|
||||
|
||||
fprintf(f, "%d\n", n);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a size string together
|
||||
*/
|
||||
int store_size(char *buffer, unsigned long value)
|
||||
{
|
||||
unsigned long divisor = 1;
|
||||
char trailer = 0;
|
||||
int n;
|
||||
|
||||
if (value > 1000000000UL) {
|
||||
divisor = 100000000UL;
|
||||
trailer = 'G';
|
||||
} else if (value > 1000000UL) {
|
||||
divisor = 100000UL;
|
||||
trailer = 'M';
|
||||
} else if (value > 1000UL) {
|
||||
divisor = 100;
|
||||
trailer = 'K';
|
||||
}
|
||||
|
||||
value /= divisor;
|
||||
n = sprintf(buffer, "%ld",value);
|
||||
if (trailer) {
|
||||
buffer[n] = trailer;
|
||||
n++;
|
||||
buffer[n] = 0;
|
||||
}
|
||||
if (divisor != 1) {
|
||||
memmove(buffer + n - 2, buffer + n - 3, 4);
|
||||
buffer[n-2] = '.';
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void decode_numa_list(int *numa, char *t)
|
||||
{
|
||||
int node;
|
||||
int nr;
|
||||
|
||||
memset(numa, 0, MAX_NODES * sizeof(int));
|
||||
|
||||
while (*t == 'N') {
|
||||
t++;
|
||||
node = strtoul(t, &t, 10);
|
||||
if (*t == '=') {
|
||||
t++;
|
||||
nr = strtoul(t, &t, 10);
|
||||
numa[node] = nr;
|
||||
if (node > highest_node)
|
||||
highest_node = node;
|
||||
}
|
||||
while (*t == ' ')
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
void slab_validate(struct slabinfo *s)
|
||||
{
|
||||
set_obj(s, "validate", 1);
|
||||
}
|
||||
|
||||
void slab_shrink(struct slabinfo *s)
|
||||
{
|
||||
set_obj(s, "shrink", 1);
|
||||
}
|
||||
|
||||
int line = 0;
|
||||
|
||||
void first_line(void)
|
||||
{
|
||||
printf("Name Objects Objsize Space "
|
||||
"Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the shortest alias of a slab
|
||||
*/
|
||||
struct aliasinfo *find_one_alias(struct slabinfo *find)
|
||||
{
|
||||
struct aliasinfo *a;
|
||||
struct aliasinfo *best = NULL;
|
||||
|
||||
for(a = aliasinfo;a < aliasinfo + aliases; a++) {
|
||||
if (a->slab == find &&
|
||||
(!best || strlen(best->name) < strlen(a->name))) {
|
||||
best = a;
|
||||
if (strncmp(a->name,"kmall", 5) == 0)
|
||||
return best;
|
||||
}
|
||||
}
|
||||
if (best)
|
||||
return best;
|
||||
fatal("Cannot find alias for %s\n", find->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long slab_size(struct slabinfo *s)
|
||||
{
|
||||
return s->slabs * (page_size << s->order);
|
||||
}
|
||||
|
||||
|
||||
void slabcache(struct slabinfo *s)
|
||||
{
|
||||
char size_str[20];
|
||||
char dist_str[40];
|
||||
char flags[20];
|
||||
char *p = flags;
|
||||
|
||||
if (skip_zero && !s->slabs)
|
||||
return;
|
||||
|
||||
store_size(size_str, slab_size(s));
|
||||
sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs);
|
||||
|
||||
if (!line++)
|
||||
first_line();
|
||||
|
||||
if (s->aliases)
|
||||
*p++ = '*';
|
||||
if (s->cache_dma)
|
||||
*p++ = 'd';
|
||||
if (s->hwcache_align)
|
||||
*p++ = 'A';
|
||||
if (s->poison)
|
||||
*p++ = 'P';
|
||||
if (s->reclaim_account)
|
||||
*p++ = 'a';
|
||||
if (s->red_zone)
|
||||
*p++ = 'Z';
|
||||
if (s->sanity_checks)
|
||||
*p++ = 'F';
|
||||
if (s->store_user)
|
||||
*p++ = 'U';
|
||||
if (s->trace)
|
||||
*p++ = 'T';
|
||||
|
||||
*p = 0;
|
||||
printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
|
||||
s->name, s->objects, s->object_size, size_str, dist_str,
|
||||
s->objs_per_slab, s->order,
|
||||
s->slabs ? (s->partial * 100) / s->slabs : 100,
|
||||
s->slabs ? (s->objects * s->object_size * 100) /
|
||||
(s->slabs * (page_size << s->order)) : 100,
|
||||
flags);
|
||||
}
|
||||
|
||||
void slab_numa(struct slabinfo *s)
|
||||
{
|
||||
int node;
|
||||
|
||||
if (!highest_node)
|
||||
fatal("No NUMA information available.\n");
|
||||
|
||||
if (skip_zero && !s->slabs)
|
||||
return;
|
||||
|
||||
if (!line) {
|
||||
printf("\nSlab Node ");
|
||||
for(node = 0; node <= highest_node; node++)
|
||||
printf(" %4d", node);
|
||||
printf("\n----------------------");
|
||||
for(node = 0; node <= highest_node; node++)
|
||||
printf("-----");
|
||||
printf("\n");
|
||||
}
|
||||
printf("%-21s ", s->name);
|
||||
for(node = 0; node <= highest_node; node++) {
|
||||
char b[20];
|
||||
|
||||
store_size(b, s->numa[node]);
|
||||
printf(" %4s", b);
|
||||
}
|
||||
printf("\n");
|
||||
line++;
|
||||
}
|
||||
|
||||
void show_tracking(struct slabinfo *s)
|
||||
{
|
||||
printf("\n%s: Calls to allocate a slab object\n", s->name);
|
||||
printf("---------------------------------------------------\n");
|
||||
if (read_obj("alloc_calls"))
|
||||
printf(buffer);
|
||||
|
||||
printf("%s: Calls to free a slab object\n", s->name);
|
||||
printf("-----------------------------------------------\n");
|
||||
if (read_obj("free_calls"))
|
||||
printf(buffer);
|
||||
|
||||
}
|
||||
|
||||
void totals(void)
|
||||
{
|
||||
struct slabinfo *s;
|
||||
|
||||
int used_slabs = 0;
|
||||
char b1[20], b2[20], b3[20], b4[20];
|
||||
unsigned long long max = 1ULL << 63;
|
||||
|
||||
/* Object size */
|
||||
unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
|
||||
|
||||
/* Number of partial slabs in a slabcache */
|
||||
unsigned long long min_partial = max, max_partial = 0,
|
||||
avg_partial, total_partial = 0;
|
||||
|
||||
/* Number of slabs in a slab cache */
|
||||
unsigned long long min_slabs = max, max_slabs = 0,
|
||||
avg_slabs, total_slabs = 0;
|
||||
|
||||
/* Size of the whole slab */
|
||||
unsigned long long min_size = max, max_size = 0,
|
||||
avg_size, total_size = 0;
|
||||
|
||||
/* Bytes used for object storage in a slab */
|
||||
unsigned long long min_used = max, max_used = 0,
|
||||
avg_used, total_used = 0;
|
||||
|
||||
/* Waste: Bytes used for alignment and padding */
|
||||
unsigned long long min_waste = max, max_waste = 0,
|
||||
avg_waste, total_waste = 0;
|
||||
/* Number of objects in a slab */
|
||||
unsigned long long min_objects = max, max_objects = 0,
|
||||
avg_objects, total_objects = 0;
|
||||
/* Waste per object */
|
||||
unsigned long long min_objwaste = max,
|
||||
max_objwaste = 0, avg_objwaste,
|
||||
total_objwaste = 0;
|
||||
|
||||
/* Memory per object */
|
||||
unsigned long long min_memobj = max,
|
||||
max_memobj = 0, avg_memobj,
|
||||
total_objsize = 0;
|
||||
|
||||
/* Percentage of partial slabs per slab */
|
||||
unsigned long min_ppart = 100, max_ppart = 0,
|
||||
avg_ppart, total_ppart = 0;
|
||||
|
||||
/* Number of objects in partial slabs */
|
||||
unsigned long min_partobj = max, max_partobj = 0,
|
||||
avg_partobj, total_partobj = 0;
|
||||
|
||||
/* Percentage of partial objects of all objects in a slab */
|
||||
unsigned long min_ppartobj = 100, max_ppartobj = 0,
|
||||
avg_ppartobj, total_ppartobj = 0;
|
||||
|
||||
|
||||
for (s = slabinfo; s < slabinfo + slabs; s++) {
|
||||
unsigned long long size;
|
||||
unsigned long used;
|
||||
unsigned long long wasted;
|
||||
unsigned long long objwaste;
|
||||
long long objects_in_partial_slabs;
|
||||
unsigned long percentage_partial_slabs;
|
||||
unsigned long percentage_partial_objs;
|
||||
|
||||
if (!s->slabs || !s->objects)
|
||||
continue;
|
||||
|
||||
used_slabs++;
|
||||
|
||||
size = slab_size(s);
|
||||
used = s->objects * s->object_size;
|
||||
wasted = size - used;
|
||||
objwaste = s->slab_size - s->object_size;
|
||||
|
||||
objects_in_partial_slabs = s->objects -
|
||||
(s->slabs - s->partial - s ->cpu_slabs) *
|
||||
s->objs_per_slab;
|
||||
|
||||
if (objects_in_partial_slabs < 0)
|
||||
objects_in_partial_slabs = 0;
|
||||
|
||||
percentage_partial_slabs = s->partial * 100 / s->slabs;
|
||||
if (percentage_partial_slabs > 100)
|
||||
percentage_partial_slabs = 100;
|
||||
|
||||
percentage_partial_objs = objects_in_partial_slabs * 100
|
||||
/ s->objects;
|
||||
|
||||
if (percentage_partial_objs > 100)
|
||||
percentage_partial_objs = 100;
|
||||
|
||||
if (s->object_size < min_objsize)
|
||||
min_objsize = s->object_size;
|
||||
if (s->partial < min_partial)
|
||||
min_partial = s->partial;
|
||||
if (s->slabs < min_slabs)
|
||||
min_slabs = s->slabs;
|
||||
if (size < min_size)
|
||||
min_size = size;
|
||||
if (wasted < min_waste)
|
||||
min_waste = wasted;
|
||||
if (objwaste < min_objwaste)
|
||||
min_objwaste = objwaste;
|
||||
if (s->objects < min_objects)
|
||||
min_objects = s->objects;
|
||||
if (used < min_used)
|
||||
min_used = used;
|
||||
if (objects_in_partial_slabs < min_partobj)
|
||||
min_partobj = objects_in_partial_slabs;
|
||||
if (percentage_partial_slabs < min_ppart)
|
||||
min_ppart = percentage_partial_slabs;
|
||||
if (percentage_partial_objs < min_ppartobj)
|
||||
min_ppartobj = percentage_partial_objs;
|
||||
if (s->slab_size < min_memobj)
|
||||
min_memobj = s->slab_size;
|
||||
|
||||
if (s->object_size > max_objsize)
|
||||
max_objsize = s->object_size;
|
||||
if (s->partial > max_partial)
|
||||
max_partial = s->partial;
|
||||
if (s->slabs > max_slabs)
|
||||
max_slabs = s->slabs;
|
||||
if (size > max_size)
|
||||
max_size = size;
|
||||
if (wasted > max_waste)
|
||||
max_waste = wasted;
|
||||
if (objwaste > max_objwaste)
|
||||
max_objwaste = objwaste;
|
||||
if (s->objects > max_objects)
|
||||
max_objects = s->objects;
|
||||
if (used > max_used)
|
||||
max_used = used;
|
||||
if (objects_in_partial_slabs > max_partobj)
|
||||
max_partobj = objects_in_partial_slabs;
|
||||
if (percentage_partial_slabs > max_ppart)
|
||||
max_ppart = percentage_partial_slabs;
|
||||
if (percentage_partial_objs > max_ppartobj)
|
||||
max_ppartobj = percentage_partial_objs;
|
||||
if (s->slab_size > max_memobj)
|
||||
max_memobj = s->slab_size;
|
||||
|
||||
total_partial += s->partial;
|
||||
total_slabs += s->slabs;
|
||||
total_size += size;
|
||||
total_waste += wasted;
|
||||
|
||||
total_objects += s->objects;
|
||||
total_used += used;
|
||||
total_partobj += objects_in_partial_slabs;
|
||||
total_ppart += percentage_partial_slabs;
|
||||
total_ppartobj += percentage_partial_objs;
|
||||
|
||||
total_objwaste += s->objects * objwaste;
|
||||
total_objsize += s->objects * s->slab_size;
|
||||
}
|
||||
|
||||
if (!total_objects) {
|
||||
printf("No objects\n");
|
||||
return;
|
||||
}
|
||||
if (!used_slabs) {
|
||||
printf("No slabs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Per slab averages */
|
||||
avg_partial = total_partial / used_slabs;
|
||||
avg_slabs = total_slabs / used_slabs;
|
||||
avg_size = total_size / used_slabs;
|
||||
avg_waste = total_waste / used_slabs;
|
||||
|
||||
avg_objects = total_objects / used_slabs;
|
||||
avg_used = total_used / used_slabs;
|
||||
avg_partobj = total_partobj / used_slabs;
|
||||
avg_ppart = total_ppart / used_slabs;
|
||||
avg_ppartobj = total_ppartobj / used_slabs;
|
||||
|
||||
/* Per object object sizes */
|
||||
avg_objsize = total_used / total_objects;
|
||||
avg_objwaste = total_objwaste / total_objects;
|
||||
avg_partobj = total_partobj * 100 / total_objects;
|
||||
avg_memobj = total_objsize / total_objects;
|
||||
|
||||
printf("Slabcache Totals\n");
|
||||
printf("----------------\n");
|
||||
printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n",
|
||||
slabs, aliases, alias_targets, used_slabs);
|
||||
|
||||
store_size(b1, total_size);store_size(b2, total_waste);
|
||||
store_size(b3, total_waste * 100 / total_used);
|
||||
printf("Memory used: %6s # Loss : %6s MRatio: %6s%%\n", b1, b2, b3);
|
||||
|
||||
store_size(b1, total_objects);store_size(b2, total_partobj);
|
||||
store_size(b3, total_partobj * 100 / total_objects);
|
||||
printf("# Objects : %6s # PartObj: %6s ORatio: %6s%%\n", b1, b2, b3);
|
||||
|
||||
printf("\n");
|
||||
printf("Per Cache Average Min Max Total\n");
|
||||
printf("---------------------------------------------------------\n");
|
||||
|
||||
store_size(b1, avg_objects);store_size(b2, min_objects);
|
||||
store_size(b3, max_objects);store_size(b4, total_objects);
|
||||
printf("#Objects %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_slabs);store_size(b2, min_slabs);
|
||||
store_size(b3, max_slabs);store_size(b4, total_slabs);
|
||||
printf("#Slabs %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_partial);store_size(b2, min_partial);
|
||||
store_size(b3, max_partial);store_size(b4, total_partial);
|
||||
printf("#PartSlab %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
store_size(b1, avg_ppart);store_size(b2, min_ppart);
|
||||
store_size(b3, max_ppart);
|
||||
store_size(b4, total_partial * 100 / total_slabs);
|
||||
printf("%%PartSlab %10s%% %10s%% %10s%% %10s%%\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_partobj);store_size(b2, min_partobj);
|
||||
store_size(b3, max_partobj);
|
||||
store_size(b4, total_partobj);
|
||||
printf("PartObjs %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
|
||||
store_size(b3, max_ppartobj);
|
||||
store_size(b4, total_partobj * 100 / total_objects);
|
||||
printf("%% PartObj %10s%% %10s%% %10s%% %10s%%\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_size);store_size(b2, min_size);
|
||||
store_size(b3, max_size);store_size(b4, total_size);
|
||||
printf("Memory %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_used);store_size(b2, min_used);
|
||||
store_size(b3, max_used);store_size(b4, total_used);
|
||||
printf("Used %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
store_size(b1, avg_waste);store_size(b2, min_waste);
|
||||
store_size(b3, max_waste);store_size(b4, total_waste);
|
||||
printf("Loss %10s %10s %10s %10s\n",
|
||||
b1, b2, b3, b4);
|
||||
|
||||
printf("\n");
|
||||
printf("Per Object Average Min Max\n");
|
||||
printf("---------------------------------------------\n");
|
||||
|
||||
store_size(b1, avg_memobj);store_size(b2, min_memobj);
|
||||
store_size(b3, max_memobj);
|
||||
printf("Memory %10s %10s %10s\n",
|
||||
b1, b2, b3);
|
||||
store_size(b1, avg_objsize);store_size(b2, min_objsize);
|
||||
store_size(b3, max_objsize);
|
||||
printf("User %10s %10s %10s\n",
|
||||
b1, b2, b3);
|
||||
|
||||
store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
|
||||
store_size(b3, max_objwaste);
|
||||
printf("Loss %10s %10s %10s\n",
|
||||
b1, b2, b3);
|
||||
}
|
||||
|
||||
void sort_slabs(void)
|
||||
{
|
||||
struct slabinfo *s1,*s2;
|
||||
|
||||
for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
|
||||
for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
|
||||
int result;
|
||||
|
||||
if (sort_size)
|
||||
result = slab_size(s1) < slab_size(s2);
|
||||
else
|
||||
result = strcasecmp(s1->name, s2->name);
|
||||
|
||||
if (show_inverted)
|
||||
result = -result;
|
||||
|
||||
if (result > 0) {
|
||||
struct slabinfo t;
|
||||
|
||||
memcpy(&t, s1, sizeof(struct slabinfo));
|
||||
memcpy(s1, s2, sizeof(struct slabinfo));
|
||||
memcpy(s2, &t, sizeof(struct slabinfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sort_aliases(void)
|
||||
{
|
||||
struct aliasinfo *a1,*a2;
|
||||
|
||||
for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
|
||||
for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
|
||||
char *n1, *n2;
|
||||
|
||||
n1 = a1->name;
|
||||
n2 = a2->name;
|
||||
if (show_alias && !show_inverted) {
|
||||
n1 = a1->ref;
|
||||
n2 = a2->ref;
|
||||
}
|
||||
if (strcasecmp(n1, n2) > 0) {
|
||||
struct aliasinfo t;
|
||||
|
||||
memcpy(&t, a1, sizeof(struct aliasinfo));
|
||||
memcpy(a1, a2, sizeof(struct aliasinfo));
|
||||
memcpy(a2, &t, sizeof(struct aliasinfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void link_slabs(void)
|
||||
{
|
||||
struct aliasinfo *a;
|
||||
struct slabinfo *s;
|
||||
|
||||
for (a = aliasinfo; a < aliasinfo + aliases; a++) {
|
||||
|
||||
for(s = slabinfo; s < slabinfo + slabs; s++)
|
||||
if (strcmp(a->ref, s->name) == 0) {
|
||||
a->slab = s;
|
||||
s->refs++;
|
||||
break;
|
||||
}
|
||||
if (s == slabinfo + slabs)
|
||||
fatal("Unresolved alias %s\n", a->ref);
|
||||
}
|
||||
}
|
||||
|
||||
void alias(void)
|
||||
{
|
||||
struct aliasinfo *a;
|
||||
char *active = NULL;
|
||||
|
||||
sort_aliases();
|
||||
link_slabs();
|
||||
|
||||
for(a = aliasinfo; a < aliasinfo + aliases; a++) {
|
||||
|
||||
if (!show_single_ref && a->slab->refs == 1)
|
||||
continue;
|
||||
|
||||
if (!show_inverted) {
|
||||
if (active) {
|
||||
if (strcmp(a->slab->name, active) == 0) {
|
||||
printf(" %s", a->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
printf("\n%-20s <- %s", a->slab->name, a->name);
|
||||
active = a->slab->name;
|
||||
}
|
||||
else
|
||||
printf("%-20s -> %s\n", a->name, a->slab->name);
|
||||
}
|
||||
if (active)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void rename_slabs(void)
|
||||
{
|
||||
struct slabinfo *s;
|
||||
struct aliasinfo *a;
|
||||
|
||||
for (s = slabinfo; s < slabinfo + slabs; s++) {
|
||||
if (*s->name != ':')
|
||||
continue;
|
||||
|
||||
if (s->refs > 1 && !show_first_alias)
|
||||
continue;
|
||||
|
||||
a = find_one_alias(s);
|
||||
|
||||
s->name = a->name;
|
||||
}
|
||||
}
|
||||
|
||||
int slab_mismatch(char *slab)
|
||||
{
|
||||
return regexec(&pattern, slab, 0, NULL, 0);
|
||||
}
|
||||
|
||||
void read_slab_dir(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
struct slabinfo *slab = slabinfo;
|
||||
struct aliasinfo *alias = aliasinfo;
|
||||
char *p;
|
||||
char *t;
|
||||
int count;
|
||||
|
||||
dir = opendir(".");
|
||||
while ((de = readdir(dir))) {
|
||||
if (de->d_name[0] == '.' ||
|
||||
slab_mismatch(de->d_name))
|
||||
continue;
|
||||
switch (de->d_type) {
|
||||
case DT_LNK:
|
||||
alias->name = strdup(de->d_name);
|
||||
count = readlink(de->d_name, buffer, sizeof(buffer));
|
||||
|
||||
if (count < 0)
|
||||
fatal("Cannot read symlink %s\n", de->d_name);
|
||||
|
||||
buffer[count] = 0;
|
||||
p = buffer + count;
|
||||
while (p > buffer && p[-1] != '/')
|
||||
p--;
|
||||
alias->ref = strdup(p);
|
||||
alias++;
|
||||
break;
|
||||
case DT_DIR:
|
||||
if (chdir(de->d_name))
|
||||
fatal("Unable to access slab %s\n", slab->name);
|
||||
slab->name = strdup(de->d_name);
|
||||
slab->alias = 0;
|
||||
slab->refs = 0;
|
||||
slab->aliases = get_obj("aliases");
|
||||
slab->align = get_obj("align");
|
||||
slab->cache_dma = get_obj("cache_dma");
|
||||
slab->cpu_slabs = get_obj("cpu_slabs");
|
||||
slab->destroy_by_rcu = get_obj("destroy_by_rcu");
|
||||
slab->hwcache_align = get_obj("hwcache_align");
|
||||
slab->object_size = get_obj("object_size");
|
||||
slab->objects = get_obj("objects");
|
||||
slab->objs_per_slab = get_obj("objs_per_slab");
|
||||
slab->order = get_obj("order");
|
||||
slab->partial = get_obj("partial");
|
||||
slab->partial = get_obj_and_str("partial", &t);
|
||||
decode_numa_list(slab->numa_partial, t);
|
||||
slab->poison = get_obj("poison");
|
||||
slab->reclaim_account = get_obj("reclaim_account");
|
||||
slab->red_zone = get_obj("red_zone");
|
||||
slab->sanity_checks = get_obj("sanity_checks");
|
||||
slab->slab_size = get_obj("slab_size");
|
||||
slab->slabs = get_obj_and_str("slabs", &t);
|
||||
decode_numa_list(slab->numa, t);
|
||||
slab->store_user = get_obj("store_user");
|
||||
slab->trace = get_obj("trace");
|
||||
chdir("..");
|
||||
if (slab->name[0] == ':')
|
||||
alias_targets++;
|
||||
slab++;
|
||||
break;
|
||||
default :
|
||||
fatal("Unknown file type %lx\n", de->d_type);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
slabs = slab - slabinfo;
|
||||
aliases = alias - aliasinfo;
|
||||
if (slabs > MAX_SLABS)
|
||||
fatal("Too many slabs\n");
|
||||
if (aliases > MAX_ALIASES)
|
||||
fatal("Too many aliases\n");
|
||||
}
|
||||
|
||||
void output_slabs(void)
|
||||
{
|
||||
struct slabinfo *slab;
|
||||
|
||||
for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
|
||||
|
||||
if (slab->alias)
|
||||
continue;
|
||||
|
||||
|
||||
if (show_numa)
|
||||
slab_numa(slab);
|
||||
else
|
||||
if (show_track)
|
||||
show_tracking(slab);
|
||||
else
|
||||
if (validate)
|
||||
slab_validate(slab);
|
||||
else
|
||||
if (shrink)
|
||||
slab_shrink(slab);
|
||||
else {
|
||||
if (show_slab)
|
||||
slabcache(slab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct option opts[] = {
|
||||
{ "aliases", 0, NULL, 'a' },
|
||||
{ "slabs", 0, NULL, 'l' },
|
||||
{ "numa", 0, NULL, 'n' },
|
||||
{ "zero", 0, NULL, 'z' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "validate", 0, NULL, 'v' },
|
||||
{ "first-alias", 0, NULL, 'f' },
|
||||
{ "shrink", 0, NULL, 's' },
|
||||
{ "track", 0, NULL, 't'},
|
||||
{ "inverted", 0, NULL, 'i'},
|
||||
{ "1ref", 0, NULL, '1'},
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int err;
|
||||
char *pattern_source;
|
||||
|
||||
page_size = getpagesize();
|
||||
if (chdir("/sys/slab"))
|
||||
fatal("This kernel does not have SLUB support.\n");
|
||||
|
||||
while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1)
|
||||
switch(c) {
|
||||
case '1':
|
||||
show_single_ref = 1;
|
||||
break;
|
||||
case 'a':
|
||||
show_alias = 1;
|
||||
break;
|
||||
case 'f':
|
||||
show_first_alias = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
case 'i':
|
||||
show_inverted = 1;
|
||||
break;
|
||||
case 'n':
|
||||
show_numa = 1;
|
||||
break;
|
||||
case 's':
|
||||
shrink = 1;
|
||||
break;
|
||||
case 'l':
|
||||
show_slab = 1;
|
||||
break;
|
||||
case 't':
|
||||
show_track = 1;
|
||||
break;
|
||||
case 'v':
|
||||
validate = 1;
|
||||
break;
|
||||
case 'z':
|
||||
skip_zero = 0;
|
||||
break;
|
||||
case 'T':
|
||||
show_totals = 1;
|
||||
break;
|
||||
case 'S':
|
||||
sort_size = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("%s: Invalid option '%c'\n", argv[0], optopt);
|
||||
|
||||
}
|
||||
|
||||
if (!show_slab && !show_alias && !show_track
|
||||
&& !validate && !shrink)
|
||||
show_slab = 1;
|
||||
|
||||
if (argc > optind)
|
||||
pattern_source = argv[optind];
|
||||
else
|
||||
pattern_source = ".*";
|
||||
|
||||
err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
|
||||
if (err)
|
||||
fatal("%s: Invalid pattern '%s' code %d\n",
|
||||
argv[0], pattern_source, err);
|
||||
read_slab_dir();
|
||||
if (show_alias)
|
||||
alias();
|
||||
else
|
||||
if (show_totals)
|
||||
totals();
|
||||
else {
|
||||
link_slabs();
|
||||
rename_slabs();
|
||||
sort_slabs();
|
||||
output_slabs();
|
||||
}
|
||||
return 0;
|
||||
}
|
113
Documentation/vm/slub.txt
Normal file
113
Documentation/vm/slub.txt
Normal file
@ -0,0 +1,113 @@
|
||||
Short users guide for SLUB
|
||||
--------------------------
|
||||
|
||||
First of all slub should transparently replace SLAB. If you enable
|
||||
SLUB then everything should work the same (Note the word "should".
|
||||
There is likely not much value in that word at this point).
|
||||
|
||||
The basic philosophy of SLUB is very different from SLAB. SLAB
|
||||
requires rebuilding the kernel to activate debug options for all
|
||||
SLABS. SLUB always includes full debugging but its off by default.
|
||||
SLUB can enable debugging only for selected slabs in order to avoid
|
||||
an impact on overall system performance which may make a bug more
|
||||
difficult to find.
|
||||
|
||||
In order to switch debugging on one can add a option "slub_debug"
|
||||
to the kernel command line. That will enable full debugging for
|
||||
all slabs.
|
||||
|
||||
Typically one would then use the "slabinfo" command to get statistical
|
||||
data and perform operation on the slabs. By default slabinfo only lists
|
||||
slabs that have data in them. See "slabinfo -h" for more options when
|
||||
running the command. slabinfo can be compiled with
|
||||
|
||||
gcc -o slabinfo Documentation/vm/slabinfo.c
|
||||
|
||||
Some of the modes of operation of slabinfo require that slub debugging
|
||||
be enabled on the command line. F.e. no tracking information will be
|
||||
available without debugging on and validation can only partially
|
||||
be performed if debugging was not switched on.
|
||||
|
||||
Some more sophisticated uses of slub_debug:
|
||||
-------------------------------------------
|
||||
|
||||
Parameters may be given to slub_debug. If none is specified then full
|
||||
debugging is enabled. Format:
|
||||
|
||||
slub_debug=<Debug-Options> Enable options for all slabs
|
||||
slub_debug=<Debug-Options>,<slab name>
|
||||
Enable options only for select slabs
|
||||
|
||||
Possible debug options are
|
||||
F Sanity checks on (enables SLAB_DEBUG_FREE. Sorry
|
||||
SLAB legacy issues)
|
||||
Z Red zoning
|
||||
P Poisoning (object and padding)
|
||||
U User tracking (free and alloc)
|
||||
T Trace (please only use on single slabs)
|
||||
|
||||
F.e. in order to boot just with sanity checks and red zoning one would specify:
|
||||
|
||||
slub_debug=FZ
|
||||
|
||||
Trying to find an issue in the dentry cache? Try
|
||||
|
||||
slub_debug=,dentry_cache
|
||||
|
||||
to only enable debugging on the dentry cache.
|
||||
|
||||
Red zoning and tracking may realign the slab. We can just apply sanity checks
|
||||
to the dentry cache with
|
||||
|
||||
slub_debug=F,dentry_cache
|
||||
|
||||
In case you forgot to enable debugging on the kernel command line: It is
|
||||
possible to enable debugging manually when the kernel is up. Look at the
|
||||
contents of:
|
||||
|
||||
/sys/slab/<slab name>/
|
||||
|
||||
Look at the writable files. Writing 1 to them will enable the
|
||||
corresponding debug option. All options can be set on a slab that does
|
||||
not contain objects. If the slab already contains objects then sanity checks
|
||||
and tracing may only be enabled. The other options may cause the realignment
|
||||
of objects.
|
||||
|
||||
Careful with tracing: It may spew out lots of information and never stop if
|
||||
used on the wrong slab.
|
||||
|
||||
SLAB Merging
|
||||
------------
|
||||
|
||||
If no debugging is specified then SLUB may merge similar slabs together
|
||||
in order to reduce overhead and increase cache hotness of objects.
|
||||
slabinfo -a displays which slabs were merged together.
|
||||
|
||||
Getting more performance
|
||||
------------------------
|
||||
|
||||
To some degree SLUB's performance is limited by the need to take the
|
||||
list_lock once in a while to deal with partial slabs. That overhead is
|
||||
governed by the order of the allocation for each slab. The allocations
|
||||
can be influenced by kernel parameters:
|
||||
|
||||
slub_min_objects=x (default 8)
|
||||
slub_min_order=x (default 0)
|
||||
slub_max_order=x (default 4)
|
||||
|
||||
slub_min_objects allows to specify how many objects must at least fit
|
||||
into one slab in order for the allocation order to be acceptable.
|
||||
In general slub will be able to perform this number of allocations
|
||||
on a slab without consulting centralized resources (list_lock) where
|
||||
contention may occur.
|
||||
|
||||
slub_min_order specifies a minim order of slabs. A similar effect like
|
||||
slub_min_objects.
|
||||
|
||||
slub_max_order specified the order at which slub_min_objects should no
|
||||
longer be checked. This is useful to avoid SLUB trying to generate
|
||||
super large order pages to fit slub_min_objects of a slab cache with
|
||||
large object sizes into one high order page.
|
||||
|
||||
|
||||
Christoph Lameter, <clameter@sgi.com>, April 10, 2007
|
@ -149,7 +149,19 @@ NUMA
|
||||
|
||||
numa=noacpi Don't parse the SRAT table for NUMA setup
|
||||
|
||||
numa=fake=X Fake X nodes and ignore NUMA setup of the actual machine.
|
||||
numa=fake=CMDLINE
|
||||
If a number, fakes CMDLINE nodes and ignores NUMA setup of the
|
||||
actual machine. Otherwise, system memory is configured
|
||||
depending on the sizes and coefficients listed. For example:
|
||||
numa=fake=2*512,1024,4*256,*128
|
||||
gives two 512M nodes, a 1024M node, four 256M nodes, and the
|
||||
rest split into 128M chunks. If the last character of CMDLINE
|
||||
is a *, the remaining memory is divided up equally among its
|
||||
coefficient:
|
||||
numa=fake=2*512,2*
|
||||
gives two 512M nodes and the rest split into two nodes.
|
||||
Otherwise, the remaining system RAM is allocated to an
|
||||
additional node.
|
||||
|
||||
numa=hotadd=percent
|
||||
Only allow hotadd memory to preallocate page structures upto
|
||||
|
66
Documentation/x86_64/fake-numa-for-cpusets
Normal file
66
Documentation/x86_64/fake-numa-for-cpusets
Normal file
@ -0,0 +1,66 @@
|
||||
Using numa=fake and CPUSets for Resource Management
|
||||
Written by David Rientjes <rientjes@cs.washington.edu>
|
||||
|
||||
This document describes how the numa=fake x86_64 command-line option can be used
|
||||
in conjunction with cpusets for coarse memory management. Using this feature,
|
||||
you can create fake NUMA nodes that represent contiguous chunks of memory and
|
||||
assign them to cpusets and their attached tasks. This is a way of limiting the
|
||||
amount of system memory that are available to a certain class of tasks.
|
||||
|
||||
For more information on the features of cpusets, see Documentation/cpusets.txt.
|
||||
There are a number of different configurations you can use for your needs. For
|
||||
more information on the numa=fake command line option and its various ways of
|
||||
configuring fake nodes, see Documentation/x86_64/boot-options.txt.
|
||||
|
||||
For the purposes of this introduction, we'll assume a very primitive NUMA
|
||||
emulation setup of "numa=fake=4*512,". This will split our system memory into
|
||||
four equal chunks of 512M each that we can now use to assign to cpusets. As
|
||||
you become more familiar with using this combination for resource control,
|
||||
you'll determine a better setup to minimize the number of nodes you have to deal
|
||||
with.
|
||||
|
||||
A machine may be split as follows with "numa=fake=4*512," as reported by dmesg:
|
||||
|
||||
Faking node 0 at 0000000000000000-0000000020000000 (512MB)
|
||||
Faking node 1 at 0000000020000000-0000000040000000 (512MB)
|
||||
Faking node 2 at 0000000040000000-0000000060000000 (512MB)
|
||||
Faking node 3 at 0000000060000000-0000000080000000 (512MB)
|
||||
...
|
||||
On node 0 totalpages: 130975
|
||||
On node 1 totalpages: 131072
|
||||
On node 2 totalpages: 131072
|
||||
On node 3 totalpages: 131072
|
||||
|
||||
Now following the instructions for mounting the cpusets filesystem from
|
||||
Documentation/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
|
||||
address spaces) to individual cpusets:
|
||||
|
||||
[root@xroads /]# mkdir exampleset
|
||||
[root@xroads /]# mount -t cpuset none exampleset
|
||||
[root@xroads /]# mkdir exampleset/ddset
|
||||
[root@xroads /]# cd exampleset/ddset
|
||||
[root@xroads /exampleset/ddset]# echo 0-1 > cpus
|
||||
[root@xroads /exampleset/ddset]# echo 0-1 > mems
|
||||
|
||||
Now this cpuset, 'ddset', will only allowed access to fake nodes 0 and 1 for
|
||||
memory allocations (1G).
|
||||
|
||||
You can now assign tasks to these cpusets to limit the memory resources
|
||||
available to them according to the fake nodes assigned as mems:
|
||||
|
||||
[root@xroads /exampleset/ddset]# echo $$ > tasks
|
||||
[root@xroads /exampleset/ddset]# dd if=/dev/zero of=tmp bs=1024 count=1G
|
||||
[1] 13425
|
||||
|
||||
Notice the difference between the system memory usage as reported by
|
||||
/proc/meminfo between the restricted cpuset case above and the unrestricted
|
||||
case (i.e. running the same 'dd' command without assigning it to a fake NUMA
|
||||
cpuset):
|
||||
Unrestricted Restricted
|
||||
MemTotal: 3091900 kB 3091900 kB
|
||||
MemFree: 42113 kB 1513236 kB
|
||||
|
||||
This allows for coarse memory management for the tasks you assign to particular
|
||||
cpusets. Since cpusets can form a hierarchy, you can create some pretty
|
||||
interesting combinations of use-cases for various classes of tasks for your
|
||||
memory management needs.
|
@ -36,7 +36,12 @@ between all CPUs.
|
||||
|
||||
check_interval
|
||||
How often to poll for corrected machine check errors, in seconds
|
||||
(Note output is hexademical). Default 5 minutes.
|
||||
(Note output is hexademical). Default 5 minutes. When the poller
|
||||
finds MCEs it triggers an exponential speedup (poll more often) on
|
||||
the polling interval. When the poller stops finding MCEs, it
|
||||
triggers an exponential backoff (poll less often) on the polling
|
||||
interval. The check_interval variable is both the initial and
|
||||
maximum polling interval.
|
||||
|
||||
tolerant
|
||||
Tolerance level. When a machine check exception occurs for a non
|
||||
|
11
Kbuild
11
Kbuild
@ -2,6 +2,7 @@
|
||||
# Kbuild for top-level directory of the kernel
|
||||
# This file takes care of the following:
|
||||
# 1) Generate asm-offsets.h
|
||||
# 2) Check for missing system calls
|
||||
|
||||
#####
|
||||
# 1) Generate asm-offsets.h
|
||||
@ -46,3 +47,13 @@ $(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild
|
||||
$(Q)mkdir -p $(dir $@)
|
||||
$(call cmd,offsets)
|
||||
|
||||
#####
|
||||
# 2) Check for missing system calls
|
||||
#
|
||||
|
||||
quiet_cmd_syscalls = CALL $<
|
||||
cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags)
|
||||
|
||||
PHONY += missing-syscalls
|
||||
missing-syscalls: scripts/checksyscalls.sh FORCE
|
||||
$(call cmd,syscalls)
|
||||
|
95
MAINTAINERS
95
MAINTAINERS
@ -700,6 +700,44 @@ P: Richard Purdie
|
||||
M: rpurdie@rpsys.net
|
||||
S: Maintained
|
||||
|
||||
BLACKFIN ARCHITECTURE
|
||||
P: Aubrey Li
|
||||
M: aubrey.li@analog.com
|
||||
P: Bernd Schmidt
|
||||
M: bernd.schmidt@analog.com
|
||||
P: Bryan Wu
|
||||
M: bryan.wu@analog.com
|
||||
P: Grace Pan
|
||||
M: grace.pan@analog.com
|
||||
P: Michael Hennerich
|
||||
M: michael.hennerich@analog.com
|
||||
P: Mike Frysinger
|
||||
M: michael.frysinger@analog.com
|
||||
P: Jane Lv
|
||||
M: jane.lv@analog.com
|
||||
P: Jerry Zeng
|
||||
M: jerry.zeng@analog.com
|
||||
P: Jie Zhang
|
||||
M: jie.zhang@analog.com
|
||||
P: Robin Getz
|
||||
M: robin.getz@analog.com
|
||||
P: Roy Huang
|
||||
M: roy.huang@analog.com
|
||||
P: Sonic Zhang
|
||||
M: sonic.zhang@analog.com
|
||||
P: Yi Li
|
||||
M: yi.li@analog.com
|
||||
L: uclinux-dist-devel@blackfin.uclinux.org
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
|
||||
BLACKFIN SERIAL DRIVER
|
||||
P: Aubrey Li
|
||||
M: aubrey.li@analog.com
|
||||
L: uclinux-dist-devel@blackfin.uclinux.org
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
|
||||
BAYCOM/HDLCDRV DRIVERS FOR AX.25
|
||||
P: Thomas Sailer
|
||||
M: t.sailer@alumni.ethz.ch
|
||||
@ -733,6 +771,13 @@ M: tigran@aivazian.fsnet.co.uk
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
BLACKFIN I2C TWI DRIVER
|
||||
P: Sonic Zhang
|
||||
M: sonic.zhang@analog.com
|
||||
L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
|
||||
W: http://blackfin.uclinux.org/
|
||||
S: Supported
|
||||
|
||||
BLOCK LAYER
|
||||
P: Jens Axboe
|
||||
M: axboe@kernel.dk
|
||||
@ -1459,6 +1504,11 @@ L: linux-scsi@vger.kernel.org
|
||||
W: http://www.icp-vortex.com/
|
||||
S: Supported
|
||||
|
||||
GENERIC GPIO I2C DRIVER
|
||||
P: Haavard Skinnemoen
|
||||
M: hskinnemoen@atmel.com
|
||||
S: Supported
|
||||
|
||||
GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS
|
||||
P: Krzysztof Halasa
|
||||
M: khc@pm.waw.pl
|
||||
@ -1605,7 +1655,7 @@ S: Maintained
|
||||
|
||||
HPET: x86_64
|
||||
P: Andi Kleen and Vojtech Pavlik
|
||||
M: ak@muc.de and vojtech@suse.cz
|
||||
M: andi@firstfloor.org and vojtech@suse.cz
|
||||
S: Maintained
|
||||
|
||||
HPET: ACPI hpet.c
|
||||
@ -1631,6 +1681,13 @@ L: i2c@lm-sensors.org
|
||||
T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/
|
||||
S: Maintained
|
||||
|
||||
I2C-TINY-USB DRIVER
|
||||
P: Till Harbaum
|
||||
M: till@harbaum.org
|
||||
L: i2c@lm-sensors.org
|
||||
T: http://www.harbaum.org/till/i2c_tiny_usb
|
||||
S: Maintained
|
||||
|
||||
i386 BOOT CODE
|
||||
P: Riley H. Williams
|
||||
M: Riley@Williams.Name
|
||||
@ -2209,6 +2266,16 @@ M: philb@gnu.org
|
||||
W: http://www.tazenda.demon.co.uk/phil/linux-hp
|
||||
S: Maintained
|
||||
|
||||
MAC80211
|
||||
P: Jiri Benc
|
||||
M: jbenc@suse.cz
|
||||
P: Michael Wu
|
||||
M: flamingice@sourmilk.net
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://linuxwireless.org/
|
||||
T: git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git
|
||||
S: Maintained
|
||||
|
||||
MARVELL YUKON / SYSKONNECT DRIVER
|
||||
P: Mirko Lindner
|
||||
M: mlindner@syskonnect.de
|
||||
@ -2623,6 +2690,19 @@ T: git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
|
||||
T: cvs cvs.parisc-linux.org:/var/cvs/linux-2.6
|
||||
S: Maintained
|
||||
|
||||
PARAVIRT_OPS INTERFACE
|
||||
P: Jeremy Fitzhardinge
|
||||
M: jeremy@xensource.com
|
||||
P: Chris Wright
|
||||
M: chrisw@sous-sol.org
|
||||
P: Zachary Amsden
|
||||
M: zach@vmware.com
|
||||
P: Rusty Russell
|
||||
M: rusty@rustcorp.com.au
|
||||
L: virtualization@lists.osdl.org
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
|
||||
PC87360 HARDWARE MONITORING DRIVER
|
||||
P: Jim Cromie
|
||||
M: jim.cromie@gmail.com
|
||||
@ -3627,8 +3707,8 @@ W: http://www.kroah.com/linux/
|
||||
S: Maintained
|
||||
|
||||
USB SERIAL WHITEHEAT DRIVER
|
||||
P: Stuart MacDonald
|
||||
M: stuartm@connecttech.com
|
||||
P: Support Department
|
||||
M: support@connecttech.com
|
||||
L: linux-usb-users@lists.sourceforge.net
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
W: http://www.connecttech.com
|
||||
@ -3847,6 +3927,15 @@ M: eis@baty.hanse.de
|
||||
L: linux-x25@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
XEN HYPERVISOR INTERFACE
|
||||
P: Jeremy Fitzhardinge
|
||||
M: jeremy@xensource.com
|
||||
P: Chris Wright
|
||||
M: chrisw@sous-sol.org
|
||||
L: virtualization@lists.osdl.org
|
||||
L: xen-devel@lists.xensource.com
|
||||
S: Supported
|
||||
|
||||
XFS FILESYSTEM
|
||||
P: Silicon Graphics Inc
|
||||
P: Tim Shimmin, David Chatterton
|
||||
|
17
Makefile
17
Makefile
@ -491,7 +491,7 @@ endif
|
||||
include $(srctree)/arch/$(ARCH)/Makefile
|
||||
|
||||
ifdef CONFIG_FRAME_POINTER
|
||||
CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
|
||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
else
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
endif
|
||||
@ -576,7 +576,7 @@ libs-y := $(libs-y1) $(libs-y2)
|
||||
# ---------------------------------------------------------------------------
|
||||
# vmlinux is built from the objects selected by $(vmlinux-init) and
|
||||
# $(vmlinux-main). Most are built-in.o files from top-level directories
|
||||
# in the kernel tree, others are specified in arch/$(ARCH)Makefile.
|
||||
# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
|
||||
# Ordering when linking is important, and $(vmlinux-init) must be first.
|
||||
#
|
||||
# vmlinux
|
||||
@ -603,6 +603,7 @@ vmlinux-init := $(head-y) $(init-y)
|
||||
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
|
||||
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
|
||||
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
|
||||
export KBUILD_VMLINUX_OBJS := $(vmlinux-all)
|
||||
|
||||
# Rule to link vmlinux - also used during CONFIG_KALLSYMS
|
||||
# May be overridden by arch/$(ARCH)/Makefile
|
||||
@ -855,6 +856,7 @@ archprepare: prepare1 scripts_basic
|
||||
|
||||
prepare0: archprepare FORCE
|
||||
$(Q)$(MAKE) $(build)=.
|
||||
$(Q)$(MAKE) $(build)=. missing-syscalls
|
||||
|
||||
# All the preparing..
|
||||
prepare: prepare0
|
||||
@ -1277,10 +1279,7 @@ endif
|
||||
ALLSOURCE_ARCHS := $(ARCH)
|
||||
|
||||
define find-sources
|
||||
( find $(__srctree) $(RCS_FIND_IGNORE) \
|
||||
\( -name include -o -name arch \) -prune -o \
|
||||
-name $1 -print; \
|
||||
for ARCH in $(ALLSOURCE_ARCHS) ; do \
|
||||
( for ARCH in $(ALLSOURCE_ARCHS) ; do \
|
||||
find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
|
||||
-name $1 -print; \
|
||||
done ; \
|
||||
@ -1294,7 +1293,11 @@ define find-sources
|
||||
-name $1 -print; \
|
||||
done ; \
|
||||
find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
|
||||
-name $1 -print )
|
||||
-name $1 -print; \
|
||||
find $(__srctree) $(RCS_FIND_IGNORE) \
|
||||
\( -name include -o -name arch \) -prune -o \
|
||||
-name $1 -print; \
|
||||
)
|
||||
endef
|
||||
|
||||
define all-sources
|
||||
|
@ -467,3 +467,9 @@ start_kernel(void)
|
||||
#endif
|
||||
runkernel();
|
||||
}
|
||||
|
||||
/* dummy function, should never be called. */
|
||||
void *__kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
return (void *)NULL;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ extern int end;
|
||||
static ulg free_mem_ptr;
|
||||
static ulg free_mem_ptr_end;
|
||||
|
||||
#define HEAP_SIZE 0x2000
|
||||
#define HEAP_SIZE 0x3000
|
||||
|
||||
#include "../../../lib/inflate.c"
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <linux/a.out.h>
|
||||
#include <linux/coff.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/string.h>
|
||||
#ifdef __ELF__
|
||||
# include <linux/elf.h>
|
||||
#endif
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
@ -93,7 +93,6 @@ osf_set_program_attributes(unsigned long text_start, unsigned long text_len,
|
||||
* offset differences aren't the same as "d_reclen").
|
||||
*/
|
||||
#define NAME_OFFSET offsetof (struct osf_dirent, d_name)
|
||||
#define ROUND_UP(x) (((x)+3) & ~3)
|
||||
|
||||
struct osf_dirent {
|
||||
unsigned int d_ino;
|
||||
@ -115,7 +114,7 @@ osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
|
||||
{
|
||||
struct osf_dirent __user *dirent;
|
||||
struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
|
||||
unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
|
||||
unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));
|
||||
unsigned int d_ino;
|
||||
|
||||
buf->error = -EINVAL; /* only used if we fail */
|
||||
@ -174,7 +173,6 @@ osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent,
|
||||
return error;
|
||||
}
|
||||
|
||||
#undef ROUND_UP
|
||||
#undef NAME_OFFSET
|
||||
|
||||
asmlinkage unsigned long
|
||||
@ -1267,6 +1265,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
|
||||
if (len > limit)
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags & MAP_FIXED)
|
||||
return addr;
|
||||
|
||||
/* First, see if the given suggestion fits.
|
||||
|
||||
The OSF/1 loader (/sbin/loader) relies on us returning an
|
||||
|
@ -164,9 +164,9 @@ srmcons_get_private_struct(struct srmcons_private **ps)
|
||||
int retval = 0;
|
||||
|
||||
if (srmconsp == NULL) {
|
||||
srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
|
||||
spin_lock_irqsave(&srmconsp_lock, flags);
|
||||
|
||||
srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
|
||||
if (srmconsp == NULL)
|
||||
retval = -ENOMEM;
|
||||
else {
|
||||
|
@ -69,7 +69,7 @@ SECTIONS
|
||||
. = ALIGN(8);
|
||||
SECURITY_INIT
|
||||
|
||||
. = ALIGN(64);
|
||||
. = ALIGN(8192);
|
||||
__per_cpu_start = .;
|
||||
.data.percpu : { *(.data.percpu) }
|
||||
__per_cpu_end = .;
|
||||
|
@ -29,6 +29,10 @@ config GENERIC_TIME
|
||||
bool
|
||||
default n
|
||||
|
||||
config GENERIC_CLOCKEVENTS
|
||||
bool
|
||||
default n
|
||||
|
||||
config MMU
|
||||
bool
|
||||
default y
|
||||
@ -67,6 +71,14 @@ config GENERIC_HARDIRQS
|
||||
bool
|
||||
default y
|
||||
|
||||
config STACKTRACE_SUPPORT
|
||||
bool
|
||||
default y
|
||||
|
||||
config LOCKDEP_SUPPORT
|
||||
bool
|
||||
default y
|
||||
|
||||
config TRACE_IRQFLAGS_SUPPORT
|
||||
bool
|
||||
default y
|
||||
@ -162,6 +174,8 @@ config ARCH_VERSATILE
|
||||
select ARM_AMBA
|
||||
select ARM_VIC
|
||||
select ICST307
|
||||
select GENERIC_TIME
|
||||
select GENERIC_CLOCKEVENTS
|
||||
help
|
||||
This enables support for ARM Ltd Versatile board.
|
||||
|
||||
@ -255,6 +269,7 @@ config ARCH_IOP13XX
|
||||
depends on MMU
|
||||
select PLAT_IOP
|
||||
select PCI
|
||||
select ARCH_SUPPORTS_MSI
|
||||
help
|
||||
Support for Intel's IOP13XX (XScale) family of processors.
|
||||
|
||||
@ -262,6 +277,7 @@ config ARCH_IXP4XX
|
||||
bool "IXP4xx-based"
|
||||
depends on MMU
|
||||
select GENERIC_TIME
|
||||
select GENERIC_CLOCKEVENTS
|
||||
help
|
||||
Support for Intel's IXP4XX (XScale) family of processors.
|
||||
|
||||
@ -363,6 +379,7 @@ config ARCH_LH7A40X
|
||||
config ARCH_OMAP
|
||||
bool "TI OMAP"
|
||||
select GENERIC_GPIO
|
||||
select GENERIC_TIME
|
||||
help
|
||||
Support for TI's OMAP platform (OMAP1 and OMAP2).
|
||||
|
||||
@ -513,6 +530,8 @@ endmenu
|
||||
|
||||
menu "Kernel Features"
|
||||
|
||||
source "kernel/time/Kconfig"
|
||||
|
||||
config SMP
|
||||
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && REALVIEW_MPCORE
|
||||
@ -572,6 +591,7 @@ config PREEMPT
|
||||
|
||||
config NO_IDLE_HZ
|
||||
bool "Dynamic tick timer"
|
||||
depends on !GENERIC_CLOCKEVENTS
|
||||
help
|
||||
Select this option if you want to disable continuous timer ticks
|
||||
and have them programmed to occur as required. This option saves
|
||||
@ -669,6 +689,7 @@ config LEDS_TIMER
|
||||
bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
|
||||
MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
|
||||
depends on LEDS
|
||||
depends on !GENERIC_CLOCKEVENTS
|
||||
default y if ARCH_EBSA110
|
||||
help
|
||||
If you say Y here, one of the system LEDs (the green one on the
|
||||
|
@ -61,6 +61,12 @@
|
||||
cmp r7, r3
|
||||
beq 99f
|
||||
|
||||
@ picotux 200 : 963
|
||||
mov r3, #(MACH_TYPE_PICOTUX2XX & 0xff)
|
||||
orr r3, r3, #(MACH_TYPE_PICOTUX2XX & 0xff00)
|
||||
cmp r7, r3
|
||||
beq 99f
|
||||
|
||||
@ Ajeco 1ARM : 1075
|
||||
mov r3, #(MACH_TYPE_ONEARM & 0xff)
|
||||
orr r3, r3, #(MACH_TYPE_ONEARM & 0xff00)
|
||||
|
@ -239,7 +239,7 @@ extern int end;
|
||||
static ulg free_mem_ptr;
|
||||
static ulg free_mem_ptr_end;
|
||||
|
||||
#define HEAP_SIZE 0x2000
|
||||
#define HEAP_SIZE 0x3000
|
||||
|
||||
#include "../../../../lib/inflate.c"
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -117,11 +117,13 @@ CONFIG_ARCH_ADI_COYOTE=y
|
||||
CONFIG_ARCH_IXDP425=y
|
||||
CONFIG_MACH_IXDPG425=y
|
||||
CONFIG_MACH_IXDP465=y
|
||||
CONFIG_MACH_KIXRP435=y
|
||||
CONFIG_ARCH_IXCDP1100=y
|
||||
CONFIG_ARCH_PRPMC1100=y
|
||||
CONFIG_MACH_NAS100D=y
|
||||
CONFIG_ARCH_IXDP4XX=y
|
||||
CONFIG_CPU_IXP46X=y
|
||||
CONFIG_CPU_IXP43X=y
|
||||
# CONFIG_MACH_GTWX5715 is not set
|
||||
|
||||
#
|
||||
|
1386
arch/arm/configs/picotux200_defconfig
Normal file
1386
arch/arm/configs/picotux200_defconfig
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,8 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
|
||||
# Object file lists.
|
||||
|
||||
obj-y := compat.o entry-armv.o entry-common.o irq.o \
|
||||
process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \
|
||||
time.o traps.o
|
||||
process.o ptrace.o semaphore.o setup.o signal.o \
|
||||
sys_arm.o stacktrace.o time.o traps.o
|
||||
|
||||
obj-$(CONFIG_ISA_DMA_API) += dma.o
|
||||
obj-$(CONFIG_ARCH_ACORN) += ecard.o
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
#include <asm/ecard.h>
|
||||
@ -50,6 +51,8 @@
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#include "ecard.h"
|
||||
|
||||
#ifndef CONFIG_ARCH_RPC
|
||||
#define HAVE_EXPMASK
|
||||
#endif
|
||||
@ -123,7 +126,7 @@ static void ecard_task_reset(struct ecard_request *req)
|
||||
|
||||
res = ec->slot_no == 8
|
||||
? &ec->resource[ECARD_RES_MEMC]
|
||||
: ec->type == ECARD_EASI
|
||||
: ec->easi
|
||||
? &ec->resource[ECARD_RES_EASI]
|
||||
: &ec->resource[ECARD_RES_IOCSYNC];
|
||||
|
||||
@ -178,7 +181,7 @@ static void ecard_task_readbytes(struct ecard_request *req)
|
||||
index += 1;
|
||||
}
|
||||
} else {
|
||||
unsigned long base = (ec->type == ECARD_EASI
|
||||
unsigned long base = (ec->easi
|
||||
? &ec->resource[ECARD_RES_EASI]
|
||||
: &ec->resource[ECARD_RES_IOCSYNC])->start;
|
||||
void __iomem *pbase = (void __iomem *)base;
|
||||
@ -263,8 +266,6 @@ static int ecard_init_mm(void)
|
||||
static int
|
||||
ecard_task(void * unused)
|
||||
{
|
||||
daemonize("kecardd");
|
||||
|
||||
/*
|
||||
* Allocate a mm. We're not a lazy-TLB kernel task since we need
|
||||
* to set page table entries where the user space would be. Note
|
||||
@ -727,7 +728,7 @@ static int ecard_prints(char *buffer, ecard_t *ec)
|
||||
char *start = buffer;
|
||||
|
||||
buffer += sprintf(buffer, " %d: %s ", ec->slot_no,
|
||||
ec->type == ECARD_EASI ? "EASI" : " ");
|
||||
ec->easi ? "EASI" : " ");
|
||||
|
||||
if (ec->cid.id == 0) {
|
||||
struct in_chunk_dir incd;
|
||||
@ -814,7 +815,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot)
|
||||
}
|
||||
|
||||
ec->slot_no = slot;
|
||||
ec->type = type;
|
||||
ec->easi = type == ECARD_EASI;
|
||||
ec->irq = NO_IRQ;
|
||||
ec->fiq = NO_IRQ;
|
||||
ec->dma = NO_DMA;
|
||||
@ -825,6 +826,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot)
|
||||
ec->dev.bus = &ecard_bus_type;
|
||||
ec->dev.dma_mask = &ec->dma_mask;
|
||||
ec->dma_mask = (u64)0xffffffff;
|
||||
ec->dev.coherent_dma_mask = ec->dma_mask;
|
||||
|
||||
if (slot < 4) {
|
||||
ec_set_resource(ec, ECARD_RES_MEMC,
|
||||
@ -907,7 +909,7 @@ static ssize_t ecard_show_device(struct device *dev, struct device_attribute *at
|
||||
static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(dev);
|
||||
return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC");
|
||||
return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
|
||||
}
|
||||
|
||||
static struct device_attribute ecard_dev_attrs[] = {
|
||||
@ -1058,13 +1060,14 @@ ecard_probe(int slot, card_type_t type)
|
||||
*/
|
||||
static int __init ecard_init(void)
|
||||
{
|
||||
int slot, irqhw, ret;
|
||||
struct task_struct *task;
|
||||
int slot, irqhw;
|
||||
|
||||
ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
task = kthread_run(ecard_task, NULL, "kecardd");
|
||||
if (IS_ERR(task)) {
|
||||
printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
|
||||
PTR_ERR(task));
|
||||
return PTR_ERR(task);
|
||||
}
|
||||
|
||||
printk("Probing expansion cards\n");
|
||||
|
56
arch/arm/kernel/ecard.h
Normal file
56
arch/arm/kernel/ecard.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* ecard.h
|
||||
*
|
||||
* Copyright 2007 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* Definitions internal to ecard.c - for it's use only!!
|
||||
*
|
||||
* External expansion card header as read from the card
|
||||
*/
|
||||
struct ex_ecid {
|
||||
unsigned char r_irq:1;
|
||||
unsigned char r_zero:1;
|
||||
unsigned char r_fiq:1;
|
||||
unsigned char r_id:4;
|
||||
unsigned char r_a:1;
|
||||
|
||||
unsigned char r_cd:1;
|
||||
unsigned char r_is:1;
|
||||
unsigned char r_w:2;
|
||||
unsigned char r_r1:4;
|
||||
|
||||
unsigned char r_r2:8;
|
||||
|
||||
unsigned char r_prod[2];
|
||||
|
||||
unsigned char r_manu[2];
|
||||
|
||||
unsigned char r_country;
|
||||
|
||||
unsigned char r_fiqmask;
|
||||
unsigned char r_fiqoff[3];
|
||||
|
||||
unsigned char r_irqmask;
|
||||
unsigned char r_irqoff[3];
|
||||
};
|
||||
|
||||
/*
|
||||
* Chunk directory entry as read from the card
|
||||
*/
|
||||
struct ex_chunk_dir {
|
||||
unsigned char r_id;
|
||||
unsigned char r_len[3];
|
||||
unsigned long r_start;
|
||||
union {
|
||||
char string[256];
|
||||
char data[1];
|
||||
} d;
|
||||
#define c_id(x) ((x)->r_id)
|
||||
#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
|
||||
#define c_start(x) ((x)->r_start)
|
||||
};
|
@ -257,7 +257,9 @@ __create_page_tables:
|
||||
* Map some ram to cover our .data and .bss areas.
|
||||
*/
|
||||
orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
|
||||
.if (KERNEL_RAM_PADDR & 0x00f00000)
|
||||
orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
|
||||
.endif
|
||||
add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
|
||||
str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
|
||||
ldr r6, =(_end - 1)
|
||||
@ -274,7 +276,9 @@ __create_page_tables:
|
||||
*/
|
||||
add r0, r4, #PAGE_OFFSET >> 18
|
||||
orr r6, r7, #(PHYS_OFFSET & 0xff000000)
|
||||
orr r6, r6, #(PHYS_OFFSET & 0x00e00000)
|
||||
.if (PHYS_OFFSET & 0x00f00000)
|
||||
orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
|
||||
.endif
|
||||
str r6, [r0]
|
||||
|
||||
#ifdef CONFIG_DEBUG_LL
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/smp.h>
|
||||
@ -109,7 +108,7 @@ static struct irq_desc bad_irq_desc = {
|
||||
* come via this function. Instead, they should provide their
|
||||
* own 'handler'
|
||||
*/
|
||||
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/a.out.h>
|
||||
@ -28,6 +27,7 @@
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/elfcore.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include <asm/leds.h>
|
||||
#include <asm/processor.h>
|
||||
@ -160,9 +160,11 @@ void cpu_idle(void)
|
||||
if (!idle)
|
||||
idle = default_idle;
|
||||
leds_event(led_idle_start);
|
||||
tick_nohz_stop_sched_tick();
|
||||
while (!need_resched())
|
||||
idle();
|
||||
leds_event(led_idle_end);
|
||||
tick_nohz_restart_sched_tick();
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
preempt_disable();
|
||||
|
@ -457,13 +457,10 @@ void ptrace_cancel_bpt(struct task_struct *child)
|
||||
|
||||
/*
|
||||
* Called by kernel/ptrace.c when detaching..
|
||||
*
|
||||
* Make sure the single step bit is not set.
|
||||
*/
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
child->ptrace &= ~PT_SINGLESTEP;
|
||||
ptrace_cancel_bpt(child);
|
||||
single_step_disable(child);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -712,9 +709,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
else
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
child->exit_code = data;
|
||||
/* make sure single-step breakpoint is gone. */
|
||||
child->ptrace &= ~PT_SINGLESTEP;
|
||||
ptrace_cancel_bpt(child);
|
||||
single_step_disable(child);
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
@ -725,9 +720,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
* exit.
|
||||
*/
|
||||
case PTRACE_KILL:
|
||||
/* make sure single-step breakpoint is gone. */
|
||||
child->ptrace &= ~PT_SINGLESTEP;
|
||||
ptrace_cancel_bpt(child);
|
||||
single_step_disable(child);
|
||||
if (child->exit_state != EXIT_ZOMBIE) {
|
||||
child->exit_code = SIGKILL;
|
||||
wake_up_process(child);
|
||||
@ -742,7 +735,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
ret = -EIO;
|
||||
if (!valid_signal(data))
|
||||
break;
|
||||
child->ptrace |= PT_SINGLESTEP;
|
||||
single_step_enable(child);
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
child->exit_code = data;
|
||||
/* give it a chance to run. */
|
||||
@ -786,8 +779,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
break;
|
||||
|
||||
case PTRACE_SET_SYSCALL:
|
||||
task_thread_info(child)->syscall = data;
|
||||
ret = 0;
|
||||
child->ptrace_message = data;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_CRUNCH
|
||||
@ -824,7 +817,7 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
|
||||
ip = regs->ARM_ip;
|
||||
regs->ARM_ip = why;
|
||||
|
||||
current->ptrace_message = scno;
|
||||
current_thread_info()->syscall = scno;
|
||||
|
||||
/* the 0x80 provides a way for the tracing parent to distinguish
|
||||
between a syscall stop and SIGTRAP delivery */
|
||||
@ -841,5 +834,5 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
|
||||
}
|
||||
regs->ARM_ip = ip;
|
||||
|
||||
return current->ptrace_message;
|
||||
return current_thread_info()->syscall;
|
||||
}
|
||||
|
@ -7,6 +7,45 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
extern void ptrace_cancel_bpt(struct task_struct *);
|
||||
extern void ptrace_set_bpt(struct task_struct *);
|
||||
extern void ptrace_break(struct task_struct *, struct pt_regs *);
|
||||
|
||||
/*
|
||||
* make sure single-step breakpoint is gone.
|
||||
*/
|
||||
static inline void single_step_disable(struct task_struct *task)
|
||||
{
|
||||
task->ptrace &= ~PT_SINGLESTEP;
|
||||
ptrace_cancel_bpt(task);
|
||||
}
|
||||
|
||||
static inline void single_step_enable(struct task_struct *task)
|
||||
{
|
||||
task->ptrace |= PT_SINGLESTEP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send SIGTRAP if we're single-stepping
|
||||
*/
|
||||
static inline void single_step_trap(struct task_struct *task)
|
||||
{
|
||||
if (task->ptrace & PT_SINGLESTEP) {
|
||||
ptrace_cancel_bpt(task);
|
||||
send_sig(SIGTRAP, task, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void single_step_clear(struct task_struct *task)
|
||||
{
|
||||
if (task->ptrace & PT_SINGLESTEP)
|
||||
ptrace_cancel_bpt(task);
|
||||
}
|
||||
|
||||
static inline void single_step_set(struct task_struct *task)
|
||||
{
|
||||
if (task->ptrace & PT_SINGLESTEP)
|
||||
ptrace_set_bpt(task);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
@ -285,11 +284,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
|
||||
if (restore_sigframe(regs, frame))
|
||||
goto badframe;
|
||||
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
if (current->ptrace & PT_SINGLESTEP) {
|
||||
ptrace_cancel_bpt(current);
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
}
|
||||
single_step_trap(current);
|
||||
|
||||
return regs->ARM_r0;
|
||||
|
||||
@ -324,11 +319,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
|
||||
if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
|
||||
goto badframe;
|
||||
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
if (current->ptrace & PT_SINGLESTEP) {
|
||||
ptrace_cancel_bpt(current);
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
}
|
||||
single_step_trap(current);
|
||||
|
||||
return regs->ARM_r0;
|
||||
|
||||
@ -644,14 +635,12 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
||||
if (try_to_freeze())
|
||||
goto no_signal;
|
||||
|
||||
if (current->ptrace & PT_SINGLESTEP)
|
||||
ptrace_cancel_bpt(current);
|
||||
single_step_clear(current);
|
||||
|
||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||
if (signr > 0) {
|
||||
handle_signal(signr, &ka, &info, oldset, regs, syscall);
|
||||
if (current->ptrace & PT_SINGLESTEP)
|
||||
ptrace_set_bpt(current);
|
||||
single_step_set(current);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -705,8 +694,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
||||
restart_syscall(regs);
|
||||
}
|
||||
}
|
||||
if (current->ptrace & PT_SINGLESTEP)
|
||||
ptrace_set_bpt(current);
|
||||
single_step_set(current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
73
arch/arm/kernel/stacktrace.c
Normal file
73
arch/arm/kernel/stacktrace.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/stacktrace.h>
|
||||
|
||||
#include "stacktrace.h"
|
||||
|
||||
int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
|
||||
int (*fn)(struct stackframe *, void *), void *data)
|
||||
{
|
||||
struct stackframe *frame;
|
||||
|
||||
do {
|
||||
/*
|
||||
* Check current frame pointer is within bounds
|
||||
*/
|
||||
if ((fp - 12) < low || fp + 4 >= high)
|
||||
break;
|
||||
|
||||
frame = (struct stackframe *)(fp - 12);
|
||||
|
||||
if (fn(frame, data))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Update the low bound - the next frame must always
|
||||
* be at a higher address than the current frame.
|
||||
*/
|
||||
low = fp + 4;
|
||||
fp = frame->fp;
|
||||
} while (fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STACKTRACE
|
||||
struct stack_trace_data {
|
||||
struct stack_trace *trace;
|
||||
unsigned int skip;
|
||||
};
|
||||
|
||||
static int save_trace(struct stackframe *frame, void *d)
|
||||
{
|
||||
struct stack_trace_data *data = d;
|
||||
struct stack_trace *trace = data->trace;
|
||||
|
||||
if (data->skip) {
|
||||
data->skip--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
trace->entries[trace->nr_entries++] = frame->lr;
|
||||
|
||||
return trace->nr_entries >= trace->max_entries;
|
||||
}
|
||||
|
||||
void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
|
||||
{
|
||||
struct stack_trace_data data;
|
||||
unsigned long fp, base;
|
||||
|
||||
data.trace = trace;
|
||||
data.skip = trace->skip;
|
||||
|
||||
if (task) {
|
||||
base = (unsigned long)task_stack_page(task);
|
||||
fp = 0; /* FIXME */
|
||||
} else {
|
||||
base = (unsigned long)task_stack_page(current);
|
||||
asm("mov %0, fp" : "=r" (fp));
|
||||
}
|
||||
|
||||
walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
|
||||
}
|
||||
#endif
|
9
arch/arm/kernel/stacktrace.h
Normal file
9
arch/arm/kernel/stacktrace.h
Normal file
@ -0,0 +1,9 @@
|
||||
struct stackframe {
|
||||
unsigned long fp;
|
||||
unsigned long sp;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
};
|
||||
|
||||
int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
|
||||
int (*fn)(struct stackframe *, void *), void *data);
|
@ -327,6 +327,7 @@ void restore_time_delta(struct timespec *delta, struct timespec *rtc)
|
||||
}
|
||||
EXPORT_SYMBOL(restore_time_delta);
|
||||
|
||||
#ifndef CONFIG_GENERIC_CLOCKEVENTS
|
||||
/*
|
||||
* Kernel system timer support.
|
||||
*/
|
||||
@ -340,8 +341,9 @@ void timer_tick(void)
|
||||
update_process_times(user_mode(get_irq_regs()));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
|
||||
static int timer_suspend(struct sys_device *dev, pm_message_t state)
|
||||
{
|
||||
struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/signal.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
@ -45,7 +44,18 @@ static int __init user_debug_setup(char *str)
|
||||
__setup("user_debug=", user_debug_setup);
|
||||
#endif
|
||||
|
||||
void dump_backtrace_entry(unsigned long where, unsigned long from)
|
||||
static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
|
||||
|
||||
static inline int in_exception_text(unsigned long ptr)
|
||||
{
|
||||
extern char __exception_text_start[];
|
||||
extern char __exception_text_end[];
|
||||
|
||||
return ptr >= (unsigned long)&__exception_text_start &&
|
||||
ptr < (unsigned long)&__exception_text_end;
|
||||
}
|
||||
|
||||
void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
|
||||
{
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
printk("[<%08lx>] ", where);
|
||||
@ -55,6 +65,9 @@ void dump_backtrace_entry(unsigned long where, unsigned long from)
|
||||
#else
|
||||
printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
|
||||
#endif
|
||||
|
||||
if (in_exception_text(where))
|
||||
dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -266,13 +279,14 @@ void unregister_undef_hook(struct undef_hook *hook)
|
||||
spin_unlock_irqrestore(&undef_lock, flags);
|
||||
}
|
||||
|
||||
asmlinkage void do_undefinstr(struct pt_regs *regs)
|
||||
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||||
{
|
||||
unsigned int correction = thumb_mode(regs) ? 2 : 4;
|
||||
unsigned int instr;
|
||||
struct undef_hook *hook;
|
||||
siginfo_t info;
|
||||
void __user *pc;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* According to the ARM ARM, PC is 2 or 4 bytes ahead,
|
||||
@ -291,7 +305,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
|
||||
get_user(instr, (u32 __user *)pc);
|
||||
}
|
||||
|
||||
spin_lock_irq(&undef_lock);
|
||||
spin_lock_irqsave(&undef_lock, flags);
|
||||
list_for_each_entry(hook, &undef_hook, node) {
|
||||
if ((instr & hook->instr_mask) == hook->instr_val &&
|
||||
(regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
|
||||
@ -301,7 +315,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&undef_lock);
|
||||
spin_unlock_irqrestore(&undef_lock, flags);
|
||||
|
||||
#ifdef CONFIG_DEBUG_USER
|
||||
if (user_debug & UDBG_UNDEFINED) {
|
||||
|
@ -59,7 +59,7 @@ SECTIONS
|
||||
usr/built-in.o(.init.ramfs)
|
||||
__initramfs_end = .;
|
||||
#endif
|
||||
. = ALIGN(64);
|
||||
. = ALIGN(4096);
|
||||
__per_cpu_start = .;
|
||||
*(.data.percpu)
|
||||
__per_cpu_end = .;
|
||||
@ -83,6 +83,9 @@ SECTIONS
|
||||
|
||||
.text : { /* Real text segment */
|
||||
_text = .; /* Text and read-only data */
|
||||
__exception_text_start = .;
|
||||
*(.exception.text)
|
||||
__exception_text_end = .;
|
||||
*(.text)
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
|
@ -17,8 +17,8 @@
|
||||
@ fp is 0 or stack frame
|
||||
|
||||
#define frame r4
|
||||
#define next r5
|
||||
#define save r6
|
||||
#define sv_fp r5
|
||||
#define sv_pc r6
|
||||
#define mask r7
|
||||
#define offset r8
|
||||
|
||||
@ -31,108 +31,106 @@ ENTRY(c_backtrace)
|
||||
#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
|
||||
mov pc, lr
|
||||
#else
|
||||
|
||||
stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location...
|
||||
tst r1, #0x10 @ 26 or 32-bit?
|
||||
moveq mask, #0xfc000003
|
||||
movne mask, #0
|
||||
tst mask, r0
|
||||
movne r0, #0
|
||||
movs frame, r0
|
||||
1: moveq r0, #-2
|
||||
ldmeqfd sp!, {r4 - r8, pc}
|
||||
movs frame, r0 @ if frame pointer is zero
|
||||
beq no_frame @ we have no stack frames
|
||||
|
||||
2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction
|
||||
ldr r0, [sp], #4
|
||||
adr r1, 2b - 4
|
||||
tst r1, #0x10 @ 26 or 32-bit mode?
|
||||
moveq mask, #0xfc000003 @ mask for 26-bit
|
||||
movne mask, #0 @ mask for 32-bit
|
||||
|
||||
1: stmfd sp!, {pc} @ calculate offset of PC stored
|
||||
ldr r0, [sp], #4 @ by stmfd for this CPU
|
||||
adr r1, 1b
|
||||
sub offset, r0, r1
|
||||
|
||||
3: tst frame, mask @ Check for address exceptions...
|
||||
bne 1b
|
||||
/*
|
||||
* Stack frame layout:
|
||||
* optionally saved caller registers (r4 - r10)
|
||||
* saved fp
|
||||
* saved sp
|
||||
* saved lr
|
||||
* frame => saved pc
|
||||
* optionally saved arguments (r0 - r3)
|
||||
* saved sp => <next word>
|
||||
*
|
||||
* Functions start with the following code sequence:
|
||||
* mov ip, sp
|
||||
* stmfd sp!, {r0 - r3} (optional)
|
||||
* corrected pc => stmfd sp!, {..., fp, ip, lr, pc}
|
||||
*/
|
||||
for_each_frame: tst frame, mask @ Check for address exceptions
|
||||
bne no_frame
|
||||
|
||||
1001: ldr next, [frame, #-12] @ get fp
|
||||
1002: ldr r2, [frame, #-4] @ get lr
|
||||
1003: ldr r3, [frame, #0] @ get pc
|
||||
sub save, r3, offset @ Correct PC for prefetching
|
||||
bic save, save, mask
|
||||
1004: ldr r1, [save, #0] @ get instruction at function
|
||||
mov r1, r1, lsr #10
|
||||
ldr r3, .Ldsi+4
|
||||
teq r1, r3
|
||||
subeq save, save, #4
|
||||
mov r0, save
|
||||
bic r1, r2, mask
|
||||
1001: ldr sv_pc, [frame, #0] @ get saved pc
|
||||
1002: ldr sv_fp, [frame, #-12] @ get saved fp
|
||||
|
||||
sub sv_pc, sv_pc, offset @ Correct PC for prefetching
|
||||
bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
|
||||
|
||||
1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
|
||||
ldr r3, .Ldsi+4 @ adjust saved 'pc' back one
|
||||
teq r3, r2, lsr #10 @ instruction
|
||||
subne r0, sv_pc, #4 @ allow for mov
|
||||
subeq r0, sv_pc, #8 @ allow for mov + stmia
|
||||
|
||||
ldr r1, [frame, #-4] @ get saved lr
|
||||
mov r2, frame
|
||||
bic r1, r1, mask @ mask PC/LR for the mode
|
||||
bl dump_backtrace_entry
|
||||
|
||||
ldr r0, [frame, #-8] @ get sp
|
||||
sub r0, r0, #4
|
||||
1005: ldr r1, [save, #4] @ get instruction at function+4
|
||||
mov r3, r1, lsr #10
|
||||
ldr r2, .Ldsi+4
|
||||
teq r3, r2 @ Check for stmia sp!, {args}
|
||||
addeq save, save, #4 @ next instruction
|
||||
bleq .Ldumpstm
|
||||
ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
|
||||
ldr r3, .Ldsi+4
|
||||
teq r3, r1, lsr #10
|
||||
ldreq r0, [frame, #-8] @ get sp
|
||||
subeq r0, r0, #4 @ point at the last arg
|
||||
bleq .Ldumpstm @ dump saved registers
|
||||
|
||||
sub r0, frame, #16
|
||||
1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction
|
||||
mov r3, r1, lsr #10
|
||||
ldr r2, .Ldsi
|
||||
teq r3, r2
|
||||
bleq .Ldumpstm
|
||||
1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc}
|
||||
ldr r3, .Ldsi @ instruction exists,
|
||||
teq r3, r1, lsr #10
|
||||
subeq r0, frame, #16
|
||||
bleq .Ldumpstm @ dump saved registers
|
||||
|
||||
/*
|
||||
* A zero next framepointer means we're done.
|
||||
*/
|
||||
teq next, #0
|
||||
ldmeqfd sp!, {r4 - r8, pc}
|
||||
teq sv_fp, #0 @ zero saved fp means
|
||||
beq no_frame @ no further frames
|
||||
|
||||
/*
|
||||
* The next framepointer must be above the
|
||||
* current framepointer.
|
||||
*/
|
||||
cmp next, frame
|
||||
mov frame, next
|
||||
bhi 3b
|
||||
b 1007f
|
||||
cmp sv_fp, frame @ next frame must be
|
||||
mov frame, sv_fp @ above the current frame
|
||||
bhi for_each_frame
|
||||
|
||||
/*
|
||||
* Fixup for LDMDB. Note that this must not be in the fixup section.
|
||||
*/
|
||||
1007: ldr r0, =.Lbad
|
||||
1006: adr r0, .Lbad
|
||||
mov r1, frame
|
||||
bl printk
|
||||
ldmfd sp!, {r4 - r8, pc}
|
||||
.ltorg
|
||||
no_frame: ldmfd sp!, {r4 - r8, pc}
|
||||
|
||||
.section __ex_table,"a"
|
||||
.align 3
|
||||
.long 1001b, 1007b
|
||||
.long 1002b, 1007b
|
||||
.long 1003b, 1007b
|
||||
.long 1004b, 1007b
|
||||
.long 1005b, 1007b
|
||||
.long 1006b, 1007b
|
||||
.long 1001b, 1006b
|
||||
.long 1002b, 1006b
|
||||
.long 1003b, 1006b
|
||||
.long 1004b, 1006b
|
||||
.previous
|
||||
|
||||
#define instr r4
|
||||
#define reg r5
|
||||
#define stack r6
|
||||
|
||||
.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, r8, lr}
|
||||
.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr}
|
||||
mov stack, r0
|
||||
mov instr, r1
|
||||
mov reg, #9
|
||||
mov reg, #10
|
||||
mov r7, #0
|
||||
1: mov r3, #1
|
||||
tst instr, r3, lsl reg
|
||||
beq 2f
|
||||
add r7, r7, #1
|
||||
teq r7, #4
|
||||
moveq r7, #0
|
||||
moveq r3, #'\n'
|
||||
movne r3, #' '
|
||||
ldr r2, [stack], #-4
|
||||
mov r1, reg
|
||||
teq r7, #6
|
||||
moveq r7, #1
|
||||
moveq r1, #'\n'
|
||||
movne r1, #' '
|
||||
ldr r3, [stack], #-4
|
||||
mov r2, reg
|
||||
adr r0, .Lfp
|
||||
bl printk
|
||||
2: subs reg, reg, #1
|
||||
@ -140,14 +138,13 @@ ENTRY(c_backtrace)
|
||||
teq r7, #0
|
||||
adrne r0, .Lcr
|
||||
blne printk
|
||||
mov r0, stack
|
||||
ldmfd sp!, {instr, reg, stack, r7, r8, pc}
|
||||
ldmfd sp!, {instr, reg, stack, r7, pc}
|
||||
|
||||
.Lfp: .asciz " r%d = %08X%c"
|
||||
.Lfp: .asciz "%cr%d:%08x"
|
||||
.Lcr: .asciz "\n"
|
||||
.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
|
||||
.align
|
||||
.Ldsi: .word 0x00e92dd8 >> 2
|
||||
.word 0x00e92d00 >> 2
|
||||
.Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc}
|
||||
.word 0xe92d0000 >> 10 @ stmfd sp!, {}
|
||||
|
||||
#endif
|
||||
|
@ -26,8 +26,6 @@
|
||||
* Note that ADDR_LIMIT is either 0 or 0xc0000000.
|
||||
* Note also that it is intended that __get_user_bad is not global.
|
||||
*/
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
.global __get_user_1
|
||||
|
@ -26,8 +26,6 @@
|
||||
* Note that ADDR_LIMIT is either 0 or 0xc0000000
|
||||
* Note also that it is intended that __put_user_bad is not global.
|
||||
*/
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
.global __put_user_1
|
||||
|
@ -81,6 +81,13 @@ config MACH_KB9200
|
||||
Select this if you are using KwikByte's KB920x board.
|
||||
<http://kwikbyte.com/KB9202_description_new.htm>
|
||||
|
||||
config MACH_PICOTUX2XX
|
||||
bool "picotux 200"
|
||||
depends on ARCH_AT91RM9200
|
||||
help
|
||||
Select this if you are using a picotux 200.
|
||||
<http://www.picotux.com/>
|
||||
|
||||
config MACH_KAFA
|
||||
bool "Sperry-Sun KAFA board"
|
||||
depends on ARCH_AT91RM9200
|
||||
|
@ -25,6 +25,7 @@ obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o
|
||||
obj-$(CONFIG_MACH_KB9200) += board-kb9202.o
|
||||
obj-$(CONFIG_MACH_ATEB9200) += board-eb9200.o
|
||||
obj-$(CONFIG_MACH_KAFA) += board-kafa.o
|
||||
obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o
|
||||
|
||||
# AT91SAM9260 board-specific support
|
||||
obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
|
||||
|
@ -117,6 +117,21 @@ static struct clk pioD_clk = {
|
||||
.pmc_mask = 1 << AT91RM9200_ID_PIOD,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc0_clk = {
|
||||
.name = "ssc0_clk",
|
||||
.pmc_mask = 1 << AT91RM9200_ID_SSC0,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc1_clk = {
|
||||
.name = "ssc1_clk",
|
||||
.pmc_mask = 1 << AT91RM9200_ID_SSC1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc2_clk = {
|
||||
.name = "ssc2_clk",
|
||||
.pmc_mask = 1 << AT91RM9200_ID_SSC2,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk tc0_clk = {
|
||||
.name = "tc0_clk",
|
||||
.pmc_mask = 1 << AT91RM9200_ID_TC0,
|
||||
@ -161,7 +176,9 @@ static struct clk *periph_clocks[] __initdata = {
|
||||
&udc_clk,
|
||||
&twi_clk,
|
||||
&spi_clk,
|
||||
// ssc 0 .. ssc2
|
||||
&ssc0_clk,
|
||||
&ssc1_clk,
|
||||
&ssc2_clk,
|
||||
&tc0_clk,
|
||||
&tc1_clk,
|
||||
&tc2_clk,
|
||||
|
@ -119,6 +119,11 @@ static struct clk spi1_clk = {
|
||||
.pmc_mask = 1 << AT91SAM9260_ID_SPI1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc_clk = {
|
||||
.name = "ssc_clk",
|
||||
.pmc_mask = 1 << AT91SAM9260_ID_SSC,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk tc0_clk = {
|
||||
.name = "tc0_clk",
|
||||
.pmc_mask = 1 << AT91SAM9260_ID_TC0,
|
||||
@ -193,7 +198,7 @@ static struct clk *periph_clocks[] __initdata = {
|
||||
&twi_clk,
|
||||
&spi0_clk,
|
||||
&spi1_clk,
|
||||
// ssc
|
||||
&ssc_clk,
|
||||
&tc0_clk,
|
||||
&tc1_clk,
|
||||
&tc2_clk,
|
||||
|
@ -97,6 +97,21 @@ static struct clk spi1_clk = {
|
||||
.pmc_mask = 1 << AT91SAM9261_ID_SPI1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc0_clk = {
|
||||
.name = "ssc0_clk",
|
||||
.pmc_mask = 1 << AT91SAM9261_ID_SSC0,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc1_clk = {
|
||||
.name = "ssc1_clk",
|
||||
.pmc_mask = 1 << AT91SAM9261_ID_SSC1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc2_clk = {
|
||||
.name = "ssc2_clk",
|
||||
.pmc_mask = 1 << AT91SAM9261_ID_SSC2,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk tc0_clk = {
|
||||
.name = "tc0_clk",
|
||||
.pmc_mask = 1 << AT91SAM9261_ID_TC0,
|
||||
@ -135,7 +150,9 @@ static struct clk *periph_clocks[] __initdata = {
|
||||
&twi_clk,
|
||||
&spi0_clk,
|
||||
&spi1_clk,
|
||||
// ssc 0 .. ssc2
|
||||
&ssc0_clk,
|
||||
&ssc1_clk,
|
||||
&ssc2_clk,
|
||||
&tc0_clk,
|
||||
&tc1_clk,
|
||||
&tc2_clk,
|
||||
|
@ -430,9 +430,9 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
|
||||
* LCD Controller
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
#if defined(CONFIG_FB_AT91) || defined(CONFIG_FB_AT91_MODULE)
|
||||
#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
|
||||
static u64 lcdc_dmamask = 0xffffffffUL;
|
||||
static struct at91fb_info lcdc_data;
|
||||
static struct atmel_lcdfb_info lcdc_data;
|
||||
|
||||
static struct resource lcdc_resources[] = {
|
||||
[0] = {
|
||||
@ -455,7 +455,7 @@ static struct resource lcdc_resources[] = {
|
||||
};
|
||||
|
||||
static struct platform_device at91_lcdc_device = {
|
||||
.name = "at91-fb",
|
||||
.name = "atmel_lcdfb",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &lcdc_dmamask,
|
||||
@ -466,7 +466,7 @@ static struct platform_device at91_lcdc_device = {
|
||||
.num_resources = ARRAY_SIZE(lcdc_resources),
|
||||
};
|
||||
|
||||
void __init at91_add_device_lcdc(struct at91fb_info *data)
|
||||
void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
|
||||
{
|
||||
if (!data) {
|
||||
return;
|
||||
@ -499,7 +499,7 @@ void __init at91_add_device_lcdc(struct at91fb_info *data)
|
||||
platform_device_register(&at91_lcdc_device);
|
||||
}
|
||||
#else
|
||||
void __init at91_add_device_lcdc(struct at91fb_info *data) {}
|
||||
void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -87,6 +87,11 @@ static struct clk mmc1_clk = {
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_MCI1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk can_clk = {
|
||||
.name = "can_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_CAN,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk twi_clk = {
|
||||
.name = "twi_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_TWI,
|
||||
@ -102,16 +107,46 @@ static struct clk spi1_clk = {
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_SPI1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc0_clk = {
|
||||
.name = "ssc0_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_SSC0,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ssc1_clk = {
|
||||
.name = "ssc1_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_SSC1,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk ac97_clk = {
|
||||
.name = "ac97_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_AC97C,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk tcb_clk = {
|
||||
.name = "tcb_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_TCB,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk pwmc_clk = {
|
||||
.name = "pwmc_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_PWMC,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk macb_clk = {
|
||||
.name = "macb_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_EMAC,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk dma_clk = {
|
||||
.name = "dma_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_DMA,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk twodge_clk = {
|
||||
.name = "2dge_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_2DGE,
|
||||
.type = CLK_TYPE_PERIPHERAL,
|
||||
};
|
||||
static struct clk udc_clk = {
|
||||
.name = "udc_clk",
|
||||
.pmc_mask = 1 << AT91SAM9263_ID_UDP,
|
||||
@ -142,20 +177,21 @@ static struct clk *periph_clocks[] __initdata = {
|
||||
&usart2_clk,
|
||||
&mmc0_clk,
|
||||
&mmc1_clk,
|
||||
// can
|
||||
&can_clk,
|
||||
&twi_clk,
|
||||
&spi0_clk,
|
||||
&spi1_clk,
|
||||
// ssc0 .. ssc1
|
||||
// ac97
|
||||
&ssc0_clk,
|
||||
&ssc1_clk,
|
||||
&ac97_clk,
|
||||
&tcb_clk,
|
||||
// pwmc
|
||||
&pwmc_clk,
|
||||
&macb_clk,
|
||||
// 2dge
|
||||
&twodge_clk,
|
||||
&udc_clk,
|
||||
&isi_clk,
|
||||
&lcdc_clk,
|
||||
// dma
|
||||
&dma_clk,
|
||||
&ohci_clk,
|
||||
// irq0 .. irq1
|
||||
};
|
||||
|
@ -572,6 +572,130 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* AC97
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
|
||||
static u64 ac97_dmamask = 0xffffffffUL;
|
||||
static struct atmel_ac97_data ac97_data;
|
||||
|
||||
static struct resource ac97_resources[] = {
|
||||
[0] = {
|
||||
.start = AT91SAM9263_BASE_AC97C,
|
||||
.end = AT91SAM9263_BASE_AC97C + SZ_16K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AT91SAM9263_ID_AC97C,
|
||||
.end = AT91SAM9263_ID_AC97C,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device at91sam9263_ac97_device = {
|
||||
.name = "ac97c",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.dma_mask = &ac97_dmamask,
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
.platform_data = &ac97_data,
|
||||
},
|
||||
.resource = ac97_resources,
|
||||
.num_resources = ARRAY_SIZE(ac97_resources),
|
||||
};
|
||||
|
||||
void __init at91_add_device_ac97(struct atmel_ac97_data *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
at91_set_A_periph(AT91_PIN_PB0, 0); /* AC97FS */
|
||||
at91_set_A_periph(AT91_PIN_PB1, 0); /* AC97CK */
|
||||
at91_set_A_periph(AT91_PIN_PB2, 0); /* AC97TX */
|
||||
at91_set_A_periph(AT91_PIN_PB3, 0); /* AC97RX */
|
||||
|
||||
/* reset */
|
||||
if (data->reset_pin)
|
||||
at91_set_gpio_output(data->reset_pin, 0);
|
||||
|
||||
ac97_data = *ek_data;
|
||||
platform_device_register(&at91sam9263_ac97_device);
|
||||
}
|
||||
#else
|
||||
void __init at91_add_device_ac97(struct atmel_ac97_data *data) {}
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* LCD Controller
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
|
||||
static u64 lcdc_dmamask = 0xffffffffUL;
|
||||
static struct atmel_lcdfb_info lcdc_data;
|
||||
|
||||
static struct resource lcdc_resources[] = {
|
||||
[0] = {
|
||||
.start = AT91SAM9263_LCDC_BASE,
|
||||
.end = AT91SAM9263_LCDC_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = AT91SAM9263_ID_LCDC,
|
||||
.end = AT91SAM9263_ID_LCDC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device at91_lcdc_device = {
|
||||
.name = "atmel_lcdfb",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &lcdc_dmamask,
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
.platform_data = &lcdc_data,
|
||||
},
|
||||
.resource = lcdc_resources,
|
||||
.num_resources = ARRAY_SIZE(lcdc_resources),
|
||||
};
|
||||
|
||||
void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDHSYNC */
|
||||
at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDDOTCK */
|
||||
at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDDEN */
|
||||
at91_set_B_periph(AT91_PIN_PB9, 0); /* LCDCC */
|
||||
at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD2 */
|
||||
at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD3 */
|
||||
at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD4 */
|
||||
at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD5 */
|
||||
at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD6 */
|
||||
at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD7 */
|
||||
at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD10 */
|
||||
at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD11 */
|
||||
at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD12 */
|
||||
at91_set_B_periph(AT91_PIN_PC12, 0); /* LCDD13 */
|
||||
at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD14 */
|
||||
at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD15 */
|
||||
at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD18 */
|
||||
at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD19 */
|
||||
at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDD20 */
|
||||
at91_set_B_periph(AT91_PIN_PC17, 0); /* LCDD21 */
|
||||
at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDD22 */
|
||||
at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDD23 */
|
||||
|
||||
lcdc_data = *data;
|
||||
platform_device_register(&at91_lcdc_device);
|
||||
}
|
||||
#else
|
||||
void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* LEDs
|
||||
* -------------------------------------------------------------------- */
|
||||
|
166
arch/arm/mach-at91/board-picotux200.c
Normal file
166
arch/arm/mach-at91/board-picotux200.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-at91/board-picotux200.c
|
||||
*
|
||||
* Copyright (C) 2005 SAN People
|
||||
* Copyright (C) 2007 Kleinhenz Elektronik GmbH
|
||||
*
|
||||
* 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/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/at91rm9200_mc.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
|
||||
/*
|
||||
* Serial port configuration.
|
||||
* 0 .. 3 = USART0 .. USART3
|
||||
* 4 = DBGU
|
||||
*/
|
||||
static struct at91_uart_config __initdata picotux200_uart_config = {
|
||||
.console_tty = 0, /* ttyS0 */
|
||||
.nr_tty = 2,
|
||||
.tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */
|
||||
};
|
||||
|
||||
static void __init picotux200_map_io(void)
|
||||
{
|
||||
/* Initialize processor: 18.432 MHz crystal */
|
||||
at91rm9200_initialize(18432000, AT91RM9200_BGA);
|
||||
|
||||
/* Setup the serial ports and console */
|
||||
at91_init_serial(&picotux200_uart_config);
|
||||
}
|
||||
|
||||
static void __init picotux200_init_irq(void)
|
||||
{
|
||||
at91rm9200_init_interrupts(NULL);
|
||||
}
|
||||
|
||||
static struct at91_eth_data __initdata picotux200_eth_data = {
|
||||
.phy_irq_pin = AT91_PIN_PC4,
|
||||
.is_rmii = 1,
|
||||
};
|
||||
|
||||
static struct at91_usbh_data __initdata picotux200_usbh_data = {
|
||||
.ports = 1,
|
||||
};
|
||||
|
||||
// static struct at91_udc_data __initdata picotux200_udc_data = {
|
||||
// .vbus_pin = AT91_PIN_PD4,
|
||||
// .pullup_pin = AT91_PIN_PD5,
|
||||
// };
|
||||
|
||||
static struct at91_mmc_data __initdata picotux200_mmc_data = {
|
||||
.det_pin = AT91_PIN_PB27,
|
||||
.slot_b = 0,
|
||||
.wire4 = 1,
|
||||
.wp_pin = AT91_PIN_PA17,
|
||||
};
|
||||
|
||||
// static struct spi_board_info picotux200_spi_devices[] = {
|
||||
// { /* DataFlash chip */
|
||||
// .modalias = "mtd_dataflash",
|
||||
// .chip_select = 0,
|
||||
// .max_speed_hz = 15 * 1000 * 1000,
|
||||
// },
|
||||
// #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
|
||||
// { /* DataFlash card */
|
||||
// .modalias = "mtd_dataflash",
|
||||
// .chip_select = 3,
|
||||
// .max_speed_hz = 15 * 1000 * 1000,
|
||||
// },
|
||||
// #endif
|
||||
// };
|
||||
|
||||
#define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
|
||||
#define PICOTUX200_FLASH_SIZE 0x400000
|
||||
|
||||
static struct physmap_flash_data picotux200_flash_data = {
|
||||
.width = 2,
|
||||
};
|
||||
|
||||
static struct resource picotux200_flash_resource = {
|
||||
.start = PICOTUX200_FLASH_BASE,
|
||||
.end = PICOTUX200_FLASH_BASE + PICOTUX200_FLASH_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
static struct platform_device picotux200_flash = {
|
||||
.name = "physmap-flash",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &picotux200_flash_data,
|
||||
},
|
||||
.resource = &picotux200_flash_resource,
|
||||
.num_resources = 1,
|
||||
};
|
||||
|
||||
static void __init picotux200_board_init(void)
|
||||
{
|
||||
/* Serial */
|
||||
at91_add_device_serial();
|
||||
/* Ethernet */
|
||||
at91_add_device_eth(&picotux200_eth_data);
|
||||
/* USB Host */
|
||||
at91_add_device_usbh(&picotux200_usbh_data);
|
||||
/* USB Device */
|
||||
// at91_add_device_udc(&picotux200_udc_data);
|
||||
// at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */
|
||||
/* I2C */
|
||||
at91_add_device_i2c();
|
||||
/* SPI */
|
||||
// at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices));
|
||||
#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
|
||||
/* DataFlash card */
|
||||
at91_set_gpio_output(AT91_PIN_PB22, 0);
|
||||
#else
|
||||
/* MMC */
|
||||
at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
|
||||
at91_add_device_mmc(0, &picotux200_mmc_data);
|
||||
#endif
|
||||
/* NOR Flash */
|
||||
platform_device_register(&picotux200_flash);
|
||||
}
|
||||
|
||||
MACHINE_START(PICOTUX2XX, "picotux 200")
|
||||
/* Maintainer: Kleinhenz Elektronik GmbH */
|
||||
.phys_io = AT91_BASE_SYS,
|
||||
.io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
|
||||
.boot_params = AT91_SDRAM_BASE + 0x100,
|
||||
.timer = &at91rm9200_timer,
|
||||
.map_io = picotux200_map_io,
|
||||
.init_irq = picotux200_init_irq,
|
||||
.init_machine = picotux200_board_init,
|
||||
MACHINE_END
|
@ -104,9 +104,9 @@ static struct spi_board_info ek_spi_devices[] = {
|
||||
},
|
||||
#endif
|
||||
#endif
|
||||
#if defined(CONFIG_SND_AT73C213)
|
||||
#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
|
||||
{ /* AT73C213 DAC */
|
||||
.modalias = "snd_at73c213",
|
||||
.modalias = "at73c213",
|
||||
.chip_select = 0,
|
||||
.max_speed_hz = 10 * 1000 * 1000,
|
||||
.bus_num = 1,
|
||||
@ -118,7 +118,7 @@ static struct spi_board_info ek_spi_devices[] = {
|
||||
/*
|
||||
* MACB Ethernet device
|
||||
*/
|
||||
static struct __initdata at91_eth_data ek_macb_data = {
|
||||
static struct at91_eth_data __initdata ek_macb_data = {
|
||||
.phy_irq_pin = AT91_PIN_PA7,
|
||||
.is_rmii = 1,
|
||||
};
|
||||
@ -140,7 +140,7 @@ static struct mtd_partition __initdata ek_nand_partition[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct mtd_partition *nand_partitions(int size, int *num_partitions)
|
||||
static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
|
||||
{
|
||||
*num_partitions = ARRAY_SIZE(ek_nand_partition);
|
||||
return ek_nand_partition;
|
||||
@ -188,6 +188,8 @@ static void __init ek_board_init(void)
|
||||
at91_add_device_eth(&ek_macb_data);
|
||||
/* MMC */
|
||||
at91_add_device_mmc(0, &ek_mmc_data);
|
||||
/* I2C */
|
||||
at91_add_device_i2c();
|
||||
}
|
||||
|
||||
MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
#include <linux/dm9000.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
@ -194,6 +195,41 @@ static struct at91_nand_data __initdata ek_nand_data = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* ADS7846 Touchscreen
|
||||
*/
|
||||
#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
|
||||
|
||||
static int ads7843_pendown_state(void)
|
||||
{
|
||||
return !at91_get_gpio_value(AT91_PIN_PC2); /* Touchscreen PENIRQ */
|
||||
}
|
||||
|
||||
static struct ads7846_platform_data ads_info = {
|
||||
.model = 7843,
|
||||
.x_min = 150,
|
||||
.x_max = 3830,
|
||||
.y_min = 190,
|
||||
.y_max = 3830,
|
||||
.vref_delay_usecs = 100,
|
||||
.x_plate_ohms = 450,
|
||||
.y_plate_ohms = 250,
|
||||
.pressure_max = 15000,
|
||||
.debounce_max = 1,
|
||||
.debounce_rep = 0,
|
||||
.debounce_tol = (~0),
|
||||
.get_pendown_state = ads7843_pendown_state,
|
||||
};
|
||||
|
||||
static void __init ek_add_device_ts(void)
|
||||
{
|
||||
at91_set_B_periph(AT91_PIN_PC2, 1); /* External IRQ0, with pullup */
|
||||
at91_set_gpio_input(AT91_PIN_PA11, 1); /* Touchscreen BUSY signal */
|
||||
}
|
||||
#else
|
||||
static void __init ek_add_device_ts(void) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SPI devices
|
||||
*/
|
||||
@ -204,6 +240,16 @@ static struct spi_board_info ek_spi_devices[] = {
|
||||
.max_speed_hz = 15 * 1000 * 1000,
|
||||
.bus_num = 0,
|
||||
},
|
||||
#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
|
||||
{
|
||||
.modalias = "ads7846",
|
||||
.chip_select = 2,
|
||||
.max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
|
||||
.bus_num = 0,
|
||||
.platform_data = &ads_info,
|
||||
.irq = AT91SAM9261_ID_IRQ0,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
|
||||
{ /* DataFlash card - jumper (J12) configurable to CS3 or CS0 */
|
||||
.modalias = "mtd_dataflash",
|
||||
@ -211,9 +257,9 @@ static struct spi_board_info ek_spi_devices[] = {
|
||||
.max_speed_hz = 15 * 1000 * 1000,
|
||||
.bus_num = 0,
|
||||
},
|
||||
#elif defined(CONFIG_SND_AT73C213)
|
||||
#elif defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
|
||||
{ /* AT73C213 DAC */
|
||||
.modalias = "snd_at73c213",
|
||||
.modalias = "at73c213",
|
||||
.chip_select = 3,
|
||||
.max_speed_hz = 10 * 1000 * 1000,
|
||||
.bus_num = 0,
|
||||
@ -241,6 +287,8 @@ static void __init ek_board_init(void)
|
||||
#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
|
||||
/* SPI */
|
||||
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
|
||||
/* Touchscreen */
|
||||
ek_add_device_ts();
|
||||
#else
|
||||
/* MMC */
|
||||
at91_add_device_mmc(0, &ek_mmc_data);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/setup.h>
|
||||
@ -85,6 +86,40 @@ static struct at91_udc_data __initdata ek_udc_data = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ADS7846 Touchscreen
|
||||
*/
|
||||
#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
|
||||
static int ads7843_pendown_state(void)
|
||||
{
|
||||
return !at91_get_gpio_value(AT91_PIN_PA15); /* Touchscreen PENIRQ */
|
||||
}
|
||||
|
||||
static struct ads7846_platform_data ads_info = {
|
||||
.model = 7843,
|
||||
.x_min = 150,
|
||||
.x_max = 3830,
|
||||
.y_min = 190,
|
||||
.y_max = 3830,
|
||||
.vref_delay_usecs = 100,
|
||||
.x_plate_ohms = 450,
|
||||
.y_plate_ohms = 250,
|
||||
.pressure_max = 15000,
|
||||
.debounce_max = 1,
|
||||
.debounce_rep = 0,
|
||||
.debounce_tol = (~0),
|
||||
.get_pendown_state = ads7843_pendown_state,
|
||||
};
|
||||
|
||||
static void __init ek_add_device_ts(void)
|
||||
{
|
||||
at91_set_B_periph(AT91_PIN_PA15, 1); /* External IRQ1, with pullup */
|
||||
at91_set_gpio_input(AT91_PIN_PA31, 1); /* Touchscreen BUSY signal */
|
||||
}
|
||||
#else
|
||||
static void __init ek_add_device_ts(void) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SPI devices.
|
||||
*/
|
||||
@ -97,6 +132,16 @@ static struct spi_board_info ek_spi_devices[] = {
|
||||
.bus_num = 0,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
|
||||
{
|
||||
.modalias = "ads7846",
|
||||
.chip_select = 3,
|
||||
.max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
|
||||
.bus_num = 0,
|
||||
.platform_data = &ads_info,
|
||||
.irq = AT91SAM9263_ID_IRQ1,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -111,6 +156,14 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* MACB Ethernet device
|
||||
*/
|
||||
static struct at91_eth_data __initdata ek_macb_data = {
|
||||
.is_rmii = 1,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* NAND flash
|
||||
*/
|
||||
@ -148,6 +201,14 @@ static struct at91_nand_data __initdata ek_nand_data = {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* AC97
|
||||
*/
|
||||
static struct atmel_ac97_data ek_ac97_data = {
|
||||
.reset_pin = AT91_PIN_PA13,
|
||||
};
|
||||
|
||||
|
||||
static void __init ek_board_init(void)
|
||||
{
|
||||
/* Serial */
|
||||
@ -157,11 +218,20 @@ static void __init ek_board_init(void)
|
||||
/* USB Device */
|
||||
at91_add_device_udc(&ek_udc_data);
|
||||
/* SPI */
|
||||
at91_set_gpio_output(AT91_PIN_PE20, 1); /* select spi0 clock */
|
||||
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
|
||||
/* Touchscreen */
|
||||
ek_add_device_ts();
|
||||
/* MMC */
|
||||
at91_add_device_mmc(1, &ek_mmc_data);
|
||||
/* Ethernet */
|
||||
at91_add_device_eth(&ek_macb_data);
|
||||
/* NAND */
|
||||
at91_add_device_nand(&ek_nand_data);
|
||||
/* I2C */
|
||||
at91_add_device_i2c();
|
||||
/* AC97 */
|
||||
at91_add_device_ac97(&ek_ac97_data);
|
||||
}
|
||||
|
||||
MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
|
||||
|
@ -102,6 +102,26 @@ EXPORT_SYMBOL(__readb);
|
||||
EXPORT_SYMBOL(__readw);
|
||||
EXPORT_SYMBOL(__readl);
|
||||
|
||||
void readsw(void __iomem *addr, void *data, int len)
|
||||
{
|
||||
void __iomem *a = __isamem_convert_addr(addr);
|
||||
|
||||
BUG_ON((unsigned long)addr & 1);
|
||||
|
||||
__raw_readsw(a, data, len);
|
||||
}
|
||||
EXPORT_SYMBOL(readsw);
|
||||
|
||||
void readsl(void __iomem *addr, void *data, int len)
|
||||
{
|
||||
void __iomem *a = __isamem_convert_addr(addr);
|
||||
|
||||
BUG_ON((unsigned long)addr & 3);
|
||||
|
||||
__raw_readsl(a, data, len);
|
||||
}
|
||||
EXPORT_SYMBOL(readsl);
|
||||
|
||||
void __writeb(u8 val, void __iomem *addr)
|
||||
{
|
||||
void __iomem *a = __isamem_convert_addr(addr);
|
||||
@ -137,6 +157,26 @@ EXPORT_SYMBOL(__writeb);
|
||||
EXPORT_SYMBOL(__writew);
|
||||
EXPORT_SYMBOL(__writel);
|
||||
|
||||
void writesw(void __iomem *addr, void *data, int len)
|
||||
{
|
||||
void __iomem *a = __isamem_convert_addr(addr);
|
||||
|
||||
BUG_ON((unsigned long)addr & 1);
|
||||
|
||||
__raw_writesw(a, data, len);
|
||||
}
|
||||
EXPORT_SYMBOL(writesw);
|
||||
|
||||
void writesl(void __iomem *addr, void *data, int len)
|
||||
{
|
||||
void __iomem *a = __isamem_convert_addr(addr);
|
||||
|
||||
BUG_ON((unsigned long)addr & 3);
|
||||
|
||||
__raw_writesl(a, data, len);
|
||||
}
|
||||
EXPORT_SYMBOL(writesl);
|
||||
|
||||
#define SUPERIO_PORT(p) \
|
||||
(((p) >> 3) == (0x3f8 >> 3) || \
|
||||
((p) >> 3) == (0x2f8 >> 3) || \
|
||||
|
@ -27,6 +27,10 @@ struct clk {
|
||||
u32 enable_mask;
|
||||
};
|
||||
|
||||
static struct clk clk_uart = {
|
||||
.name = "UARTCLK",
|
||||
.rate = 14745600,
|
||||
};
|
||||
static struct clk clk_pll1 = {
|
||||
.name = "pll1",
|
||||
};
|
||||
@ -50,6 +54,7 @@ static struct clk clk_usb_host = {
|
||||
|
||||
|
||||
static struct clk *clocks[] = {
|
||||
&clk_uart,
|
||||
&clk_pll1,
|
||||
&clk_f,
|
||||
&clk_h,
|
||||
|
@ -10,7 +10,6 @@
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -23,7 +23,6 @@
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -7,5 +7,6 @@ obj-$(CONFIG_ARCH_IOP13XX) += setup.o
|
||||
obj-$(CONFIG_ARCH_IOP13XX) += irq.o
|
||||
obj-$(CONFIG_ARCH_IOP13XX) += pci.o
|
||||
obj-$(CONFIG_ARCH_IOP13XX) += io.o
|
||||
obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o
|
||||
obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o
|
||||
obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o
|
||||
|
@ -41,7 +41,7 @@ void * __iomem __iop13xx_io(unsigned long io_addr)
|
||||
EXPORT_SYMBOL(__iop13xx_io);
|
||||
|
||||
void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
|
||||
unsigned long flags)
|
||||
unsigned int mtype)
|
||||
{
|
||||
void __iomem * retval;
|
||||
|
||||
@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
|
||||
(cookie - IOP13XX_PCIE_LOWER_MEM_RA));
|
||||
break;
|
||||
case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA:
|
||||
retval = __ioremap(IOP13XX_PBI_LOWER_MEM_PA +
|
||||
(cookie - IOP13XX_PBI_LOWER_MEM_RA),
|
||||
size, flags);
|
||||
retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA +
|
||||
(cookie - IOP13XX_PBI_LOWER_MEM_RA),
|
||||
size, mtype);
|
||||
break;
|
||||
case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
|
||||
retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
|
||||
@ -75,7 +75,7 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
|
||||
retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
|
||||
break;
|
||||
default:
|
||||
retval = __ioremap(cookie, size, flags);
|
||||
retval = __arm_ioremap(cookie, size, mtype);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -75,11 +75,14 @@ static void __init iq81340mc_init(void)
|
||||
{
|
||||
iop13xx_platform_init();
|
||||
iq81340mc_pci_init();
|
||||
iop13xx_add_tpmi_devices();
|
||||
}
|
||||
|
||||
static void __init iq81340mc_timer_init(void)
|
||||
{
|
||||
iop_init_time(400000000);
|
||||
unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio();
|
||||
printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq);
|
||||
iop_init_time(bus_freq);
|
||||
}
|
||||
|
||||
static struct sys_timer iq81340mc_timer = {
|
||||
|
@ -77,11 +77,14 @@ static void __init iq81340sc_init(void)
|
||||
{
|
||||
iop13xx_platform_init();
|
||||
iq81340sc_pci_init();
|
||||
iop13xx_add_tpmi_devices();
|
||||
}
|
||||
|
||||
static void __init iq81340sc_timer_init(void)
|
||||
{
|
||||
iop_init_time(400000000);
|
||||
unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio();
|
||||
printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq);
|
||||
iop_init_time(bus_freq);
|
||||
}
|
||||
|
||||
static struct sys_timer iq81340sc_timer = {
|
||||
|
@ -88,9 +88,9 @@ void iop13xx_map_pci_memory(void)
|
||||
|
||||
if (end) {
|
||||
iop13xx_atux_mem_base =
|
||||
(u32) __ioremap_pfn(
|
||||
(u32) __arm_ioremap_pfn(
|
||||
__phys_to_pfn(IOP13XX_PCIX_LOWER_MEM_PA)
|
||||
, 0, iop13xx_atux_mem_size, 0);
|
||||
, 0, iop13xx_atux_mem_size, MT_DEVICE);
|
||||
if (!iop13xx_atux_mem_base) {
|
||||
printk("%s: atux allocation "
|
||||
"failed\n", __FUNCTION__);
|
||||
@ -114,9 +114,9 @@ void iop13xx_map_pci_memory(void)
|
||||
|
||||
if (end) {
|
||||
iop13xx_atue_mem_base =
|
||||
(u32) __ioremap_pfn(
|
||||
(u32) __arm_ioremap_pfn(
|
||||
__phys_to_pfn(IOP13XX_PCIE_LOWER_MEM_PA)
|
||||
, 0, iop13xx_atue_mem_size, 0);
|
||||
, 0, iop13xx_atue_mem_size, MT_DEVICE);
|
||||
if (!iop13xx_atue_mem_base) {
|
||||
printk("%s: atue allocation "
|
||||
"failed\n", __FUNCTION__);
|
||||
@ -1023,7 +1023,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
|
||||
<< IOP13XX_ATUX_PCIXSR_FUNC_NUM;
|
||||
__raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR);
|
||||
|
||||
res[0].start = IOP13XX_PCIX_LOWER_IO_PA;
|
||||
res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET;
|
||||
res[0].end = IOP13XX_PCIX_UPPER_IO_PA;
|
||||
res[0].name = "IQ81340 ATUX PCI I/O Space";
|
||||
res[0].flags = IORESOURCE_IO;
|
||||
@ -1033,7 +1033,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
|
||||
res[1].name = "IQ81340 ATUX PCI Memory Space";
|
||||
res[1].flags = IORESOURCE_MEM;
|
||||
sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET;
|
||||
sys->io_offset = IOP13XX_PCIX_IO_OFFSET;
|
||||
sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA;
|
||||
break;
|
||||
case IOP13XX_INIT_ATU_ATUE:
|
||||
/* Note: the function number field in the PCSR is ro */
|
||||
@ -1044,7 +1044,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
|
||||
|
||||
__raw_writel(pcsr, IOP13XX_ATUE_PCSR);
|
||||
|
||||
res[0].start = IOP13XX_PCIE_LOWER_IO_PA;
|
||||
res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET;
|
||||
res[0].end = IOP13XX_PCIE_UPPER_IO_PA;
|
||||
res[0].name = "IQ81340 ATUE PCI I/O Space";
|
||||
res[0].flags = IORESOURCE_IO;
|
||||
@ -1054,7 +1054,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
|
||||
res[1].name = "IQ81340 ATUE PCI Memory Space";
|
||||
res[1].flags = IORESOURCE_MEM;
|
||||
sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET;
|
||||
sys->io_offset = IOP13XX_PCIE_IO_OFFSET;
|
||||
sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA;
|
||||
sys->map_irq = iop13xx_pcie_map_irq;
|
||||
break;
|
||||
default:
|
||||
|
@ -258,15 +258,11 @@ void __init iop13xx_platform_init(void)
|
||||
|
||||
if (init_uart == IOP13XX_INIT_UART_DEFAULT) {
|
||||
switch (iop13xx_dev_id()) {
|
||||
/* enable both uarts on iop341 and iop342 */
|
||||
/* enable both uarts on iop341 */
|
||||
case 0x3380:
|
||||
case 0x3384:
|
||||
case 0x3388:
|
||||
case 0x338c:
|
||||
case 0x3382:
|
||||
case 0x3386:
|
||||
case 0x338a:
|
||||
case 0x338e:
|
||||
init_uart |= IOP13XX_INIT_UART_0;
|
||||
init_uart |= IOP13XX_INIT_UART_1;
|
||||
break;
|
||||
|
234
arch/arm/mach-iop13xx/tpmi.c
Normal file
234
arch/arm/mach-iop13xx/tpmi.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* iop13xx tpmi device resources
|
||||
* Copyright (c) 2005-2006, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/sizes.h>
|
||||
|
||||
/* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */
|
||||
#define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12))
|
||||
#define IOP13XX_TPMI_MEM(dev) IOP13XX_REG_ADDR32_PHYS(0x60000 + (dev << 13))
|
||||
#define IOP13XX_TPMI_CTRL(dev) IOP13XX_REG_ADDR32_PHYS(0x50000 + (dev << 10))
|
||||
#define IOP13XX_TPMI_MMR_SIZE (SZ_4K - 1)
|
||||
#define IOP13XX_TPMI_MEM_SIZE (255)
|
||||
#define IOP13XX_TPMI_MEM_CTRL (SZ_1K - 1)
|
||||
#define IOP13XX_TPMI_RESOURCE_MMR 0
|
||||
#define IOP13XX_TPMI_RESOURCE_MEM 1
|
||||
#define IOP13XX_TPMI_RESOURCE_CTRL 2
|
||||
#define IOP13XX_TPMI_RESOURCE_IRQ 3
|
||||
|
||||
static struct resource iop13xx_tpmi_0_resources[] = {
|
||||
[IOP13XX_TPMI_RESOURCE_MMR] = {
|
||||
.start = IOP13XX_TPMI_MMR(4), /* tpmi0 starts at dev == 4 */
|
||||
.end = IOP13XX_TPMI_MMR(4) + IOP13XX_TPMI_MMR_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_MEM] = {
|
||||
.start = IOP13XX_TPMI_MEM(0),
|
||||
.end = IOP13XX_TPMI_MEM(0) + IOP13XX_TPMI_MEM_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_CTRL] = {
|
||||
.start = IOP13XX_TPMI_CTRL(0),
|
||||
.end = IOP13XX_TPMI_CTRL(0) + IOP13XX_TPMI_MEM_CTRL,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_IRQ] = {
|
||||
.start = IRQ_IOP13XX_TPMI0_OUT,
|
||||
.end = IRQ_IOP13XX_TPMI0_OUT,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource iop13xx_tpmi_1_resources[] = {
|
||||
[IOP13XX_TPMI_RESOURCE_MMR] = {
|
||||
.start = IOP13XX_TPMI_MMR(1),
|
||||
.end = IOP13XX_TPMI_MMR(1) + IOP13XX_TPMI_MMR_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_MEM] = {
|
||||
.start = IOP13XX_TPMI_MEM(1),
|
||||
.end = IOP13XX_TPMI_MEM(1) + IOP13XX_TPMI_MEM_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_CTRL] = {
|
||||
.start = IOP13XX_TPMI_CTRL(1),
|
||||
.end = IOP13XX_TPMI_CTRL(1) + IOP13XX_TPMI_MEM_CTRL,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_IRQ] = {
|
||||
.start = IRQ_IOP13XX_TPMI1_OUT,
|
||||
.end = IRQ_IOP13XX_TPMI1_OUT,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource iop13xx_tpmi_2_resources[] = {
|
||||
[IOP13XX_TPMI_RESOURCE_MMR] = {
|
||||
.start = IOP13XX_TPMI_MMR(2),
|
||||
.end = IOP13XX_TPMI_MMR(2) + IOP13XX_TPMI_MMR_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_MEM] = {
|
||||
.start = IOP13XX_TPMI_MEM(2),
|
||||
.end = IOP13XX_TPMI_MEM(2) + IOP13XX_TPMI_MEM_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_CTRL] = {
|
||||
.start = IOP13XX_TPMI_CTRL(2),
|
||||
.end = IOP13XX_TPMI_CTRL(2) + IOP13XX_TPMI_MEM_CTRL,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_IRQ] = {
|
||||
.start = IRQ_IOP13XX_TPMI2_OUT,
|
||||
.end = IRQ_IOP13XX_TPMI2_OUT,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource iop13xx_tpmi_3_resources[] = {
|
||||
[IOP13XX_TPMI_RESOURCE_MMR] = {
|
||||
.start = IOP13XX_TPMI_MMR(3),
|
||||
.end = IOP13XX_TPMI_MMR(3) + IOP13XX_TPMI_MMR_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_MEM] = {
|
||||
.start = IOP13XX_TPMI_MEM(3),
|
||||
.end = IOP13XX_TPMI_MEM(3) + IOP13XX_TPMI_MEM_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_CTRL] = {
|
||||
.start = IOP13XX_TPMI_CTRL(3),
|
||||
.end = IOP13XX_TPMI_CTRL(3) + IOP13XX_TPMI_MEM_CTRL,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[IOP13XX_TPMI_RESOURCE_IRQ] = {
|
||||
.start = IRQ_IOP13XX_TPMI3_OUT,
|
||||
.end = IRQ_IOP13XX_TPMI3_OUT,
|
||||
.flags = IORESOURCE_IRQ
|
||||
}
|
||||
};
|
||||
|
||||
u64 iop13xx_tpmi_mask = DMA_64BIT_MASK;
|
||||
static struct platform_device iop13xx_tpmi_0_device = {
|
||||
.name = "iop-tpmi",
|
||||
.id = 0,
|
||||
.num_resources = 4,
|
||||
.resource = iop13xx_tpmi_0_resources,
|
||||
.dev = {
|
||||
.dma_mask = &iop13xx_tpmi_mask,
|
||||
.coherent_dma_mask = DMA_64BIT_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device iop13xx_tpmi_1_device = {
|
||||
.name = "iop-tpmi",
|
||||
.id = 1,
|
||||
.num_resources = 4,
|
||||
.resource = iop13xx_tpmi_1_resources,
|
||||
.dev = {
|
||||
.dma_mask = &iop13xx_tpmi_mask,
|
||||
.coherent_dma_mask = DMA_64BIT_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device iop13xx_tpmi_2_device = {
|
||||
.name = "iop-tpmi",
|
||||
.id = 2,
|
||||
.num_resources = 4,
|
||||
.resource = iop13xx_tpmi_2_resources,
|
||||
.dev = {
|
||||
.dma_mask = &iop13xx_tpmi_mask,
|
||||
.coherent_dma_mask = DMA_64BIT_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device iop13xx_tpmi_3_device = {
|
||||
.name = "iop-tpmi",
|
||||
.id = 3,
|
||||
.num_resources = 4,
|
||||
.resource = iop13xx_tpmi_3_resources,
|
||||
.dev = {
|
||||
.dma_mask = &iop13xx_tpmi_mask,
|
||||
.coherent_dma_mask = DMA_64BIT_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
__init void iop13xx_add_tpmi_devices(void)
|
||||
{
|
||||
unsigned short device_id;
|
||||
|
||||
/* tpmi's not present on iop341 or iop342 */
|
||||
if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX)
|
||||
/* ATUE must be present */
|
||||
device_id = __raw_readw(IOP13XX_ATUE_DID);
|
||||
else
|
||||
/* ATUX must be present */
|
||||
device_id = __raw_readw(IOP13XX_ATUX_DID);
|
||||
|
||||
switch (device_id) {
|
||||
/* iop34[1|2] 0-tpmi */
|
||||
case 0x3380:
|
||||
case 0x3384:
|
||||
case 0x3388:
|
||||
case 0x338c:
|
||||
case 0x3382:
|
||||
case 0x3386:
|
||||
case 0x338a:
|
||||
case 0x338e:
|
||||
return;
|
||||
/* iop348 1-tpmi */
|
||||
case 0x3310:
|
||||
case 0x3312:
|
||||
case 0x3314:
|
||||
case 0x3318:
|
||||
case 0x331a:
|
||||
case 0x331c:
|
||||
case 0x33c0:
|
||||
case 0x33c2:
|
||||
case 0x33c4:
|
||||
case 0x33c8:
|
||||
case 0x33ca:
|
||||
case 0x33cc:
|
||||
case 0x33b0:
|
||||
case 0x33b2:
|
||||
case 0x33b4:
|
||||
case 0x33b8:
|
||||
case 0x33ba:
|
||||
case 0x33bc:
|
||||
case 0x3320:
|
||||
case 0x3322:
|
||||
case 0x3324:
|
||||
case 0x3328:
|
||||
case 0x332a:
|
||||
case 0x332c:
|
||||
platform_device_register(&iop13xx_tpmi_0_device);
|
||||
return;
|
||||
default:
|
||||
platform_device_register(&iop13xx_tpmi_0_device);
|
||||
platform_device_register(&iop13xx_tpmi_1_device);
|
||||
platform_device_register(&iop13xx_tpmi_2_device);
|
||||
platform_device_register(&iop13xx_tpmi_3_device);
|
||||
return;
|
||||
}
|
||||
}
|
@ -34,6 +34,14 @@ config MACH_N2100
|
||||
Say Y here if you want to run your kernel on the Thecus n2100
|
||||
NAS appliance.
|
||||
|
||||
config IOP3XX_ATU
|
||||
bool "Enable the PCI Controller"
|
||||
default y
|
||||
help
|
||||
Say Y here if you want the IOP to initialize its PCI Controller.
|
||||
Say N if the IOP is an add in card, the host system owns the PCI
|
||||
bus in this case.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
@ -178,9 +178,10 @@ static struct hw_pci iq31244_pci __initdata = {
|
||||
|
||||
static int __init iq31244_pci_init(void)
|
||||
{
|
||||
if (is_ep80219())
|
||||
pci_common_init(&ep80219_pci);
|
||||
else if (machine_is_iq31244()) {
|
||||
if (is_ep80219()) {
|
||||
if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE)
|
||||
pci_common_init(&ep80219_pci);
|
||||
} else if (machine_is_iq31244()) {
|
||||
if (is_80219()) {
|
||||
printk("note: iq31244 board type has been selected\n");
|
||||
printk("note: to select ep80219 operation:\n");
|
||||
@ -189,7 +190,9 @@ static int __init iq31244_pci_init(void)
|
||||
printk("\t2/ update boot loader to pass"
|
||||
" the ep80219 id: %d\n", MACH_TYPE_EP80219);
|
||||
}
|
||||
pci_common_init(&iq31244_pci);
|
||||
|
||||
if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE)
|
||||
pci_common_init(&iq31244_pci);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -113,7 +113,8 @@ static struct hw_pci iq80321_pci __initdata = {
|
||||
|
||||
static int __init iq80321_pci_init(void)
|
||||
{
|
||||
if (machine_is_iq80321())
|
||||
if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
|
||||
machine_is_iq80321())
|
||||
pci_common_init(&iq80321_pci);
|
||||
|
||||
return 0;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user