Merge branch 'master' into gfs2

This commit is contained in:
Steven Whitehouse 2006-09-28 08:29:59 -04:00
commit 185a257f2f
1941 changed files with 87478 additions and 33031 deletions

View file

@ -1,13 +1,12 @@
What: devfs
Date: July 2005
Date: July 2005 (scheduled), finally removed in kernel v2.6.18
Contact: Greg Kroah-Hartman <gregkh@suse.de>
Description:
devfs has been unmaintained for a number of years, has unfixable
races, contains a naming policy within the kernel that is
against the LSB, and can be replaced by using udev.
The files fs/devfs/*, include/linux/devfs_fs*.h will be removed,
The files fs/devfs/*, include/linux/devfs_fs*.h were removed,
along with the the assorted devfs function calls throughout the
kernel tree.
Users:

View file

@ -0,0 +1,88 @@
What: /sys/power/
Date: August 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power directory will contain files that will
provide a unified interface to the power management
subsystem.
What: /sys/power/state
Date: August 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power/state file controls the system power state.
Reading from this file returns what states are supported,
which is hard-coded to 'standby' (Power-On Suspend), 'mem'
(Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
Writing to this file one of these strings causes the system to
transition into that state. Please see the file
Documentation/power/states.txt for a description of each of
these states.
What: /sys/power/disk
Date: August 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power/disk file controls the operating mode of the
suspend-to-disk mechanism. Reading from this file returns
the name of the method by which the system will be put to
sleep on the next suspend. There are four methods supported:
'firmware' - means that the memory image will be saved to disk
by some firmware, in which case we also assume that the
firmware will handle the system suspend.
'platform' - the memory image will be saved by the kernel and
the system will be put to sleep by the platform driver (e.g.
ACPI or other PM registers).
'shutdown' - the memory image will be saved by the kernel and
the system will be powered off.
'reboot' - the memory image will be saved by the kernel and
the system will be rebooted.
The suspend-to-disk method may be chosen by writing to this
file one of the accepted strings:
'firmware'
'platform'
'shutdown'
'reboot'
It will only change to 'firmware' or 'platform' if the system
supports that.
What: /sys/power/image_size
Date: August 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power/image_size file controls the size of the image
created by the suspend-to-disk mechanism. It can be written a
string representing a non-negative integer that will be used
as an upper limit of the image size, in bytes. The kernel's
suspend-to-disk code will do its best to ensure the image size
will not exceed this number. However, if it turns out to be
impossible, the kernel will try to suspend anyway using the
smallest image possible. In particular, if "0" is written to
this file, the suspend image will be as small as possible.
Reading from this file will display the current image size
limit, which is set to 500 MB by default.
What: /sys/power/pm_trace
Date: August 2006
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
The /sys/power/pm_trace file controls the code which saves the
last PM event point in the RTC across reboots, so that you can
debug a machine that just hangs during suspend (or more
commonly, during resume). Namely, the RTC is only used to save
the last PM event point if this file contains '1'. Initially
it contains '0' which may be changed to '1' by writing a
string representing a nonzero integer into it.
To use this debugging feature you should attempt to suspend
the machine, then reboot it and run
dmesg -s 1000000 | grep 'hash matches'
CAUTION: Using it will cause your machine's real-time (CMOS)
clock to be set to a random invalid time after a resume.

View file

@ -43,59 +43,52 @@
<para>A Universal Serial Bus (USB) is used to connect a host,
such as a PC or workstation, to a number of peripheral
devices. USB uses a tree structure, with the host at the
devices. USB uses a tree structure, with the host as the
root (the system's master), hubs as interior nodes, and
peripheral devices as leaves (and slaves).
peripherals as leaves (and slaves).
Modern PCs support several such trees of USB devices, usually
one USB 2.0 tree (480 Mbit/sec each) with
a few USB 1.1 trees (12 Mbit/sec each) that are used when you
connect a USB 1.1 device directly to the machine's "root hub".
</para>
<para>That master/slave asymmetry was designed in part for
ease of use. It is not physically possible to assemble
(legal) USB cables incorrectly: all upstream "to-the-host"
connectors are the rectangular type, matching the sockets on
root hubs, and the downstream type are the squarish type
(or they are built in to the peripheral).
Software doesn't need to deal with distributed autoconfiguration
since the pre-designated master node manages all that.
At the electrical level, bus protocol overhead is reduced by
eliminating arbitration and moving scheduling into host software.
<para>That master/slave asymmetry was designed-in for a number of
reasons, one being ease of use. It is not physically possible to
assemble (legal) USB cables incorrectly: all upstream "to the host"
connectors are the rectangular type (matching the sockets on
root hubs), and all downstream connectors are the squarish type
(or they are built into the peripheral).
Also, the host software doesn't need to deal with distributed
auto-configuration since the pre-designated master node manages all that.
And finally, at the electrical level, bus protocol overhead is reduced by
eliminating arbitration and moving scheduling into the host software.
</para>
<para>USB 1.0 was announced in January 1996, and was revised
<para>USB 1.0 was announced in January 1996 and was revised
as USB 1.1 (with improvements in hub specification and
support for interrupt-out transfers) in September 1998.
USB 2.0 was released in April 2000, including high speed
transfers and transaction translating hubs (used for USB 1.1
USB 2.0 was released in April 2000, adding high-speed
transfers and transaction-translating hubs (used for USB 1.1
and 1.0 backward compatibility).
</para>
<para>USB support was added to Linux early in the 2.2 kernel series
shortly before the 2.3 development forked off. Updates
from 2.3 were regularly folded back into 2.2 releases, bringing
new features such as <filename>/sbin/hotplug</filename> support,
more drivers, and more robustness.
The 2.5 kernel series continued such improvements, and also
worked on USB 2.0 support,
higher performance,
better consistency between host controller drivers,
API simplification (to make bugs less likely),
and providing internal "kerneldoc" documentation.
<para>Kernel developers added USB support to Linux early in the 2.2 kernel
series, shortly before 2.3 development forked. Updates from 2.3 were
regularly folded back into 2.2 releases, which improved reliability and
brought <filename>/sbin/hotplug</filename> support as well more drivers.
Such improvements were continued in the 2.5 kernel series, where they added
USB 2.0 support, improved performance, and made the host controller drivers
(HCDs) more consistent. They also simplified the API (to make bugs less
likely) and added internal "kerneldoc" documentation.
</para>
<para>Linux can run inside USB devices as well as on
the hosts that control the devices.
Because the Linux 2.x USB support evolved to support mass market
platforms such as Apple Macintosh or PC-compatible systems,
it didn't address design concerns for those types of USB systems.
So it can't be used inside mass-market PDAs, or other peripherals.
USB device drivers running inside those Linux peripherals
But USB device drivers running inside those peripherals
don't do the same things as the ones running inside hosts,
and so they've been given a different name:
they're called <emphasis>gadget drivers</emphasis>.
This document does not present gadget drivers.
so they've been given a different name:
<emphasis>gadget drivers</emphasis>.
This document does not cover gadget drivers.
</para>
</chapter>
@ -103,17 +96,14 @@
<chapter id="host">
<title>USB Host-Side API Model</title>
<para>Within the kernel,
host-side drivers for USB devices talk to the "usbcore" APIs.
There are two types of public "usbcore" APIs, targetted at two different
layers of USB driver. Those are
<emphasis>general purpose</emphasis> drivers, exposed through
driver frameworks such as block, character, or network devices;
and drivers that are <emphasis>part of the core</emphasis>,
which are involved in managing a USB bus.
Such core drivers include the <emphasis>hub</emphasis> driver,
which manages trees of USB devices, and several different kinds
of <emphasis>host controller driver (HCD)</emphasis>,
<para>Host-side drivers for USB devices talk to the "usbcore" APIs.
There are two. One is intended for
<emphasis>general-purpose</emphasis> drivers (exposed through
driver frameworks), and the other is for drivers that are
<emphasis>part of the core</emphasis>.
Such core drivers include the <emphasis>hub</emphasis> driver
(which manages trees of USB devices) and several different kinds
of <emphasis>host controller drivers</emphasis>,
which control individual busses.
</para>
@ -122,21 +112,21 @@
<itemizedlist>
<listitem><para>USB supports four kinds of data transfer
(control, bulk, interrupt, and isochronous). Two transfer
types use bandwidth as it's available (control and bulk),
while the other two types of transfer (interrupt and isochronous)
<listitem><para>USB supports four kinds of data transfers
(control, bulk, interrupt, and isochronous). Two of them (control
and bulk) use bandwidth as it's available,
while the other two (interrupt and isochronous)
are scheduled to provide guaranteed bandwidth.
</para></listitem>
<listitem><para>The device description model includes one or more
"configurations" per device, only one of which is active at a time.
Devices that are capable of high speed operation must also support
full speed configurations, along with a way to ask about the
"other speed" configurations that might be used.
Devices that are capable of high-speed operation must also support
full-speed configurations, along with a way to ask about the
"other speed" configurations which might be used.
</para></listitem>
<listitem><para>Configurations have one or more "interface", each
<listitem><para>Configurations have one or more "interfaces", each
of which may have "alternate settings". Interfaces may be
standardized by USB "Class" specifications, or may be specific to
a vendor or device.</para>
@ -162,7 +152,7 @@
</para></listitem>
<listitem><para>The Linux USB API supports synchronous calls for
control and bulk messaging.
control and bulk messages.
It also supports asynchnous calls for all kinds of data transfer,
using request structures called "URBs" (USB Request Blocks).
</para></listitem>
@ -463,14 +453,25 @@
file in your Linux kernel sources.
</para>
<para>Otherwise the main use for this file from programs
is to poll() it to get notifications of usb devices
as they're plugged or unplugged.
To see what changed, you'd need to read the file and
compare "before" and "after" contents, scan the filesystem,
or see its hotplug event.
</para>
<para>This file, in combination with the poll() system call, can
also be used to detect when devices are added or removed:
<programlisting>int fd;
struct pollfd pfd;
fd = open("/proc/bus/usb/devices", O_RDONLY);
pfd = { fd, POLLIN, 0 };
for (;;) {
/* The first time through, this call will return immediately. */
poll(&amp;pfd, 1, -1);
/* To see what's changed, compare the file's previous and current
contents or scan the filesystem. (Scanning is more precise.) */
}</programlisting>
Note that this behavior is intended to be used for informational
and debug purposes. It would be more appropriate to use programs
such as udev or HAL to initialize a device or start a user-mode
helper program, for instance.
</para>
</sect1>
<sect1>

View file

@ -358,7 +358,8 @@ Here is a list of some of the different kernel trees available:
quilt trees:
- USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de>
kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
- x86-64, partly i386, Andi Kleen <ak@suse.de>
ftp.firstfloor.org:/pub/ak/x86_64/quilt/
Bug Reporting
-------------

View file

@ -2543,6 +2543,9 @@ Your cooperation is appreciated.
64 = /dev/usb/rio500 Diamond Rio 500
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
67 = /dev/usb/adutux0 1st Ontrak ADU device
...
76 = /dev/usb/adutux10 10th Ontrak ADU device
96 = /dev/usb/hiddev0 1st USB HID device
...
111 = /dev/usb/hiddev15 16th USB HID device

View file

@ -6,6 +6,21 @@ be removed from this file.
---------------------------
What: /sys/devices/.../power/state
dev->power.power_state
dpm_runtime_{suspend,resume)()
When: July 2007
Why: Broken design for runtime control over driver power states, confusing
driver-internal runtime power management with: mechanisms to support
system-wide sleep state transitions; event codes that distinguish
different phases of swsusp "sleep" transitions; and userspace policy
inputs. This framework was never widely used, and most attempts to
use it were broken. Drivers should instead be exposing domain-specific
interfaces either to kernel or to userspace.
Who: Pavel Machek <pavel@suse.cz>
---------------------------
What: RAW driver (CONFIG_RAW_DRIVER)
When: December 2005
Why: declared obsolete since kernel 2.6.3
@ -55,6 +70,18 @@ Who: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
---------------------------
What: sys_sysctl
When: January 2007
Why: The same information is available through /proc/sys and that is the
interface user space prefers to use. And there do not appear to be
any existing user in user space of sys_sysctl. The additional
maintenance overhead of keeping a set of binary names gets
in the way of doing a good job of maintaining this interface.
Who: Eric Biederman <ebiederm@xmission.com>
---------------------------
What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
When: November 2005
Files: drivers/pcmcia/: pcmcia_ioctl.c
@ -202,14 +229,6 @@ Who: Nick Piggin <npiggin@suse.de>
---------------------------
What: Support for the MIPS EV96100 evaluation board
When: September 2006
Why: Does no longer build since at least November 15, 2003, apparently
no userbase left.
Who: Ralf Baechle <ralf@linux-mips.org>
---------------------------
What: Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board
When: September 2006
Why: Does no longer build since quite some time, and was never popular,
@ -294,3 +313,24 @@ Why: The frame diverter is included in most distribution kernels, but is
It is not clear if anyone is still using it.
Who: Stephen Hemminger <shemminger@osdl.org>
---------------------------
What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
When: Oktober 2008
Why: The stacking of class devices makes these values misleading and
inconsistent.
Class devices should not carry any of these properties, and bus
devices have SUBSYTEM and DRIVER as a replacement.
Who: Kay Sievers <kay.sievers@suse.de>
---------------------------
What: i2c-isa
When: December 2006
Why: i2c-isa is a non-sense and doesn't fit in the device driver
model. Drivers relying on it are better implemented as platform
drivers.
Who: Jean Delvare <khali@linux-fr.org>
---------------------------

View file

@ -1124,11 +1124,15 @@ debugging information is displayed on console.
NMI switch that most IA32 servers have fires unknown NMI up, for example.
If a system hangs up, try pressing the NMI switch.
[NOTE]
This function and oprofile share a NMI callback. Therefore this function
cannot be enabled when oprofile is activated.
And NMI watchdog will be disabled when the value in this file is set to
non-zero.
nmi_watchdog
------------
Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero
the NMI watchdog is enabled and will continuously test all online cpus to
determine whether or not they are still functioning properly.
Because the NMI watchdog shares registers with oprofile, by disabling the NMI
watchdog, oprofile may have more registers to utilize.
2.4 /proc/sys/vm - The virtual memory subsystem

View file

@ -7,9 +7,12 @@ Supported adapters:
* VIA Technologies, Inc. VT82C686A/B
Datasheet: Sometimes available at the VIA website
* VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R
* VIA Technologies, Inc. VT8231, VT8233, VT8233A
Datasheet: available on request from VIA
* VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251
Datasheet: available on request and under NDA from VIA
Authors:
Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
@ -39,6 +42,8 @@ Your lspci -n listing must show one of these :
device 1106:8235 (VT8231 function 4)
device 1106:3177 (VT8235)
device 1106:3227 (VT8237R)
device 1106:3337 (VT8237A)
device 1106:3287 (VT8251)
If none of these show up, you should look in the BIOS for settings like
enable ACPI / SMBus or even USB.

View file

@ -6,9 +6,12 @@ This module is a very simple fake I2C/SMBus driver. It implements four
types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
(r/w) word data.
You need to provide a chip address as a module parameter when loading
this driver, which will then only react to SMBus commands to this address.
No hardware is needed nor associated with this module. It will accept write
quick commands to all addresses; it will respond to the other commands (also
to all addresses) by reading from or writing to an array in memory. It will
quick commands to one address; it will respond to the other commands (also
to one address) by reading from or writing to an array in memory. It will
also spam the kernel logs for every command it handles.
A pointer register with auto-increment is implemented for all byte
@ -21,6 +24,11 @@ The typical use-case is like this:
3. load the target sensors chip driver module
4. observe its behavior in the kernel log
PARAMETERS:
int chip_addr:
The SMBus address to emulate a chip at.
CAVEATS:
There are independent arrays for byte/data and word/data commands. Depending
@ -33,6 +41,9 @@ If the hardware for your driver has banked registers (e.g. Winbond sensors
chips) this module will not work well - although it could be extended to
support that pretty easily.
Only one chip address is supported - although this module could be
extended to support more.
If you spam it hard enough, printk can be lossy. This module really wants
something like relayfs.

View file

@ -421,6 +421,11 @@ more details, with real examples.
The second argument is optional, and if supplied will be used
if first argument is not supported.
as-instr
as-instr checks if the assembler reports a specific instruction
and then outputs either option1 or option2
C escapes are supported in the test instruction
cc-option
cc-option is used to check if $(CC) supports a given option, and not
supported to use an optional second option.

View file

@ -573,8 +573,6 @@ running once the system is up.
gscd= [HW,CD]
Format: <io>
gt96100eth= [NET] MIPS GT96100 Advanced Communication Controller
gus= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma16>
@ -1240,7 +1238,11 @@ running once the system is up.
bootloader. This is currently used on
IXP2000 systems where the bus has to be
configured a certain way for adjunct CPUs.
noearly [X86] Don't do any early type 1 scanning.
This might help on some broken boards which
machine check when some devices' config space
is read. But various workarounds are disabled
and some IOMMU drivers will not work.
pcmv= [HW,PCMCIA] BadgePAD 4
pd. [PARIDE]
@ -1363,6 +1365,14 @@ running once the system is up.
reserve= [KNL,BUGS] Force the kernel to ignore some iomem area
reservetop= [IA-32]
Format: nn[KMG]
Reserves a hole at the top of the kernel virtual
address space.
reset_devices [KNL] Force drivers to reset the underlying device
during initialization.
resume= [SWSUSP]
Specify the partition device for software suspend

View file

@ -192,6 +192,17 @@ or, for backwards compatibility, the option value. E.g.,
arp_interval
Specifies the ARP link monitoring frequency in milliseconds.
The ARP monitor works by periodically checking the slave
devices to determine whether they have sent or received
traffic recently (the precise criteria depends upon the
bonding mode, and the state of the slave). Regular traffic is
generated via ARP probes issued for the addresses specified by
the arp_ip_target option.
This behavior can be modified by the arp_validate option,
below.
If ARP monitoring is used in an etherchannel compatible mode
(modes 0 and 2), the switch should be configured in a mode
that evenly distributes packets across all links. If the
@ -213,6 +224,54 @@ arp_ip_target
maximum number of targets that can be specified is 16. The
default value is no IP addresses.
arp_validate
Specifies whether or not ARP probes and replies should be
validated in the active-backup mode. This causes the ARP
monitor to examine the incoming ARP requests and replies, and
only consider a slave to be up if it is receiving the
appropriate ARP traffic.
Possible values are:
none or 0
No validation is performed. This is the default.
active or 1
Validation is performed only for the active slave.
backup or 2
Validation is performed only for backup slaves.
all or 3
Validation is performed for all slaves.
For the active slave, the validation checks ARP replies to
confirm that they were generated by an arp_ip_target. Since
backup slaves do not typically receive these replies, the
validation performed for backup slaves is on the ARP request
sent out via the active slave. It is possible that some
switch or network configurations may result in situations
wherein the backup slaves do not receive the ARP requests; in
such a situation, validation of backup slaves must be
disabled.
This option is useful in network configurations in which
multiple bonding hosts are concurrently issuing ARPs to one or
more targets beyond a common switch. Should the link between
the switch and target fail (but not the switch itself), the
probe traffic generated by the multiple bonding instances will
fool the standard ARP monitor into considering the links as
still up. Use of the arp_validate option can resolve this, as
the ARP monitor will only consider ARP requests and replies
associated with its own instance of bonding.
This option was added in bonding version 3.1.0.
downdelay
Specifies the time, in milliseconds, to wait before disabling

View file

@ -1,7 +1,6 @@
DCCP protocol
============
Last updated: 10 November 2005
Contents
========
@ -42,8 +41,11 @@ Socket options
DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
calculations.
DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the
specification. If you don't set it you will get EPROTO.
DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
the socket will fall back to 0 (which means that no meaningful service code
is present). Connecting sockets set at most one service option; for
listening sockets, multiple service codes can be specified.
Notes
=====

View file

@ -116,6 +116,9 @@ FURTHER NOTES ON NO-MMU MMAP
(*) A list of all the mappings on the system is visible through /proc/maps in
no-MMU mode.
(*) A list of all the mappings in use by a process is visible through
/proc/<pid>/maps in no-MMU mode.
(*) Supplying MAP_FIXED or a requesting a particular mapping address will
result in an error.
@ -125,6 +128,49 @@ FURTHER NOTES ON NO-MMU MMAP
error will result if they don't. This is most likely to be encountered
with character device files, pipes, fifos and sockets.
==========================
INTERPROCESS SHARED MEMORY
==========================
Both SYSV IPC SHM shared memory and POSIX shared memory is supported in NOMMU
mode. The former through the usual mechanism, the latter through files created
on ramfs or tmpfs mounts.
=======
FUTEXES
=======
Futexes are supported in NOMMU mode if the arch supports them. An error will
be given if an address passed to the futex system call lies outside the
mappings made by a process or if the mapping in which the address lies does not
support futexes (such as an I/O chardev mapping).
=============
NO-MMU MREMAP
=============
The mremap() function is partially supported. It may change the size of a
mapping, and may move it[*] if MREMAP_MAYMOVE is specified and if the new size
of the mapping exceeds the size of the slab object currently occupied by the
memory to which the mapping refers, or if a smaller slab object could be used.
MREMAP_FIXED is not supported, though it is ignored if there's no change of
address and the object does not need to be moved.
Shared mappings may not be moved. Shareable mappings may not be moved either,
even if they are not currently shared.
The mremap() function must be given an exact match for base address and size of
a previously mapped object. It may not be used to create holes in existing
mappings, move parts of existing mappings or resize parts of mappings. It must
act on a complete mapping.
[*] Not currently supported.
============================================
PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT
============================================

View file

@ -0,0 +1,253 @@
The PCI Express Advanced Error Reporting Driver Guide HOWTO
T. Long Nguyen <tom.l.nguyen@intel.com>
Yanmin Zhang <yanmin.zhang@intel.com>
07/29/2006
1. Overview
1.1 About this guide
This guide describes the basics of the PCI Express Advanced Error
Reporting (AER) driver and provides information on how to use it, as
well as how to enable the drivers of endpoint devices to conform with
PCI Express AER driver.
1.2 Copyright © Intel Corporation 2006.
1.3 What is the PCI Express AER Driver?
PCI Express error signaling can occur on the PCI Express link itself
or on behalf of transactions initiated on the link. PCI Express
defines two error reporting paradigms: the baseline capability and
the Advanced Error Reporting capability. The baseline capability is
required of all PCI Express components providing a minimum defined
set of error reporting requirements. Advanced Error Reporting
capability is implemented with a PCI Express advanced error reporting
extended capability structure providing more robust error reporting.
The PCI Express AER driver provides the infrastructure to support PCI
Express Advanced Error Reporting capability. The PCI Express AER
driver provides three basic functions:
- Gathers the comprehensive error information if errors occurred.
- Reports error to the users.
- Performs error recovery actions.
AER driver only attaches root ports which support PCI-Express AER
capability.
2. User Guide
2.1 Include the PCI Express AER Root Driver into the Linux Kernel
The PCI Express AER Root driver is a Root Port service driver attached
to the PCI Express Port Bus driver. If a user wants to use it, the driver
has to be compiled. Option CONFIG_PCIEAER supports this capability. It
depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and
CONFIG_PCIEAER = y.
2.2 Load PCI Express AER Root Driver
There is a case where a system has AER support in BIOS. Enabling the AER
Root driver and having AER support in BIOS may result unpredictable
behavior. To avoid this conflict, a successful load of the AER Root driver
requires ACPI _OSC support in the BIOS to allow the AER Root driver to
request for native control of AER. See the PCI FW 3.0 Specification for
details regarding OSC usage. Currently, lots of firmwares don't provide
_OSC support while they use PCI Express. To support such firmwares,
forceload, a parameter of type bool, could enable AER to continue to
be initiated although firmwares have no _OSC support. To enable the
walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line
when booting kernel. Note that forceload=n by default.
2.3 AER error output
When a PCI-E AER error is captured, an error message will be outputed to
console. If it's a correctable error, it is outputed as a warning.
Otherwise, it is printed as an error. So users could choose different
log level to filter out correctable error messages.
Below shows an example.
+------ PCI-Express Device Error -----+
Error Severity : Uncorrected (Fatal)
PCIE Bus Error type : Transaction Layer
Unsupported Request : First
Requester ID : 0500
VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h
TLB Header:
04000001 00200a03 05010000 00050100
In the example, 'Requester ID' means the ID of the device who sends
the error message to root port. Pls. refer to pci express specs for
other fields.
3. Developer Guide
To enable AER aware support requires a software driver to configure
the AER capability structure within its device and to provide callbacks.
To support AER better, developers need understand how AER does work
firstly.
PCI Express errors are classified into two types: correctable errors
and uncorrectable errors. This classification is based on the impacts
of those errors, which may result in degraded performance or function
failure.
Correctable errors pose no impacts on the functionality of the
interface. The PCI Express protocol can recover without any software
intervention or any loss of data. These errors are detected and
corrected by hardware. Unlike correctable errors, uncorrectable
errors impact functionality of the interface. Uncorrectable errors
can cause a particular transaction or a particular PCI Express link
to be unreliable. Depending on those error conditions, uncorrectable
errors are further classified into non-fatal errors and fatal errors.
Non-fatal errors cause the particular transaction to be unreliable,
but the PCI Express link itself is fully functional. Fatal errors, on
the other hand, cause the link to be unreliable.
When AER is enabled, a PCI Express device will automatically send an
error message to the PCIE root port above it when the device captures
an error. The Root Port, upon receiving an error reporting message,
internally processes and logs the error message in its PCI Express
capability structure. Error information being logged includes storing
the error reporting agent's requestor ID into the Error Source
Identification Registers and setting the error bits of the Root Error
Status Register accordingly. If AER error reporting is enabled in Root
Error Command Register, the Root Port generates an interrupt if an
error is detected.
Note that the errors as described above are related to the PCI Express
hierarchy and links. These errors do not include any device specific
errors because device specific errors will still get sent directly to
the device driver.
3.1 Configure the AER capability structure
AER aware drivers of PCI Express component need change the device
control registers to enable AER. They also could change AER registers,
including mask and severity registers. Helper function
pci_enable_pcie_error_reporting could be used to enable AER. See
section 3.3.
3.2. Provide callbacks
3.2.1 callback reset_link to reset pci express link
This callback is used to reset the pci express physical link when a
fatal error happens. The root port aer service driver provides a
default reset_link function, but different upstream ports might
have different specifications to reset pci express link, so all
upstream ports should provide their own reset_link functions.
In struct pcie_port_service_driver, a new pointer, reset_link, is
added.
pci_ers_result_t (*reset_link) (struct pci_dev *dev);
Section 3.2.2.2 provides more detailed info on when to call
reset_link.
3.2.2 PCI error-recovery callbacks
The PCI Express AER Root driver uses error callbacks to coordinate
with downstream device drivers associated with a hierarchy in question
when performing error recovery actions.
Data struct pci_driver has a pointer, err_handler, to point to
pci_error_handlers who consists of a couple of callback function
pointers. AER driver follows the rules defined in
pci-error-recovery.txt except pci express specific parts (e.g.
reset_link). Pls. refer to pci-error-recovery.txt for detailed
definitions of the callbacks.
Below sections specify when to call the error callback functions.
3.2.2.1 Correctable errors
Correctable errors pose no impacts on the functionality of
the interface. The PCI Express protocol can recover without any
software intervention or any loss of data. These errors do not
require any recovery actions. The AER driver clears the device's
correctable error status register accordingly and logs these errors.
3.2.2.2 Non-correctable (non-fatal and fatal) errors
If an error message indicates a non-fatal error, performing link reset
at upstream is not required. The AER driver calls error_detected(dev,
pci_channel_io_normal) to all drivers associated within a hierarchy in
question. for example,
EndPoint<==>DownstreamPort B<==>UpstreamPort A<==>RootPort.
If Upstream port A captures an AER error, the hierarchy consists of
Downstream port B and EndPoint.
A driver may return PCI_ERS_RESULT_CAN_RECOVER,
PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on
whether it can recover or the AER driver calls mmio_enabled as next.
If an error message indicates a fatal error, kernel will broadcast
error_detected(dev, pci_channel_io_frozen) to all drivers within
a hierarchy in question. Then, performing link reset at upstream is
necessary. As different kinds of devices might use different approaches
to reset link, AER port service driver is required to provide the
function to reset link. Firstly, kernel looks for if the upstream
component has an aer driver. If it has, kernel uses the reset_link
callback of the aer driver. If the upstream component has no aer driver
and the port is downstream port, we will use the aer driver of the
root port who reports the AER error. As for upstream ports,
they should provide their own aer service drivers with reset_link
function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
to mmio_enabled.
3.3 helper functions
3.3.1 int pci_find_aer_capability(struct pci_dev *dev);
pci_find_aer_capability locates the PCI Express AER capability
in the device configuration space. If the device doesn't support
PCI-Express AER, the function returns 0.
3.3.2 int pci_enable_pcie_error_reporting(struct pci_dev *dev);
pci_enable_pcie_error_reporting enables the device to send error
messages to root port when an error is detected. Note that devices
don't enable the error reporting by default, so device drivers need
call this function to enable it.
3.3.3 int pci_disable_pcie_error_reporting(struct pci_dev *dev);
pci_disable_pcie_error_reporting disables the device to send error
messages to root port when an error is detected.
3.3.4 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable
error status register.
3.4 Frequent Asked Questions
Q: What happens if a PCI Express device driver does not provide an
error recovery handler (pci_driver->err_handler is equal to NULL)?
A: The devices attached with the driver won't be recovered. If the
error is fatal, kernel will print out warning messages. Please refer
to section 3 for more information.
Q: What happens if an upstream port service driver does not provide
callback reset_link?
A: Fatal error recovery will fail if the errors are reported by the
upstream ports who are attached by the service driver.
Q: How does this infrastructure deal with driver that is not PCI
Express aware?
A: This infrastructure calls the error callback functions of the
driver when an error happens. But if the driver is not aware of
PCI Express, the device might not report its own errors to root
port.
Q: What modifications will that driver need to make it compatible
with the PCI Express AER Root driver?
A: It could call the helper functions to enable AER in devices and
cleanup uncorrectable status register. Pls. refer to section 3.3.

View file

@ -1,208 +1,553 @@
Most of the code in Linux is device drivers, so most of the Linux power
management code is also driver-specific. Most drivers will do very little;
others, especially for platforms with small batteries (like cell phones),
will do a lot.
Device Power Management
This writeup gives an overview of how drivers interact with system-wide
power management goals, emphasizing the models and interfaces that are
shared by everything that hooks up to the driver model core. Read it as
background for the domain-specific work you'd do with any specific driver.
Device power management encompasses two areas - the ability to save
state and transition a device to a low-power state when the system is
entering a low-power state; and the ability to transition a device to
a low-power state while the system is running (and independently of
any other power management activity).
Two Models for Device Power Management
======================================
Drivers will use one or both of these models to put devices into low-power
states:
System Sleep model:
Drivers can enter low power states as part of entering system-wide
low-power states like "suspend-to-ram", or (mostly for systems with
disks) "hibernate" (suspend-to-disk).
This is something that device, bus, and class drivers collaborate on
by implementing various role-specific suspend and resume methods to
cleanly power down hardware and software subsystems, then reactivate
them without loss of data.
Some drivers can manage hardware wakeup events, which make the system
leave that low-power state. This feature may be disabled using the
relevant /sys/devices/.../power/wakeup file; enabling it may cost some
power usage, but let the whole system enter low power states more often.
Runtime Power Management model:
Drivers may also enter low power states while the system is running,
independently of other power management activity. Upstream drivers
will normally not know (or care) if the device is in some low power
state when issuing requests; the driver will auto-resume anything
that's needed when it gets a request.
This doesn't have, or need much infrastructure; it's just something you
should do when writing your drivers. For example, clk_disable() unused
clocks as part of minimizing power drain for currently-unused hardware.
Of course, sometimes clusters of drivers will collaborate with each
other, which could involve task-specific power management.
There's not a lot to be said about those low power states except that they
are very system-specific, and often device-specific. Also, that if enough
drivers put themselves into low power states (at "runtime"), the effect may be
the same as entering some system-wide low-power state (system sleep) ... and
that synergies exist, so that several drivers using runtime pm might put the
system into a state where even deeper power saving options are available.
Most suspended devices will have quiesced all I/O: no more DMA or irqs, no
more data read or written, and requests from upstream drivers are no longer
accepted. A given bus or platform may have different requirements though.
Examples of hardware wakeup events include an alarm from a real time clock,
network wake-on-LAN packets, keyboard or mouse activity, and media insertion
or removal (for PCMCIA, MMC/SD, USB, and so on).
Methods
Interfaces for Entering System Sleep States
===========================================
Most of the programming interfaces a device driver needs to know about
relate to that first model: entering a system-wide low power state,
rather than just minimizing power consumption by one device.
The methods to suspend and resume devices reside in struct bus_type:
Bus Driver Methods
------------------
The core methods to suspend and resume devices reside in struct bus_type.
These are mostly of interest to people writing infrastructure for busses
like PCI or USB, or because they define the primitives that device drivers
may need to apply in domain-specific ways to their devices:
struct bus_type {
...
int (*suspend)(struct device * dev, pm_message_t state);
int (*resume)(struct device * dev);
...
int (*suspend)(struct device *dev, pm_message_t state);
int (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device *dev);
int (*resume)(struct device *dev);
};
Each bus driver is responsible implementing these methods, translating
the call into a bus-specific request and forwarding the call to the
bus-specific drivers. For example, PCI drivers implement suspend() and
resume() methods in struct pci_driver. The PCI core is simply
responsible for translating the pointers to PCI-specific ones and
calling the low-level driver.
Bus drivers implement those methods as appropriate for the hardware and
the drivers using it; PCI works differently from USB, and so on. Not many
people write bus drivers; most driver code is a "device driver" that
builds on top of bus-specific framework code.
This is done to a) ease transition to the new power management methods
and leverage the existing PM code in various bus drivers; b) allow
buses to implement generic and default PM routines for devices, and c)
make the flow of execution obvious to the reader.
For more information on these driver calls, see the description later;
they are called in phases for every device, respecting the parent-child
sequencing in the driver model tree. Note that as this is being written,
only the suspend() and resume() are widely available; not many bus drivers
leverage all of those phases, or pass them down to lower driver levels.
System Power Management
/sys/devices/.../power/wakeup files
-----------------------------------
All devices in the driver model have two flags to control handling of
wakeup events, which are hardware signals that can force the device and/or
system out of a low power state. These are initialized by bus or device
driver code using device_init_wakeup(dev,can_wakeup).
When the system enters a low-power state, the device tree is walked in
a depth-first fashion to transition each device into a low-power
state. The ordering of the device tree is guaranteed by the order in
which devices get registered - children are never registered before
their ancestors, and devices are placed at the back of the list when
registered. By walking the list in reverse order, we are guaranteed to
suspend devices in the proper order.
The "can_wakeup" flag just records whether the device (and its driver) can
physically support wakeup events. When that flag is clear, the sysfs
"wakeup" file is empty, and device_may_wakeup() returns false.
Devices are suspended once with interrupts enabled. Drivers are
expected to stop I/O transactions, save device state, and place the
device into a low-power state. Drivers may sleep, allocate memory,
etc. at will.
For devices that can issue wakeup events, a separate flag controls whether
that device should try to use its wakeup mechanism. The initial value of
device_may_wakeup() will be true, so that the device's "wakeup" file holds
the value "enabled". Userspace can change that to "disabled" so that
device_may_wakeup() returns false; or change it back to "enabled" (so that
it returns true again).
Some devices are broken and will inevitably have problems powering
down or disabling themselves with interrupts enabled. For these
special cases, they may return -EAGAIN. This will put the device on a
list to be taken care of later. When interrupts are disabled, before
we enter the low-power state, their drivers are called again to put
their device to sleep.
On resume, the devices that returned -EAGAIN will be called to power
themselves back on with interrupts disabled. Once interrupts have been
re-enabled, the rest of the drivers will be called to resume their
devices. On resume, a driver is responsible for powering back on each
device, restoring state, and re-enabling I/O transactions for that
device.
EXAMPLE: PCI Device Driver Methods
-----------------------------------
PCI framework software calls these methods when the PCI device driver bound
to a device device has provided them:
struct pci_driver {
...
int (*suspend)(struct pci_device *pdev, pm_message_t state);
int (*suspend_late)(struct pci_device *pdev, pm_message_t state);
int (*resume_early)(struct pci_device *pdev);
int (*resume)(struct pci_device *pdev);
};
Drivers will implement those methods, and call PCI-specific procedures
like pci_set_power_state(), pci_enable_wake(), pci_save_state(), and
pci_restore_state() to manage PCI-specific mechanisms. (PCI config space
could be saved during driver probe, if it weren't for the fact that some
systems rely on userspace tweaking using setpci.) Devices are suspended
before their bridges enter low power states, and likewise bridges resume
before their devices.
Upper Layers of Driver Stacks
-----------------------------
Device drivers generally have at least two interfaces, and the methods
sketched above are the ones which apply to the lower level (nearer PCI, USB,
or other bus hardware). The network and block layers are examples of upper
level interfaces, as is a character device talking to userspace.
Power management requests normally need to flow through those upper levels,
which often use domain-oriented requests like "blank that screen". In
some cases those upper levels will have power management intelligence that
relates to end-user activity, or other devices that work in cooperation.
When those interfaces are structured using class interfaces, there is a
standard way to have the upper layer stop issuing requests to a given
class device (and restart later):
struct class {
...
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
};
Those calls are issued in specific phases of the process by which the
system enters a low power "suspend" state, or resumes from it.
Calling Drivers to Enter System Sleep States
============================================
When the system enters a low power state, each device's driver is asked
to suspend the device by putting it into state compatible with the target
system state. That's usually some version of "off", but the details are
system-specific. Also, wakeup-enabled devices will usually stay partly
functional in order to wake the system.
When the system leaves that low power state, the device's driver is asked
to resume it. The suspend and resume operations always go together, and
both are multi-phase operations.
For simple drivers, suspend might quiesce the device using the class code
and then turn its hardware as "off" as possible with late_suspend. The
matching resume calls would then completely reinitialize the hardware
before reactivating its class I/O queues.
More power-aware drivers drivers will use more than one device low power
state, either at runtime or during system sleep states, and might trigger
system wakeup events.
Call Sequence Guarantees
------------------------
To ensure that bridges and similar links needed to talk to a device are
available when the device is suspended or resumed, the device tree is
walked in a bottom-up order to suspend devices. A top-down order is
used to resume those devices.
The ordering of the device tree is defined by the order in which devices
get registered: a child can never be registered, probed or resumed before
its parent; and can't be removed or suspended after that parent.
The policy is that the device tree should match hardware bus topology.
(Or at least the control bus, for devices which use multiple busses.)
Suspending Devices
------------------
Suspending a given device is done in several phases. Suspending the
system always includes every phase, executing calls for every device
before the next phase begins. Not all busses or classes support all
these callbacks; and not all drivers use all the callbacks.
The phases are seen by driver notifications issued in this order:
1 class.suspend(dev, message) is called after tasks are frozen, for
devices associated with a class that has such a method. This
method may sleep.
Since I/O activity usually comes from such higher layers, this is
a good place to quiesce all drivers of a given type (and keep such
code out of those drivers).
2 bus.suspend(dev, message) is called next. This method may sleep,
and is often morphed into a device driver call with bus-specific
parameters and/or rules.
This call should handle parts of device suspend logic that require
sleeping. It probably does work to quiesce the device which hasn't
been abstracted into class.suspend() or bus.suspend_late().
3 bus.suspend_late(dev, message) is called with IRQs disabled, and
with only one CPU active. Until the bus.resume_early() phase
completes (see later), IRQs are not enabled again. This method
won't be exposed by all busses; for message based busses like USB,
I2C, or SPI, device interactions normally require IRQs. This bus
call may be morphed into a driver call with bus-specific parameters.
This call might save low level hardware state that might otherwise
be lost in the upcoming low power state, and actually put the
device into a low power state ... so that in some cases the device
may stay partly usable until this late. This "late" call may also
help when coping with hardware that behaves badly.
The pm_message_t parameter is currently used to refine those semantics
(described later).
At the end of those phases, drivers should normally have stopped all I/O
transactions (DMA, IRQs), saved enough state that they can re-initialize
or restore previous state (as needed by the hardware), and placed the
device into a low-power state. On many platforms they will also use
clk_disable() to gate off one or more clock sources; sometimes they will
also switch off power supplies, or reduce voltages. Drivers which have
runtime PM support may already have performed some or all of the steps
needed to prepare for the upcoming system sleep state.
When any driver sees that its device_can_wakeup(dev), it should make sure
to use the relevant hardware signals to trigger a system wakeup event.
For example, enable_irq_wake() might identify GPIO signals hooked up to
a switch or other external hardware, and pci_enable_wake() does something
similar for PCI's PME# signal.
If a driver (or bus, or class) fails it suspend method, the system won't
enter the desired low power state; it will resume all the devices it's
suspended so far.
Note that drivers may need to perform different actions based on the target
system lowpower/sleep state. At this writing, there are only platform
specific APIs through which drivers could determine those target states.
Device Low Power (suspend) States
---------------------------------
Device low-power states aren't very standard. One device might only handle
"on" and "off, while another might support a dozen different versions of
"on" (how many engines are active?), plus a state that gets back to "on"
faster than from a full "off".
Some busses define rules about what different suspend states mean. PCI
gives one example: after the suspend sequence completes, a non-legacy
PCI device may not perform DMA or issue IRQs, and any wakeup events it
issues would be issued through the PME# bus signal. Plus, there are
several PCI-standard device states, some of which are optional.
In contrast, integrated system-on-chip processors often use irqs as the
wakeup event sources (so drivers would call enable_irq_wake) and might
be able to treat DMA completion as a wakeup event (sometimes DMA can stay
active too, it'd only be the CPU and some peripherals that sleep).
Some details here may be platform-specific. Systems may have devices that
can be fully active in certain sleep states, such as an LCD display that's
refreshed using DMA while most of the system is sleeping lightly ... and
its frame buffer might even be updated by a DSP or other non-Linux CPU while
the Linux control processor stays idle.
Moreover, the specific actions taken may depend on the target system state.
One target system state might allow a given device to be very operational;
another might require a hard shut down with re-initialization on resume.
And two different target systems might use the same device in different
ways; the aforementioned LCD might be active in one product's "standby",
but a different product using the same SOC might work differently.
Meaning of pm_message_t.event
-----------------------------
Parameters to suspend calls include the device affected and a message of
type pm_message_t, which has one field: the event. If driver does not
recognize the event code, suspend calls may abort the request and return
a negative errno. However, most drivers will be fine if they implement
PM_EVENT_SUSPEND semantics for all messages.
The event codes are used to refine the goal of suspending the device, and
mostly matter when creating or resuming system memory image snapshots, as
used with suspend-to-disk:
PM_EVENT_SUSPEND -- quiesce the driver and put hardware into a low-power
state. When used with system sleep states like "suspend-to-RAM" or
"standby", the upcoming resume() call will often be able to rely on
state kept in hardware, or issue system wakeup events. When used
instead with suspend-to-disk, few devices support this capability;
most are completely powered off.
PM_EVENT_FREEZE -- quiesce the driver, but don't necessarily change into
any low power mode. A system snapshot is about to be taken, often
followed by a call to the driver's resume() method. Neither wakeup
events nor DMA are allowed.
PM_EVENT_PRETHAW -- quiesce the driver, knowing that the upcoming resume()
will restore a suspend-to-disk snapshot from a different kernel image.
Drivers that are smart enough to look at their hardware state during
resume() processing need that state to be correct ... a PRETHAW could
be used to invalidate that state (by resetting the device), like a
shutdown() invocation would before a kexec() or system halt. Other
drivers might handle this the same way as PM_EVENT_FREEZE. Neither
wakeup events nor DMA are allowed.
To enter "standby" (ACPI S1) or "Suspend to RAM" (STR, ACPI S3) states, or
the similarly named APM states, only PM_EVENT_SUSPEND is used; for "Suspend
to Disk" (STD, hibernate, ACPI S4), all of those event codes are used.
There's also PM_EVENT_ON, a value which never appears as a suspend event
but is sometimes used to record the "not suspended" device state.
Resuming Devices
----------------
Resuming is done in multiple phases, much like suspending, with all
devices processing each phase's calls before the next phase begins.
The phases are seen by driver notifications issued in this order:
1 bus.resume_early(dev) is called with IRQs disabled, and with
only one CPU active. As with bus.suspend_late(), this method
won't be supported on busses that require IRQs in order to
interact with devices.
This reverses the effects of bus.suspend_late().
2 bus.resume(dev) is called next. This may be morphed into a device
driver call with bus-specific parameters; implementations may sleep.
This reverses the effects of bus.suspend().
3 class.resume(dev) is called for devices associated with a class
that has such a method. Implementations may sleep.
This reverses the effects of class.suspend(), and would usually
reactivate the device's I/O queue.
At the end of those phases, drivers should normally be as functional as
they were before suspending: I/O can be performed using DMA and IRQs, and
the relevant clocks are gated on. The device need not be "fully on"; it
might be in a runtime lowpower/suspend state that acts as if it were.
However, the details here may again be platform-specific. For example,
some systems support multiple "run" states, and the mode in effect at
the end of resume() might not be the one which preceded suspension.
That means availability of certain clocks or power supplies changed,
which could easily affect how a driver works.
Drivers need to be able to handle hardware which has been reset since the
suspend methods were called, for example by complete reinitialization.
This may be the hardest part, and the one most protected by NDA'd documents
and chip errata. It's simplest if the hardware state hasn't changed since
the suspend() was called, but that can't always be guaranteed.
Drivers must also be prepared to notice that the device has been removed
while the system was powered off, whenever that's physically possible.
PCMCIA, MMC, USB, Firewire, SCSI, and even IDE are common examples of busses
where common Linux platforms will see such removal. Details of how drivers
will notice and handle such removals are currently bus-specific, and often
involve a separate thread.
Note that the bus-specific runtime PM wakeup mechanism can exist, and might
be defined to share some of the same driver code as for system wakeup. For
example, a bus-specific device driver's resume() method might be used there,
so it wouldn't only be called from bus.resume() during system-wide wakeup.
See bus-specific information about how runtime wakeup events are handled.
System Devices
--------------
System devices follow a slightly different API, which can be found in
include/linux/sysdev.h
drivers/base/sys.c
System devices will only be suspended with interrupts disabled, and
after all other devices have been suspended. On resume, they will be
resumed before any other devices, and also with interrupts disabled.
System devices will only be suspended with interrupts disabled, and after
all other devices have been suspended. On resume, they will be resumed
before any other devices, and also with interrupts disabled.
That is, IRQs are disabled, the suspend_late() phase begins, then the
sysdev_driver.suspend() phase, and the system enters a sleep state. Then
the sysdev_driver.resume() phase begins, followed by the resume_early()
phase, after which IRQs are enabled.
Code to actually enter and exit the system-wide low power state sometimes
involves hardware details that are only known to the boot firmware, and
may leave a CPU running software (from SRAM or flash memory) that monitors
the system and manages its wakeup sequence.
Runtime Power Management
========================
Many devices are able to dynamically power down while the system is still
running. This feature is useful for devices that are not being used, and
can offer significant power savings on a running system. These devices
often support a range of runtime power states, which might use names such
as "off", "sleep", "idle", "active", and so on. Those states will in some
cases (like PCI) be partially constrained by a bus the device uses, and will
usually include hardware states that are also used in system sleep states.
Many devices are able to dynamically power down while the system is
still running. This feature is useful for devices that are not being
used, and can offer significant power savings on a running system.
However, note that if a driver puts a device into a runtime low power state
and the system then goes into a system-wide sleep state, it normally ought
to resume into that runtime low power state rather than "full on". Such
distinctions would be part of the driver-internal state machine for that
hardware; the whole point of runtime power management is to be sure that
drivers are decoupled in that way from the state machine governing phases
of the system-wide power/sleep state transitions.
In each device's directory, there is a 'power' directory, which
contains at least a 'state' file. Reading from this file displays what
power state the device is currently in. Writing to this file initiates
a transition to the specified power state, which must be a decimal in
the range 1-3, inclusive; or 0 for 'On'.
The PM core will call the ->suspend() method in the bus_type object
that the device belongs to if the specified state is not 0, or
->resume() if it is.
Power Saving Techniques
-----------------------
Normally runtime power management is handled by the drivers without specific
userspace or kernel intervention, by device-aware use of techniques like:
Nothing will happen if the specified state is the same state the
device is currently in.
Using information provided by other system layers
- stay deeply "off" except between open() and close()
- if transceiver/PHY indicates "nobody connected", stay "off"
- application protocols may include power commands or hints
If the device is already in a low-power state, and the specified state
is another, but different, low-power state, the ->resume() method will
first be called to power the device back on, then ->suspend() will be
called again with the new state.
Using fewer CPU cycles
- using DMA instead of PIO
- removing timers, or making them lower frequency
- shortening "hot" code paths
- eliminating cache misses
- (sometimes) offloading work to device firmware
The driver is responsible for saving the working state of the device
and putting it into the low-power state specified. If this was
successful, it returns 0, and the device's power_state field is
updated.
Reducing other resource costs
- gating off unused clocks in software (or hardware)
- switching off unused power supplies
- eliminating (or delaying/merging) IRQs
- tuning DMA to use word and/or burst modes
The driver must take care to know whether or not it is able to
properly resume the device, including all step of reinitialization
necessary. (This is the hardest part, and the one most protected by
NDA'd documents).
Using device-specific low power states
- using lower voltages
- avoiding needless DMA transfers
The driver must also take care not to suspend a device that is
currently in use. It is their responsibility to provide their own
exclusion mechanisms.
Read your hardware documentation carefully to see the opportunities that
may be available. If you can, measure the actual power usage and check
it against the budget established for your project.
The runtime power transition happens with interrupts enabled. If a
device cannot support being powered down with interrupts, it may
return -EAGAIN (as it would during a system power management
transition), but it will _not_ be called again, and the transaction
will fail.
There is currently no way to know what states a device or driver
supports a priori. This will change in the future.
Examples: USB hosts, system timer, system CPU
----------------------------------------------
USB host controllers make interesting, if complex, examples. In many cases
these have no work to do: no USB devices are connected, or all of them are
in the USB "suspend" state. Linux host controller drivers can then disable
periodic DMA transfers that would otherwise be a constant power drain on the
memory subsystem, and enter a suspend state. In power-aware controllers,
entering that suspend state may disable the clock used with USB signaling,
saving a certain amount of power.
pm_message_t meaning
The controller will be woken from that state (with an IRQ) by changes to the
signal state on the data lines of a given port, for example by an existing
peripheral requesting "remote wakeup" or by plugging a new peripheral. The
same wakeup mechanism usually works from "standby" sleep states, and on some
systems also from "suspend to RAM" (or even "suspend to disk") states.
(Except that ACPI may be involved instead of normal IRQs, on some hardware.)
pm_message_t has two fields. event ("major"), and flags. If driver
does not know event code, it aborts the request, returning error. Some
drivers may need to deal with special cases based on the actual type
of suspend operation being done at the system level. This is why
there are flags.
System devices like timers and CPUs may have special roles in the platform
power management scheme. For example, system timers using a "dynamic tick"
approach don't just save CPU cycles (by eliminating needless timer IRQs),
but they may also open the door to using lower power CPU "idle" states that
cost more than a jiffie to enter and exit. On x86 systems these are states
like "C3"; note that periodic DMA transfers from a USB host controller will
also prevent entry to a C3 state, much like a periodic timer IRQ.
Event codes are:
That kind of runtime mechanism interaction is common. "System On Chip" (SOC)
processors often have low power idle modes that can't be entered unless
certain medium-speed clocks (often 12 or 48 MHz) are gated off. When the
drivers gate those clocks effectively, then the system idle task may be able
to use the lower power idle modes and thereby increase battery life.
ON -- no need to do anything except special cases like broken
HW.
If the CPU can have a "cpufreq" driver, there also may be opportunities
to shift to lower voltage settings and reduce the power cost of executing
a given number of instructions. (Without voltage adjustment, it's rare
for cpufreq to save much power; the cost-per-instruction must go down.)
# NOTIFICATION -- pretty much same as ON?
FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from
scratch. That probably means stop accepting upstream requests, the
actual policy of what to do with them being specific to a given
driver. It's acceptable for a network driver to just drop packets
while a block driver is expected to block the queue so no request is
lost. (Use IDE as an example on how to do that). FREEZE requires no
power state change, and it's expected for drivers to be able to
quickly transition back to operating state.
/sys/devices/.../power/state files
==================================
For now you can also test some of this functionality using sysfs.
SUSPEND -- like FREEZE, but also put hardware into low-power state. If
there's need to distinguish several levels of sleep, additional flag
is probably best way to do that.
DEPRECATED: USE "power/state" ONLY FOR DRIVER TESTING, AND
AVOID USING dev->power.power_state IN DRIVERS.
Transitions are only from a resumed state to a suspended state, never
between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen,
FREEZE -> SUSPEND or SUSPEND -> FREEZE can not).
THESE WILL BE REMOVED. IF THE "power/state" FILE GETS REPLACED,
IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
All events are:
In each device's directory, there is a 'power' directory, which contains
at least a 'state' file. The value of this field is effectively boolean,
PM_EVENT_ON or PM_EVENT_SUSPEND.
[NOTE NOTE NOTE: If you are driver author, you should not care; you
should only look at event, and ignore flags.]
* Reading from this file displays a value corresponding to
the power.power_state.event field. All nonzero values are
displayed as "2", corresponding to a low power state; zero
is displayed as "0", corresponding to normal operation.
#Prepare for suspend -- userland is still running but we are going to
#enter suspend state. This gives drivers chance to load firmware from
#disk and store it in memory, or do other activities taht require
#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these
#are forbiden once the suspend dance is started.. event = ON, flags =
#PREPARE_TO_SUSPEND
* Writing to this file initiates a transition using the
specified event code number; only '0', '2', and '3' are
accepted (without a newline); '2' and '3' are both
mapped to PM_EVENT_SUSPEND.
Apm standby -- prepare for APM event. Quiesce devices to make life
easier for APM BIOS. event = FREEZE, flags = APM_STANDBY
On writes, the PM core relies on that recorded event code and the device/bus
capabilities to determine whether it uses a partial suspend() or resume()
sequence to change things so that the recorded event corresponds to the
numeric parameter.
Apm suspend -- same as APM_STANDBY, but it we should probably avoid
spinning down disks. event = FREEZE, flags = APM_SUSPEND
- If the bus requires the irqs-disabled suspend_late()/resume_early()
phases, writes fail because those operations are not supported here.
System halt, reboot -- quiesce devices to make life easier for BIOS. event
= FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT
- If the recorded value is the expected value, nothing is done.
System shutdown -- at least disks need to be spun down, or data may be
lost. Quiesce devices, just to make life easier for BIOS. event =
FREEZE, flags = SYSTEM_SHUTDOWN
- If the recorded value is nonzero, the device is partially resumed,
using the bus.resume() and/or class.resume() methods.
Kexec -- turn off DMAs and put hardware into some state where new
kernel can take over. event = FREEZE, flags = KEXEC
- If the target value is nonzero, the device is partially suspended,
using the class.suspend() and/or bus.suspend() methods and the
PM_EVENT_SUSPEND message.
Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake
may need to be enabled on some devices. This actually has at least 3
subtypes, system can reboot, enter S4 and enter S5 at the end of
swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT,
SYSTEM_SHUTDOWN, SYSTEM_S4
Suspend to ram -- put devices into low power state. event = SUSPEND,
flags = SUSPEND_TO_RAM
Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put
devices into low power mode, but you must be able to reinitialize
device from scratch in resume method. This has two flavors, its done
once on suspending kernel, once on resuming kernel. event = FREEZE,
flags = DURING_SUSPEND or DURING_RESUME
Device detach requested from /sys -- deinitialize device; proably same as
SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
= FREEZE, flags = DEV_DETACH.
#These are not really events sent:
#
#System fully on -- device is working normally; this is probably never
#passed to suspend() method... event = ON, flags = 0
#
#Ready after resume -- userland is now running, again. Time to free any
#memory you ate during prepare to suspend... event = ON, flags =
#READY_AFTER_RESUME
#
Drivers have no way to tell whether their suspend() and resume() calls
have come through the sysfs power/state file or as part of entering a
system sleep state, except that when accessed through sysfs the normal
parent/child sequencing rules are ignored. Drivers (such as bus, bridge,
or hub drivers) which expose child devices may need to enforce those rules
on their own.

View file

@ -52,3 +52,18 @@ suspend image will be as small as possible.
Reading from this file will display the current image size limit, which
is set to 500 MB by default.
/sys/power/pm_trace controls the code which saves the last PM event point in
the RTC across reboots, so that you can debug a machine that just hangs
during suspend (or more commonly, during resume). Namely, the RTC is only
used to save the last PM event point if this file contains '1'. Initially it
contains '0' which may be changed to '1' by writing a string representing a
nonzero integer into it.
To use this debugging feature you should attempt to suspend the machine, then
reboot it and run
dmesg -s 1000000 | grep 'hash matches'
CAUTION: Using it will cause your machine's real-time (CMOS) clock to be
set to a random invalid time after a resume.

View file

@ -41,11 +41,6 @@ Board-specific code:
|
.. more boards here ...
It should also be noted that each board is required to have some certain
headers. At the time of this writing, io.h is the only thing that needs
to be provided for each board, and can generally just reference generic
functions (with the exception of isa_port2addr).
Next, for companion chips:
.
`-- arch
@ -104,12 +99,13 @@ and then populate that with sub-directories for each member of the family.
Both the Solution Engine and the hp6xx boards are an example of this.
After you have setup your new arch/sh/boards/ directory, remember that you
also must add a directory in include/asm-sh for headers localized to this
board. In order to interoperate seamlessly with the build system, it's best
to have this directory the same as the arch/sh/boards/ directory name,
though if your board is again part of a family, the build system has ways
of dealing with this, and you can feel free to name the directory after
the family member itself.
should also add a directory in include/asm-sh for headers localized to this
board (if there are going to be more than one). In order to interoperate
seamlessly with the build system, it's best to have this directory the same
as the arch/sh/boards/ directory name, though if your board is again part of
a family, the build system has ways of dealing with this (via incdir-y
overloading), and you can feel free to name the directory after the family
member itself.
There are a few things that each board is required to have, both in the
arch/sh/boards and the include/asm-sh/ heirarchy. In order to better
@ -122,6 +118,7 @@ might look something like:
* arch/sh/boards/vapor/setup.c - Setup code for imaginary board
*/
#include <linux/init.h>
#include <asm/rtc.h> /* for board_time_init() */
const char *get_system_type(void)
{
@ -152,79 +149,57 @@ int __init platform_setup(void)
}
Our new imaginary board will also have to tie into the machvec in order for it
to be of any use. Currently the machvec is slowly on its way out, but is still
required for the time being. As such, let us take a look at what needs to be
done for the machvec assignment.
to be of any use.
machvec functions fall into a number of categories:
- I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
- I/O remapping functions (ioremap etc)
- some initialisation functions
- a 'heartbeat' function
- some miscellaneous flags
- I/O mapping functions (ioport_map, ioport_unmap, etc).
- a 'heartbeat' function.
- PCI and IRQ initialization routines.
- Consistent allocators (for boards that need special allocators,
particularly for allocating out of some board-specific SRAM for DMA
handles).
The tree can be built in two ways:
- as a fully generic build. All drivers are linked in, and all functions
go through the machvec
- as a machine specific build. In this case only the required drivers
will be linked in, and some macros may be redefined to not go through
the machvec where performance is important (in particular IO functions).
There are machvec functions added and removed over time, so always be sure to
consult include/asm-sh/machvec.h for the current state of the machvec.
There are three ways in which IO can be performed:
- none at all. This is really only useful for the 'unknown' machine type,
which us designed to run on a machine about which we know nothing, and
so all all IO instructions do nothing.
- fully custom. In this case all IO functions go to a machine specific
set of functions which can do what they like
- a generic set of functions. These will cope with most situations,
and rely on a single function, mv_port2addr, which is called through the
machine vector, and converts an IO address into a memory address, which
can be read from/written to directly.
The kernel will automatically wrap in generic routines for undefined function
pointers in the machvec at boot time, as machvec functions are referenced
unconditionally throughout most of the tree. Some boards have incredibly
sparse machvecs (such as the dreamcast and sh03), whereas others must define
virtually everything (rts7751r2d).
Thus adding a new machine involves the following steps (I will assume I am
adding a machine called vapor):
Adding a new machine is relatively trivial (using vapor as an example):
- add a new file include/asm-sh/vapor/io.h which contains prototypes for
If the board-specific definitions are quite minimalistic, as is the case for
the vast majority of boards, simply having a single board-specific header is
sufficient.
- add a new file include/asm-sh/vapor.h which contains prototypes for
any machine specific IO functions prefixed with the machine name, for
example vapor_inb. These will be needed when filling out the machine
vector.
This is the minimum that is required, however there are ample
opportunities to optimise this. In particular, by making the prototypes
inline function definitions, it is possible to inline the function when
building machine specific versions. Note that the machine vector
functions will still be needed, so that a module built for a generic
setup can be loaded.
Note that these prototypes are generated automatically by setting
__IO_PREFIX to something sensible. A typical example would be:
- add a new file arch/sh/boards/vapor/mach.c. This contains the definition
of the machine vector. When building the machine specific version, this
will be the real machine vector (via an alias), while in the generic
version is used to initialise the machine vector, and then freed, by
making it initdata. This should be defined as:
#define __IO_PREFIX vapor
#include <asm/io_generic.h>
struct sh_machine_vector mv_vapor __initmv = {
.mv_name = "vapor",
}
ALIAS_MV(vapor)
somewhere in the board-specific header. Any boards being ported that still
have a legacy io.h should remove it entirely and switch to the new model.
- finally add a file arch/sh/boards/vapor/io.c, which contains
definitions of the machine specific io functions.
- Add machine vector definitions to the board's setup.c. At a bare minimum,
this must be defined as something like:
A note about initialisation functions. Three initialisation functions are
provided in the machine vector:
- mv_arch_init - called very early on from setup_arch
- mv_init_irq - called from init_IRQ, after the generic SH interrupt
initialisation
- mv_init_pci - currently not used
struct sh_machine_vector mv_vapor __initmv = {
.mv_name = "vapor",
};
ALIAS_MV(vapor)
Any other remaining functions which need to be called at start up can be
added to the list using the __initcalls macro (or module_init if the code
can be built as a module). Many generic drivers probe to see if the device
they are targeting is present, however this may not always be appropriate,
so a flag can be added to the machine vector which will be set on those
machines which have the hardware in question, reducing the probe to a
single conditional.
- finally add a file arch/sh/boards/vapor/io.c, which contains definitions of
the machine specific io functions (if there are enough to warrant it).
3. Hooking into the Build System
================================
@ -303,4 +278,3 @@ which will in turn copy the defconfig for this board, run it through
oldconfig (prompting you for any new options since the time of creation),
and start you on your way to having a functional kernel for your new
board.

View file

@ -0,0 +1,33 @@
Notes on register bank usage in the kernel
==========================================
Introduction
------------
The SH-3 and SH-4 CPU families traditionally include a single partial register
bank (selected by SR.RB, only r0 ... r7 are banked), whereas other families
may have more full-featured banking or simply no such capabilities at all.
SR.RB banking
-------------
In the case of this type of banking, banked registers are mapped directly to
r0 ... r7 if SR.RB is set to the bank we are interested in, otherwise ldc/stc
can still be used to reference the banked registers (as r0_bank ... r7_bank)
when in the context of another bank. The developer must keep the SR.RB value
in mind when writing code that utilizes these banked registers, for obvious
reasons. Userspace is also not able to poke at the bank1 values, so these can
be used rather effectively as scratch registers by the kernel.
Presently the kernel uses several of these registers.
- r0_bank, r1_bank (referenced as k0 and k1, used for scratch
registers when doing exception handling).
- r2_bank (used to track the EXPEVT/INTEVT code)
- Used by do_IRQ() and friends for doing irq mapping based off
of the interrupt exception vector jump table offset
- r6_bank (global interrupt mask)
- The SR.IMASK interrupt handler makes use of this to set the
interrupt priority level (used by local_irq_enable())
- r7_bank (current)

View file

@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/vm:
- drop-caches
- zone_reclaim_mode
- min_unmapped_ratio
- min_slab_ratio
- panic_on_oom
==============================================================
@ -138,7 +139,6 @@ This is value ORed together of
1 = Zone reclaim on
2 = Zone reclaim writes dirty pages out
4 = Zone reclaim swaps pages
8 = Also do a global slab reclaim pass
zone_reclaim_mode is set during bootup to 1 if it is determined that pages
from remote zones will cause a measurable performance reduction. The
@ -162,18 +162,13 @@ Allowing regular swap effectively restricts allocations to the local
node unless explicitly overridden by memory policies or cpuset
configurations.
It may be advisable to allow slab reclaim if the system makes heavy
use of files and builds up large slab caches. However, the slab
shrink operation is global, may take a long time and free slabs
in all nodes of the system.
=============================================================
min_unmapped_ratio:
This is available only on NUMA kernels.
A percentage of the file backed pages in each zone. Zone reclaim will only
A percentage of the total pages in each zone. Zone reclaim will only
occur if more than this percentage of pages are file backed and unmapped.
This is to insure that a minimal amount of local pages is still available for
file I/O even if the node is overallocated.
@ -182,6 +177,24 @@ The default is 1 percent.
=============================================================
min_slab_ratio:
This is available only on NUMA kernels.
A percentage of the total pages in each zone. On Zone reclaim
(fallback from the local zone occurs) slabs will be reclaimed if more
than this percentage of pages in a zone are reclaimable slab pages.
This insures that the slab growth stays under control even in NUMA
systems that rarely perform global reclaim.
The default is 5 percent.
Note that slab reclaim is triggered in a per zone / node fashion.
The process of reclaiming slab memory is currently not node specific
and may not be fast.
=============================================================
panic_on_oom
This enables or disables panic on out-of-memory feature. If this is set to 1,

View file

@ -98,13 +98,13 @@ one or more packets could finish before an error stops further endpoint I/O.
error, a failure to respond (often caused by
device disconnect), or some other fault.
-ETIMEDOUT (**) No response packet received within the prescribed
-ETIME (**) No response packet received within the prescribed
bus turn-around time. This error may instead be
reported as -EPROTO or -EILSEQ.
Note that the synchronous USB message functions
also use this code to indicate timeout expired
before the transfer completed.
-ETIMEDOUT Synchronous USB message functions use this code
to indicate timeout expired before the transfer
completed, and no other error was reported by HC.
-EPIPE (**) Endpoint stalled. For non-control endpoints,
reset this status with usb_clear_halt().
@ -163,6 +163,3 @@ usb_get_*/usb_set_*():
usb_control_msg():
usb_bulk_msg():
-ETIMEDOUT Timeout expired before the transfer completed.
In the future this code may change to -ETIME,
whose definition is a closer match to this sort
of error.

View file

@ -433,6 +433,11 @@ Options supported:
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
AIRcable USB Dongle Bluetooth driver
If there is the cdc_acm driver loaded in the system, you will find that the
cdc_acm claims the device before AIRcable can. This is simply corrected
by unloading both modules and then loading the aircable module before
cdc_acm module
Generic Serial driver

View file

@ -245,6 +245,13 @@ Debugging
newfallback: use new unwinder but fall back to old if it gets
stuck (default)
call_trace=[old|both|newfallback|new]
old: use old inexact backtracer
new: use new exact dwarf2 unwinder
both: print entries from both
newfallback: use new unwinder but fall back to old if it gets
stuck (default)
Misc
noreplacement Don't replace instructions with more appropriate ones

View file

@ -0,0 +1,99 @@
Most of the text from Keith Owens, hacked by AK
x86_64 page size (PAGE_SIZE) is 4K.
Like all other architectures, x86_64 has a kernel stack for every
active thread. These thread stacks are THREAD_SIZE (2*PAGE_SIZE) big.
These stacks contain useful data as long as a thread is alive or a
zombie. While the thread is in user space the kernel stack is empty
except for the thread_info structure at the bottom.
In addition to the per thread stacks, there are specialized stacks
associated with each cpu. These stacks are only used while the kernel
is in control on that cpu, when a cpu returns to user space the
specialized stacks contain no useful data. The main cpu stacks is
* Interrupt stack. IRQSTACKSIZE
Used for external hardware interrupts. If this is the first external
hardware interrupt (i.e. not a nested hardware interrupt) then the
kernel switches from the current task to the interrupt stack. Like
the split thread and interrupt stacks on i386 (with CONFIG_4KSTACKS),
this gives more room for kernel interrupt processing without having
to increase the size of every per thread stack.
The interrupt stack is also used when processing a softirq.
Switching to the kernel interrupt stack is done by software based on a
per CPU interrupt nest counter. This is needed because x86-64 "IST"
hardware stacks cannot nest without races.
x86_64 also has a feature which is not available on i386, the ability
to automatically switch to a new stack for designated events such as
double fault or NMI, which makes it easier to handle these unusual
events on x86_64. This feature is called the Interrupt Stack Table
(IST). There can be up to 7 IST entries per cpu. The IST code is an
index into the Task State Segment (TSS), the IST entries in the TSS
point to dedicated stacks, each stack can be a different size.
An IST is selected by an non-zero value in the IST field of an
interrupt-gate descriptor. When an interrupt occurs and the hardware
loads such a descriptor, the hardware automatically sets the new stack
pointer based on the IST value, then invokes the interrupt handler. If
software wants to allow nested IST interrupts then the handler must
adjust the IST values on entry to and exit from the interrupt handler.
(this is occasionally done, e.g. for debug exceptions)
Events with different IST codes (i.e. with different stacks) can be
nested. For example, a debug interrupt can safely be interrupted by an
NMI. arch/x86_64/kernel/entry.S::paranoidentry adjusts the stack
pointers on entry to and exit from all IST events, in theory allowing
IST events with the same code to be nested. However in most cases, the
stack size allocated to an IST assumes no nesting for the same code.
If that assumption is ever broken then the stacks will become corrupt.
The currently assigned IST stacks are :-
* STACKFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
Used for interrupt 12 - Stack Fault Exception (#SS).
This allows to recover from invalid stack segments. Rarely
happens.
* DOUBLEFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
Used for interrupt 8 - Double Fault Exception (#DF).
Invoked when handling a exception causes another exception. Happens
when the kernel is very confused (e.g. kernel stack pointer corrupt)
Using a separate stack allows to recover from it well enough in many
cases to still output an oops.
* NMI_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
Used for non-maskable interrupts (NMI).
NMI can be delivered at any time, including when the kernel is in the
middle of switching stacks. Using IST for NMI events avoids making
assumptions about the previous state of the kernel stack.
* DEBUG_STACK. DEBUG_STKSZ
Used for hardware debug interrupts (interrupt 1) and for software
debug interrupts (INT3).
When debugging a kernel, debug interrupts (both hardware and
software) can occur at any time. Using IST for these interrupts
avoids making assumptions about the previous state of the kernel
stack.
* MCE_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
Used for interrupt 18 - Machine Check Exception (#MC).
MCE can be delivered at any time, including when the kernel is in the
middle of switching stacks. Using IST for MCE events avoids making
assumptions about the previous state of the kernel stack.
For more details see the Intel IA32 or AMD AMD64 architecture manuals.

View file

@ -443,6 +443,23 @@ W: http://people.redhat.com/sgrubb/audit/
T: git kernel.org:/pub/scm/linux/kernel/git/dwmw2/audit-2.6.git
S: Maintained
AVR32 ARCHITECTURE
P: Atmel AVR32 Support Team
M: avr32@atmel.com
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
W: http://www.atmel.com/products/AVR32/
W: http://avr32linux.org/
W: http://avrfreaks.net/
S: Supported
AVR32/AT32AP MACHINE SUPPORT
P: Atmel AVR32 Support Team
M: avr32@atmel.com
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
AX.25 NETWORK LAYER
P: Ralf Baechle
M: ralf@linux-mips.org
@ -2049,6 +2066,13 @@ L: netfilter@lists.netfilter.org
L: netfilter-devel@lists.netfilter.org
S: Supported
NETLABEL
P: Paul Moore
M: paul.moore@hp.com
W: http://netlabel.sf.net
L: netdev@vger.kernel.org
S: Supported
NETROM NETWORK LAYER
P: Ralf Baechle
M: ralf@linux-mips.org
@ -2673,7 +2697,6 @@ M: josejx@gentoo.org
P: Daniel Drake
M: dsd@gentoo.org
W: http://softmac.sipsolutions.net/
L: softmac-dev@sipsolutions.net
L: netdev@vger.kernel.org
S: Maintained

View file

@ -1385,9 +1385,13 @@ endif #ifeq ($(config-targets),1)
endif #ifeq ($(mixed-targets),1)
PHONY += checkstack kernelrelease kernelversion
# Use $(SUBARCH) here instead of $(ARCH) so that this works for UML.
# In the UML case, $(SUBARCH) is the name of the underlying
# architecture, while for all other arches, it is the same as $(ARCH).
checkstack:
$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
$(PERL) $(src)/scripts/checkstack.pl $(ARCH)
$(PERL) $(src)/scripts/checkstack.pl $(SUBARCH)
kernelrelease:
$(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \

View file

@ -381,7 +381,7 @@ config ALPHA_EV56
config ALPHA_EV56
prompt "EV56 CPU (speed >= 333MHz)?"
depends on ALPHA_NORITAKE && ALPHA_PRIMO
depends on ALPHA_NORITAKE || ALPHA_PRIMO
config ALPHA_EV56
prompt "EV56 CPU (speed >= 400MHz)?"

View file

@ -270,7 +270,7 @@ callback_init(void * kernel_end)
void
paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
unsigned long zones_size[MAX_NR_ZONES] = {0, };
unsigned long dma_pfn, high_pfn;
dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;

View file

@ -284,21 +284,9 @@ static struct pxaficp_platform_data corgi_ficp_platform_data = {
/*
* USB Device Controller
*/
static void corgi_udc_command(int cmd)
{
switch(cmd) {
case PXA2XX_UDC_CMD_CONNECT:
GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
break;
case PXA2XX_UDC_CMD_DISCONNECT:
GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
break;
}
}
static struct pxa2xx_udc_mach_info udc_info __initdata = {
/* no connect GPIO; corgi can't tell connection status */
.udc_command = corgi_udc_command,
.gpio_pullup = CORGI_GPIO_USB_PULLUP,
};
@ -350,7 +338,6 @@ static void __init corgi_init(void)
corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
pxa_set_udc_info(&udc_info);

View file

@ -177,7 +177,7 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
* Free the page table, if there was one.
*/
if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
pte_free_kernel(pmd_page_kernel(pmd));
pte_free_kernel(pmd_page_vaddr(pmd));
}
addr += PGDIR_SIZE;

View file

@ -26,7 +26,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/usb_otg.h>
#include <linux/usb/otg.h>
#include <asm/io.h>
#include <asm/irq.h>

196
arch/avr32/Kconfig Normal file
View file

@ -0,0 +1,196 @@
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
mainmenu "Linux Kernel Configuration"
config AVR32
bool
default y
# With EMBEDDED=n, we get lots of stuff automatically selected
# that we usually don't need on AVR32.
select EMBEDDED
help
AVR32 is a high-performance 32-bit RISC microprocessor core,
designed for cost-sensitive embedded applications, with particular
emphasis on low power consumption and high code density.
There is an AVR32 Linux project with a web page at
http://avr32linux.org/.
config UID16
bool
config GENERIC_HARDIRQS
bool
default y
config HARDIRQS_SW_RESEND
bool
default y
config GENERIC_IRQ_PROBE
bool
default y
config RWSEM_GENERIC_SPINLOCK
bool
default y
config GENERIC_TIME
bool
default y
config RWSEM_XCHGADD_ALGORITHM
bool
config GENERIC_BUST_SPINLOCK
bool
config GENERIC_HWEIGHT
bool
default y
config GENERIC_CALIBRATE_DELAY
bool
default y
source "init/Kconfig"
menu "System Type and features"
config SUBARCH_AVR32B
bool
config MMU
bool
config PERFORMANCE_COUNTERS
bool
config PLATFORM_AT32AP
bool
select SUBARCH_AVR32B
select MMU
select PERFORMANCE_COUNTERS
choice
prompt "AVR32 CPU type"
default CPU_AT32AP7000
config CPU_AT32AP7000
bool "AT32AP7000"
select PLATFORM_AT32AP
endchoice
#
# CPU Daughterboards for ATSTK1000
config BOARD_ATSTK1002
bool
choice
prompt "AVR32 board type"
default BOARD_ATSTK1000
config BOARD_ATSTK1000
bool "ATSTK1000 evaluation board"
select BOARD_ATSTK1002 if CPU_AT32AP7000
endchoice
choice
prompt "Boot loader type"
default LOADER_U_BOOT
config LOADER_U_BOOT
bool "U-Boot (or similar) bootloader"
endchoice
config LOAD_ADDRESS
hex
default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
config ENTRY_ADDRESS
hex
default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
config PHYS_OFFSET
hex
default 0x10000000 if CPU_AT32AP7000=y
source "kernel/Kconfig.preempt"
config HAVE_ARCH_BOOTMEM_NODE
bool
default n
config ARCH_HAVE_MEMORY_PRESENT
bool
default n
config NEED_NODE_MEMMAP_SIZE
bool
default n
config ARCH_FLATMEM_ENABLE
bool
default y
config ARCH_DISCONTIGMEM_ENABLE
bool
default n
config ARCH_SPARSEMEM_ENABLE
bool
default n
source "mm/Kconfig"
config OWNERSHIP_TRACE
bool "Ownership trace support"
default y
help
Say Y to generate an Ownership Trace message on every context switch,
enabling Nexus-compliant debuggers to keep track of the PID of the
currently executing task.
# FPU emulation goes here
source "kernel/Kconfig.hz"
config CMDLINE
string "Default kernel command line"
default ""
help
If you don't have a boot loader capable of passing a command line string
to the kernel, you may specify one here. As a minimum, you should specify
the memory size and the root device (e.g., mem=8M, root=/dev/nfs).
endmenu
menu "Bus options"
config PCI
bool
source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
endmenu
menu "Executable file formats"
source "fs/Kconfig.binfmt"
endmenu
source "net/Kconfig"
source "drivers/Kconfig"
source "fs/Kconfig"
source "arch/avr32/Kconfig.debug"
source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"

19
arch/avr32/Kconfig.debug Normal file
View file

@ -0,0 +1,19 @@
menu "Kernel hacking"
config TRACE_IRQFLAGS_SUPPORT
bool
default y
source "lib/Kconfig.debug"
config KPROBES
bool "Kprobes"
depends on DEBUG_KERNEL
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
endmenu

84
arch/avr32/Makefile Normal file
View file

@ -0,0 +1,84 @@
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
# Copyright (C) 2004-2006 Atmel Corporation.
# Default target when executing plain make
.PHONY: all
all: uImage vmlinux.elf linux.lst
KBUILD_DEFCONFIG := atstk1002_defconfig
CFLAGS += -pipe -fno-builtin -mno-pic
AFLAGS += -mrelax -mno-pic
CFLAGS_MODULE += -mno-relax
LDFLAGS_vmlinux += --relax
cpuflags-$(CONFIG_CPU_AP7000) += -mcpu=ap7000
CFLAGS += $(cpuflags-y)
AFLAGS += $(cpuflags-y)
CHECKFLAGS += -D__avr32__
LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
head-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/head.o
head-y += arch/avr32/kernel/head.o
core-$(CONFIG_PLATFORM_AT32AP) += arch/avr32/mach-at32ap/
core-$(CONFIG_BOARD_ATSTK1000) += arch/avr32/boards/atstk1000/
core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/
core-y += arch/avr32/kernel/
core-y += arch/avr32/mm/
libs-y += arch/avr32/lib/ #$(LIBGCC)
archincdir-$(CONFIG_PLATFORM_AT32AP) := arch-at32ap
include/asm-avr32/.arch: $(wildcard include/config/platform/*.h) include/config/auto.conf
@echo ' SYMLINK include/asm-avr32/arch -> include/asm-avr32/$(archincdir-y)'
ifneq ($(KBUILD_SRC),)
$(Q)mkdir -p include/asm-avr32
$(Q)ln -fsn $(srctree)/include/asm-avr32/$(archincdir-y) include/asm-avr32/arch
else
$(Q)ln -fsn $(archincdir-y) include/asm-avr32/arch
endif
@touch $@
archprepare: include/asm-avr32/.arch
BOOT_TARGETS := vmlinux.elf vmlinux.bin uImage uImage.srec
.PHONY: $(BOOT_TARGETS) install
boot := arch/$(ARCH)/boot/images
KBUILD_IMAGE := $(boot)/uImage
vmlinux.elf: KBUILD_IMAGE := $(boot)/vmlinux.elf
vmlinux.cso: KBUILD_IMAGE := $(boot)/vmlinux.cso
uImage.srec: KBUILD_IMAGE := $(boot)/uImage.srec
uImage: KBUILD_IMAGE := $(boot)/uImage
quiet_cmd_listing = LST $@
cmd_listing = avr32-linux-objdump $(OBJDUMPFLAGS) -lS $< > $@
quiet_cmd_disasm = DIS $@
cmd_disasm = avr32-linux-objdump $(OBJDUMPFLAGS) -d $< > $@
vmlinux.elf vmlinux.bin uImage.srec uImage vmlinux.cso: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
install: vmlinux
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
linux.s: vmlinux
$(call if_changed,disasm)
linux.lst: vmlinux
$(call if_changed,listing)
define archhelp
@echo '* vmlinux.elf - ELF image with load address 0'
@echo ' vmlinux.cso - PathFinder CSO image'
@echo ' uImage - Create a bootable image for U-Boot'
endef

View file

@ -0,0 +1,2 @@
obj-y += setup.o spi.o flash.o
obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o

View file

@ -0,0 +1,37 @@
/*
* ATSTK1002 daughterboard-specific init code
*
* Copyright (C) 2005-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <asm/arch/board.h>
struct eth_platform_data __initdata eth0_data = {
.valid = 1,
.mii_phy_addr = 0x10,
.is_rmii = 0,
.hw_addr = { 0x6a, 0x87, 0x71, 0x14, 0xcd, 0xcb },
};
extern struct lcdc_platform_data atstk1000_fb0_data;
static int __init atstk1002_init(void)
{
at32_add_system_devices();
at32_add_device_usart(1); /* /dev/ttyS0 */
at32_add_device_usart(2); /* /dev/ttyS1 */
at32_add_device_usart(3); /* /dev/ttyS2 */
at32_add_device_eth(0, &eth0_data);
at32_add_device_spi(0);
at32_add_device_lcdc(0, &atstk1000_fb0_data);
return 0;
}
postcore_initcall(atstk1002_init);

View file

@ -0,0 +1,95 @@
/*
* ATSTK1000 board-specific flash initialization
*
* Copyright (C) 2005-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <asm/arch/smc.h>
static struct smc_config flash_config __initdata = {
.ncs_read_setup = 0,
.nrd_setup = 40,
.ncs_write_setup = 0,
.nwe_setup = 10,
.ncs_read_pulse = 80,
.nrd_pulse = 40,
.ncs_write_pulse = 65,
.nwe_pulse = 55,
.read_cycle = 120,
.write_cycle = 120,
.bus_width = 2,
.nrd_controlled = 1,
.nwe_controlled = 1,
.byte_write = 1,
};
static struct mtd_partition flash_parts[] = {
{
.name = "u-boot",
.offset = 0x00000000,
.size = 0x00020000, /* 128 KiB */
.mask_flags = MTD_WRITEABLE,
},
{
.name = "root",
.offset = 0x00020000,
.size = 0x007d0000,
},
{
.name = "env",
.offset = 0x007f0000,
.size = 0x00010000,
.mask_flags = MTD_WRITEABLE,
},
};
static struct physmap_flash_data flash_data = {
.width = 2,
.nr_parts = ARRAY_SIZE(flash_parts),
.parts = flash_parts,
};
static struct resource flash_resource = {
.start = 0x00000000,
.end = 0x007fffff,
.flags = IORESOURCE_MEM,
};
static struct platform_device flash_device = {
.name = "physmap-flash",
.id = 0,
.resource = &flash_resource,
.num_resources = 1,
.dev = {
.platform_data = &flash_data,
},
};
/* This needs to be called after the SMC has been initialized */
static int __init atstk1000_flash_init(void)
{
int ret;
ret = smc_set_configuration(0, &flash_config);
if (ret < 0) {
printk(KERN_ERR "atstk1000: failed to set NOR flash timing\n");
return ret;
}
platform_device_register(&flash_device);
return 0;
}
device_initcall(atstk1000_flash_init);

View file

@ -0,0 +1,59 @@
/*
* ATSTK1000 board-specific setup code.
*
* Copyright (C) 2005-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/bootmem.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/linkage.h>
#include <asm/setup.h>
#include <asm/arch/board.h>
/* Initialized by bootloader-specific startup code. */
struct tag *bootloader_tags __initdata;
struct lcdc_platform_data __initdata atstk1000_fb0_data;
asmlinkage void __init board_early_init(void)
{
extern void sdram_init(void);
#ifdef CONFIG_LOADER_STANDALONE
sdram_init();
#endif
}
void __init board_setup_fbmem(unsigned long fbmem_start,
unsigned long fbmem_size)
{
if (!fbmem_size)
return;
if (!fbmem_start) {
void *fbmem;
fbmem = alloc_bootmem_low_pages(fbmem_size);
fbmem_start = __pa(fbmem);
} else {
pg_data_t *pgdat;
for_each_online_pgdat(pgdat) {
if (fbmem_start >= pgdat->bdata->node_boot_start
&& fbmem_start <= pgdat->bdata->node_low_pfn)
reserve_bootmem_node(pgdat, fbmem_start,
fbmem_size);
}
}
printk("%luKiB framebuffer memory at address 0x%08lx\n",
fbmem_size >> 10, fbmem_start);
atstk1000_fb0_data.fbmem_start = fbmem_start;
atstk1000_fb0_data.fbmem_size = fbmem_size;
}

View file

@ -0,0 +1,27 @@
/*
* ATSTK1000 SPI devices
*
* Copyright (C) 2005 Atmel Norway
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/spi/spi.h>
static struct spi_board_info spi_board_info[] __initdata = {
{
.modalias = "ltv350qv",
.max_speed_hz = 16000000,
.bus_num = 0,
.chip_select = 1,
},
};
static int board_init_spi(void)
{
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
return 0;
}
arch_initcall(board_init_spi);

View file

@ -0,0 +1,62 @@
#
# Copyright (C) 2004-2006 Atmel Corporation
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
MKIMAGE := $(srctree)/scripts/mkuboot.sh
extra-y := vmlinux.bin vmlinux.gz
OBJCOPYFLAGS_vmlinux.bin := -O binary
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A avr32 -O linux -T kernel \
-C gzip -a $(CONFIG_LOAD_ADDRESS) -e $(CONFIG_ENTRY_ADDRESS) \
-n 'Linux-$(KERNELRELEASE)' -d $< $@
targets += uImage uImage.srec
$(obj)/uImage: $(obj)/vmlinux.gz
$(call if_changed,uimage)
@echo ' Image $@ is ready'
OBJCOPYFLAGS_uImage.srec := -I binary -O srec
$(obj)/uImage.srec: $(obj)/uImage
$(call if_changed,objcopy)
OBJCOPYFLAGS_vmlinux.elf := --change-section-lma .text-0x80000000 \
--change-section-lma __ex_table-0x80000000 \
--change-section-lma .rodata-0x80000000 \
--change-section-lma .data-0x80000000 \
--change-section-lma .init-0x80000000 \
--change-section-lma .bss-0x80000000 \
--change-section-lma .initrd-0x80000000 \
--change-section-lma __param-0x80000000 \
--change-section-lma __ksymtab-0x80000000 \
--change-section-lma __ksymtab_gpl-0x80000000 \
--change-section-lma __kcrctab-0x80000000 \
--change-section-lma __kcrctab_gpl-0x80000000 \
--change-section-lma __ksymtab_strings-0x80000000 \
--change-section-lma .got-0x80000000 \
--set-start 0xa0000000
$(obj)/vmlinux.elf: vmlinux FORCE
$(call if_changed,objcopy)
quiet_cmd_sfdwarf = SFDWARF $@
cmd_sfdwarf = sfdwarf $< TO $@ GNUAVR IW $(SFDWARF_FLAGS) > $(obj)/sfdwarf.log
$(obj)/vmlinux.cso: $(obj)/vmlinux.elf FORCE
$(call if_changed,sfdwarf)
install: $(BOOTIMAGE)
sh $(srctree)/install-kernel.sh $<
# Generated files to be removed upon make clean
clean-files := vmlinux* uImage uImage.srec

View file

@ -0,0 +1,3 @@
extra-y := head.o
obj-y := empty.o

View file

@ -0,0 +1 @@
/* Empty file */

View file

@ -0,0 +1,60 @@
/*
* Startup code for use with the u-boot bootloader.
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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 <asm/setup.h>
/*
* The kernel is loaded where we want it to be and all caches
* have just been flushed. We get two parameters from u-boot:
*
* r12 contains a magic number (ATAG_MAGIC)
* r11 points to a tag table providing information about
* the system.
*/
.section .init.text,"ax"
.global _start
_start:
/* Check if the boot loader actually provided a tag table */
lddpc r0, magic_number
cp.w r12, r0
brne no_tag_table
/* Initialize .bss */
lddpc r2, bss_start_addr
lddpc r3, end_addr
mov r0, 0
mov r1, 0
1: st.d r2++, r0
cp r2, r3
brlo 1b
/*
* Save the tag table address for later use. This must be done
* _after_ .bss has been initialized...
*/
lddpc r0, tag_table_addr
st.w r0[0], r11
/* Jump to loader-independent setup code */
rjmp kernel_entry
.align 2
magic_number:
.long ATAG_MAGIC
tag_table_addr:
.long bootloader_tags
bss_start_addr:
.long __bss_start
end_addr:
.long _end
no_tag_table:
sub r12, pc, (. - 2f)
bral panic
2: .asciz "Boot loader didn't provide correct magic number\n"

View file

@ -1,158 +1,15 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.18-rc1
# Thu Jul 6 10:04:05 2006
# Tue Jul 11 12:41:36 2006
#
CONFIG_MIPS=y
#
# Machine selection
#
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
# CONFIG_MIPS_PB1100 is not set
# CONFIG_MIPS_PB1500 is not set
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_PB1200 is not set
# CONFIG_MIPS_DB1000 is not set
# CONFIG_MIPS_DB1100 is not set
# CONFIG_MIPS_DB1500 is not set
# CONFIG_MIPS_DB1550 is not set
# CONFIG_MIPS_DB1200 is not set
# CONFIG_MIPS_MIRAGE is not set
# CONFIG_BASLER_EXCITE is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
CONFIG_MIPS_EV96100=y
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_WR_PPMC is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MOMENCO_JAGUAR_ATX is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_MOMENCO_OCELOT_3 is not set
# CONFIG_MOMENCO_OCELOT_C is not set
# CONFIG_MOMENCO_OCELOT_G is not set
# CONFIG_MIPS_XXS1500 is not set
# CONFIG_PNX8550_V2PCI is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_DDB5477 is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_QEMU is not set
# CONFIG_MARKEINS is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SIBYTE_SWARM is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_PTSWARM is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SNI_RM200_PCI is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
CONFIG_AVR32=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS_GT64120=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_MIPS_GT96100=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
# CPU selection
#
# CONFIG_CPU_MIPS32_R1 is not set
# CONFIG_CPU_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
CONFIG_CPU_RM7000=y
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_SYS_HAS_CPU_R5000=y
CONFIG_SYS_HAS_CPU_RM7000=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
#
# Kernel type
#
CONFIG_32BIT=y
# CONFIG_64BIT is not set
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_BOARD_SCACHE=y
CONFIG_RM7000_CPU_SCACHE=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_VPE_LOADER is not set
# CONFIG_64BIT_PHYS_ADDR is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
# CONFIG_HZ_48 is not set
# CONFIG_HZ_100 is not set
# CONFIG_HZ_128 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_256 is not set
CONFIG_HZ_1000=y
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@ -166,34 +23,34 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
# General setup
#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_SYSVIPC is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_RELAY=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
# CONFIG_HOTPLUG is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_SLAB is not set
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
CONFIG_BASE_SMALL=1
CONFIG_SLOB=y
#
# Loadable module support
@ -201,52 +58,81 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
#
# Block layer
#
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_IOSCHED_AS is not set
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
# CONFIG_DEFAULT_AS is not set
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_DEFAULT_NOOP=y
CONFIG_DEFAULT_IOSCHED="noop"
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
# System Type and features
#
CONFIG_HW_HAS_PCI=y
# CONFIG_PCI is not set
CONFIG_SUBARCH_AVR32B=y
CONFIG_MMU=y
CONFIG_PERFORMANCE_COUNTERS=y
CONFIG_PLATFORM_AT32AP=y
CONFIG_CPU_AT32AP7000=y
CONFIG_BOARD_ATSTK1002=y
CONFIG_BOARD_ATSTK1000=y
CONFIG_LOADER_U_BOOT=y
CONFIG_LOAD_ADDRESS=0x10000000
CONFIG_ENTRY_ADDRESS=0x90000000
CONFIG_PHYS_OFFSET=0x10000000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
# CONFIG_OWNERSHIP_TRACE is not set
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_CMDLINE=""
#
# Bus options
#
#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set
#
# PCI Hotplug Support
#
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_TRAD_SIGNALS=y
#
# Networking
@ -257,18 +143,17 @@ CONFIG_NET=y
# Networking options
#
# CONFIG_NETDEBUG is not set
# CONFIG_PACKET is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_DHCP=y
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
@ -279,8 +164,8 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@ -288,7 +173,7 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
CONFIG_NETWORK_SECMARK=y
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@ -327,16 +212,11 @@ CONFIG_NETWORK_SECMARK=y
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_NET_TCPPROBE is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_IEEE80211=m
# CONFIG_IEEE80211_DEBUG is not set
CONFIG_IEEE80211_CRYPT_WEP=m
CONFIG_IEEE80211_CRYPT_CCMP=m
CONFIG_IEEE80211_SOFTMAC=m
# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
CONFIG_WIRELESS_EXT=y
# CONFIG_IEEE80211 is not set
#
# Device Drivers
@ -346,14 +226,15 @@ CONFIG_WIRELESS_EXT=y
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
CONFIG_CONNECTOR=m
# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@ -373,14 +254,15 @@ CONFIG_CONNECTOR=m
# Block devices
#
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CDROM_PKTCDVD=m
CONFIG_CDROM_PKTCDVD_BUFFERS=8
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
CONFIG_ATA_OVER_ETH=m
CONFIG_BLK_DEV_LOOP=m
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
@ -390,7 +272,7 @@ CONFIG_ATA_OVER_ETH=m
#
# SCSI device support
#
CONFIG_RAID_ATTRS=m
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
#
@ -415,34 +297,22 @@ CONFIG_RAID_ATTRS=m
# Network device support
#
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
CONFIG_TUN=m
#
# PHY device support
#
CONFIG_PHYLIB=m
#
# MII PHY device drivers
#
CONFIG_MARVELL_PHY=m
CONFIG_DAVICOM_PHY=m
CONFIG_QSEMI_PHY=m
CONFIG_LXT_PHY=m
CONFIG_CICADA_PHY=m
CONFIG_VITESSE_PHY=m
CONFIG_SMSC_PHY=m
# CONFIG_PHYLIB is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
CONFIG_MIPS_GT96100ETH=y
# CONFIG_DM9000 is not set
CONFIG_MII=y
CONFIG_MACB=y
#
# Ethernet (1000 Mbit)
@ -465,7 +335,15 @@ CONFIG_MIPS_GT96100ETH=y
# Wan interfaces
#
# CONFIG_WAN is not set
# CONFIG_PPP is not set
CONFIG_PPP=m
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_FILTER is not set
CONFIG_PPP_ASYNC=m
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=m
# CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
@ -485,65 +363,35 @@ CONFIG_MIPS_GT96100ETH=y
#
# Input device support
#
CONFIG_INPUT=y
#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
# CONFIG_INPUT is not set
#
# Hardware I/O ports
#
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_LIBPS2 is not set
CONFIG_SERIO_RAW=m
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_AT91=y
CONFIG_SERIAL_AT91_CONSOLE=y
# CONFIG_SERIAL_AT91_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_LEGACY_PTYS is not set
#
# IPMI
@ -579,13 +427,23 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# SPI support
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
CONFIG_SPI=y
# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
#
# SPI Master Controller Drivers
#
CONFIG_SPI_ATMEL=m
# CONFIG_SPI_BITBANG is not set
#
# SPI Protocol Masters
#
#
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
#
# Hardware Monitoring support
@ -612,13 +470,28 @@ CONFIG_VIDEO_V4L2=y
# Graphics support
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
CONFIG_FB=m
CONFIG_FB_CFB_FILLRECT=m
CONFIG_FB_CFB_COPYAREA=m
CONFIG_FB_CFB_IMAGEBLIT=m
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
CONFIG_FB_SIDSA=m
CONFIG_FB_SIDSA_DEFAULT_BPP=24
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
# Console display driver support
# Logo configuration
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
# CONFIG_LOGO is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_LCD_CLASS_DEVICE=m
CONFIG_LCD_DEVICE=y
CONFIG_LCD_LTV350QV=m
#
# Sound
@ -697,15 +570,14 @@ CONFIG_EXT2_FS=y
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
CONFIG_MINIX_FS=m
CONFIG_ROMFS_FS=m
# CONFIG_INOTIFY is not set
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
CONFIG_FUSE_FS=m
# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@ -716,8 +588,11 @@ CONFIG_FUSE_FS=m
#
# DOS/FAT/NT Filesystems
#
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
#
@ -726,10 +601,10 @@ CONFIG_FUSE_FS=m
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
# CONFIG_TMPFS is not set
CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
CONFIG_CONFIGFS_FS=m
#
# Miscellaneous filesystems
@ -752,19 +627,25 @@ CONFIG_RAMFS=y
# Network File Systems
#
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
CONFIG_CIFS=m
# CONFIG_CIFS_STATS is not set
# CONFIG_CIFS_WEAK_PW_HASH is not set
# CONFIG_CIFS_XATTR is not set
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_EXPERIMENTAL is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@ -779,60 +660,84 @@ CONFIG_MSDOS_PARTITION=y
#
# Native Language Support
#
# CONFIG_NLS is not set
#
# Profiling support
#
# CONFIG_PROFILING is not set
CONFIG_NLS=m
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=m
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
CONFIG_NLS_CODEPAGE_850=m
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ASCII is not set
CONFIG_NLS_ISO8859_1=m
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_FS is not set
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE=""
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
CONFIG_FRAME_POINTER=y
# CONFIG_UNWIND_INFO is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_KPROBES=y
#
# Security options
#
CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
# CONFIG_CRYPTO_TEST is not set
# CONFIG_CRYPTO is not set
#
# Hardware crypto devices
@ -841,10 +746,9 @@ CONFIG_CRYPTO_CRC32C=m
#
# Library routines
#
# CONFIG_CRC_CCITT is not set
CONFIG_CRC16=m
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
CONFIG_CRC32=m
CONFIG_LIBCRC32C=m
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
CONFIG_PLIST=y

View file

@ -0,0 +1,18 @@
#
# Makefile for the Linux/AVR32 kernel.
#
extra-y := head.o vmlinux.lds
obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o
obj-y += syscall_table.o syscall-stubs.o irq.o
obj-y += setup.o traps.o semaphore.o ptrace.o
obj-y += signal.o sys_avr32.o process.o time.o
obj-y += init_task.o switch_to.o cpu.o
obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o
obj-$(CONFIG_KPROBES) += kprobes.o
USE_STANDARD_AS_RULE := true
%.lds: %.lds.c FORCE
$(call if_changed_dep,cpp_lds_S)

View file

@ -0,0 +1,25 @@
/*
* Generate definitions needed by assembly language modules.
* This code generates raw asm output which is post-processed
* to extract and format the required data.
*/
#include <linux/thread_info.h>
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
#define BLANK() asm volatile("\n->" : : )
#define OFFSET(sym, str, mem) \
DEFINE(sym, offsetof(struct str, mem));
void foo(void)
{
OFFSET(TI_task, thread_info, task);
OFFSET(TI_exec_domain, thread_info, exec_domain);
OFFSET(TI_flags, thread_info, flags);
OFFSET(TI_cpu, thread_info, cpu);
OFFSET(TI_preempt_count, thread_info, preempt_count);
OFFSET(TI_restart_block, thread_info, restart_block);
}

View file

@ -0,0 +1,55 @@
/*
* Export AVR32-specific functions for loadable modules.
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <asm/checksum.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
/*
* GCC functions
*/
extern unsigned long long __avr32_lsl64(unsigned long long u, unsigned long b);
extern unsigned long long __avr32_lsr64(unsigned long long u, unsigned long b);
extern unsigned long long __avr32_asr64(unsigned long long u, unsigned long b);
EXPORT_SYMBOL(__avr32_lsl64);
EXPORT_SYMBOL(__avr32_lsr64);
EXPORT_SYMBOL(__avr32_asr64);
/*
* String functions
*/
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
/*
* Userspace access stuff.
*/
EXPORT_SYMBOL(copy_from_user);
EXPORT_SYMBOL(copy_to_user);
EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(strncpy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(clear_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
/* Delay loops (lib/delay.S) */
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__const_udelay);
/* Bit operations (lib/findbit.S) */
EXPORT_SYMBOL(find_first_zero_bit);
EXPORT_SYMBOL(find_next_zero_bit);
EXPORT_SYMBOL(find_first_bit);
EXPORT_SYMBOL(find_next_bit);
EXPORT_SYMBOL(generic_find_next_zero_le_bit);

327
arch/avr32/kernel/cpu.c Normal file
View file

@ -0,0 +1,327 @@
/*
* Copyright (C) 2005-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
#include <linux/percpu.h>
#include <linux/param.h>
#include <linux/errno.h>
#include <asm/setup.h>
#include <asm/sysreg.h>
static DEFINE_PER_CPU(struct cpu, cpu_devices);
#ifdef CONFIG_PERFORMANCE_COUNTERS
/*
* XXX: If/when a SMP-capable implementation of AVR32 will ever be
* made, we must make sure that the code executes on the correct CPU.
*/
static ssize_t show_pc0event(struct sys_device *dev, char *buf)
{
unsigned long pccr;
pccr = sysreg_read(PCCR);
return sprintf(buf, "0x%lx\n", (pccr >> 12) & 0x3f);
}
static ssize_t store_pc0event(struct sys_device *dev, const char *buf,
size_t count)
{
unsigned long val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (endp == buf || val > 0x3f)
return -EINVAL;
val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff);
sysreg_write(PCCR, val);
return count;
}
static ssize_t show_pc0count(struct sys_device *dev, char *buf)
{
unsigned long pcnt0;
pcnt0 = sysreg_read(PCNT0);
return sprintf(buf, "%lu\n", pcnt0);
}
static ssize_t store_pc0count(struct sys_device *dev, const char *buf,
size_t count)
{
unsigned long val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (endp == buf)
return -EINVAL;
sysreg_write(PCNT0, val);
return count;
}
static ssize_t show_pc1event(struct sys_device *dev, char *buf)
{
unsigned long pccr;
pccr = sysreg_read(PCCR);
return sprintf(buf, "0x%lx\n", (pccr >> 18) & 0x3f);
}
static ssize_t store_pc1event(struct sys_device *dev, const char *buf,
size_t count)
{
unsigned long val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (endp == buf || val > 0x3f)
return -EINVAL;
val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff);
sysreg_write(PCCR, val);
return count;
}
static ssize_t show_pc1count(struct sys_device *dev, char *buf)
{
unsigned long pcnt1;
pcnt1 = sysreg_read(PCNT1);
return sprintf(buf, "%lu\n", pcnt1);
}
static ssize_t store_pc1count(struct sys_device *dev, const char *buf,
size_t count)
{
unsigned long val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (endp == buf)
return -EINVAL;
sysreg_write(PCNT1, val);
return count;
}
static ssize_t show_pccycles(struct sys_device *dev, char *buf)
{
unsigned long pccnt;
pccnt = sysreg_read(PCCNT);
return sprintf(buf, "%lu\n", pccnt);
}
static ssize_t store_pccycles(struct sys_device *dev, const char *buf,
size_t count)
{
unsigned long val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (endp == buf)
return -EINVAL;
sysreg_write(PCCNT, val);
return count;
}
static ssize_t show_pcenable(struct sys_device *dev, char *buf)
{
unsigned long pccr;
pccr = sysreg_read(PCCR);
return sprintf(buf, "%c\n", (pccr & 1)?'1':'0');
}
static ssize_t store_pcenable(struct sys_device *dev, const char *buf,
size_t count)
{
unsigned long pccr, val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (endp == buf)
return -EINVAL;
if (val)
val = 1;
pccr = sysreg_read(PCCR);
pccr = (pccr & ~1UL) | val;
sysreg_write(PCCR, pccr);
return count;
}
static SYSDEV_ATTR(pc0event, 0600, show_pc0event, store_pc0event);
static SYSDEV_ATTR(pc0count, 0600, show_pc0count, store_pc0count);
static SYSDEV_ATTR(pc1event, 0600, show_pc1event, store_pc1event);
static SYSDEV_ATTR(pc1count, 0600, show_pc1count, store_pc1count);
static SYSDEV_ATTR(pccycles, 0600, show_pccycles, store_pccycles);
static SYSDEV_ATTR(pcenable, 0600, show_pcenable, store_pcenable);
#endif /* CONFIG_PERFORMANCE_COUNTERS */
static int __init topology_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
struct cpu *c = &per_cpu(cpu_devices, cpu);
register_cpu(c, cpu);
#ifdef CONFIG_PERFORMANCE_COUNTERS
sysdev_create_file(&c->sysdev, &attr_pc0event);
sysdev_create_file(&c->sysdev, &attr_pc0count);
sysdev_create_file(&c->sysdev, &attr_pc1event);
sysdev_create_file(&c->sysdev, &attr_pc1count);
sysdev_create_file(&c->sysdev, &attr_pccycles);
sysdev_create_file(&c->sysdev, &attr_pcenable);
#endif
}
return 0;
}
subsys_initcall(topology_init);
static const char *cpu_names[] = {
"Morgan",
"AP7000",
};
#define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
static const char *arch_names[] = {
"AVR32A",
"AVR32B",
};
#define NR_ARCH_NAMES ARRAY_SIZE(arch_names)
static const char *mmu_types[] = {
"No MMU",
"ITLB and DTLB",
"Shared TLB",
"MPU"
};
void __init setup_processor(void)
{
unsigned long config0, config1;
unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
unsigned tmp;
config0 = sysreg_read(CONFIG0); /* 0x0000013e; */
config1 = sysreg_read(CONFIG1); /* 0x01f689a2; */
cpu_id = config0 >> 24;
cpu_rev = (config0 >> 16) & 0xff;
arch_id = (config0 >> 13) & 0x07;
arch_rev = (config0 >> 10) & 0x07;
mmu_type = (config0 >> 7) & 0x03;
boot_cpu_data.arch_type = arch_id;
boot_cpu_data.cpu_type = cpu_id;
boot_cpu_data.arch_revision = arch_rev;
boot_cpu_data.cpu_revision = cpu_rev;
boot_cpu_data.tlb_config = mmu_type;
tmp = (config1 >> 13) & 0x07;
if (tmp) {
boot_cpu_data.icache.ways = 1 << ((config1 >> 10) & 0x07);
boot_cpu_data.icache.sets = 1 << ((config1 >> 16) & 0x0f);
boot_cpu_data.icache.linesz = 1 << (tmp + 1);
}
tmp = (config1 >> 3) & 0x07;
if (tmp) {
boot_cpu_data.dcache.ways = 1 << (config1 & 0x07);
boot_cpu_data.dcache.sets = 1 << ((config1 >> 6) & 0x0f);
boot_cpu_data.dcache.linesz = 1 << (tmp + 1);
}
if ((cpu_id >= NR_CPU_NAMES) || (arch_id >= NR_ARCH_NAMES)) {
printk ("Unknown CPU configuration (ID %02x, arch %02x), "
"continuing anyway...\n",
cpu_id, arch_id);
return;
}
printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
cpu_names[cpu_id], cpu_id, cpu_rev,
arch_names[arch_id], arch_rev);
printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
printk ("CPU: features:");
if (config0 & (1 << 6))
printk(" fpu");
if (config0 & (1 << 5))
printk(" java");
if (config0 & (1 << 4))
printk(" perfctr");
if (config0 & (1 << 3))
printk(" ocd");
printk("\n");
}
#ifdef CONFIG_PROC_FS
static int c_show(struct seq_file *m, void *v)
{
unsigned int icache_size, dcache_size;
unsigned int cpu = smp_processor_id();
icache_size = boot_cpu_data.icache.ways *
boot_cpu_data.icache.sets *
boot_cpu_data.icache.linesz;
dcache_size = boot_cpu_data.dcache.ways *
boot_cpu_data.dcache.sets *
boot_cpu_data.dcache.linesz;
seq_printf(m, "processor\t: %d\n", cpu);
if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
seq_printf(m, "cpu family\t: %s revision %d\n",
arch_names[boot_cpu_data.arch_type],
boot_cpu_data.arch_revision);
if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
seq_printf(m, "cpu type\t: %s revision %d\n",
cpu_names[boot_cpu_data.cpu_type],
boot_cpu_data.cpu_revision);
seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
icache_size >> 10,
boot_cpu_data.icache.ways,
boot_cpu_data.icache.sets,
boot_cpu_data.icache.linesz);
seq_printf(m, "d-cache\t\t: %dK (%u ways x %u sets x %u)\n",
dcache_size >> 10,
boot_cpu_data.dcache.ways,
boot_cpu_data.dcache.sets,
boot_cpu_data.dcache.linesz);
seq_printf(m, "bogomips\t: %lu.%02lu\n",
boot_cpu_data.loops_per_jiffy / (500000/HZ),
(boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
return *pos < 1 ? (void *)1 : NULL;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return NULL;
}
static void c_stop(struct seq_file *m, void *v)
{
}
struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = c_show
};
#endif /* CONFIG_PROC_FS */

View file

@ -0,0 +1,678 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This file contains the low-level entry-points into the kernel, that is,
* exception handlers, debug trap handlers, interrupt handlers and the
* system call handler.
*/
#include <linux/errno.h>
#include <asm/asm.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
#include <asm/ocd.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
#include <asm/sysreg.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#ifdef CONFIG_PREEMPT
# define preempt_stop mask_interrupts
#else
# define preempt_stop
# define fault_resume_kernel fault_restore_all
#endif
#define __MASK(x) ((1 << (x)) - 1)
#define IRQ_MASK ((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \
(__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT))
.section .ex.text,"ax",@progbits
.align 2
exception_vectors:
bral handle_critical
.align 2
bral handle_critical
.align 2
bral do_bus_error_write
.align 2
bral do_bus_error_read
.align 2
bral do_nmi_ll
.align 2
bral handle_address_fault
.align 2
bral handle_protection_fault
.align 2
bral handle_debug
.align 2
bral do_illegal_opcode_ll
.align 2
bral do_illegal_opcode_ll
.align 2
bral do_illegal_opcode_ll
.align 2
bral do_fpe_ll
.align 2
bral do_illegal_opcode_ll
.align 2
bral handle_address_fault
.align 2
bral handle_address_fault
.align 2
bral handle_protection_fault
.align 2
bral handle_protection_fault
.align 2
bral do_dtlb_modified
/*
* r0 : PGD/PT/PTE
* r1 : Offending address
* r2 : Scratch register
* r3 : Cause (5, 12 or 13)
*/
#define tlbmiss_save pushm r0-r3
#define tlbmiss_restore popm r0-r3
.section .tlbx.ex.text,"ax",@progbits
.global itlb_miss
itlb_miss:
tlbmiss_save
rjmp tlb_miss_common
.section .tlbr.ex.text,"ax",@progbits
dtlb_miss_read:
tlbmiss_save
rjmp tlb_miss_common
.section .tlbw.ex.text,"ax",@progbits
dtlb_miss_write:
tlbmiss_save
.global tlb_miss_common
tlb_miss_common:
mfsr r0, SYSREG_PTBR
mfsr r1, SYSREG_TLBEAR
/* Is it the vmalloc space? */
bld r1, 31
brcs handle_vmalloc_miss
/* First level lookup */
pgtbl_lookup:
lsr r2, r1, PGDIR_SHIFT
ld.w r0, r0[r2 << 2]
bld r0, _PAGE_BIT_PRESENT
brcc page_table_not_present
/* TODO: Check access rights on page table if necessary */
/* Translate to virtual address in P1. */
andl r0, 0xf000
sbr r0, 31
/* Second level lookup */
lsl r1, (32 - PGDIR_SHIFT)
lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
add r2, r0, r1 << 2
ld.w r1, r2[0]
bld r1, _PAGE_BIT_PRESENT
brcc page_not_present
/* Mark the page as accessed */
sbr r1, _PAGE_BIT_ACCESSED
st.w r2[0], r1
/* Drop software flags */
andl r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
mtsr SYSREG_TLBELO, r1
/* Figure out which entry we want to replace */
mfsr r0, SYSREG_TLBARLO
clz r2, r0
brcc 1f
mov r1, -1 /* All entries have been accessed, */
mtsr SYSREG_TLBARLO, r1 /* so reset TLBAR */
mov r2, 0 /* and start at 0 */
1: mfsr r1, SYSREG_MMUCR
lsl r2, 14
andl r1, 0x3fff, COH
or r1, r2
mtsr SYSREG_MMUCR, r1
tlbw
tlbmiss_restore
rete
handle_vmalloc_miss:
/* Simply do the lookup in init's page table */
mov r0, lo(swapper_pg_dir)
orh r0, hi(swapper_pg_dir)
rjmp pgtbl_lookup
/* --- System Call --- */
.section .scall.text,"ax",@progbits
system_call:
pushm r12 /* r12_orig */
stmts --sp, r0-lr
zero_fp
mfsr r0, SYSREG_RAR_SUP
mfsr r1, SYSREG_RSR_SUP
stm --sp, r0-r1
/* check for syscall tracing */
get_thread_info r0
ld.w r1, r0[TI_flags]
bld r1, TIF_SYSCALL_TRACE
brcs syscall_trace_enter
syscall_trace_cont:
cp.w r8, NR_syscalls
brhs syscall_badsys
lddpc lr, syscall_table_addr
ld.w lr, lr[r8 << 2]
mov r8, r5 /* 5th argument (6th is pushed by stub) */
icall lr
.global syscall_return
syscall_return:
get_thread_info r0
mask_interrupts /* make sure we don't miss an interrupt
setting need_resched or sigpending
between sampling and the rets */
/* Store the return value so that the correct value is loaded below */
stdsp sp[REG_R12], r12
ld.w r1, r0[TI_flags]
andl r1, _TIF_ALLWORK_MASK, COH
brne syscall_exit_work
syscall_exit_cont:
popm r8-r9
mtsr SYSREG_RAR_SUP, r8
mtsr SYSREG_RSR_SUP, r9
ldmts sp++, r0-lr
sub sp, -4 /* r12_orig */
rets
.align 2
syscall_table_addr:
.long sys_call_table
syscall_badsys:
mov r12, -ENOSYS
rjmp syscall_return
.global ret_from_fork
ret_from_fork:
rcall schedule_tail
/* check for syscall tracing */
get_thread_info r0
ld.w r1, r0[TI_flags]
andl r1, _TIF_ALLWORK_MASK, COH
brne syscall_exit_work
rjmp syscall_exit_cont
syscall_trace_enter:
pushm r8-r12
rcall syscall_trace
popm r8-r12
rjmp syscall_trace_cont
syscall_exit_work:
bld r1, TIF_SYSCALL_TRACE
brcc 1f
unmask_interrupts
rcall syscall_trace
mask_interrupts
ld.w r1, r0[TI_flags]
1: bld r1, TIF_NEED_RESCHED
brcc 2f
unmask_interrupts
rcall schedule
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp 1b
2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
tst r1, r2
breq 3f
unmask_interrupts
mov r12, sp
mov r11, r0
rcall do_notify_resume
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp 1b
3: bld r1, TIF_BREAKPOINT
brcc syscall_exit_cont
mfsr r3, SYSREG_TLBEHI
lddsp r2, sp[REG_PC]
andl r3, 0xff, COH
lsl r3, 1
sbr r3, 30
sbr r3, 0
mtdr DBGREG_BWA2A, r2
mtdr DBGREG_BWC2A, r3
rjmp syscall_exit_cont
/* The slow path of the TLB miss handler */
page_table_not_present:
page_not_present:
tlbmiss_restore
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
rcall do_page_fault
rjmp ret_from_exception
/* This function expects to find offending PC in SYSREG_RAR_EX */
save_full_context_ex:
mfsr r8, SYSREG_RSR_EX
mov r12, r8
andh r8, (MODE_MASK >> 16), COH
mfsr r11, SYSREG_RAR_EX
brne 2f
1: pushm r11, r12 /* PC and SR */
unmask_exceptions
ret r12
2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR)
stdsp sp[4], r10 /* replace saved SP */
rjmp 1b
/* Low-level exception handlers */
handle_critical:
pushm r12
pushm r0-r12
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
rcall do_critical_exception
/* We should never get here... */
bad_return:
sub r12, pc, (. - 1f)
bral panic
.align 2
1: .asciz "Return from critical exception!"
.align 1
do_bus_error_write:
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mov r11, 1
rjmp 1f
do_bus_error_read:
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mov r11, 0
1: mfsr r12, SYSREG_BEAR
mov r10, sp
rcall do_bus_error
rjmp ret_from_exception
.align 1
do_nmi_ll:
sub sp, 4
stmts --sp, r0-lr
/* FIXME: Make sure RAR_NMI and RSR_NMI are pushed instead of *_EX */
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
rcall do_nmi
rjmp bad_return
handle_address_fault:
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
rcall do_address_exception
rjmp ret_from_exception
handle_protection_fault:
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
rcall do_page_fault
rjmp ret_from_exception
.align 1
do_illegal_opcode_ll:
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
rcall do_illegal_opcode
rjmp ret_from_exception
do_dtlb_modified:
pushm r0-r3
mfsr r1, SYSREG_TLBEAR
mfsr r0, SYSREG_PTBR
lsr r2, r1, PGDIR_SHIFT
ld.w r0, r0[r2 << 2]
lsl r1, (32 - PGDIR_SHIFT)
lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
/* Translate to virtual address in P1 */
andl r0, 0xf000
sbr r0, 31
add r2, r0, r1 << 2
ld.w r3, r2[0]
sbr r3, _PAGE_BIT_DIRTY
mov r0, r3
st.w r2[0], r3
/* The page table is up-to-date. Update the TLB entry as well */
andl r0, lo(_PAGE_FLAGS_HARDWARE_MASK)
mtsr SYSREG_TLBELO, r0
/* MMUCR[DRP] is updated automatically, so let's go... */
tlbw
popm r0-r3
rete
do_fpe_ll:
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
unmask_interrupts
mov r12, 26
mov r11, sp
rcall do_fpe
rjmp ret_from_exception
ret_from_exception:
mask_interrupts
lddsp r4, sp[REG_SR]
andh r4, (MODE_MASK >> 16), COH
brne fault_resume_kernel
get_thread_info r0
ld.w r1, r0[TI_flags]
andl r1, _TIF_WORK_MASK, COH
brne fault_exit_work
fault_resume_user:
popm r8-r9
mask_exceptions
mtsr SYSREG_RAR_EX, r8
mtsr SYSREG_RSR_EX, r9
ldmts sp++, r0-lr
sub sp, -4
rete
fault_resume_kernel:
#ifdef CONFIG_PREEMPT
get_thread_info r0
ld.w r2, r0[TI_preempt_count]
cp.w r2, 0
brne 1f
ld.w r1, r0[TI_flags]
bld r1, TIF_NEED_RESCHED
brcc 1f
lddsp r4, sp[REG_SR]
bld r4, SYSREG_GM_OFFSET
brcs 1f
rcall preempt_schedule_irq
1:
#endif
popm r8-r9
mask_exceptions
mfsr r1, SYSREG_SR
mtsr SYSREG_RAR_EX, r8
mtsr SYSREG_RSR_EX, r9
popm lr
sub sp, -4 /* ignore SP */
popm r0-r12
sub sp, -4 /* ignore r12_orig */
rete
irq_exit_work:
/* Switch to exception mode so that we can share the same code. */
mfsr r8, SYSREG_SR
cbr r8, SYSREG_M0_OFFSET
orh r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2))
mtsr SYSREG_SR, r8
sub pc, -2
get_thread_info r0
ld.w r1, r0[TI_flags]
fault_exit_work:
bld r1, TIF_NEED_RESCHED
brcc 1f
unmask_interrupts
rcall schedule
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp fault_exit_work
1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
tst r1, r2
breq 2f
unmask_interrupts
mov r12, sp
mov r11, r0
rcall do_notify_resume
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp fault_exit_work
2: bld r1, TIF_BREAKPOINT
brcc fault_resume_user
mfsr r3, SYSREG_TLBEHI
lddsp r2, sp[REG_PC]
andl r3, 0xff, COH
lsl r3, 1
sbr r3, 30
sbr r3, 0
mtdr DBGREG_BWA2A, r2
mtdr DBGREG_BWC2A, r3
rjmp fault_resume_user
/* If we get a debug trap from privileged context we end up here */
handle_debug_priv:
/* Fix up LR and SP in regs. r11 contains the mode we came from */
mfsr r8, SYSREG_SR
mov r9, r8
andh r8, hi(~MODE_MASK)
or r8, r11
mtsr SYSREG_SR, r8
sub pc, -2
stdsp sp[REG_LR], lr
mtsr SYSREG_SR, r9
sub pc, -2
sub r10, sp, -FRAME_SIZE_FULL
stdsp sp[REG_SP], r10
mov r12, sp
rcall do_debug_priv
/* Now, put everything back */
ssrf SR_EM_BIT
popm r10, r11
mtsr SYSREG_RAR_DBG, r10
mtsr SYSREG_RSR_DBG, r11
mfsr r8, SYSREG_SR
mov r9, r8
andh r8, hi(~MODE_MASK)
andh r11, hi(MODE_MASK)
or r8, r11
mtsr SYSREG_SR, r8
sub pc, -2
popm lr
mtsr SYSREG_SR, r9
sub pc, -2
sub sp, -4 /* skip SP */
popm r0-r12
sub sp, -4
retd
/*
* At this point, everything is masked, that is, interrupts,
* exceptions and debugging traps. We might get called from
* interrupt or exception context in some rare cases, but this
* will be taken care of by do_debug(), so we're not going to
* do a 100% correct context save here.
*/
handle_debug:
sub sp, 4 /* r12_orig */
stmts --sp, r0-lr
mfsr r10, SYSREG_RAR_DBG
mfsr r11, SYSREG_RSR_DBG
unmask_exceptions
pushm r10,r11
andh r11, (MODE_MASK >> 16), COH
brne handle_debug_priv
mov r12, sp
rcall do_debug
lddsp r10, sp[REG_SR]
andh r10, (MODE_MASK >> 16), COH
breq debug_resume_user
debug_restore_all:
popm r10,r11
mask_exceptions
mtsr SYSREG_RSR_DBG, r11
mtsr SYSREG_RAR_DBG, r10
ldmts sp++, r0-lr
sub sp, -4
retd
debug_resume_user:
get_thread_info r0
mask_interrupts
ld.w r1, r0[TI_flags]
andl r1, _TIF_DBGWORK_MASK, COH
breq debug_restore_all
1: bld r1, TIF_NEED_RESCHED
brcc 2f
unmask_interrupts
rcall schedule
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp 1b
2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
tst r1, r2
breq 3f
unmask_interrupts
mov r12, sp
mov r11, r0
rcall do_notify_resume
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp 1b
3: bld r1, TIF_SINGLE_STEP
brcc debug_restore_all
mfdr r2, DBGREG_DC
sbr r2, DC_SS_BIT
mtdr DBGREG_DC, r2
rjmp debug_restore_all
.set rsr_int0, SYSREG_RSR_INT0
.set rsr_int1, SYSREG_RSR_INT1
.set rsr_int2, SYSREG_RSR_INT2
.set rsr_int3, SYSREG_RSR_INT3
.set rar_int0, SYSREG_RAR_INT0
.set rar_int1, SYSREG_RAR_INT1
.set rar_int2, SYSREG_RAR_INT2
.set rar_int3, SYSREG_RAR_INT3
.macro IRQ_LEVEL level
.type irq_level\level, @function
irq_level\level:
sub sp, 4 /* r12_orig */
stmts --sp,r0-lr
mfsr r8, rar_int\level
mfsr r9, rsr_int\level
pushm r8-r9
mov r11, sp
mov r12, \level
rcall do_IRQ
lddsp r4, sp[REG_SR]
andh r4, (MODE_MASK >> 16), COH
#ifdef CONFIG_PREEMPT
brne 2f
#else
brne 1f
#endif
get_thread_info r0
ld.w r1, r0[TI_flags]
andl r1, _TIF_WORK_MASK, COH
brne irq_exit_work
1: popm r8-r9
mtsr rar_int\level, r8
mtsr rsr_int\level, r9
ldmts sp++,r0-lr
sub sp, -4 /* ignore r12_orig */
rete
#ifdef CONFIG_PREEMPT
2:
get_thread_info r0
ld.w r2, r0[TI_preempt_count]
cp.w r2, 0
brne 1b
ld.w r1, r0[TI_flags]
bld r1, TIF_NEED_RESCHED
brcc 1b
lddsp r4, sp[REG_SR]
bld r4, SYSREG_GM_OFFSET
brcs 1b
rcall preempt_schedule_irq
rjmp 1b
#endif
.endm
.section .irq.text,"ax",@progbits
.global irq_level0
.global irq_level1
.global irq_level2
.global irq_level3
IRQ_LEVEL 0
IRQ_LEVEL 1
IRQ_LEVEL 2
IRQ_LEVEL 3

45
arch/avr32/kernel/head.S Normal file
View file

@ -0,0 +1,45 @@
/*
* Non-board-specific low-level startup code
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/thread_info.h>
#include <asm/sysreg.h>
.section .init.text,"ax"
.global kernel_entry
kernel_entry:
/* Initialize status register */
lddpc r0, init_sr
mtsr SYSREG_SR, r0
/* Set initial stack pointer */
lddpc sp, stack_addr
sub sp, -THREAD_SIZE
#ifdef CONFIG_FRAME_POINTER
/* Mark last stack frame */
mov lr, 0
mov r7, 0
#endif
/* Set up the PIO, SDRAM controller, early printk, etc. */
rcall board_early_init
/* Start the show */
lddpc pc, kernel_start_addr
.align 2
init_sr:
.long 0x007f0000 /* Supervisor mode, everything masked */
stack_addr:
.long init_thread_union
kernel_start_addr:
.long start_kernel

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/init_task.h>
#include <linux/mqueue.h>
#include <asm/pgtable.h>
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
struct mm_struct init_mm = INIT_MM(init_mm);
EXPORT_SYMBOL(init_mm);
/*
* Initial thread structure. Must be aligned on an 8192-byte boundary.
*/
union thread_union init_thread_union
__attribute__((__section__(".data.init_task"))) =
{ INIT_THREAD_INFO(init_task) };
/*
* Initial task structure.
*
* All other task structs will be allocated on slabs in fork.c
*/
struct task_struct init_task = INIT_TASK(init_task);
EXPORT_SYMBOL(init_task);

71
arch/avr32/kernel/irq.c Normal file
View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* Based on arch/i386/kernel/irq.c
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
* instead of just grabbing them. Thus setups with different IRQ numbers
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
*
* IRQ's are in fact implemented a bit like signal handlers for the kernel.
* Naturally it's not a 1:1 relation, but there are similarities.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/sysdev.h>
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves.
*/
void ack_bad_irq(unsigned int irq)
{
printk("unexpected IRQ %u\n", irq);
}
#ifdef CONFIG_PROC_FS
int show_interrupts(struct seq_file *p, void *v)
{
int i = *(loff_t *)v, cpu;
struct irqaction *action;
unsigned long flags;
if (i == 0) {
seq_puts(p, " ");
for_each_online_cpu(cpu)
seq_printf(p, "CPU%d ", cpu);
seq_putc(p, '\n');
}
if (i < NR_IRQS) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
if (!action)
goto unlock;
seq_printf(p, "%3d: ", i);
for_each_online_cpu(cpu)
seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name);
seq_putc(p, '\n');
unlock:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
}
return 0;
}
#endif

270
arch/avr32/kernel/kprobes.c Normal file
View file

@ -0,0 +1,270 @@
/*
* Kernel Probes (KProbes)
*
* Copyright (C) 2005-2006 Atmel Corporation
*
* Based on arch/ppc64/kernel/kprobes.c
* Copyright (C) IBM Corporation, 2002, 2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <asm/cacheflush.h>
#include <asm/kdebug.h>
#include <asm/ocd.h>
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
static unsigned long kprobe_status;
static struct pt_regs jprobe_saved_regs;
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
int ret = 0;
if ((unsigned long)p->addr & 0x01) {
printk("Attempt to register kprobe at an unaligned address\n");
ret = -EINVAL;
}
/* XXX: Might be a good idea to check if p->addr is a valid
* kernel address as well... */
if (!ret) {
pr_debug("copy kprobe at %p\n", p->addr);
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
}
return ret;
}
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
pr_debug("arming kprobe at %p\n", p->addr);
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long)p->addr,
(unsigned long)p->addr + sizeof(kprobe_opcode_t));
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
pr_debug("disarming kprobe at %p\n", p->addr);
*p->addr = p->opcode;
flush_icache_range((unsigned long)p->addr,
(unsigned long)p->addr + sizeof(kprobe_opcode_t));
}
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
unsigned long dc;
pr_debug("preparing to singlestep over %p (PC=%08lx)\n",
p->addr, regs->pc);
BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D)));
dc = __mfdr(DBGREG_DC);
dc |= DC_SS;
__mtdr(DBGREG_DC, dc);
/*
* We must run the instruction from its original location
* since it may actually reference PC.
*
* TODO: Do the instruction replacement directly in icache.
*/
*p->addr = p->opcode;
flush_icache_range((unsigned long)p->addr,
(unsigned long)p->addr + sizeof(kprobe_opcode_t));
}
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
unsigned long dc;
pr_debug("resuming execution at PC=%08lx\n", regs->pc);
dc = __mfdr(DBGREG_DC);
dc &= ~DC_SS;
__mtdr(DBGREG_DC, dc);
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long)p->addr,
(unsigned long)p->addr + sizeof(kprobe_opcode_t));
}
static void __kprobes set_current_kprobe(struct kprobe *p)
{
__get_cpu_var(current_kprobe) = p;
}
static int __kprobes kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
void *addr = (void *)regs->pc;
int ret = 0;
pr_debug("kprobe_handler: kprobe_running=%d\n",
kprobe_running());
/*
* We don't want to be preempted for the entire
* duration of kprobe processing
*/
preempt_disable();
/* Check that we're not recursing */
if (kprobe_running()) {
p = get_kprobe(addr);
if (p) {
if (kprobe_status == KPROBE_HIT_SS) {
printk("FIXME: kprobe hit while single-stepping!\n");
goto no_kprobe;
}
printk("FIXME: kprobe hit while handling another kprobe\n");
goto no_kprobe;
} else {
p = kprobe_running();
if (p->break_handler && p->break_handler(p, regs))
goto ss_probe;
}
/* If it's not ours, can't be delete race, (we hold lock). */
goto no_kprobe;
}
p = get_kprobe(addr);
if (!p)
goto no_kprobe;
kprobe_status = KPROBE_HIT_ACTIVE;
set_current_kprobe(p);
if (p->pre_handler && p->pre_handler(p, regs))
/* handler has already set things up, so skip ss setup */
return 1;
ss_probe:
prepare_singlestep(p, regs);
kprobe_status = KPROBE_HIT_SS;
return 1;
no_kprobe:
return ret;
}
static int __kprobes post_kprobe_handler(struct pt_regs *regs)
{
struct kprobe *cur = kprobe_running();
pr_debug("post_kprobe_handler, cur=%p\n", cur);
if (!cur)
return 0;
if (cur->post_handler) {
kprobe_status = KPROBE_HIT_SSDONE;
cur->post_handler(cur, regs, 0);
}
resume_execution(cur, regs);
reset_current_kprobe();
preempt_enable_no_resched();
return 1;
}
static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
pr_debug("kprobe_fault_handler: trapnr=%d\n", trapnr);
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
return 1;
if (kprobe_status & KPROBE_HIT_SS) {
resume_execution(cur, regs);
preempt_enable_no_resched();
}
return 0;
}
/*
* Wrapper routine to for handling exceptions.
*/
int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
int ret = NOTIFY_DONE;
pr_debug("kprobe_exceptions_notify: val=%lu, data=%p\n",
val, data);
switch (val) {
case DIE_BREAKPOINT:
if (kprobe_handler(args->regs))
ret = NOTIFY_STOP;
break;
case DIE_SSTEP:
if (post_kprobe_handler(args->regs))
ret = NOTIFY_STOP;
break;
case DIE_FAULT:
if (kprobe_running()
&& kprobe_fault_handler(args->regs, args->trapnr))
ret = NOTIFY_STOP;
break;
default:
break;
}
return ret;
}
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
/*
* TODO: We should probably save some of the stack here as
* well, since gcc may pass arguments on the stack for certain
* functions (lots of arguments, large aggregates, varargs)
*/
/* setup return addr to the jprobe handler routine */
regs->pc = (unsigned long)jp->entry;
return 1;
}
void __kprobes jprobe_return(void)
{
asm volatile("breakpoint" ::: "memory");
}
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
/*
* FIXME - we should ideally be validating that we got here 'cos
* of the "trap" in jprobe_return() above, before restoring the
* saved regs...
*/
memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
return 1;
}
int __init arch_init_kprobes(void)
{
printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
__mtdr(DBGREG_DC, DC_MM | DC_DBE);
/* TODO: Register kretprobe trampoline */
return 0;
}

324
arch/avr32/kernel/module.c Normal file
View file

@ -0,0 +1,324 @@
/*
* AVR32-specific kernel module loader
*
* Copyright (C) 2005-2006 Atmel Corporation
*
* GOT initialization parts are based on the s390 version
* Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/moduleloader.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
void *module_alloc(unsigned long size)
{
if (size == 0)
return NULL;
return vmalloc(size);
}
void module_free(struct module *mod, void *module_region)
{
vfree(mod->arch.syminfo);
mod->arch.syminfo = NULL;
vfree(module_region);
/* FIXME: if module_region == mod->init_region, trim exception
* table entries. */
}
static inline int check_rela(Elf32_Rela *rela, struct module *module,
char *strings, Elf32_Sym *symbols)
{
struct mod_arch_syminfo *info;
info = module->arch.syminfo + ELF32_R_SYM(rela->r_info);
switch (ELF32_R_TYPE(rela->r_info)) {
case R_AVR32_GOT32:
case R_AVR32_GOT16:
case R_AVR32_GOT8:
case R_AVR32_GOT21S:
case R_AVR32_GOT18SW: /* mcall */
case R_AVR32_GOT16S: /* ld.w */
if (rela->r_addend != 0) {
printk(KERN_ERR
"GOT relocation against %s at offset %u with addend\n",
strings + symbols[ELF32_R_SYM(rela->r_info)].st_name,
rela->r_offset);
return -ENOEXEC;
}
if (info->got_offset == -1UL) {
info->got_offset = module->arch.got_size;
module->arch.got_size += sizeof(void *);
}
pr_debug("GOT[%3lu] %s\n", info->got_offset,
strings + symbols[ELF32_R_SYM(rela->r_info)].st_name);
break;
}
return 0;
}
int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
char *secstrings, struct module *module)
{
Elf32_Shdr *symtab;
Elf32_Sym *symbols;
Elf32_Rela *rela;
char *strings;
int nrela, i, j;
int ret;
/* Find the symbol table */
symtab = NULL;
for (i = 0; i < hdr->e_shnum; i++)
switch (sechdrs[i].sh_type) {
case SHT_SYMTAB:
symtab = &sechdrs[i];
break;
}
if (!symtab) {
printk(KERN_ERR "module %s: no symbol table\n", module->name);
return -ENOEXEC;
}
/* Allocate room for one syminfo structure per symbol. */
module->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym);
module->arch.syminfo = vmalloc(module->arch.nsyms
* sizeof(struct mod_arch_syminfo));
if (!module->arch.syminfo)
return -ENOMEM;
symbols = (void *)hdr + symtab->sh_offset;
strings = (void *)hdr + sechdrs[symtab->sh_link].sh_offset;
for (i = 0; i < module->arch.nsyms; i++) {
if (symbols[i].st_shndx == SHN_UNDEF &&
strcmp(strings + symbols[i].st_name,
"_GLOBAL_OFFSET_TABLE_") == 0)
/* "Define" it as absolute. */
symbols[i].st_shndx = SHN_ABS;
module->arch.syminfo[i].got_offset = -1UL;
module->arch.syminfo[i].got_initialized = 0;
}
/* Allocate GOT entries for symbols that need it. */
module->arch.got_size = 0;
for (i = 0; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_type != SHT_RELA)
continue;
nrela = sechdrs[i].sh_size / sizeof(Elf32_Rela);
rela = (void *)hdr + sechdrs[i].sh_offset;
for (j = 0; j < nrela; j++) {
ret = check_rela(rela + j, module,
strings, symbols);
if (ret)
goto out_free_syminfo;
}
}
/*
* Increase core size to make room for GOT and set start
* offset for GOT.
*/
module->core_size = ALIGN(module->core_size, 4);
module->arch.got_offset = module->core_size;
module->core_size += module->arch.got_size;
return 0;
out_free_syminfo:
vfree(module->arch.syminfo);
module->arch.syminfo = NULL;
return ret;
}
static inline int reloc_overflow(struct module *module, const char *reloc_name,
Elf32_Addr relocation)
{
printk(KERN_ERR "module %s: Value %lx does not fit relocation %s\n",
module->name, (unsigned long)relocation, reloc_name);
return -ENOEXEC;
}
#define get_u16(loc) (*((uint16_t *)loc))
#define put_u16(loc, val) (*((uint16_t *)loc) = (val))
int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relindex,
struct module *module)
{
Elf32_Shdr *symsec = sechdrs + symindex;
Elf32_Shdr *relsec = sechdrs + relindex;
Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
Elf32_Rela *rel = (void *)relsec->sh_addr;
unsigned int i;
int ret = 0;
for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) {
struct mod_arch_syminfo *info;
Elf32_Sym *sym;
Elf32_Addr relocation;
uint32_t *location;
uint32_t value;
location = (void *)dstsec->sh_addr + rel->r_offset;
sym = (Elf32_Sym *)symsec->sh_addr + ELF32_R_SYM(rel->r_info);
relocation = sym->st_value + rel->r_addend;
info = module->arch.syminfo + ELF32_R_SYM(rel->r_info);
/* Initialize GOT entry if necessary */
switch (ELF32_R_TYPE(rel->r_info)) {
case R_AVR32_GOT32:
case R_AVR32_GOT16:
case R_AVR32_GOT8:
case R_AVR32_GOT21S:
case R_AVR32_GOT18SW:
case R_AVR32_GOT16S:
if (!info->got_initialized) {
Elf32_Addr *gotent;
gotent = (module->module_core
+ module->arch.got_offset
+ info->got_offset);
*gotent = relocation;
info->got_initialized = 1;
}
relocation = info->got_offset;
break;
}
switch (ELF32_R_TYPE(rel->r_info)) {
case R_AVR32_32:
case R_AVR32_32_CPENT:
*location = relocation;
break;
case R_AVR32_22H_PCREL:
relocation -= (Elf32_Addr)location;
if ((relocation & 0xffe00001) != 0
&& (relocation & 0xffc00001) != 0xffc00000)
return reloc_overflow(module,
"R_AVR32_22H_PCREL",
relocation);
relocation >>= 1;
value = *location;
value = ((value & 0xe1ef0000)
| (relocation & 0xffff)
| ((relocation & 0x10000) << 4)
| ((relocation & 0x1e0000) << 8));
*location = value;
break;
case R_AVR32_11H_PCREL:
relocation -= (Elf32_Addr)location;
if ((relocation & 0xfffffc01) != 0
&& (relocation & 0xfffff801) != 0xfffff800)
return reloc_overflow(module,
"R_AVR32_11H_PCREL",
relocation);
value = get_u16(location);
value = ((value & 0xf00c)
| ((relocation & 0x1fe) << 3)
| ((relocation & 0x600) >> 9));
put_u16(location, value);
break;
case R_AVR32_9H_PCREL:
relocation -= (Elf32_Addr)location;
if ((relocation & 0xffffff01) != 0
&& (relocation & 0xfffffe01) != 0xfffffe00)
return reloc_overflow(module,
"R_AVR32_9H_PCREL",
relocation);
value = get_u16(location);
value = ((value & 0xf00f)
| ((relocation & 0x1fe) << 3));
put_u16(location, value);
break;
case R_AVR32_9UW_PCREL:
relocation -= ((Elf32_Addr)location) & 0xfffffffc;
if ((relocation & 0xfffffc03) != 0)
return reloc_overflow(module,
"R_AVR32_9UW_PCREL",
relocation);
value = get_u16(location);
value = ((value & 0xf80f)
| ((relocation & 0x1fc) << 2));
put_u16(location, value);
break;
case R_AVR32_GOTPC:
/*
* R6 = PC - (PC - GOT)
*
* At this point, relocation contains the
* value of PC. Just subtract the value of
* GOT, and we're done.
*/
pr_debug("GOTPC: PC=0x%lx, got_offset=0x%lx, core=0x%p\n",
relocation, module->arch.got_offset,
module->module_core);
relocation -= ((unsigned long)module->module_core
+ module->arch.got_offset);
*location = relocation;
break;
case R_AVR32_GOT18SW:
if ((relocation & 0xfffe0003) != 0
&& (relocation & 0xfffc0003) != 0xffff0000)
return reloc_overflow(module, "R_AVR32_GOT18SW",
relocation);
relocation >>= 2;
/* fall through */
case R_AVR32_GOT16S:
if ((relocation & 0xffff8000) != 0
&& (relocation & 0xffff0000) != 0xffff0000)
return reloc_overflow(module, "R_AVR32_GOT16S",
relocation);
pr_debug("GOT reloc @ 0x%lx -> %lu\n",
rel->r_offset, relocation);
value = *location;
value = ((value & 0xffff0000)
| (relocation & 0xffff));
*location = value;
break;
default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
module->name, ELF32_R_TYPE(rel->r_info));
return -ENOEXEC;
}
}
return ret;
}
int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relindex,
struct module *module)
{
printk(KERN_ERR "module %s: REL relocations are not supported\n",
module->name);
return -ENOEXEC;
}
int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
struct module *module)
{
vfree(module->arch.syminfo);
module->arch.syminfo = NULL;
return 0;
}
void module_arch_cleanup(struct module *module)
{
}

276
arch/avr32/kernel/process.c Normal file
View file

@ -0,0 +1,276 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/fs.h>
#include <linux/ptrace.h>
#include <linux/reboot.h>
#include <linux/unistd.h>
#include <asm/sysreg.h>
#include <asm/ocd.h>
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
/*
* This file handles the architecture-dependent parts of process handling..
*/
void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
/* TODO: Enter sleep mode */
while (!need_resched())
cpu_relax();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}
void machine_halt(void)
{
}
void machine_power_off(void)
{
}
void machine_restart(char *cmd)
{
__mtdr(DBGREG_DC, DC_DBE);
__mtdr(DBGREG_DC, DC_RES);
while (1) ;
}
/*
* PC is actually discarded when returning from a system call -- the
* return address must be stored in LR. This function will make sure
* LR points to do_exit before starting the thread.
*
* Also, when returning from fork(), r12 is 0, so we must copy the
* argument as well.
*
* r0 : The argument to the main thread function
* r1 : The address of do_exit
* r2 : The address of the main thread function
*/
asmlinkage extern void kernel_thread_helper(void);
__asm__(" .type kernel_thread_helper, @function\n"
"kernel_thread_helper:\n"
" mov r12, r0\n"
" mov lr, r2\n"
" mov pc, r1\n"
" .size kernel_thread_helper, . - kernel_thread_helper");
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.r0 = (unsigned long)arg;
regs.r1 = (unsigned long)fn;
regs.r2 = (unsigned long)do_exit;
regs.lr = (unsigned long)kernel_thread_helper;
regs.pc = (unsigned long)kernel_thread_helper;
regs.sr = MODE_SUPERVISOR;
return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
0, &regs, 0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc
*/
void exit_thread(void)
{
/* nothing to do */
}
void flush_thread(void)
{
/* nothing to do */
}
void release_thread(struct task_struct *dead_task)
{
/* do nothing */
}
static const char *cpu_modes[] = {
"Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
"Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
};
void show_regs(struct pt_regs *regs)
{
unsigned long sp = regs->sp;
unsigned long lr = regs->lr;
unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
if (!user_mode(regs))
sp = (unsigned long)regs + FRAME_SIZE_FULL;
print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("LR is at %s\n", lr);
printk("pc : [<%08lx>] lr : [<%08lx>] %s\n"
"sp : %08lx r12: %08lx r11: %08lx\n",
instruction_pointer(regs),
lr, print_tainted(), sp, regs->r12, regs->r11);
printk("r10: %08lx r9 : %08lx r8 : %08lx\n",
regs->r10, regs->r9, regs->r8);
printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
regs->r7, regs->r6, regs->r5, regs->r4);
printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
regs->r3, regs->r2, regs->r1, regs->r0);
printk("Flags: %c%c%c%c%c\n",
regs->sr & SR_Q ? 'Q' : 'q',
regs->sr & SR_V ? 'V' : 'v',
regs->sr & SR_N ? 'N' : 'n',
regs->sr & SR_Z ? 'Z' : 'z',
regs->sr & SR_C ? 'C' : 'c');
printk("Mode bits: %c%c%c%c%c%c%c%c%c\n",
regs->sr & SR_H ? 'H' : 'h',
regs->sr & SR_R ? 'R' : 'r',
regs->sr & SR_J ? 'J' : 'j',
regs->sr & SR_EM ? 'E' : 'e',
regs->sr & SR_I3M ? '3' : '.',
regs->sr & SR_I2M ? '2' : '.',
regs->sr & SR_I1M ? '1' : '.',
regs->sr & SR_I0M ? '0' : '.',
regs->sr & SR_GM ? 'G' : 'g');
printk("CPU Mode: %s\n", cpu_modes[mode]);
show_trace(NULL, (unsigned long *)sp, regs);
}
EXPORT_SYMBOL(show_regs);
/* Fill in the fpu structure for a core dump. This is easy -- we don't have any */
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
{
/* Not valid */
return 0;
}
asmlinkage void ret_from_fork(void);
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
unsigned long unused,
struct task_struct *p, struct pt_regs *regs)
{
struct pt_regs *childregs;
childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)p->thread_info)) - 1;
*childregs = *regs;
if (user_mode(regs))
childregs->sp = usp;
else
childregs->sp = (unsigned long)p->thread_info + THREAD_SIZE;
childregs->r12 = 0; /* Set return value for child */
p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
p->thread.cpu_context.ksp = (unsigned long)childregs;
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
return 0;
}
/* r12-r8 are dummy parameters to force the compiler to use the stack */
asmlinkage int sys_fork(struct pt_regs *regs)
{
return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
unsigned long parent_tidptr,
unsigned long child_tidptr, struct pt_regs *regs)
{
if (!newsp)
newsp = regs->sp;
return do_fork(clone_flags, newsp, regs, 0,
(int __user *)parent_tidptr,
(int __user *)child_tidptr);
}
asmlinkage int sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs,
0, NULL, NULL);
}
asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv,
char __user *__user *uenvp, struct pt_regs *regs)
{
int error;
char *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, uargv, uenvp, regs);
if (error == 0)
current->ptrace &= ~PT_DTRACE;
putname(filename);
out:
return error;
}
/*
* This function is supposed to answer the question "who called
* schedule()?"
*/
unsigned long get_wchan(struct task_struct *p)
{
unsigned long pc;
unsigned long stack_page;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack_page = (unsigned long)p->thread_info;
BUG_ON(!stack_page);
/*
* The stored value of PC is either the address right after
* the call to __switch_to() or ret_from_fork.
*/
pc = thread_saved_pc(p);
if (in_sched_functions(pc)) {
#ifdef CONFIG_FRAME_POINTER
unsigned long fp = p->thread.cpu_context.r7;
BUG_ON(fp < stack_page || fp > (THREAD_SIZE + stack_page));
pc = *(unsigned long *)fp;
#else
/*
* We depend on the frame size of schedule here, which
* is actually quite ugly. It might be possible to
* determine the frame size automatically at build
* time by doing this:
* - compile sched.c
* - disassemble the resulting sched.o
* - look for 'sub sp,??' shortly after '<schedule>:'
*/
unsigned long sp = p->thread.cpu_context.ksp + 16;
BUG_ON(sp < stack_page || sp > (THREAD_SIZE + stack_page));
pc = *(unsigned long *)sp;
#endif
}
return pc;
}

371
arch/avr32/kernel/ptrace.c Normal file
View file

@ -0,0 +1,371 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/user.h>
#include <linux/security.h>
#include <linux/unistd.h>
#include <linux/notifier.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
#include <asm/ocd.h>
#include <asm/mmu_context.h>
#include <asm/kdebug.h>
static struct pt_regs *get_user_regs(struct task_struct *tsk)
{
return (struct pt_regs *)((unsigned long) tsk->thread_info +
THREAD_SIZE - sizeof(struct pt_regs));
}
static void ptrace_single_step(struct task_struct *tsk)
{
pr_debug("ptrace_single_step: pid=%u, SR=0x%08lx\n",
tsk->pid, tsk->thread.cpu_context.sr);
if (!(tsk->thread.cpu_context.sr & SR_D)) {
/*
* Set a breakpoint at the current pc to force the
* process into debug mode. The syscall/exception
* exit code will set a breakpoint at the return
* address when this flag is set.
*/
pr_debug("ptrace_single_step: Setting TIF_BREAKPOINT\n");
set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
}
/* The monitor code will do the actual step for us */
set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
}
/*
* Called by kernel/ptrace.c when detaching
*
* Make sure any single step bits, etc. are not set
*/
void ptrace_disable(struct task_struct *child)
{
clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
}
/*
* Handle hitting a breakpoint
*/
static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
{
siginfo_t info;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
info.si_addr = (void __user *)instruction_pointer(regs);
pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n",
tsk->pid, info.si_addr);
force_sig_info(SIGTRAP, &info, tsk);
}
/*
* Read the word at offset "offset" into the task's "struct user". We
* actually access the pt_regs struct stored on the kernel stack.
*/
static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
unsigned long __user *data)
{
unsigned long *regs;
unsigned long value;
pr_debug("ptrace_read_user(%p, %#lx, %p)\n",
tsk, offset, data);
if (offset & 3 || offset >= sizeof(struct user)) {
printk("ptrace_read_user: invalid offset 0x%08lx\n", offset);
return -EIO;
}
regs = (unsigned long *)get_user_regs(tsk);
value = 0;
if (offset < sizeof(struct pt_regs))
value = regs[offset / sizeof(regs[0])];
return put_user(value, data);
}
/*
* Write the word "value" to offset "offset" into the task's "struct
* user". We actually access the pt_regs struct stored on the kernel
* stack.
*/
static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
unsigned long value)
{
unsigned long *regs;
if (offset & 3 || offset >= sizeof(struct user)) {
printk("ptrace_write_user: invalid offset 0x%08lx\n", offset);
return -EIO;
}
if (offset >= sizeof(struct pt_regs))
return 0;
regs = (unsigned long *)get_user_regs(tsk);
regs[offset / sizeof(regs[0])] = value;
return 0;
}
static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
{
struct pt_regs *regs = get_user_regs(tsk);
return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0;
}
static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
{
struct pt_regs newregs;
int ret;
ret = -EFAULT;
if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) {
struct pt_regs *regs = get_user_regs(tsk);
ret = -EINVAL;
if (valid_user_regs(&newregs)) {
*regs = newregs;
ret = 0;
}
}
return ret;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
unsigned long tmp;
int ret;
pr_debug("arch_ptrace(%ld, %ld, %#lx, %#lx)\n",
request, child->pid, addr, data);
pr_debug("ptrace: Enabling monitor mode...\n");
__mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE);
switch (request) {
/* Read the word at location addr in the child process */
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
if (ret == sizeof(tmp))
ret = put_user(tmp, (unsigned long __user *)data);
else
ret = -EIO;
break;
case PTRACE_PEEKUSR:
ret = ptrace_read_user(child, addr,
(unsigned long __user *)data);
break;
/* Write the word in data at location addr */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
ret = access_process_vm(child, addr, &data, sizeof(data), 1);
if (ret == sizeof(data))
ret = 0;
else
ret = -EIO;
break;
case PTRACE_POKEUSR:
ret = ptrace_write_user(child, addr, data);
break;
/* continue and stop at next (return from) syscall */
case PTRACE_SYSCALL:
/* restart after signal */
case PTRACE_CONT:
ret = -EIO;
if (!valid_signal(data))
break;
if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
/* XXX: Are we sure no breakpoints are active here? */
wake_up_process(child);
ret = 0;
break;
/*
* Make the child exit. Best I can do is send it a
* SIGKILL. Perhaps it should be put in the status that it
* wants to exit.
*/
case PTRACE_KILL:
ret = 0;
if (child->exit_state == EXIT_ZOMBIE)
break;
child->exit_code = SIGKILL;
wake_up_process(child);
break;
/*
* execute single instruction.
*/
case PTRACE_SINGLESTEP:
ret = -EIO;
if (!valid_signal(data))
break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
ptrace_single_step(child);
child->exit_code = data;
wake_up_process(child);
ret = 0;
break;
/* Detach a process that was attached */
case PTRACE_DETACH:
ret = ptrace_detach(child, data);
break;
case PTRACE_GETREGS:
ret = ptrace_getregs(child, (void __user *)data);
break;
case PTRACE_SETREGS:
ret = ptrace_setregs(child, (const void __user *)data);
break;
default:
ret = ptrace_request(child, request, addr, data);
break;
}
pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
return ret;
}
asmlinkage void syscall_trace(void)
{
pr_debug("syscall_trace called\n");
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
if (!(current->ptrace & PT_PTRACED))
return;
pr_debug("syscall_trace: notifying parent\n");
/* The 0x80 provides a way for the tracing parent to
* distinguish between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
/*
* this isn't the same as continuing with a signal, but it
* will do for normal use. strace only continues with a
* signal if the stopping signal is not SIGTRAP. -brl
*/
if (current->exit_code) {
pr_debug("syscall_trace: sending signal %d to PID %u\n",
current->exit_code, current->pid);
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
}
asmlinkage void do_debug_priv(struct pt_regs *regs)
{
unsigned long dc, ds;
unsigned long die_val;
ds = __mfdr(DBGREG_DS);
pr_debug("do_debug_priv: pc = %08lx, ds = %08lx\n", regs->pc, ds);
if (ds & DS_SSS)
die_val = DIE_SSTEP;
else
die_val = DIE_BREAKPOINT;
if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP)
return;
if (likely(ds & DS_SSS)) {
extern void itlb_miss(void);
extern void tlb_miss_common(void);
struct thread_info *ti;
dc = __mfdr(DBGREG_DC);
dc &= ~DC_SS;
__mtdr(DBGREG_DC, dc);
ti = current_thread_info();
ti->flags |= _TIF_BREAKPOINT;
/* The TLB miss handlers don't check thread flags */
if ((regs->pc >= (unsigned long)&itlb_miss)
&& (regs->pc <= (unsigned long)&tlb_miss_common)) {
__mtdr(DBGREG_BWA2A, sysreg_read(RAR_EX));
__mtdr(DBGREG_BWC2A, 0x40000001 | (get_asid() << 1));
}
/*
* If we're running in supervisor mode, the breakpoint
* will take us where we want directly, no need to
* single step.
*/
if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR)
ti->flags |= TIF_SINGLE_STEP;
} else {
panic("Unable to handle debug trap at pc = %08lx\n",
regs->pc);
}
}
/*
* Handle breakpoints, single steps and other debuggy things. To keep
* things simple initially, we run with interrupts and exceptions
* disabled all the time.
*/
asmlinkage void do_debug(struct pt_regs *regs)
{
unsigned long dc, ds;
ds = __mfdr(DBGREG_DS);
pr_debug("do_debug: pc = %08lx, ds = %08lx\n", regs->pc, ds);
if (test_thread_flag(TIF_BREAKPOINT)) {
pr_debug("TIF_BREAKPOINT set\n");
/* We're taking care of it */
clear_thread_flag(TIF_BREAKPOINT);
__mtdr(DBGREG_BWC2A, 0);
}
if (test_thread_flag(TIF_SINGLE_STEP)) {
pr_debug("TIF_SINGLE_STEP set, ds = 0x%08lx\n", ds);
if (ds & DS_SSS) {
dc = __mfdr(DBGREG_DC);
dc &= ~DC_SS;
__mtdr(DBGREG_DC, dc);
clear_thread_flag(TIF_SINGLE_STEP);
ptrace_break(current, regs);
}
} else {
/* regular breakpoint */
ptrace_break(current, regs);
}
}

View file

@ -0,0 +1,148 @@
/*
* AVR32 sempahore implementation.
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* Based on linux/arch/i386/kernel/semaphore.c
* Copyright (C) 1999 Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <asm/semaphore.h>
#include <asm/atomic.h>
/*
* Semaphores are implemented using a two-way counter:
* The "count" variable is decremented for each process
* that tries to acquire the semaphore, while the "sleeping"
* variable is a count of such acquires.
*
* Notably, the inline "up()" and "down()" functions can
* efficiently test if they need to do any extra work (up
* needs to do something only if count was negative before
* the increment operation.
*
* "sleeping" and the contention routine ordering is protected
* by the spinlock in the semaphore's waitqueue head.
*
* Note that these functions are only called when there is
* contention on the lock, and as such all this is the
* "non-critical" part of the whole semaphore business. The
* critical part is the inline stuff in <asm/semaphore.h>
* where we want to avoid any extra jumps and calls.
*/
/*
* Logic:
* - only on a boundary condition do we need to care. When we go
* from a negative count to a non-negative, we wake people up.
* - when we go from a non-negative count to a negative do we
* (a) synchronize with the "sleeper" count and (b) make sure
* that we're on the wakeup list before we synchronize so that
* we cannot lose wakeup events.
*/
void __up(struct semaphore *sem)
{
wake_up(&sem->wait);
}
EXPORT_SYMBOL(__up);
void __sched __down(struct semaphore *sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
unsigned long flags;
tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irqsave(&sem->wait.lock, flags);
add_wait_queue_exclusive_locked(&sem->wait, &wait);
sem->sleepers++;
for (;;) {
int sleepers = sem->sleepers;
/*
* Add "everybody else" into it. They aren't
* playing, because we own the spinlock in
* the wait_queue_head.
*/
if (atomic_add_return(sleepers - 1, &sem->count) >= 0) {
sem->sleepers = 0;
break;
}
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irqrestore(&sem->wait.lock, flags);
schedule();
spin_lock_irqsave(&sem->wait.lock, flags);
tsk->state = TASK_UNINTERRUPTIBLE;
}
remove_wait_queue_locked(&sem->wait, &wait);
wake_up_locked(&sem->wait);
spin_unlock_irqrestore(&sem->wait.lock, flags);
tsk->state = TASK_RUNNING;
}
EXPORT_SYMBOL(__down);
int __sched __down_interruptible(struct semaphore *sem)
{
int retval = 0;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
unsigned long flags;
tsk->state = TASK_INTERRUPTIBLE;
spin_lock_irqsave(&sem->wait.lock, flags);
add_wait_queue_exclusive_locked(&sem->wait, &wait);
sem->sleepers++;
for (;;) {
int sleepers = sem->sleepers;
/*
* With signals pending, this turns into the trylock
* failure case - we won't be sleeping, and we can't
* get the lock as it has contention. Just correct the
* count and exit.
*/
if (signal_pending(current)) {
retval = -EINTR;
sem->sleepers = 0;
atomic_add(sleepers, &sem->count);
break;
}
/*
* Add "everybody else" into it. They aren't
* playing, because we own the spinlock in
* the wait_queue_head.
*/
if (atomic_add_return(sleepers - 1, &sem->count) >= 0) {
sem->sleepers = 0;
break;
}
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irqrestore(&sem->wait.lock, flags);
schedule();
spin_lock_irqsave(&sem->wait.lock, flags);
tsk->state = TASK_INTERRUPTIBLE;
}
remove_wait_queue_locked(&sem->wait, &wait);
wake_up_locked(&sem->wait);
spin_unlock_irqrestore(&sem->wait.lock, flags);
tsk->state = TASK_RUNNING;
return retval;
}
EXPORT_SYMBOL(__down_interruptible);

335
arch/avr32/kernel/setup.c Normal file
View file

@ -0,0 +1,335 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/console.h>
#include <linux/ioport.h>
#include <linux/bootmem.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/root_dev.h>
#include <linux/cpu.h>
#include <asm/sections.h>
#include <asm/processor.h>
#include <asm/pgtable.h>
#include <asm/setup.h>
#include <asm/sysreg.h>
#include <asm/arch/board.h>
#include <asm/arch/init.h>
extern int root_mountflags;
/*
* Bootloader-provided information about physical memory
*/
struct tag_mem_range *mem_phys;
struct tag_mem_range *mem_reserved;
struct tag_mem_range *mem_ramdisk;
/*
* Initialize loops_per_jiffy as 5000000 (500MIPS).
* Better make it too large than too small...
*/
struct avr32_cpuinfo boot_cpu_data = {
.loops_per_jiffy = 5000000
};
EXPORT_SYMBOL(boot_cpu_data);
static char command_line[COMMAND_LINE_SIZE];
/*
* Should be more than enough, but if you have a _really_ complex
* setup, you might need to increase the size of this...
*/
static struct tag_mem_range __initdata mem_range_cache[32];
static unsigned mem_range_next_free;
/*
* Standard memory resources
*/
static struct resource mem_res[] = {
{
.name = "Kernel code",
.start = 0,
.end = 0,
.flags = IORESOURCE_MEM
},
{
.name = "Kernel data",
.start = 0,
.end = 0,
.flags = IORESOURCE_MEM,
},
};
#define kernel_code mem_res[0]
#define kernel_data mem_res[1]
/*
* Early framebuffer allocation. Works as follows:
* - If fbmem_size is zero, nothing will be allocated or reserved.
* - If fbmem_start is zero when setup_bootmem() is called,
* fbmem_size bytes will be allocated from the bootmem allocator.
* - If fbmem_start is nonzero, an area of size fbmem_size will be
* reserved at the physical address fbmem_start if necessary. If
* the area isn't in a memory region known to the kernel, it will
* be left alone.
*
* Board-specific code may use these variables to set up platform data
* for the framebuffer driver if fbmem_size is nonzero.
*/
static unsigned long __initdata fbmem_start;
static unsigned long __initdata fbmem_size;
/*
* "fbmem=xxx[kKmM]" allocates the specified amount of boot memory for
* use as framebuffer.
*
* "fbmem=xxx[kKmM]@yyy[kKmM]" defines a memory region of size xxx and
* starting at yyy to be reserved for use as framebuffer.
*
* The kernel won't verify that the memory region starting at yyy
* actually contains usable RAM.
*/
static int __init early_parse_fbmem(char *p)
{
fbmem_size = memparse(p, &p);
if (*p == '@')
fbmem_start = memparse(p, &p);
return 0;
}
early_param("fbmem", early_parse_fbmem);
static inline void __init resource_init(void)
{
struct tag_mem_range *region;
kernel_code.start = __pa(init_mm.start_code);
kernel_code.end = __pa(init_mm.end_code - 1);
kernel_data.start = __pa(init_mm.end_code);
kernel_data.end = __pa(init_mm.brk - 1);
for (region = mem_phys; region; region = region->next) {
struct resource *res;
unsigned long phys_start, phys_end;
if (region->size == 0)
continue;
phys_start = region->addr;
phys_end = phys_start + region->size - 1;
res = alloc_bootmem_low(sizeof(*res));
res->name = "System RAM";
res->start = phys_start;
res->end = phys_end;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
request_resource (&iomem_resource, res);
if (kernel_code.start >= res->start &&
kernel_code.end <= res->end)
request_resource (res, &kernel_code);
if (kernel_data.start >= res->start &&
kernel_data.end <= res->end)
request_resource (res, &kernel_data);
}
}
static int __init parse_tag_core(struct tag *tag)
{
if (tag->hdr.size > 2) {
if ((tag->u.core.flags & 1) == 0)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = new_decode_dev(tag->u.core.rootdev);
}
return 0;
}
__tagtable(ATAG_CORE, parse_tag_core);
static int __init parse_tag_mem_range(struct tag *tag,
struct tag_mem_range **root)
{
struct tag_mem_range *cur, **pprev;
struct tag_mem_range *new;
/*
* Ignore zero-sized entries. If we're running standalone, the
* SDRAM code may emit such entries if something goes
* wrong...
*/
if (tag->u.mem_range.size == 0)
return 0;
/*
* Copy the data so the bootmem init code doesn't need to care
* about it.
*/
if (mem_range_next_free >=
(sizeof(mem_range_cache) / sizeof(mem_range_cache[0])))
panic("Physical memory map too complex!\n");
new = &mem_range_cache[mem_range_next_free++];
*new = tag->u.mem_range;
pprev = root;
cur = *root;
while (cur) {
pprev = &cur->next;
cur = cur->next;
}
*pprev = new;
new->next = NULL;
return 0;
}
static int __init parse_tag_mem(struct tag *tag)
{
return parse_tag_mem_range(tag, &mem_phys);
}
__tagtable(ATAG_MEM, parse_tag_mem);
static int __init parse_tag_cmdline(struct tag *tag)
{
strlcpy(saved_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
return 0;
}
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
static int __init parse_tag_rdimg(struct tag *tag)
{
return parse_tag_mem_range(tag, &mem_ramdisk);
}
__tagtable(ATAG_RDIMG, parse_tag_rdimg);
static int __init parse_tag_clock(struct tag *tag)
{
/*
* We'll figure out the clocks by peeking at the system
* manager regs directly.
*/
return 0;
}
__tagtable(ATAG_CLOCK, parse_tag_clock);
static int __init parse_tag_rsvd_mem(struct tag *tag)
{
return parse_tag_mem_range(tag, &mem_reserved);
}
__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
static int __init parse_tag_ethernet(struct tag *tag)
{
#if 0
const struct platform_device *pdev;
/*
* We really need a bus type that supports "classes"...this
* will do for now (until we must handle other kinds of
* ethernet controllers)
*/
pdev = platform_get_device("macb", tag->u.ethernet.mac_index);
if (pdev && pdev->dev.platform_data) {
struct eth_platform_data *data = pdev->dev.platform_data;
data->valid = 1;
data->mii_phy_addr = tag->u.ethernet.mii_phy_addr;
memcpy(data->hw_addr, tag->u.ethernet.hw_address,
sizeof(data->hw_addr));
}
#endif
return 0;
}
__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
/*
* Scan the tag table for this tag, and call its parse function. The
* tag table is built by the linker from all the __tagtable
* declarations.
*/
static int __init parse_tag(struct tag *tag)
{
extern struct tagtable __tagtable_begin, __tagtable_end;
struct tagtable *t;
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag) {
t->parse(tag);
break;
}
return t < &__tagtable_end;
}
/*
* Parse all tags in the list we got from the boot loader
*/
static void __init parse_tags(struct tag *t)
{
for (; t->hdr.tag != ATAG_NONE; t = tag_next(t))
if (!parse_tag(t))
printk(KERN_WARNING
"Ignoring unrecognised tag 0x%08x\n",
t->hdr.tag);
}
void __init setup_arch (char **cmdline_p)
{
struct clk *cpu_clk;
parse_tags(bootloader_tags);
setup_processor();
setup_platform();
cpu_clk = clk_get(NULL, "cpu");
if (IS_ERR(cpu_clk)) {
printk(KERN_WARNING "Warning: Unable to get CPU clock\n");
} else {
unsigned long cpu_hz = clk_get_rate(cpu_clk);
/*
* Well, duh, but it's probably a good idea to
* increment the use count.
*/
clk_enable(cpu_clk);
boot_cpu_data.clk = cpu_clk;
boot_cpu_data.loops_per_jiffy = cpu_hz * 4;
printk("CPU: Running at %lu.%03lu MHz\n",
((cpu_hz + 500) / 1000) / 1000,
((cpu_hz + 500) / 1000) % 1000);
}
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
parse_early_param();
setup_bootmem();
board_setup_fbmem(fbmem_start, fbmem_size);
#ifdef CONFIG_VT
conswitchp = &dummy_con;
#endif
paging_init();
resource_init();
}

328
arch/avr32/kernel/signal.c Normal file
View file

@ -0,0 +1,328 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* Based on linux/arch/sh/kernel/signal.c
* Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
* Copyright (C) 1991, 1992 Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/suspend.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct pt_regs *regs)
{
return do_sigaltstack(uss, uoss, regs->sp);
}
struct rt_sigframe
{
struct siginfo info;
struct ucontext uc;
unsigned long retcode;
};
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
{
int err = 0;
#define COPY(x) err |= __get_user(regs->x, &sc->x)
COPY(sr);
COPY(pc);
COPY(lr);
COPY(sp);
COPY(r12);
COPY(r11);
COPY(r10);
COPY(r9);
COPY(r8);
COPY(r7);
COPY(r6);
COPY(r5);
COPY(r4);
COPY(r3);
COPY(r2);
COPY(r1);
COPY(r0);
#undef COPY
/*
* Don't allow anyone to pretend they're running in supervisor
* mode or something...
*/
err |= !valid_user_regs(regs);
return err;
}
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
sigset_t set;
frame = (struct rt_sigframe __user *)regs->sp;
pr_debug("SIG return: frame = %p\n", frame);
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
regs->pc, regs->lr, regs->sp);
return regs->r12;
badframe:
force_sig(SIGSEGV, current);
return 0;
}
static int
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
{
int err = 0;
#define COPY(x) err |= __put_user(regs->x, &sc->x)
COPY(sr);
COPY(pc);
COPY(lr);
COPY(sp);
COPY(r12);
COPY(r11);
COPY(r10);
COPY(r9);
COPY(r8);
COPY(r7);
COPY(r6);
COPY(r5);
COPY(r4);
COPY(r3);
COPY(r2);
COPY(r1);
COPY(r0);
#undef COPY
return err;
}
static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
{
unsigned long sp = regs->sp;
if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
return (void __user *)((sp - framesize) & ~3);
}
static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
err = -EFAULT;
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto out;
/*
* Set up the return code:
*
* mov r8, __NR_rt_sigreturn
* scall
*
* Note: This will blow up since we're using a non-executable
* stack. Better use SA_RESTORER.
*/
#if __NR_rt_sigreturn > 127
# error __NR_rt_sigreturn must be < 127 to fit in a short mov
#endif
err = __put_user(0x3008d733 | (__NR_rt_sigreturn << 20),
&frame->retcode);
err |= copy_siginfo_to_user(&frame->info, info);
/* Set up the ucontext */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
err |= __put_user((void __user *)current->sas_ss_sp,
&frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size,
&frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto out;
regs->r12 = sig;
regs->r11 = (unsigned long) &frame->info;
regs->r10 = (unsigned long) &frame->uc;
regs->sp = (unsigned long) frame;
if (ka->sa.sa_flags & SA_RESTORER)
regs->lr = (unsigned long)ka->sa.sa_restorer;
else {
printk(KERN_NOTICE "[%s:%d] did not set SA_RESTORER\n",
current->comm, current->pid);
regs->lr = (unsigned long) &frame->retcode;
}
pr_debug("SIG deliver [%s:%d]: sig=%d sp=0x%lx pc=0x%lx->0x%p lr=0x%lx\n",
current->comm, current->pid, sig, regs->sp,
regs->pc, ka->sa.sa_handler, regs->lr);
regs->pc = (unsigned long) ka->sa.sa_handler;
out:
return err;
}
static inline void restart_syscall(struct pt_regs *regs)
{
if (regs->r12 == -ERESTART_RESTARTBLOCK)
regs->r8 = __NR_restart_syscall;
else
regs->r12 = regs->r12_orig;
regs->pc -= 2;
}
static inline void
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs, int syscall)
{
int ret;
/*
* Set up the stack frame
*/
ret = setup_rt_frame(sig, ka, info, oldset, regs);
/*
* Check that the resulting registers are sane
*/
ret |= !valid_user_regs(regs);
/*
* Block the signal if we were unsuccessful.
*/
if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked,
&ka->sa.sa_mask);
sigaddset(&current->blocked, sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
if (ret == 0)
return;
force_sigsegv(sig, current);
}
/*
* Note that 'init' is a special process: it doesn't get signals it
* doesn't want to handle. Thus you cannot kill init even with a
* SIGKILL even by mistake.
*/
int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
/*
* We want the common case to go fast, which is why we may in
* certain cases get here from kernel mode. Just return
* without doing anything if so.
*/
if (!user_mode(regs))
return 0;
if (try_to_freeze()) {
signr = 0;
if (!signal_pending(current))
goto no_signal;
}
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask;
else if (!oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
no_signal:
if (syscall) {
switch (regs->r12) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
if (signr > 0) {
regs->r12 = -EINTR;
break;
}
/* fall through */
case -ERESTARTSYS:
if (signr > 0 && !(ka.sa.sa_flags & SA_RESTART)) {
regs->r12 = -EINTR;
break;
}
/* fall through */
case -ERESTARTNOINTR:
restart_syscall(regs);
}
}
if (signr == 0) {
/* No signal to deliver -- put the saved sigmask back */
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
clear_thread_flag(TIF_RESTORE_SIGMASK);
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
return 0;
}
handle_signal(signr, &ka, &info, oldset, regs, syscall);
return 1;
}
asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
{
int syscall = 0;
if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR)
syscall = 1;
if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
do_signal(regs, &current->blocked, syscall);
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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 <asm/sysreg.h>
.text
.global __switch_to
.type __switch_to, @function
/* Switch thread context from "prev" to "next", returning "last"
* r12 : prev
* r11 : &prev->thread + 1
* r10 : &next->thread
*/
__switch_to:
stm --r11, r0,r1,r2,r3,r4,r5,r6,r7,sp,lr
mfsr r9, SYSREG_SR
st.w --r11, r9
ld.w r8, r10++
/*
* schedule() may have been called from a mode with a different
* set of registers. Make sure we don't lose anything here.
*/
pushm r10,r12
mtsr SYSREG_SR, r8
frs /* flush the return stack */
sub pc, -2 /* flush the pipeline */
popm r10,r12
ldm r10++, r0,r1,r2,r3,r4,r5,r6,r7,sp,pc
.size __switch_to, . - __switch_to

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/unistd.h>
#include <asm/mman.h>
#include <asm/uaccess.h>
asmlinkage int sys_pipe(unsigned long __user *filedes)
{
int fd[2];
int error;
error = do_pipe(fd);
if (!error) {
if (copy_to_user(filedes, fd, sizeof(fd)))
error = -EFAULT;
}
return error;
}
asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, off_t offset)
{
int error = -EBADF;
struct file *file = NULL;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
return error;
}
down_write(&current->mm->mmap_sem);
error = do_mmap_pgoff(file, addr, len, prot, flags, offset);
up_write(&current->mm->mmap_sem);
if (file)
fput(file);
return error;
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2005-2006 Atmel Corporation
*
* 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.
*/
/*
* Stubs for syscalls that require access to pt_regs or that take more
* than five parameters.
*/
#define ARG6 r3
.text
.global __sys_rt_sigsuspend
.type __sys_rt_sigsuspend,@function
__sys_rt_sigsuspend:
mov r10, sp
rjmp sys_rt_sigsuspend
.global __sys_sigaltstack
.type __sys_sigaltstack,@function
__sys_sigaltstack:
mov r10, sp
rjmp sys_sigaltstack
.global __sys_rt_sigreturn
.type __sys_rt_sigreturn,@function
__sys_rt_sigreturn:
mov r12, sp
rjmp sys_rt_sigreturn
.global __sys_fork
.type __sys_fork,@function
__sys_fork:
mov r12, sp
rjmp sys_fork
.global __sys_clone
.type __sys_clone,@function
__sys_clone:
mov r8, sp
rjmp sys_clone
.global __sys_vfork
.type __sys_vfork,@function
__sys_vfork:
mov r12, sp
rjmp sys_vfork
.global __sys_execve
.type __sys_execve,@function
__sys_execve:
mov r9, sp
rjmp sys_execve
.global __sys_mmap2
.type __sys_mmap2,@function
__sys_mmap2:
pushm lr
st.w --sp, ARG6
rcall sys_mmap2
sub sp, -4
popm pc
.global __sys_sendto
.type __sys_sendto,@function
__sys_sendto:
pushm lr
st.w --sp, ARG6
rcall sys_sendto
sub sp, -4
popm pc
.global __sys_recvfrom
.type __sys_recvfrom,@function
__sys_recvfrom:
pushm lr
st.w --sp, ARG6
rcall sys_recvfrom
sub sp, -4
popm pc
.global __sys_pselect6
.type __sys_pselect6,@function
__sys_pselect6:
pushm lr
st.w --sp, ARG6
rcall sys_pselect6
sub sp, -4
popm pc
.global __sys_splice
.type __sys_splice,@function
__sys_splice:
pushm lr
st.w --sp, ARG6
rcall sys_splice
sub sp, -4
popm pc

View file

@ -0,0 +1,289 @@
/*
* AVR32 system call table
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
#define sys_nfsservctl sys_ni_syscall
#endif
#if !defined(CONFIG_SYSV_IPC)
# define sys_ipc sys_ni_syscall
#endif
.section .rodata,"a",@progbits
.type sys_call_table,@object
.global sys_call_table
.align 2
sys_call_table:
.long sys_restart_syscall
.long sys_exit
.long __sys_fork
.long sys_read
.long sys_write
.long sys_open /* 5 */
.long sys_close
.long sys_umask
.long sys_creat
.long sys_link
.long sys_unlink /* 10 */
.long __sys_execve
.long sys_chdir
.long sys_time
.long sys_mknod
.long sys_chmod /* 15 */
.long sys_chown
.long sys_lchown
.long sys_lseek
.long sys_llseek
.long sys_getpid /* 20 */
.long sys_mount
.long sys_umount
.long sys_setuid
.long sys_getuid
.long sys_stime /* 25 */
.long sys_ptrace
.long sys_alarm
.long sys_pause
.long sys_utime
.long sys_newstat /* 30 */
.long sys_newfstat
.long sys_newlstat
.long sys_access
.long sys_chroot
.long sys_sync /* 35 */
.long sys_fsync
.long sys_kill
.long sys_rename
.long sys_mkdir
.long sys_rmdir /* 40 */
.long sys_dup
.long sys_pipe
.long sys_times
.long __sys_clone
.long sys_brk /* 45 */
.long sys_setgid
.long sys_getgid
.long sys_getcwd
.long sys_geteuid
.long sys_getegid /* 50 */
.long sys_acct
.long sys_setfsuid
.long sys_setfsgid
.long sys_ioctl
.long sys_fcntl /* 55 */
.long sys_setpgid
.long sys_mremap
.long sys_setresuid
.long sys_getresuid
.long sys_setreuid /* 60 */
.long sys_setregid
.long sys_ustat
.long sys_dup2
.long sys_getppid
.long sys_getpgrp /* 65 */
.long sys_setsid
.long sys_rt_sigaction
.long __sys_rt_sigreturn
.long sys_rt_sigprocmask
.long sys_rt_sigpending /* 70 */
.long sys_rt_sigtimedwait
.long sys_rt_sigqueueinfo
.long __sys_rt_sigsuspend
.long sys_sethostname
.long sys_setrlimit /* 75 */
.long sys_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
.long sys_getgroups /* 80 */
.long sys_setgroups
.long sys_select
.long sys_symlink
.long sys_fchdir
.long sys_readlink /* 85 */
.long sys_pread64
.long sys_pwrite64
.long sys_swapon
.long sys_reboot
.long __sys_mmap2 /* 90 */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
.long sys_fchmod
.long sys_fchown /* 95 */
.long sys_getpriority
.long sys_setpriority
.long sys_wait4
.long sys_statfs
.long sys_fstatfs /* 100 */
.long sys_vhangup
.long __sys_sigaltstack
.long sys_syslog
.long sys_setitimer
.long sys_getitimer /* 105 */
.long sys_swapoff
.long sys_sysinfo
.long sys_ipc
.long sys_sendfile
.long sys_setdomainname /* 110 */
.long sys_newuname
.long sys_adjtimex
.long sys_mprotect
.long __sys_vfork
.long sys_init_module /* 115 */
.long sys_delete_module
.long sys_quotactl
.long sys_getpgid
.long sys_bdflush
.long sys_sysfs /* 120 */
.long sys_personality
.long sys_ni_syscall /* reserved for afs_syscall */
.long sys_getdents
.long sys_flock
.long sys_msync /* 125 */
.long sys_readv
.long sys_writev
.long sys_getsid
.long sys_fdatasync
.long sys_sysctl /* 130 */
.long sys_mlock
.long sys_munlock
.long sys_mlockall
.long sys_munlockall
.long sys_sched_setparam /* 135 */
.long sys_sched_getparam
.long sys_sched_setscheduler
.long sys_sched_getscheduler
.long sys_sched_yield
.long sys_sched_get_priority_max /* 140 */
.long sys_sched_get_priority_min
.long sys_sched_rr_get_interval
.long sys_nanosleep
.long sys_poll
.long sys_nfsservctl /* 145 */
.long sys_setresgid
.long sys_getresgid
.long sys_prctl
.long sys_socket
.long sys_bind /* 150 */
.long sys_connect
.long sys_listen
.long sys_accept
.long sys_getsockname
.long sys_getpeername /* 155 */
.long sys_socketpair
.long sys_send
.long sys_recv
.long __sys_sendto
.long __sys_recvfrom /* 160 */
.long sys_shutdown
.long sys_setsockopt
.long sys_getsockopt
.long sys_sendmsg
.long sys_recvmsg /* 165 */
.long sys_truncate64
.long sys_ftruncate64
.long sys_stat64
.long sys_lstat64
.long sys_fstat64 /* 170 */
.long sys_pivot_root
.long sys_mincore
.long sys_madvise
.long sys_getdents64
.long sys_fcntl64 /* 175 */
.long sys_gettid
.long sys_readahead
.long sys_setxattr
.long sys_lsetxattr
.long sys_fsetxattr /* 180 */
.long sys_getxattr
.long sys_lgetxattr
.long sys_fgetxattr
.long sys_listxattr
.long sys_llistxattr /* 185 */
.long sys_flistxattr
.long sys_removexattr
.long sys_lremovexattr
.long sys_fremovexattr
.long sys_tkill /* 190 */
.long sys_sendfile64
.long sys_futex
.long sys_sched_setaffinity
.long sys_sched_getaffinity
.long sys_capget /* 195 */
.long sys_capset
.long sys_io_setup
.long sys_io_destroy
.long sys_io_getevents
.long sys_io_submit /* 200 */
.long sys_io_cancel
.long sys_fadvise64
.long sys_exit_group
.long sys_lookup_dcookie
.long sys_epoll_create /* 205 */
.long sys_epoll_ctl
.long sys_epoll_wait
.long sys_remap_file_pages
.long sys_set_tid_address
.long sys_timer_create /* 210 */
.long sys_timer_settime
.long sys_timer_gettime
.long sys_timer_getoverrun
.long sys_timer_delete
.long sys_clock_settime /* 215 */
.long sys_clock_gettime
.long sys_clock_getres
.long sys_clock_nanosleep
.long sys_statfs64
.long sys_fstatfs64 /* 220 */
.long sys_tgkill
.long sys_ni_syscall /* reserved for TUX */
.long sys_utimes
.long sys_fadvise64_64
.long sys_cacheflush /* 225 */
.long sys_ni_syscall /* sys_vserver */
.long sys_mq_open
.long sys_mq_unlink
.long sys_mq_timedsend
.long sys_mq_timedreceive /* 230 */
.long sys_mq_notify
.long sys_mq_getsetattr
.long sys_kexec_load
.long sys_waitid
.long sys_add_key /* 235 */
.long sys_request_key
.long sys_keyctl
.long sys_ioprio_set
.long sys_ioprio_get
.long sys_inotify_init /* 240 */
.long sys_inotify_add_watch
.long sys_inotify_rm_watch
.long sys_openat
.long sys_mkdirat
.long sys_mknodat /* 245 */
.long sys_fchownat
.long sys_futimesat
.long sys_fstatat64
.long sys_unlinkat
.long sys_renameat /* 250 */
.long sys_linkat
.long sys_symlinkat
.long sys_readlinkat
.long sys_fchmodat
.long sys_faccessat /* 255 */
.long __sys_pselect6
.long sys_ppoll
.long sys_unshare
.long sys_set_robust_list
.long sys_get_robust_list /* 260 */
.long __sys_splice
.long sys_sync_file_range
.long sys_tee
.long sys_vmsplice
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */

238
arch/avr32/kernel/time.c Normal file
View file

@ -0,0 +1,238 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* Based on MIPS implementation arch/mips/kernel/time.c
* Copyright 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/time.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/profile.h>
#include <linux/sysdev.h>
#include <asm/div64.h>
#include <asm/sysreg.h>
#include <asm/io.h>
#include <asm/sections.h>
static cycle_t read_cycle_count(void)
{
return (cycle_t)sysreg_read(COUNT);
}
static struct clocksource clocksource_avr32 = {
.name = "avr32",
.rating = 350,
.read = read_cycle_count,
.mask = CLOCKSOURCE_MASK(32),
.shift = 16,
.is_continuous = 1,
};
/*
* By default we provide the null RTC ops
*/
static unsigned long null_rtc_get_time(void)
{
return mktime(2004, 1, 1, 0, 0, 0);
}
static int null_rtc_set_time(unsigned long sec)
{
return 0;
}
static unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
static int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
/* how many counter cycles in a jiffy? */
static unsigned long cycles_per_jiffy;
/* cycle counter value at the previous timer interrupt */
static unsigned int timerhi, timerlo;
/* the count value for the next timer interrupt */
static unsigned int expirelo;
static void avr32_timer_ack(void)
{
unsigned int count;
/* Ack this timer interrupt and set the next one */
expirelo += cycles_per_jiffy;
if (expirelo == 0) {
printk(KERN_DEBUG "expirelo == 0\n");
sysreg_write(COMPARE, expirelo + 1);
} else {
sysreg_write(COMPARE, expirelo);
}
/* Check to see if we have missed any timer interrupts */
count = sysreg_read(COUNT);
if ((count - expirelo) < 0x7fffffff) {
expirelo = count + cycles_per_jiffy;
sysreg_write(COMPARE, expirelo);
}
}
static unsigned int avr32_hpt_read(void)
{
return sysreg_read(COUNT);
}
/*
* Taken from MIPS c0_hpt_timer_init().
*
* Why is it so complicated, and what is "count"? My assumption is
* that `count' specifies the "reference cycle", i.e. the cycle since
* reset that should mean "zero". The reason COUNT is written twice is
* probably to make sure we don't get any timer interrupts while we
* are messing with the counter.
*/
static void avr32_hpt_init(unsigned int count)
{
count = sysreg_read(COUNT) - count;
expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
sysreg_write(COUNT, expirelo - cycles_per_jiffy);
sysreg_write(COMPARE, expirelo);
sysreg_write(COUNT, count);
}
/*
* Scheduler clock - returns current time in nanosec units.
*/
unsigned long long sched_clock(void)
{
/* There must be better ways...? */
return (unsigned long long)jiffies * (1000000000 / HZ);
}
/*
* local_timer_interrupt() does profiling and process accounting on a
* per-CPU basis.
*
* In UP mode, it is invoked from the (global) timer_interrupt.
*/
static void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
if (current->pid)
profile_tick(CPU_PROFILING, regs);
update_process_times(user_mode(regs));
}
static irqreturn_t
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int count;
/* ack timer interrupt and try to set next interrupt */
count = avr32_hpt_read();
avr32_timer_ack();
/* Update timerhi/timerlo for intra-jiffy calibration */
timerhi += count < timerlo; /* Wrap around */
timerlo = count;
/*
* Call the generic timer interrupt handler
*/
write_seqlock(&xtime_lock);
do_timer(regs);
write_sequnlock(&xtime_lock);
/*
* In UP mode, we call local_timer_interrupt() to do profiling
* and process accounting.
*
* SMP is not supported yet.
*/
local_timer_interrupt(irq, dev_id, regs);
return IRQ_HANDLED;
}
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED,
.name = "timer",
};
void __init time_init(void)
{
unsigned long mult, shift, count_hz;
int ret;
xtime.tv_sec = rtc_get_time();
xtime.tv_nsec = 0;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
printk("Before time_init: count=%08lx, compare=%08lx\n",
(unsigned long)sysreg_read(COUNT),
(unsigned long)sysreg_read(COMPARE));
count_hz = clk_get_rate(boot_cpu_data.clk);
shift = clocksource_avr32.shift;
mult = clocksource_hz2mult(count_hz, shift);
clocksource_avr32.mult = mult;
printk("Cycle counter: mult=%lu, shift=%lu\n", mult, shift);
{
u64 tmp;
tmp = TICK_NSEC;
tmp <<= shift;
tmp += mult / 2;
do_div(tmp, mult);
cycles_per_jiffy = tmp;
}
/* This sets up the high precision timer for the first interrupt. */
avr32_hpt_init(avr32_hpt_read());
printk("After time_init: count=%08lx, compare=%08lx\n",
(unsigned long)sysreg_read(COUNT),
(unsigned long)sysreg_read(COMPARE));
ret = clocksource_register(&clocksource_avr32);
if (ret)
printk(KERN_ERR
"timer: could not register clocksource: %d\n", ret);
ret = setup_irq(0, &timer_irqaction);
if (ret)
printk("timer: could not request IRQ 0: %d\n", ret);
}
static struct sysdev_class timer_class = {
set_kset_name("timer"),
};
static struct sys_device timer_device = {
.id = 0,
.cls = &timer_class,
};
static int __init init_timer_sysfs(void)
{
int err = sysdev_class_register(&timer_class);
if (!err)
err = sysdev_register(&timer_device);
return err;
}
device_initcall(init_timer_sysfs);

425
arch/avr32/kernel/traps.c Normal file
View file

@ -0,0 +1,425 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
#undef DEBUG
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/notifier.h>
#include <asm/traps.h>
#include <asm/sysreg.h>
#include <asm/addrspace.h>
#include <asm/ocd.h>
#include <asm/mmu_context.h>
#include <asm/uaccess.h>
static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
{
unsigned long p;
int i;
printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
for (p = bottom & ~31; p < top; ) {
printk("%04lx: ", p & 0xffff);
for (i = 0; i < 8; i++, p += 4) {
unsigned int val;
if (p < bottom || p >= top)
printk(" ");
else {
if (__get_user(val, (unsigned int __user *)p)) {
printk("\n");
goto out;
}
printk("%08x ", val);
}
}
printk("\n");
}
out:
return;
}
#ifdef CONFIG_FRAME_POINTER
static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs)
{
unsigned long __user *fp;
unsigned long __user *last_fp = NULL;
if (regs) {
fp = (unsigned long __user *)regs->r7;
} else if (tsk == current) {
register unsigned long __user *real_fp __asm__("r7");
fp = real_fp;
} else {
fp = (unsigned long __user *)tsk->thread.cpu_context.r7;
}
/*
* Walk the stack until (a) we get an exception, (b) the frame
* pointer becomes zero, or (c) the frame pointer gets stuck
* at the same value.
*/
while (fp && fp != last_fp) {
unsigned long lr, new_fp = 0;
last_fp = fp;
if (__get_user(lr, fp))
break;
if (fp && __get_user(new_fp, fp + 1))
break;
fp = (unsigned long __user *)new_fp;
printk(" [<%08lx>] ", lr);
print_symbol("%s\n", lr);
}
printk("\n");
}
#else
static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs)
{
unsigned long addr;
while (!kstack_end(sp)) {
addr = *sp++;
if (kernel_text_address(addr)) {
printk(" [<%08lx>] ", addr);
print_symbol("%s\n", addr);
}
}
}
#endif
void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs)
{
if (regs &&
(((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
((regs->sr & MODE_MASK) == MODE_USER)))
return;
printk ("Call trace:");
#ifdef CONFIG_KALLSYMS
printk("\n");
#endif
__show_trace(tsk, sp, regs);
printk("\n");
}
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
unsigned long stack;
if (!tsk)
tsk = current;
if (sp == 0) {
if (tsk == current) {
register unsigned long *real_sp __asm__("sp");
sp = real_sp;
} else {
sp = (unsigned long *)tsk->thread.cpu_context.ksp;
}
}
stack = (unsigned long)sp;
dump_mem("Stack: ", stack,
THREAD_SIZE + (unsigned long)tsk->thread_info);
show_trace(tsk, sp, NULL);
}
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
int register_die_notifier(struct notifier_block *nb)
{
pr_debug("register_die_notifier: %p\n", nb);
return atomic_notifier_chain_register(&avr32_die_chain, nb);
}
EXPORT_SYMBOL(register_die_notifier);
int unregister_die_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&avr32_die_chain, nb);
}
EXPORT_SYMBOL(unregister_die_notifier);
static DEFINE_SPINLOCK(die_lock);
void __die(const char *str, struct pt_regs *regs, unsigned long err,
const char *file, const char *func, unsigned long line)
{
struct task_struct *tsk = current;
static int die_counter;
console_verbose();
spin_lock_irq(&die_lock);
bust_spinlocks(1);
printk(KERN_ALERT "%s", str);
if (file && func)
printk(" in %s:%s, line %ld", file, func, line);
printk("[#%d]:\n", ++die_counter);
print_modules();
show_regs(regs);
printk("Process %s (pid: %d, stack limit = 0x%p)\n",
tsk->comm, tsk->pid, tsk->thread_info + 1);
if (!user_mode(regs) || in_interrupt()) {
dump_mem("Stack: ", regs->sp,
THREAD_SIZE + (unsigned long)tsk->thread_info);
}
bust_spinlocks(0);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err,
const char *file, const char *func, unsigned long line)
{
if (!user_mode(regs))
__die(str, regs, err, file, func, line);
}
asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
{
#ifdef CONFIG_SUBARCH_AVR32B
/*
* The exception entry always saves RSR_EX. For NMI, this is
* wrong; it should be RSR_NMI
*/
regs->sr = sysreg_read(RSR_NMI);
#endif
printk("NMI taken!!!!\n");
die("NMI", regs, ecr);
BUG();
}
asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
{
printk("Unable to handle critical exception %lu at pc = %08lx!\n",
ecr, regs->pc);
die("Oops", regs, ecr);
BUG();
}
asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
{
siginfo_t info;
die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);
#ifdef DEBUG
if (ecr == ECR_ADDR_ALIGN_X)
pr_debug("Instruction Address Exception at pc = %08lx\n",
regs->pc);
else if (ecr == ECR_ADDR_ALIGN_R)
pr_debug("Data Address Exception (Read) at pc = %08lx\n",
regs->pc);
else if (ecr == ECR_ADDR_ALIGN_W)
pr_debug("Data Address Exception (Write) at pc = %08lx\n",
regs->pc);
else
BUG();
show_regs(regs);
#endif
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
info.si_addr = (void __user *)regs->pc;
force_sig_info(SIGBUS, &info, current);
}
/* This way of handling undefined instructions is stolen from ARM */
static LIST_HEAD(undef_hook);
static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
void register_undef_hook(struct undef_hook *hook)
{
spin_lock_irq(&undef_lock);
list_add(&hook->node, &undef_hook);
spin_unlock_irq(&undef_lock);
}
void unregister_undef_hook(struct undef_hook *hook)
{
spin_lock_irq(&undef_lock);
list_del(&hook->node);
spin_unlock_irq(&undef_lock);
}
static int do_cop_absent(u32 insn)
{
int cop_nr;
u32 cpucr;
if ( (insn & 0xfdf00000) == 0xf1900000 )
/* LDC0 */
cop_nr = 0;
else
cop_nr = (insn >> 13) & 0x7;
/* Try enabling the coprocessor */
cpucr = sysreg_read(CPUCR);
cpucr |= (1 << (24 + cop_nr));
sysreg_write(CPUCR, cpucr);
cpucr = sysreg_read(CPUCR);
if ( !(cpucr & (1 << (24 + cop_nr))) ){
printk("Coprocessor #%i not found!\n", cop_nr);
return -1;
}
return 0;
}
#ifdef CONFIG_BUG
#ifdef CONFIG_DEBUG_BUGVERBOSE
static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
{
char *file;
u16 line;
char c;
if (__get_user(line, (u16 __user *)(regs->pc + 2)))
return;
if (__get_user(file, (char * __user *)(regs->pc + 4))
|| (unsigned long)file < PAGE_OFFSET
|| __get_user(c, file))
file = "<bad filename>";
printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
}
#else
static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
{
}
#endif
#endif
asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
{
u32 insn;
struct undef_hook *hook;
siginfo_t info;
void __user *pc;
if (!user_mode(regs))
goto kernel_trap;
local_irq_enable();
pc = (void __user *)instruction_pointer(regs);
if (__get_user(insn, (u32 __user *)pc))
goto invalid_area;
if (ecr == ECR_COPROC_ABSENT) {
if (do_cop_absent(insn) == 0)
return;
}
spin_lock_irq(&undef_lock);
list_for_each_entry(hook, &undef_hook, node) {
if ((insn & hook->insn_mask) == hook->insn_val) {
if (hook->fn(regs, insn) == 0) {
spin_unlock_irq(&undef_lock);
return;
}
}
}
spin_unlock_irq(&undef_lock);
invalid_area:
#ifdef DEBUG
printk("Illegal instruction at pc = %08lx\n", regs->pc);
if (regs->pc < TASK_SIZE) {
unsigned long ptbr, pgd, pte, *p;
ptbr = sysreg_read(PTBR);
p = (unsigned long *)ptbr;
pgd = p[regs->pc >> 22];
p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
pte = p[(regs->pc >> 12) & 0x3ff];
printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_addr = (void __user *)regs->pc;
switch (ecr) {
case ECR_ILLEGAL_OPCODE:
case ECR_UNIMPL_INSTRUCTION:
info.si_code = ILL_ILLOPC;
break;
case ECR_PRIVILEGE_VIOLATION:
info.si_code = ILL_PRVOPC;
break;
case ECR_COPROC_ABSENT:
info.si_code = ILL_COPROC;
break;
default:
BUG();
}
force_sig_info(SIGILL, &info, current);
return;
kernel_trap:
#ifdef CONFIG_BUG
if (__kernel_text_address(instruction_pointer(regs))) {
insn = *(u16 *)instruction_pointer(regs);
if (insn == AVR32_BUG_OPCODE) {
do_bug_verbose(regs, insn);
die("Kernel BUG", regs, 0);
return;
}
}
#endif
die("Oops: Illegal instruction in kernel code", regs, ecr);
}
asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
{
siginfo_t info;
printk("Floating-point exception at pc = %08lx\n", regs->pc);
/* We have no FPU... */
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_addr = (void __user *)regs->pc;
info.si_code = ILL_COPROC;
force_sig_info(SIGILL, &info, current);
}
void __init trap_init(void)
{
}

View file

@ -0,0 +1,139 @@
/*
* AVR32 linker script for the Linux kernel
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
#define LOAD_OFFSET 0x00000000
#include <asm-generic/vmlinux.lds.h>
OUTPUT_FORMAT("elf32-avr32", "elf32-avr32", "elf32-avr32")
OUTPUT_ARCH(avr32)
ENTRY(_start)
/* Big endian */
jiffies = jiffies_64 + 4;
SECTIONS
{
. = CONFIG_ENTRY_ADDRESS;
.init : AT(ADDR(.init) - LOAD_OFFSET) {
_stext = .;
__init_begin = .;
_sinittext = .;
*(.text.reset)
*(.init.text)
_einittext = .;
. = ALIGN(4);
__tagtable_begin = .;
*(.taglist)
__tagtable_end = .;
*(.init.data)
. = ALIGN(16);
__setup_start = .;
*(.init.setup)
__setup_end = .;
. = ALIGN(4);
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
__initcall_end = .;
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
__security_initcall_start = .;
*(.security_initcall.init)
__security_initcall_end = .;
. = ALIGN(32);
__initramfs_start = .;
*(.init.ramfs)
__initramfs_end = .;
. = ALIGN(4096);
__init_end = .;
}
. = ALIGN(8192);
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_evba = .;
_text = .;
*(.ex.text)
. = 0x50;
*(.tlbx.ex.text)
. = 0x60;
*(.tlbr.ex.text)
. = 0x70;
*(.tlbw.ex.text)
. = 0x100;
*(.scall.text)
*(.irq.text)
*(.text)
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
_etext = .;
} = 0xd703d703
. = ALIGN(4);
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
__start___ex_table = .;
*(__ex_table)
__stop___ex_table = .;
}
RODATA
. = ALIGN(8192);
.data : AT(ADDR(.data) - LOAD_OFFSET) {
_data = .;
_sdata = .;
/*
* First, the init task union, aligned to an 8K boundary.
*/
*(.data.init_task)
/* Then, the cacheline aligned data */
. = ALIGN(32);
*(.data.cacheline_aligned)
/* And the rest... */
*(.data.rel*)
*(.data)
CONSTRUCTORS
_edata = .;
}
. = ALIGN(8);
.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
__bss_start = .;
*(.bss)
*(COMMON)
. = ALIGN(8);
__bss_stop = .;
_end = .;
}
/* When something in the kernel is NOT compiled as a module, the module
* cleanup code and data are put into these segments. Both can then be
* thrown away, as cleanup code is never called unless it's a module.
*/
/DISCARD/ : {
*(.exit.text)
*(.exit.data)
*(.exitcall.exit)
}
DWARF_DEBUG
}

10
arch/avr32/lib/Makefile Normal file
View file

@ -0,0 +1,10 @@
#
# Makefile for AVR32-specific library files
#
lib-y := copy_user.o clear_user.o
lib-y += strncpy_from_user.o strnlen_user.o
lib-y += delay.o memset.o memcpy.o findbit.o
lib-y += csum_partial.o csum_partial_copy_generic.o
lib-y += io-readsw.o io-readsl.o io-writesw.o io-writesl.o
lib-y += __avr32_lsl64.o __avr32_lsr64.o __avr32_asr64.o

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2005-2006 Atmel Corporation
*
* 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.
*/
/*
* DWtype __avr32_asr64(DWtype u, word_type b)
*/
.text
.global __avr32_asr64
.type __avr32_asr64,@function
__avr32_asr64:
cp.w r12, 0
reteq r12
rsub r9, r12, 32
brle 1f
lsl r8, r11, r9
lsr r10, r10, r12
asr r11, r11, r12
or r10, r8
retal r12
1: neg r9
asr r10, r11, r9
asr r11, 31
retal r12

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2005-2006 Atmel Corporation
*
* 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.
*/
/*
* DWtype __avr32_lsl64(DWtype u, word_type b)
*/
.text
.global __avr32_lsl64
.type __avr32_lsl64,@function
__avr32_lsl64:
cp.w r12, 0
reteq r12
rsub r9, r12, 32
brle 1f
lsr r8, r10, r9
lsl r10, r10, r12
lsl r11, r11, r12
or r11, r8
retal r12
1: neg r9
lsl r11, r10, r9
mov r10, 0
retal r12

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2005-2006 Atmel Corporation
*
* 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.
*/
/*
* DWtype __avr32_lsr64(DWtype u, word_type b)
*/
.text
.global __avr32_lsr64
.type __avr32_lsr64,@function
__avr32_lsr64:
cp.w r12, 0
reteq r12
rsub r9, r12, 32
brle 1f
lsl r8, r11, r9
lsr r11, r11, r12
lsr r10, r10, r12
or r10, r8
retal r12
1: neg r9
lsr r10, r11, r9
mov r11, 0
retal r12

View file

@ -0,0 +1,76 @@
/*
* Copyright 2004-2006 Atmel Corporation
*
* 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 <asm/page.h>
#include <asm/thread_info.h>
#include <asm/asm.h>
.text
.align 1
.global clear_user
.type clear_user, "function"
clear_user:
branch_if_kernel r8, __clear_user
ret_if_privileged r8, r12, r11, r11
.global __clear_user
.type __clear_user, "function"
__clear_user:
mov r9, r12
mov r8, 0
andl r9, 3, COH
brne 5f
1: sub r11, 4
brlt 2f
10: st.w r12++, r8
sub r11, 4
brge 10b
2: sub r11, -4
reteq 0
/* Unaligned count or address */
bld r11, 1
brcc 12f
11: st.h r12++, r8
sub r11, 2
reteq 0
12: st.b r12++, r8
retal 0
/* Unaligned address */
5: cp.w r11, 4
brlt 2b
lsl r9, 2
add pc, pc, r9
13: st.b r12++, r8
sub r11, 1
14: st.b r12++, r8
sub r11, 1
15: st.b r12++, r8
sub r11, 1
rjmp 1b
.size clear_user, . - clear_user
.size __clear_user, . - __clear_user
.section .fixup, "ax"
.align 1
18: sub r11, -4
19: retal r11
.section __ex_table, "a"
.align 2
.long 10b, 18b
.long 11b, 19b
.long 12b, 19b
.long 13b, 19b
.long 14b, 19b
.long 15b, 19b

119
arch/avr32/lib/copy_user.S Normal file
View file

@ -0,0 +1,119 @@
/*
* Copy to/from userspace with optional address space checking.
*
* Copyright 2004-2006 Atmel Corporation
*
* 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 <asm/page.h>
#include <asm/thread_info.h>
#include <asm/asm.h>
/*
* __kernel_size_t
* __copy_user(void *to, const void *from, __kernel_size_t n)
*
* Returns the number of bytes not copied. Might be off by
* max 3 bytes if we get a fault in the main loop.
*
* The address-space checking functions simply fall through to
* the non-checking version.
*/
.text
.align 1
.global copy_from_user
.type copy_from_user, @function
copy_from_user:
branch_if_kernel r8, __copy_user
ret_if_privileged r8, r11, r10, r10
rjmp __copy_user
.size copy_from_user, . - copy_from_user
.global copy_to_user
.type copy_to_user, @function
copy_to_user:
branch_if_kernel r8, __copy_user
ret_if_privileged r8, r12, r10, r10
.size copy_to_user, . - copy_to_user
.global __copy_user
.type __copy_user, @function
__copy_user:
mov r9, r11
andl r9, 3, COH
brne 6f
/* At this point, from is word-aligned */
1: sub r10, 4
brlt 3f
2:
10: ld.w r8, r11++
11: st.w r12++, r8
sub r10, 4
brge 2b
3: sub r10, -4
reteq 0
/*
* Handle unaligned count. Need to be careful with r10 here so
* that we return the correct value even if we get a fault
*/
4:
20: ld.ub r8, r11++
21: st.b r12++, r8
sub r10, 1
reteq 0
22: ld.ub r8, r11++
23: st.b r12++, r8
sub r10, 1
reteq 0
24: ld.ub r8, r11++
25: st.b r12++, r8
retal 0
/* Handle unaligned from-pointer */
6: cp.w r10, 4
brlt 4b
rsub r9, r9, 4
30: ld.ub r8, r11++
31: st.b r12++, r8
sub r10, 1
sub r9, 1
breq 1b
32: ld.ub r8, r11++
33: st.b r12++, r8
sub r10, 1
sub r9, 1
breq 1b
34: ld.ub r8, r11++
35: st.b r12++, r8
sub r10, 1
rjmp 1b
.size __copy_user, . - __copy_user
.section .fixup,"ax"
.align 1
19: sub r10, -4
29: retal r10
.section __ex_table,"a"
.align 2
.long 10b, 19b
.long 11b, 19b
.long 20b, 29b
.long 21b, 29b
.long 22b, 29b
.long 23b, 29b
.long 24b, 29b
.long 25b, 29b
.long 30b, 29b
.long 31b, 29b
.long 32b, 29b
.long 33b, 29b
.long 34b, 29b
.long 35b, 29b

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
/*
* unsigned int csum_partial(const unsigned char *buff,
* int len, unsigned int sum)
*/
.text
.global csum_partial
.type csum_partial,"function"
.align 1
csum_partial:
/* checksum complete words, aligned or not */
3: sub r11, 4
brlt 5f
4: ld.w r9, r12++
add r10, r9
acr r10
sub r11, 4
brge 4b
/* return if we had a whole number of words */
5: sub r11, -4
reteq r10
/* checksum any remaining bytes at the end */
mov r9, 0
mov r8, 0
cp r11, 2
brlt 6f
ld.uh r9, r12++
sub r11, 2
breq 7f
lsl r9, 16
6: ld.ub r8, r12++
lsl r8, 8
7: or r9, r8
add r10, r9
acr r10
retal r10
.size csum_partial, . - csum_partial

View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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 <asm/errno.h>
#include <asm/asm.h>
/*
* unsigned int csum_partial_copy_generic(const char *src, char *dst, int len
* int sum, int *src_err_ptr,
* int *dst_err_ptr)
*
* Copy src to dst while checksumming, otherwise like csum_partial.
*/
.macro ld_src size, reg, ptr
9999: ld.\size \reg, \ptr
.section __ex_table, "a"
.long 9999b, fixup_ld_src
.previous
.endm
.macro st_dst size, ptr, reg
9999: st.\size \ptr, \reg
.section __ex_table, "a"
.long 9999b, fixup_st_dst
.previous
.endm
.text
.global csum_partial_copy_generic
.type csum_partial_copy_generic,"function"
.align 1
csum_partial_copy_generic:
pushm r4-r7,lr
/* The inner loop */
1: sub r10, 4
brlt 5f
2: ld_src w, r5, r12++
st_dst w, r11++, r5
add r9, r5
acr r9
sub r10, 4
brge 2b
/* return if we had a whole number of words */
5: sub r10, -4
brne 7f
6: mov r12, r9
popm r4-r7,pc
/* handle additional bytes at the tail */
7: mov r5, 0
mov r4, 32
8: ld_src ub, r6, r12++
st_dst b, r11++, r6
lsl r5, 8
sub r4, 8
bfins r5, r6, 0, 8
sub r10, 1
brne 8b
lsl r5, r5, r4
add r9, r5
acr r9
rjmp 6b
/* Exception handler */
.section .fixup,"ax"
.align 1
fixup_ld_src:
mov r9, -EFAULT
cp.w r8, 0
breq 1f
st.w r8[0], r9
1: /*
* TODO: zero the complete destination - computing the rest
* is too much work
*/
mov r9, 0
rjmp 6b
fixup_st_dst:
mov r9, -EFAULT
lddsp r8, sp[20]
cp.w r8, 0
breq 1f
st.w r8[0], r9
1: mov r9, 0
rjmp 6b
.previous

55
arch/avr32/lib/delay.c Normal file
View file

@ -0,0 +1,55 @@
/*
* Precise Delay Loops for avr32
*
* Copyright (C) 1993 Linus Torvalds
* Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
* Copyright (C) 2005-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/sysreg.h>
int read_current_timer(unsigned long *timer_value)
{
*timer_value = sysreg_read(COUNT);
return 0;
}
void __delay(unsigned long loops)
{
unsigned bclock, now;
bclock = sysreg_read(COUNT);
do {
now = sysreg_read(COUNT);
} while ((now - bclock) < loops);
}
inline void __const_udelay(unsigned long xloops)
{
unsigned long long loops;
asm("mulu.d %0, %1, %2"
: "=r"(loops)
: "r"(current_cpu_data.loops_per_jiffy * HZ), "r"(xloops));
__delay(loops >> 32);
}
void __udelay(unsigned long usecs)
{
__const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
}
void __ndelay(unsigned long nsecs)
{
__const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
}

154
arch/avr32/lib/findbit.S Normal file
View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/linkage.h>
.text
/*
* unsigned long find_first_zero_bit(const unsigned long *addr,
* unsigned long size)
*/
ENTRY(find_first_zero_bit)
cp.w r11, 0
reteq r11
mov r9, r11
1: ld.w r8, r12[0]
com r8
brne .L_found
sub r12, -4
sub r9, 32
brgt 1b
retal r11
/*
* unsigned long find_next_zero_bit(const unsigned long *addr,
* unsigned long size,
* unsigned long offset)
*/
ENTRY(find_next_zero_bit)
lsr r8, r10, 5
sub r9, r11, r10
retle r11
lsl r8, 2
add r12, r8
andl r10, 31, COH
breq 1f
/* offset is not word-aligned. Handle the first (32 - r10) bits */
ld.w r8, r12[0]
com r8
sub r12, -4
lsr r8, r8, r10
brne .L_found
/* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
add r9, r10
sub r9, 32
retle r11
/* Main loop. offset must be word-aligned */
1: ld.w r8, r12[0]
com r8
brne .L_found
sub r12, -4
sub r9, 32
brgt 1b
retal r11
/* Common return path for when a bit is actually found. */
.L_found:
brev r8
clz r10, r8
rsub r9, r11
add r10, r9
/* XXX: If we don't have to return exactly "size" when the bit
is not found, we may drop this "min" thing */
min r12, r11, r10
retal r12
/*
* unsigned long find_first_bit(const unsigned long *addr,
* unsigned long size)
*/
ENTRY(find_first_bit)
cp.w r11, 0
reteq r11
mov r9, r11
1: ld.w r8, r12[0]
cp.w r8, 0
brne .L_found
sub r12, -4
sub r9, 32
brgt 1b
retal r11
/*
* unsigned long find_next_bit(const unsigned long *addr,
* unsigned long size,
* unsigned long offset)
*/
ENTRY(find_next_bit)
lsr r8, r10, 5
sub r9, r11, r10
retle r11
lsl r8, 2
add r12, r8
andl r10, 31, COH
breq 1f
/* offset is not word-aligned. Handle the first (32 - r10) bits */
ld.w r8, r12[0]
sub r12, -4
lsr r8, r8, r10
brne .L_found
/* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
add r9, r10
sub r9, 32
retle r11
/* Main loop. offset must be word-aligned */
1: ld.w r8, r12[0]
cp.w r8, 0
brne .L_found
sub r12, -4
sub r9, 32
brgt 1b
retal r11
ENTRY(generic_find_next_zero_le_bit)
lsr r8, r10, 5
sub r9, r11, r10
retle r11
lsl r8, 2
add r12, r8
andl r10, 31, COH
breq 1f
/* offset is not word-aligned. Handle the first (32 - r10) bits */
ldswp.w r8, r12[0]
sub r12, -4
lsr r8, r8, r10
brne .L_found
/* r9 = r9 - (32 - r10) = r9 + r10 - 32 */
add r9, r10
sub r9, 32
retle r11
/* Main loop. offset must be word-aligned */
1: ldswp.w r8, r12[0]
cp.w r8, 0
brne .L_found
sub r12, -4
sub r9, 32
brgt 1b
retal r11

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
.global __raw_readsl
.type __raw_readsl,@function
__raw_readsl:
cp.w r10, 0
reteq r12
/*
* If r11 isn't properly aligned, we might get an exception on
* some implementations. But there's not much we can do about it.
*/
1: ld.w r8, r12[0]
sub r10, 1
st.w r11++, r8
brne 1b
retal r12

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
.Lnot_word_aligned:
/*
* Bad alignment will cause a hardware exception, which is as
* good as anything. No need for us to check for proper alignment.
*/
ld.uh r8, r12[0]
sub r10, 1
st.h r11++, r8
/* fall through */
.global __raw_readsw
.type __raw_readsw,@function
__raw_readsw:
cp.w r10, 0
reteq r12
mov r9, 3
tst r11, r9
brne .Lnot_word_aligned
sub r10, 2
brlt 2f
1: ldins.h r8:t, r12[0]
ldins.h r8:b, r12[0]
st.w r11++, r8
sub r10, 2
brge 1b
2: sub r10, -2
reteq r12
ld.uh r8, r12[0]
st.h r11++, r8
retal r12

View file

@ -0,0 +1,20 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
.global __raw_writesl
.type __raw_writesl,@function
__raw_writesl:
cp.w r10, 0
reteq r12
1: ld.w r8, r11++
sub r10, 1
st.w r12[0], r8
brne 1b
retal r12

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
.Lnot_word_aligned:
ld.uh r8, r11++
sub r10, 1
st.h r12[0], r8
.global __raw_writesw
.type __raw_writesw,@function
__raw_writesw:
cp.w r10, 0
mov r9, 3
reteq r12
tst r11, r9
brne .Lnot_word_aligned
sub r10, 2
brlt 2f
1: ld.w r8, r11++
bfextu r9, r8, 16, 16
st.h r12[0], r9
st.h r12[0], r8
sub r10, 2
brge 1b
2: sub r10, -2
reteq r12
ld.uh r8, r11++
st.h r12[0], r8
retal r12

33
arch/avr32/lib/libgcc.h Normal file
View file

@ -0,0 +1,33 @@
/* Definitions for various functions 'borrowed' from gcc-3.4.3 */
#define BITS_PER_UNIT 8
typedef int QItype __attribute__ ((mode (QI)));
typedef unsigned int UQItype __attribute__ ((mode (QI)));
typedef int HItype __attribute__ ((mode (HI)));
typedef unsigned int UHItype __attribute__ ((mode (HI)));
typedef int SItype __attribute__ ((mode (SI)));
typedef unsigned int USItype __attribute__ ((mode (SI)));
typedef int DItype __attribute__ ((mode (DI)));
typedef unsigned int UDItype __attribute__ ((mode (DI)));
typedef float SFtype __attribute__ ((mode (SF)));
typedef float DFtype __attribute__ ((mode (DF)));
typedef int word_type __attribute__ ((mode (__word__)));
#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
#define Wtype SItype
#define UWtype USItype
#define HWtype SItype
#define UHWtype USItype
#define DWtype DItype
#define UDWtype UDItype
#define __NW(a,b) __ ## a ## si ## b
#define __NDW(a,b) __ ## a ## di ## b
struct DWstruct {Wtype high, low;};
typedef union
{
struct DWstruct s;
DWtype ll;
} DWunion;

98
arch/avr32/lib/longlong.h Normal file
View file

@ -0,0 +1,98 @@
/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
Free Software Foundation, Inc.
This definition file is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2, or (at your option) any later version.
This definition file 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. */
/* Borrowed from gcc-3.4.3 */
#define __BITS4 (W_TYPE_SIZE / 4)
#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
#define count_leading_zeros(count, x) ((count) = __builtin_clz(x))
#define __udiv_qrnnd_c(q, r, n1, n0, d) \
do { \
UWtype __d1, __d0, __q1, __q0; \
UWtype __r1, __r0, __m; \
__d1 = __ll_highpart (d); \
__d0 = __ll_lowpart (d); \
\
__r1 = (n1) % __d1; \
__q1 = (n1) / __d1; \
__m = (UWtype) __q1 * __d0; \
__r1 = __r1 * __ll_B | __ll_highpart (n0); \
if (__r1 < __m) \
{ \
__q1--, __r1 += (d); \
if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
if (__r1 < __m) \
__q1--, __r1 += (d); \
} \
__r1 -= __m; \
\
__r0 = __r1 % __d1; \
__q0 = __r1 / __d1; \
__m = (UWtype) __q0 * __d0; \
__r0 = __r0 * __ll_B | __ll_lowpart (n0); \
if (__r0 < __m) \
{ \
__q0--, __r0 += (d); \
if (__r0 >= (d)) \
if (__r0 < __m) \
__q0--, __r0 += (d); \
} \
__r0 -= __m; \
\
(q) = (UWtype) __q1 * __ll_B | __q0; \
(r) = __r0; \
} while (0)
#define udiv_qrnnd __udiv_qrnnd_c
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
UWtype __x; \
__x = (al) - (bl); \
(sh) = (ah) - (bh) - (__x > (al)); \
(sl) = __x; \
} while (0)
#define umul_ppmm(w1, w0, u, v) \
do { \
UWtype __x0, __x1, __x2, __x3; \
UHWtype __ul, __vl, __uh, __vh; \
\
__ul = __ll_lowpart (u); \
__uh = __ll_highpart (u); \
__vl = __ll_lowpart (v); \
__vh = __ll_highpart (v); \
\
__x0 = (UWtype) __ul * __vl; \
__x1 = (UWtype) __ul * __vh; \
__x2 = (UWtype) __uh * __vl; \
__x3 = (UWtype) __uh * __vh; \
\
__x1 += __ll_highpart (__x0);/* this can't give carry */ \
__x1 += __x2; /* but this indeed can */ \
if (__x1 < __x2) /* did we get it? */ \
__x3 += __ll_B; /* yes, add it in the proper pos. */ \
\
(w1) = __x3 + __ll_highpart (__x1); \
(w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
} while (0)

62
arch/avr32/lib/memcpy.S Normal file
View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* 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.
*/
/*
* void *memcpy(void *to, const void *from, unsigned long n)
*
* This implementation does word-aligned loads in the main loop,
* possibly sacrificing alignment of stores.
*
* Hopefully, in most cases, both "to" and "from" will be
* word-aligned to begin with.
*/
.text
.global memcpy
.type memcpy, @function
memcpy:
mov r9, r11
andl r9, 3, COH
brne 1f
/* At this point, "from" is word-aligned */
2: sub r10, 4
mov r9, r12
brlt 4f
3: ld.w r8, r11++
sub r10, 4
st.w r12++, r8
brge 3b
4: neg r10
reteq r9
/* Handle unaligned count */
lsl r10, 2
add pc, pc, r10
ld.ub r8, r11++
st.b r12++, r8
ld.ub r8, r11++
st.b r12++, r8
ld.ub r8, r11++
st.b r12++, r8
retal r9
/* Handle unaligned "from" pointer */
1: sub r10, 4
brlt 4b
add r10, r9
lsl r9, 2
add pc, pc, r9
ld.ub r8, r11++
st.b r12++, r8
ld.ub r8, r11++
st.b r12++, r8
ld.ub r8, r11++
st.b r12++, r8
rjmp 2b

72
arch/avr32/lib/memset.S Normal file
View file

@ -0,0 +1,72 @@
/*
* Copyright (C) 2004-2006 Atmel Corporation
*
* Based on linux/arch/arm/lib/memset.S
* Copyright (C) 1995-2000 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.
*
* ASM optimised string functions
*/
#include <asm/asm.h>
/*
* r12: void *b
* r11: int c
* r10: size_t len
*
* Returns b in r12
*/
.text
.global memset
.type memset, @function
.align 5
memset:
mov r9, r12
mov r8, r12
or r11, r11, r11 << 8
andl r9, 3, COH
brne 1f
2: or r11, r11, r11 << 16
sub r10, 4
brlt 5f
/* Let's do some real work */
4: st.w r8++, r11
sub r10, 4
brge 4b
/*
* When we get here, we've got less than 4 bytes to set. r10
* might be negative.
*/
5: sub r10, -4
reteq r12
/* Fastpath ends here, exactly 32 bytes from memset */
/* Handle unaligned count or pointer */
bld r10, 1
brcc 6f
st.b r8++, r11
st.b r8++, r11
bld r10, 0
retcc r12
6: st.b r8++, r11
retal r12
/* Handle unaligned pointer */
1: sub r10, 4
brlt 5b
add r10, r9
lsl r9, 1
add pc, r9
st.b r8++, r11
st.b r8++, r11
st.b r8++, r11
rjmp 2b
.size memset, . - memset

View file

@ -0,0 +1,60 @@
/*
* Copy to/from userspace with optional address space checking.
*
* Copyright 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/errno.h>
#include <asm/page.h>
#include <asm/thread_info.h>
#include <asm/asm.h>
/*
* long strncpy_from_user(char *dst, const char *src, long count)
*
* On success, returns the length of the string, not including
* the terminating NUL.
*
* If the string is longer than count, returns count
*
* If userspace access fails, returns -EFAULT
*/
.text
.align 1
.global strncpy_from_user
.type strncpy_from_user, "function"
strncpy_from_user:
mov r9, -EFAULT
branch_if_kernel r8, __strncpy_from_user
ret_if_privileged r8, r11, r10, r9
.global __strncpy_from_user
.type __strncpy_from_user, "function"
__strncpy_from_user:
cp.w r10, 0
reteq 0
mov r9, r10
1: ld.ub r8, r11++
st.b r12++, r8
cp.w r8, 0
breq 2f
sub r9, 1
brne 1b
2: sub r10, r9
retal r10
.section .fixup, "ax"
.align 1
3: mov r12, -EFAULT
retal r12
.section __ex_table, "a"
.align 2
.long 1b, 3b

View file

@ -0,0 +1,67 @@
/*
* Copy to/from userspace with optional address space checking.
*
* Copyright 2004-2006 Atmel Corporation
*
* 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 <asm/page.h>
#include <asm/thread_info.h>
#include <asm/processor.h>
#include <asm/asm.h>
.text
.align 1
.global strnlen_user
.type strnlen_user, "function"
strnlen_user:
branch_if_kernel r8, __strnlen_user
sub r8, r11, 1
add r8, r12
retcs 0
brmi adjust_length /* do a closer inspection */
.global __strnlen_user
.type __strnlen_user, "function"
__strnlen_user:
mov r10, r12
10: ld.ub r8, r12++
cp.w r8, 0
breq 2f
sub r11, 1
brne 10b
sub r12, -1
2: sub r12, r10
retal r12
.type adjust_length, "function"
adjust_length:
cp.w r12, 0 /* addr must always be < TASK_SIZE */
retmi 0
pushm lr
lddpc lr, _task_size
sub r11, lr, r12
mov r9, r11
rcall __strnlen_user
cp.w r12, r9
brgt 1f
popm pc
1: popm pc, r12=0
.align 2
_task_size:
.long TASK_SIZE
.section .fixup, "ax"
.align 1
19: retal 0
.section __ex_table, "a"
.align 2
.long 10b, 19b

View file

@ -0,0 +1,2 @@
obj-y += at32ap.o clock.o pio.o intc.o extint.o hsmc.o
obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/arch/init.h>
#include <asm/arch/sm.h>
struct at32_sm system_manager;
static int __init at32_sm_init(void)
{
struct resource *regs;
struct at32_sm *sm = &system_manager;
int ret = -ENXIO;
regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
if (!regs)
goto fail;
spin_lock_init(&sm->lock);
sm->pdev = &at32_sm_device;
ret = -ENOMEM;
sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!sm->regs)
goto fail;
return 0;
fail:
printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
return ret;
}
void __init setup_platform(void)
{
at32_sm_init();
at32_clock_init();
at32_portmux_init();
/* FIXME: This doesn't belong here */
at32_setup_serial_console(1);
}
static int __init pdc_probe(struct platform_device *pdev)
{
struct clk *pclk, *hclk;
pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(pclk)) {
dev_err(&pdev->dev, "no pclk defined\n");
return PTR_ERR(pclk);
}
hclk = clk_get(&pdev->dev, "hclk");
if (IS_ERR(hclk)) {
dev_err(&pdev->dev, "no hclk defined\n");
clk_put(pclk);
return PTR_ERR(hclk);
}
clk_enable(pclk);
clk_enable(hclk);
dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n");
return 0;
}
static struct platform_driver pdc_driver = {
.probe = pdc_probe,
.driver = {
.name = "pdc",
},
};
static int __init pdc_init(void)
{
return platform_driver_register(&pdc_driver);
}
arch_initcall(pdc_init);

View file

@ -0,0 +1,876 @@
/*
* Copyright (C) 2005-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/arch/board.h>
#include <asm/arch/portmux.h>
#include <asm/arch/sm.h>
#include "clock.h"
#include "pio.h"
#include "sm.h"
#define PBMEM(base) \
{ \
.start = base, \
.end = base + 0x3ff, \
.flags = IORESOURCE_MEM, \
}
#define IRQ(num) \
{ \
.start = num, \
.end = num, \
.flags = IORESOURCE_IRQ, \
}
#define NAMED_IRQ(num, _name) \
{ \
.start = num, \
.end = num, \
.name = _name, \
.flags = IORESOURCE_IRQ, \
}
#define DEFINE_DEV(_name, _id) \
static struct platform_device _name##_id##_device = { \
.name = #_name, \
.id = _id, \
.resource = _name##_id##_resource, \
.num_resources = ARRAY_SIZE(_name##_id##_resource), \
}
#define DEFINE_DEV_DATA(_name, _id) \
static struct platform_device _name##_id##_device = { \
.name = #_name, \
.id = _id, \
.dev = { \
.platform_data = &_name##_id##_data, \
}, \
.resource = _name##_id##_resource, \
.num_resources = ARRAY_SIZE(_name##_id##_resource), \
}
#define DEV_CLK(_name, devname, bus, _index) \
static struct clk devname##_##_name = { \
.name = #_name, \
.dev = &devname##_device.dev, \
.parent = &bus##_clk, \
.mode = bus##_clk_mode, \
.get_rate = bus##_clk_get_rate, \
.index = _index, \
}
enum {
PIOA,
PIOB,
PIOC,
PIOD,
};
enum {
FUNC_A,
FUNC_B,
};
unsigned long at32ap7000_osc_rates[3] = {
[0] = 32768,
/* FIXME: these are ATSTK1002-specific */
[1] = 20000000,
[2] = 12000000,
};
static unsigned long osc_get_rate(struct clk *clk)
{
return at32ap7000_osc_rates[clk->index];
}
static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
{
unsigned long div, mul, rate;
if (!(control & SM_BIT(PLLEN)))
return 0;
div = SM_BFEXT(PLLDIV, control) + 1;
mul = SM_BFEXT(PLLMUL, control) + 1;
rate = clk->parent->get_rate(clk->parent);
rate = (rate + div / 2) / div;
rate *= mul;
return rate;
}
static unsigned long pll0_get_rate(struct clk *clk)
{
u32 control;
control = sm_readl(&system_manager, PM_PLL0);
return pll_get_rate(clk, control);
}
static unsigned long pll1_get_rate(struct clk *clk)
{
u32 control;
control = sm_readl(&system_manager, PM_PLL1);
return pll_get_rate(clk, control);
}
/*
* The AT32AP7000 has five primary clock sources: One 32kHz
* oscillator, two crystal oscillators and two PLLs.
*/
static struct clk osc32k = {
.name = "osc32k",
.get_rate = osc_get_rate,
.users = 1,
.index = 0,
};
static struct clk osc0 = {
.name = "osc0",
.get_rate = osc_get_rate,
.users = 1,
.index = 1,
};
static struct clk osc1 = {
.name = "osc1",
.get_rate = osc_get_rate,
.index = 2,
};
static struct clk pll0 = {
.name = "pll0",
.get_rate = pll0_get_rate,
.parent = &osc0,
};
static struct clk pll1 = {
.name = "pll1",
.get_rate = pll1_get_rate,
.parent = &osc0,
};
/*
* The main clock can be either osc0 or pll0. The boot loader may
* have chosen one for us, so we don't really know which one until we
* have a look at the SM.
*/
static struct clk *main_clock;
/*
* Synchronous clocks are generated from the main clock. The clocks
* must satisfy the constraint
* fCPU >= fHSB >= fPB
* i.e. each clock must not be faster than its parent.
*/
static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
{
return main_clock->get_rate(main_clock) >> shift;
};
static void cpu_clk_mode(struct clk *clk, int enabled)
{
struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
spin_lock_irqsave(&sm->lock, flags);
mask = sm_readl(sm, PM_CPU_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
sm_writel(sm, PM_CPU_MASK, mask);
spin_unlock_irqrestore(&sm->lock, flags);
}
static unsigned long cpu_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
cksel = sm_readl(&system_manager, PM_CKSEL);
if (cksel & SM_BIT(CPUDIV))
shift = SM_BFEXT(CPUSEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
static void hsb_clk_mode(struct clk *clk, int enabled)
{
struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
spin_lock_irqsave(&sm->lock, flags);
mask = sm_readl(sm, PM_HSB_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
sm_writel(sm, PM_HSB_MASK, mask);
spin_unlock_irqrestore(&sm->lock, flags);
}
static unsigned long hsb_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
cksel = sm_readl(&system_manager, PM_CKSEL);
if (cksel & SM_BIT(HSBDIV))
shift = SM_BFEXT(HSBSEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
static void pba_clk_mode(struct clk *clk, int enabled)
{
struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
spin_lock_irqsave(&sm->lock, flags);
mask = sm_readl(sm, PM_PBA_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
sm_writel(sm, PM_PBA_MASK, mask);
spin_unlock_irqrestore(&sm->lock, flags);
}
static unsigned long pba_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
cksel = sm_readl(&system_manager, PM_CKSEL);
if (cksel & SM_BIT(PBADIV))
shift = SM_BFEXT(PBASEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
static void pbb_clk_mode(struct clk *clk, int enabled)
{
struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
spin_lock_irqsave(&sm->lock, flags);
mask = sm_readl(sm, PM_PBB_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
sm_writel(sm, PM_PBB_MASK, mask);
spin_unlock_irqrestore(&sm->lock, flags);
}
static unsigned long pbb_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
cksel = sm_readl(&system_manager, PM_CKSEL);
if (cksel & SM_BIT(PBBDIV))
shift = SM_BFEXT(PBBSEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
static struct clk cpu_clk = {
.name = "cpu",
.get_rate = cpu_clk_get_rate,
.users = 1,
};
static struct clk hsb_clk = {
.name = "hsb",
.parent = &cpu_clk,
.get_rate = hsb_clk_get_rate,
};
static struct clk pba_clk = {
.name = "pba",
.parent = &hsb_clk,
.mode = hsb_clk_mode,
.get_rate = pba_clk_get_rate,
.index = 1,
};
static struct clk pbb_clk = {
.name = "pbb",
.parent = &hsb_clk,
.mode = hsb_clk_mode,
.get_rate = pbb_clk_get_rate,
.users = 1,
.index = 2,
};
/* --------------------------------------------------------------------
* Generic Clock operations
* -------------------------------------------------------------------- */
static void genclk_mode(struct clk *clk, int enabled)
{
u32 control;
BUG_ON(clk->index > 7);
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
if (enabled)
control |= SM_BIT(CEN);
else
control &= ~SM_BIT(CEN);
sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
}
static unsigned long genclk_get_rate(struct clk *clk)
{
u32 control;
unsigned long div = 1;
BUG_ON(clk->index > 7);
if (!clk->parent)
return 0;
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
if (control & SM_BIT(DIVEN))
div = 2 * (SM_BFEXT(DIV, control) + 1);
return clk->parent->get_rate(clk->parent) / div;
}
static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
{
u32 control;
unsigned long parent_rate, actual_rate, div;
BUG_ON(clk->index > 7);
if (!clk->parent)
return 0;
parent_rate = clk->parent->get_rate(clk->parent);
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
if (rate > 3 * parent_rate / 4) {
actual_rate = parent_rate;
control &= ~SM_BIT(DIVEN);
} else {
div = (parent_rate + rate) / (2 * rate) - 1;
control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
actual_rate = parent_rate / (2 * (div + 1));
}
printk("clk %s: new rate %lu (actual rate %lu)\n",
clk->name, rate, actual_rate);
if (apply)
sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
control);
return actual_rate;
}
int genclk_set_parent(struct clk *clk, struct clk *parent)
{
u32 control;
BUG_ON(clk->index > 7);
printk("clk %s: new parent %s (was %s)\n",
clk->name, parent->name,
clk->parent ? clk->parent->name : "(null)");
control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
if (parent == &osc1 || parent == &pll1)
control |= SM_BIT(OSCSEL);
else if (parent == &osc0 || parent == &pll0)
control &= ~SM_BIT(OSCSEL);
else
return -EINVAL;
if (parent == &pll0 || parent == &pll1)
control |= SM_BIT(PLLSEL);
else
control &= ~SM_BIT(PLLSEL);
sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
clk->parent = parent;
return 0;
}
/* --------------------------------------------------------------------
* System peripherals
* -------------------------------------------------------------------- */
static struct resource sm_resource[] = {
PBMEM(0xfff00000),
NAMED_IRQ(19, "eim"),
NAMED_IRQ(20, "pm"),
NAMED_IRQ(21, "rtc"),
};
struct platform_device at32_sm_device = {
.name = "sm",
.id = 0,
.resource = sm_resource,
.num_resources = ARRAY_SIZE(sm_resource),
};
DEV_CLK(pclk, at32_sm, pbb, 0);
static struct resource intc0_resource[] = {
PBMEM(0xfff00400),
};
struct platform_device at32_intc0_device = {
.name = "intc",
.id = 0,
.resource = intc0_resource,
.num_resources = ARRAY_SIZE(intc0_resource),
};
DEV_CLK(pclk, at32_intc0, pbb, 1);
static struct clk ebi_clk = {
.name = "ebi",
.parent = &hsb_clk,
.mode = hsb_clk_mode,
.get_rate = hsb_clk_get_rate,
.users = 1,
};
static struct clk hramc_clk = {
.name = "hramc",
.parent = &hsb_clk,
.mode = hsb_clk_mode,
.get_rate = hsb_clk_get_rate,
.users = 1,
};
static struct resource smc0_resource[] = {
PBMEM(0xfff03400),
};
DEFINE_DEV(smc, 0);
DEV_CLK(pclk, smc0, pbb, 13);
DEV_CLK(mck, smc0, hsb, 0);
static struct platform_device pdc_device = {
.name = "pdc",
.id = 0,
};
DEV_CLK(hclk, pdc, hsb, 4);
DEV_CLK(pclk, pdc, pba, 16);
static struct clk pico_clk = {
.name = "pico",
.parent = &cpu_clk,
.mode = cpu_clk_mode,
.get_rate = cpu_clk_get_rate,
.users = 1,
};
/* --------------------------------------------------------------------
* PIO
* -------------------------------------------------------------------- */
static struct resource pio0_resource[] = {
PBMEM(0xffe02800),
IRQ(13),
};
DEFINE_DEV(pio, 0);
DEV_CLK(mck, pio0, pba, 10);
static struct resource pio1_resource[] = {
PBMEM(0xffe02c00),
IRQ(14),
};
DEFINE_DEV(pio, 1);
DEV_CLK(mck, pio1, pba, 11);
static struct resource pio2_resource[] = {
PBMEM(0xffe03000),
IRQ(15),
};
DEFINE_DEV(pio, 2);
DEV_CLK(mck, pio2, pba, 12);
static struct resource pio3_resource[] = {
PBMEM(0xffe03400),
IRQ(16),
};
DEFINE_DEV(pio, 3);
DEV_CLK(mck, pio3, pba, 13);
void __init at32_add_system_devices(void)
{
system_manager.eim_first_irq = NR_INTERNAL_IRQS;
platform_device_register(&at32_sm_device);
platform_device_register(&at32_intc0_device);
platform_device_register(&smc0_device);
platform_device_register(&pdc_device);
platform_device_register(&pio0_device);
platform_device_register(&pio1_device);
platform_device_register(&pio2_device);
platform_device_register(&pio3_device);
}
/* --------------------------------------------------------------------
* USART
* -------------------------------------------------------------------- */
static struct resource usart0_resource[] = {
PBMEM(0xffe00c00),
IRQ(7),
};
DEFINE_DEV(usart, 0);
DEV_CLK(usart, usart0, pba, 4);
static struct resource usart1_resource[] = {
PBMEM(0xffe01000),
IRQ(7),
};
DEFINE_DEV(usart, 1);
DEV_CLK(usart, usart1, pba, 4);
static struct resource usart2_resource[] = {
PBMEM(0xffe01400),
IRQ(8),
};
DEFINE_DEV(usart, 2);
DEV_CLK(usart, usart2, pba, 5);
static struct resource usart3_resource[] = {
PBMEM(0xffe01800),
IRQ(9),
};
DEFINE_DEV(usart, 3);
DEV_CLK(usart, usart3, pba, 6);
static inline void configure_usart0_pins(void)
{
portmux_set_func(PIOA, 8, FUNC_B); /* RXD */
portmux_set_func(PIOA, 9, FUNC_B); /* TXD */
}
static inline void configure_usart1_pins(void)
{
portmux_set_func(PIOA, 17, FUNC_A); /* RXD */
portmux_set_func(PIOA, 18, FUNC_A); /* TXD */
}
static inline void configure_usart2_pins(void)
{
portmux_set_func(PIOB, 26, FUNC_B); /* RXD */
portmux_set_func(PIOB, 27, FUNC_B); /* TXD */
}
static inline void configure_usart3_pins(void)
{
portmux_set_func(PIOB, 18, FUNC_B); /* RXD */
portmux_set_func(PIOB, 17, FUNC_B); /* TXD */
}
static struct platform_device *setup_usart(unsigned int id)
{
struct platform_device *pdev;
switch (id) {
case 0:
pdev = &usart0_device;
configure_usart0_pins();
break;
case 1:
pdev = &usart1_device;
configure_usart1_pins();
break;
case 2:
pdev = &usart2_device;
configure_usart2_pins();
break;
case 3:
pdev = &usart3_device;
configure_usart3_pins();
break;
default:
pdev = NULL;
break;
}
return pdev;
}
struct platform_device *__init at32_add_device_usart(unsigned int id)
{
struct platform_device *pdev;
pdev = setup_usart(id);
if (pdev)
platform_device_register(pdev);
return pdev;
}
struct platform_device *at91_default_console_device;
void __init at32_setup_serial_console(unsigned int usart_id)
{
at91_default_console_device = setup_usart(usart_id);
}
/* --------------------------------------------------------------------
* Ethernet
* -------------------------------------------------------------------- */
static struct eth_platform_data macb0_data;
static struct resource macb0_resource[] = {
PBMEM(0xfff01800),
IRQ(25),
};
DEFINE_DEV_DATA(macb, 0);
DEV_CLK(hclk, macb0, hsb, 8);
DEV_CLK(pclk, macb0, pbb, 6);
struct platform_device *__init
at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
{
struct platform_device *pdev;
switch (id) {
case 0:
pdev = &macb0_device;
portmux_set_func(PIOC, 3, FUNC_A); /* TXD0 */
portmux_set_func(PIOC, 4, FUNC_A); /* TXD1 */
portmux_set_func(PIOC, 7, FUNC_A); /* TXEN */
portmux_set_func(PIOC, 8, FUNC_A); /* TXCK */
portmux_set_func(PIOC, 9, FUNC_A); /* RXD0 */
portmux_set_func(PIOC, 10, FUNC_A); /* RXD1 */
portmux_set_func(PIOC, 13, FUNC_A); /* RXER */
portmux_set_func(PIOC, 15, FUNC_A); /* RXDV */
portmux_set_func(PIOC, 16, FUNC_A); /* MDC */
portmux_set_func(PIOC, 17, FUNC_A); /* MDIO */
if (!data->is_rmii) {
portmux_set_func(PIOC, 0, FUNC_A); /* COL */
portmux_set_func(PIOC, 1, FUNC_A); /* CRS */
portmux_set_func(PIOC, 2, FUNC_A); /* TXER */
portmux_set_func(PIOC, 5, FUNC_A); /* TXD2 */
portmux_set_func(PIOC, 6, FUNC_A); /* TXD3 */
portmux_set_func(PIOC, 11, FUNC_A); /* RXD2 */
portmux_set_func(PIOC, 12, FUNC_A); /* RXD3 */
portmux_set_func(PIOC, 14, FUNC_A); /* RXCK */
portmux_set_func(PIOC, 18, FUNC_A); /* SPD */
}
break;
default:
return NULL;
}
memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
platform_device_register(pdev);
return pdev;
}
/* --------------------------------------------------------------------
* SPI
* -------------------------------------------------------------------- */
static struct resource spi0_resource[] = {
PBMEM(0xffe00000),
IRQ(3),
};
DEFINE_DEV(spi, 0);
DEV_CLK(mck, spi0, pba, 0);
struct platform_device *__init at32_add_device_spi(unsigned int id)
{
struct platform_device *pdev;
switch (id) {
case 0:
pdev = &spi0_device;
portmux_set_func(PIOA, 0, FUNC_A); /* MISO */
portmux_set_func(PIOA, 1, FUNC_A); /* MOSI */
portmux_set_func(PIOA, 2, FUNC_A); /* SCK */
portmux_set_func(PIOA, 3, FUNC_A); /* NPCS0 */
portmux_set_func(PIOA, 4, FUNC_A); /* NPCS1 */
portmux_set_func(PIOA, 5, FUNC_A); /* NPCS2 */
break;
default:
return NULL;
}
platform_device_register(pdev);
return pdev;
}
/* --------------------------------------------------------------------
* LCDC
* -------------------------------------------------------------------- */
static struct lcdc_platform_data lcdc0_data;
static struct resource lcdc0_resource[] = {
{
.start = 0xff000000,
.end = 0xff000fff,
.flags = IORESOURCE_MEM,
},
IRQ(1),
};
DEFINE_DEV_DATA(lcdc, 0);
DEV_CLK(hclk, lcdc0, hsb, 7);
static struct clk lcdc0_pixclk = {
.name = "pixclk",
.dev = &lcdc0_device.dev,
.mode = genclk_mode,
.get_rate = genclk_get_rate,
.set_rate = genclk_set_rate,
.set_parent = genclk_set_parent,
.index = 7,
};
struct platform_device *__init
at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
{
struct platform_device *pdev;
switch (id) {
case 0:
pdev = &lcdc0_device;
portmux_set_func(PIOC, 19, FUNC_A); /* CC */
portmux_set_func(PIOC, 20, FUNC_A); /* HSYNC */
portmux_set_func(PIOC, 21, FUNC_A); /* PCLK */
portmux_set_func(PIOC, 22, FUNC_A); /* VSYNC */
portmux_set_func(PIOC, 23, FUNC_A); /* DVAL */
portmux_set_func(PIOC, 24, FUNC_A); /* MODE */
portmux_set_func(PIOC, 25, FUNC_A); /* PWR */
portmux_set_func(PIOC, 26, FUNC_A); /* DATA0 */
portmux_set_func(PIOC, 27, FUNC_A); /* DATA1 */
portmux_set_func(PIOC, 28, FUNC_A); /* DATA2 */
portmux_set_func(PIOC, 29, FUNC_A); /* DATA3 */
portmux_set_func(PIOC, 30, FUNC_A); /* DATA4 */
portmux_set_func(PIOC, 31, FUNC_A); /* DATA5 */
portmux_set_func(PIOD, 0, FUNC_A); /* DATA6 */
portmux_set_func(PIOD, 1, FUNC_A); /* DATA7 */
portmux_set_func(PIOD, 2, FUNC_A); /* DATA8 */
portmux_set_func(PIOD, 3, FUNC_A); /* DATA9 */
portmux_set_func(PIOD, 4, FUNC_A); /* DATA10 */
portmux_set_func(PIOD, 5, FUNC_A); /* DATA11 */
portmux_set_func(PIOD, 6, FUNC_A); /* DATA12 */
portmux_set_func(PIOD, 7, FUNC_A); /* DATA13 */
portmux_set_func(PIOD, 8, FUNC_A); /* DATA14 */
portmux_set_func(PIOD, 9, FUNC_A); /* DATA15 */
portmux_set_func(PIOD, 10, FUNC_A); /* DATA16 */
portmux_set_func(PIOD, 11, FUNC_A); /* DATA17 */
portmux_set_func(PIOD, 12, FUNC_A); /* DATA18 */
portmux_set_func(PIOD, 13, FUNC_A); /* DATA19 */
portmux_set_func(PIOD, 14, FUNC_A); /* DATA20 */
portmux_set_func(PIOD, 15, FUNC_A); /* DATA21 */
portmux_set_func(PIOD, 16, FUNC_A); /* DATA22 */
portmux_set_func(PIOD, 17, FUNC_A); /* DATA23 */
clk_set_parent(&lcdc0_pixclk, &pll0);
clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
break;
default:
return NULL;
}
memcpy(pdev->dev.platform_data, data,
sizeof(struct lcdc_platform_data));
platform_device_register(pdev);
return pdev;
}
struct clk *at32_clock_list[] = {
&osc32k,
&osc0,
&osc1,
&pll0,
&pll1,
&cpu_clk,
&hsb_clk,
&pba_clk,
&pbb_clk,
&at32_sm_pclk,
&at32_intc0_pclk,
&ebi_clk,
&hramc_clk,
&smc0_pclk,
&smc0_mck,
&pdc_hclk,
&pdc_pclk,
&pico_clk,
&pio0_mck,
&pio1_mck,
&pio2_mck,
&pio3_mck,
&usart0_usart,
&usart1_usart,
&usart2_usart,
&usart3_usart,
&macb0_hclk,
&macb0_pclk,
&spi0_mck,
&lcdc0_hclk,
&lcdc0_pixclk,
};
unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
void __init at32_portmux_init(void)
{
at32_init_pio(&pio0_device);
at32_init_pio(&pio1_device);
at32_init_pio(&pio2_device);
at32_init_pio(&pio3_device);
}
void __init at32_clock_init(void)
{
struct at32_sm *sm = &system_manager;
u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
int i;
if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
main_clock = &pll0;
else
main_clock = &osc0;
if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
pll0.parent = &osc1;
if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
pll1.parent = &osc1;
/*
* Turn on all clocks that have at least one user already, and
* turn off everything else. We only do this for module
* clocks, and even though it isn't particularly pretty to
* check the address of the mode function, it should do the
* trick...
*/
for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
struct clk *clk = at32_clock_list[i];
if (clk->mode == &cpu_clk_mode)
cpu_mask |= 1 << clk->index;
else if (clk->mode == &hsb_clk_mode)
hsb_mask |= 1 << clk->index;
else if (clk->mode == &pba_clk_mode)
pba_mask |= 1 << clk->index;
else if (clk->mode == &pbb_clk_mode)
pbb_mask |= 1 << clk->index;
}
sm_writel(sm, PM_CPU_MASK, cpu_mask);
sm_writel(sm, PM_HSB_MASK, hsb_mask);
sm_writel(sm, PM_PBA_MASK, pba_mask);
sm_writel(sm, PM_PBB_MASK, pbb_mask);
}

View file

@ -0,0 +1,148 @@
/*
* Clock management for AT32AP CPUs
*
* Copyright (C) 2006 Atmel Corporation
*
* Based on arch/arm/mach-at91rm9200/clock.c
* Copyright (C) 2005 David Brownell
* Copyright (C) 2005 Ivan Kokshaysky
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/string.h>
#include "clock.h"
static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED;
struct clk *clk_get(struct device *dev, const char *id)
{
int i;
for (i = 0; i < at32_nr_clocks; i++) {
struct clk *clk = at32_clock_list[i];
if (clk->dev == dev && strcmp(id, clk->name) == 0)
return clk;
}
return ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get);
void clk_put(struct clk *clk)
{
/* clocks are static for now, we can't free them */
}
EXPORT_SYMBOL(clk_put);
static void __clk_enable(struct clk *clk)
{
if (clk->parent)
__clk_enable(clk->parent);
if (clk->users++ == 0 && clk->mode)
clk->mode(clk, 1);
}
int clk_enable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clk_lock, flags);
__clk_enable(clk);
spin_unlock_irqrestore(&clk_lock, flags);
return 0;
}
EXPORT_SYMBOL(clk_enable);
static void __clk_disable(struct clk *clk)
{
BUG_ON(clk->users == 0);
if (--clk->users == 0 && clk->mode)
clk->mode(clk, 0);
if (clk->parent)
__clk_disable(clk->parent);
}
void clk_disable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clk_lock, flags);
__clk_disable(clk);
spin_unlock_irqrestore(&clk_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long flags;
unsigned long rate;
spin_lock_irqsave(&clk_lock, flags);
rate = clk->get_rate(clk);
spin_unlock_irqrestore(&clk_lock, flags);
return rate;
}
EXPORT_SYMBOL(clk_get_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags, actual_rate;
if (!clk->set_rate)
return -ENOSYS;
spin_lock_irqsave(&clk_lock, flags);
actual_rate = clk->set_rate(clk, rate, 0);
spin_unlock_irqrestore(&clk_lock, flags);
return actual_rate;
}
EXPORT_SYMBOL(clk_round_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
long ret;
if (!clk->set_rate)
return -ENOSYS;
spin_lock_irqsave(&clk_lock, flags);
ret = clk->set_rate(clk, rate, 1);
spin_unlock_irqrestore(&clk_lock, flags);
return (ret < 0) ? ret : 0;
}
EXPORT_SYMBOL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
int ret;
if (!clk->set_parent)
return -ENOSYS;
spin_lock_irqsave(&clk_lock, flags);
ret = clk->set_parent(clk, parent);
spin_unlock_irqrestore(&clk_lock, flags);
return ret;
}
EXPORT_SYMBOL(clk_set_parent);
struct clk *clk_get_parent(struct clk *clk)
{
return clk->parent;
}
EXPORT_SYMBOL(clk_get_parent);

View file

@ -0,0 +1,30 @@
/*
* Clock management for AT32AP CPUs
*
* Copyright (C) 2006 Atmel Corporation
*
* Based on arch/arm/mach-at91rm9200/clock.c
* Copyright (C) 2005 David Brownell
* Copyright (C) 2005 Ivan Kokshaysky
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
struct clk {
const char *name; /* Clock name/function */
struct device *dev; /* Device the clock is used by */
struct clk *parent; /* Parent clock, if any */
void (*mode)(struct clk *clk, int enabled);
unsigned long (*get_rate)(struct clk *clk);
long (*set_rate)(struct clk *clk, unsigned long rate,
int apply);
int (*set_parent)(struct clk *clk, struct clk *parent);
u16 users; /* Enabled if non-zero */
u16 index; /* Sibling index */
};
extern struct clk *at32_clock_list[];
extern unsigned int at32_nr_clocks;

View file

@ -0,0 +1,171 @@
/*
* External interrupt handling for AT32AP CPUs
*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <asm/io.h>
#include <asm/arch/sm.h>
#include "sm.h"
static void eim_ack_irq(unsigned int irq)
{
struct at32_sm *sm = get_irq_chip_data(irq);
sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
}
static void eim_mask_irq(unsigned int irq)
{
struct at32_sm *sm = get_irq_chip_data(irq);
sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
}
static void eim_mask_ack_irq(unsigned int irq)
{
struct at32_sm *sm = get_irq_chip_data(irq);
sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
}
static void eim_unmask_irq(unsigned int irq)
{
struct at32_sm *sm = get_irq_chip_data(irq);
sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
}
static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
{
struct at32_sm *sm = get_irq_chip_data(irq);
unsigned int i = irq - sm->eim_first_irq;
u32 mode, edge, level;
unsigned long flags;
int ret = 0;
flow_type &= IRQ_TYPE_SENSE_MASK;
spin_lock_irqsave(&sm->lock, flags);
mode = sm_readl(sm, EIM_MODE);
edge = sm_readl(sm, EIM_EDGE);
level = sm_readl(sm, EIM_LEVEL);
switch (flow_type) {
case IRQ_TYPE_LEVEL_LOW:
mode |= 1 << i;
level &= ~(1 << i);
break;
case IRQ_TYPE_LEVEL_HIGH:
mode |= 1 << i;
level |= 1 << i;
break;
case IRQ_TYPE_EDGE_RISING:
mode &= ~(1 << i);
edge |= 1 << i;
break;
case IRQ_TYPE_EDGE_FALLING:
mode &= ~(1 << i);
edge &= ~(1 << i);
break;
default:
ret = -EINVAL;
break;
}
sm_writel(sm, EIM_MODE, mode);
sm_writel(sm, EIM_EDGE, edge);
sm_writel(sm, EIM_LEVEL, level);
spin_unlock_irqrestore(&sm->lock, flags);
return ret;
}
struct irq_chip eim_chip = {
.name = "eim",
.ack = eim_ack_irq,
.mask = eim_mask_irq,
.mask_ack = eim_mask_ack_irq,
.unmask = eim_unmask_irq,
.set_type = eim_set_irq_type,
};
static void demux_eim_irq(unsigned int irq, struct irq_desc *desc,
struct pt_regs *regs)
{
struct at32_sm *sm = desc->handler_data;
struct irq_desc *ext_desc;
unsigned long status, pending;
unsigned int i, ext_irq;
spin_lock(&sm->lock);
status = sm_readl(sm, EIM_ISR);
pending = status & sm_readl(sm, EIM_IMR);
while (pending) {
i = fls(pending) - 1;
pending &= ~(1 << i);
ext_irq = i + sm->eim_first_irq;
ext_desc = irq_desc + ext_irq;
ext_desc->handle_irq(ext_irq, ext_desc, regs);
}
spin_unlock(&sm->lock);
}
static int __init eim_init(void)
{
struct at32_sm *sm = &system_manager;
unsigned int i;
unsigned int nr_irqs;
unsigned int int_irq;
u32 pattern;
/*
* The EIM is really the same module as SM, so register
* mapping, etc. has been taken care of already.
*/
/*
* Find out how many interrupt lines that are actually
* implemented in hardware.
*/
sm_writel(sm, EIM_IDR, ~0UL);
sm_writel(sm, EIM_MODE, ~0UL);
pattern = sm_readl(sm, EIM_MODE);
nr_irqs = fls(pattern);
sm->eim_chip = &eim_chip;
for (i = 0; i < nr_irqs; i++) {
set_irq_chip(sm->eim_first_irq + i, &eim_chip);
set_irq_chip_data(sm->eim_first_irq + i, sm);
}
int_irq = platform_get_irq_byname(sm->pdev, "eim");
set_irq_chained_handler(int_irq, demux_eim_irq);
set_irq_data(int_irq, sm);
printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
sm->regs, int_irq);
printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
nr_irqs, sm->eim_first_irq);
return 0;
}
arch_initcall(eim_init);

View file

@ -0,0 +1,164 @@
/*
* Static Memory Controller for AT32 chips
*
* Copyright (C) 2006 Atmel Corporation
*
* 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.
*/
#define DEBUG
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/arch/smc.h>
#include "hsmc.h"
#define NR_CHIP_SELECTS 6
struct hsmc {
void __iomem *regs;
struct clk *pclk;
struct clk *mck;
};
static struct hsmc *hsmc;
int smc_set_configuration(int cs, const struct smc_config *config)
{
unsigned long mul;
unsigned long offset;
u32 setup, pulse, cycle, mode;
if (!hsmc)
return -ENODEV;
if (cs >= NR_CHIP_SELECTS)
return -EINVAL;
/*
* cycles = x / T = x * f
* = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536
* = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536
*/
mul = (clk_get_rate(hsmc->mck) / 10000) << 16;
mul /= 100000;
#define ns2cyc(x) ((((x) * mul) + 65535) >> 16)
setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup))
| HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup))
| HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup))
| HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup)));
pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse))
| HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse))
| HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse))
| HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse)));
cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle))
| HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle)));
switch (config->bus_width) {
case 1:
mode = HSMC_BF(DBW, HSMC_DBW_8_BITS);
break;
case 2:
mode = HSMC_BF(DBW, HSMC_DBW_16_BITS);
break;
case 4:
mode = HSMC_BF(DBW, HSMC_DBW_32_BITS);
break;
default:
return -EINVAL;
}
if (config->nrd_controlled)
mode |= HSMC_BIT(READ_MODE);
if (config->nwe_controlled)
mode |= HSMC_BIT(WRITE_MODE);
if (config->byte_write)
mode |= HSMC_BIT(BAT);
pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
cs, setup, pulse, cycle, mode);
offset = cs * 0x10;
hsmc_writel(hsmc, SETUP0 + offset, setup);
hsmc_writel(hsmc, PULSE0 + offset, pulse);
hsmc_writel(hsmc, CYCLE0 + offset, cycle);
hsmc_writel(hsmc, MODE0 + offset, mode);
hsmc_readl(hsmc, MODE0); /* I/O barrier */
return 0;
}
EXPORT_SYMBOL(smc_set_configuration);
static int hsmc_probe(struct platform_device *pdev)
{
struct resource *regs;
struct clk *pclk, *mck;
int ret;
if (hsmc)
return -EBUSY;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(pclk))
return PTR_ERR(pclk);
mck = clk_get(&pdev->dev, "mck");
if (IS_ERR(mck)) {
ret = PTR_ERR(mck);
goto out_put_pclk;
}
ret = -ENOMEM;
hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL);
if (!hsmc)
goto out_put_clocks;
clk_enable(pclk);
clk_enable(mck);
hsmc->pclk = pclk;
hsmc->mck = mck;
hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!hsmc->regs)
goto out_disable_clocks;
dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n",
(unsigned long)regs->start);
platform_set_drvdata(pdev, hsmc);
return 0;
out_disable_clocks:
clk_disable(mck);
clk_disable(pclk);
kfree(hsmc);
out_put_clocks:
clk_put(mck);
out_put_pclk:
clk_put(pclk);
hsmc = NULL;
return ret;
}
static struct platform_driver hsmc_driver = {
.probe = hsmc_probe,
.driver = {
.name = "smc",
},
};
static int __init hsmc_init(void)
{
return platform_driver_register(&hsmc_driver);
}
arch_initcall(hsmc_init);

View file

@ -0,0 +1,127 @@
/*
* Register definitions for Atmel Static Memory Controller (SMC)
*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_AVR32_HSMC_H__
#define __ASM_AVR32_HSMC_H__
/* HSMC register offsets */
#define HSMC_SETUP0 0x0000
#define HSMC_PULSE0 0x0004
#define HSMC_CYCLE0 0x0008
#define HSMC_MODE0 0x000c
#define HSMC_SETUP1 0x0010
#define HSMC_PULSE1 0x0014
#define HSMC_CYCLE1 0x0018
#define HSMC_MODE1 0x001c
#define HSMC_SETUP2 0x0020
#define HSMC_PULSE2 0x0024
#define HSMC_CYCLE2 0x0028
#define HSMC_MODE2 0x002c
#define HSMC_SETUP3 0x0030
#define HSMC_PULSE3 0x0034
#define HSMC_CYCLE3 0x0038
#define HSMC_MODE3 0x003c
#define HSMC_SETUP4 0x0040
#define HSMC_PULSE4 0x0044
#define HSMC_CYCLE4 0x0048
#define HSMC_MODE4 0x004c
#define HSMC_SETUP5 0x0050
#define HSMC_PULSE5 0x0054
#define HSMC_CYCLE5 0x0058
#define HSMC_MODE5 0x005c
/* Bitfields in SETUP0 */
#define HSMC_NWE_SETUP_OFFSET 0
#define HSMC_NWE_SETUP_SIZE 6
#define HSMC_NCS_WR_SETUP_OFFSET 8
#define HSMC_NCS_WR_SETUP_SIZE 6
#define HSMC_NRD_SETUP_OFFSET 16
#define HSMC_NRD_SETUP_SIZE 6
#define HSMC_NCS_RD_SETUP_OFFSET 24
#define HSMC_NCS_RD_SETUP_SIZE 6
/* Bitfields in PULSE0 */
#define HSMC_NWE_PULSE_OFFSET 0
#define HSMC_NWE_PULSE_SIZE 7
#define HSMC_NCS_WR_PULSE_OFFSET 8
#define HSMC_NCS_WR_PULSE_SIZE 7
#define HSMC_NRD_PULSE_OFFSET 16
#define HSMC_NRD_PULSE_SIZE 7
#define HSMC_NCS_RD_PULSE_OFFSET 24
#define HSMC_NCS_RD_PULSE_SIZE 7
/* Bitfields in CYCLE0 */
#define HSMC_NWE_CYCLE_OFFSET 0
#define HSMC_NWE_CYCLE_SIZE 9
#define HSMC_NRD_CYCLE_OFFSET 16
#define HSMC_NRD_CYCLE_SIZE 9
/* Bitfields in MODE0 */
#define HSMC_READ_MODE_OFFSET 0
#define HSMC_READ_MODE_SIZE 1
#define HSMC_WRITE_MODE_OFFSET 1
#define HSMC_WRITE_MODE_SIZE 1
#define HSMC_EXNW_MODE_OFFSET 4
#define HSMC_EXNW_MODE_SIZE 2
#define HSMC_BAT_OFFSET 8
#define HSMC_BAT_SIZE 1
#define HSMC_DBW_OFFSET 12
#define HSMC_DBW_SIZE 2
#define HSMC_TDF_CYCLES_OFFSET 16
#define HSMC_TDF_CYCLES_SIZE 4
#define HSMC_TDF_MODE_OFFSET 20
#define HSMC_TDF_MODE_SIZE 1
#define HSMC_PMEN_OFFSET 24
#define HSMC_PMEN_SIZE 1
#define HSMC_PS_OFFSET 28
#define HSMC_PS_SIZE 2
/* Constants for READ_MODE */
#define HSMC_READ_MODE_NCS_CONTROLLED 0
#define HSMC_READ_MODE_NRD_CONTROLLED 1
/* Constants for WRITE_MODE */
#define HSMC_WRITE_MODE_NCS_CONTROLLED 0
#define HSMC_WRITE_MODE_NWE_CONTROLLED 1
/* Constants for EXNW_MODE */
#define HSMC_EXNW_MODE_DISABLED 0
#define HSMC_EXNW_MODE_RESERVED 1
#define HSMC_EXNW_MODE_FROZEN 2
#define HSMC_EXNW_MODE_READY 3
/* Constants for BAT */
#define HSMC_BAT_BYTE_SELECT 0
#define HSMC_BAT_BYTE_WRITE 1
/* Constants for DBW */
#define HSMC_DBW_8_BITS 0
#define HSMC_DBW_16_BITS 1
#define HSMC_DBW_32_BITS 2
/* Bit manipulation macros */
#define HSMC_BIT(name) \
(1 << HSMC_##name##_OFFSET)
#define HSMC_BF(name,value) \
(((value) & ((1 << HSMC_##name##_SIZE) - 1)) \
<< HSMC_##name##_OFFSET)
#define HSMC_BFEXT(name,value) \
(((value) >> HSMC_##name##_OFFSET) \
& ((1 << HSMC_##name##_SIZE) - 1))
#define HSMC_BFINS(name,value,old) \
(((old) & ~(((1 << HSMC_##name##_SIZE) - 1) \
<< HSMC_##name##_OFFSET)) | HSMC_BF(name,value))
/* Register access macros */
#define hsmc_readl(port,reg) \
readl((port)->regs + HSMC_##reg)
#define hsmc_writel(port,reg,value) \
writel((value), (port)->regs + HSMC_##reg)
#endif /* __ASM_AVR32_HSMC_H__ */

View file

@ -0,0 +1,133 @@
/*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include "intc.h"
struct intc {
void __iomem *regs;
struct irq_chip chip;
};
extern struct platform_device at32_intc0_device;
/*
* TODO: We may be able to implement mask/unmask by setting IxM flags
* in the status register.
*/
static void intc_mask_irq(unsigned int irq)
{
}
static void intc_unmask_irq(unsigned int irq)
{
}
static struct intc intc0 = {
.chip = {
.name = "intc",
.mask = intc_mask_irq,
.unmask = intc_unmask_irq,
},
};
/*
* All interrupts go via intc at some point.
*/
asmlinkage void do_IRQ(int level, struct pt_regs *regs)
{
struct irq_desc *desc;
unsigned int irq;
unsigned long status_reg;
local_irq_disable();
irq_enter();
irq = intc_readl(&intc0, INTCAUSE0 - 4 * level);
desc = irq_desc + irq;
desc->handle_irq(irq, desc, regs);
/*
* Clear all interrupt level masks so that we may handle
* interrupts during softirq processing. If this is a nested
* interrupt, interrupts must stay globally disabled until we
* return.
*/
status_reg = sysreg_read(SR);
status_reg &= ~(SYSREG_BIT(I0M) | SYSREG_BIT(I1M)
| SYSREG_BIT(I2M) | SYSREG_BIT(I3M));
sysreg_write(SR, status_reg);
irq_exit();
}
void __init init_IRQ(void)
{
extern void _evba(void);
extern void irq_level0(void);
struct resource *regs;
struct clk *pclk;
unsigned int i;
u32 offset, readback;
regs = platform_get_resource(&at32_intc0_device, IORESOURCE_MEM, 0);
if (!regs) {
printk(KERN_EMERG "intc: no mmio resource defined\n");
goto fail;
}
pclk = clk_get(&at32_intc0_device.dev, "pclk");
if (IS_ERR(pclk)) {
printk(KERN_EMERG "intc: no clock defined\n");
goto fail;
}
clk_enable(pclk);
intc0.regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!intc0.regs) {
printk(KERN_EMERG "intc: failed to map registers (0x%08lx)\n",
(unsigned long)regs->start);
goto fail;
}
/*
* Initialize all interrupts to level 0 (lowest priority). The
* priority level may be changed by calling
* irq_set_priority().
*
*/
offset = (unsigned long)&irq_level0 - (unsigned long)&_evba;
for (i = 0; i < NR_INTERNAL_IRQS; i++) {
intc_writel(&intc0, INTPR0 + 4 * i, offset);
readback = intc_readl(&intc0, INTPR0 + 4 * i);
if (readback == offset)
set_irq_chip_and_handler(i, &intc0.chip,
handle_simple_irq);
}
/* Unmask all interrupt levels */
sysreg_write(SR, (sysreg_read(SR)
& ~(SR_I3M | SR_I2M | SR_I1M | SR_I0M)));
return;
fail:
panic("Interrupt controller initialization failed!\n");
}

View file

@ -0,0 +1,327 @@
/*
* Automatically generated by gen-header.xsl
*/
#ifndef __ASM_AVR32_PERIHP_INTC_H__
#define __ASM_AVR32_PERIHP_INTC_H__
#define INTC_NUM_INT_GRPS 33
#define INTC_INTPR0 0x0
# define INTC_INTPR0_INTLEV_OFFSET 30
# define INTC_INTPR0_INTLEV_SIZE 2
# define INTC_INTPR0_OFFSET_OFFSET 0
# define INTC_INTPR0_OFFSET_SIZE 24
#define INTC_INTREQ0 0x100
# define INTC_INTREQ0_IREQUEST0_OFFSET 0
# define INTC_INTREQ0_IREQUEST0_SIZE 1
# define INTC_INTREQ0_IREQUEST1_OFFSET 1
# define INTC_INTREQ0_IREQUEST1_SIZE 1
#define INTC_INTPR1 0x4
# define INTC_INTPR1_INTLEV_OFFSET 30
# define INTC_INTPR1_INTLEV_SIZE 2
# define INTC_INTPR1_OFFSET_OFFSET 0
# define INTC_INTPR1_OFFSET_SIZE 24
#define INTC_INTREQ1 0x104
# define INTC_INTREQ1_IREQUEST32_OFFSET 0
# define INTC_INTREQ1_IREQUEST32_SIZE 1
# define INTC_INTREQ1_IREQUEST33_OFFSET 1
# define INTC_INTREQ1_IREQUEST33_SIZE 1
# define INTC_INTREQ1_IREQUEST34_OFFSET 2
# define INTC_INTREQ1_IREQUEST34_SIZE 1
# define INTC_INTREQ1_IREQUEST35_OFFSET 3
# define INTC_INTREQ1_IREQUEST35_SIZE 1
# define INTC_INTREQ1_IREQUEST36_OFFSET 4
# define INTC_INTREQ1_IREQUEST36_SIZE 1
# define INTC_INTREQ1_IREQUEST37_OFFSET 5
# define INTC_INTREQ1_IREQUEST37_SIZE 1
#define INTC_INTPR2 0x8
# define INTC_INTPR2_INTLEV_OFFSET 30
# define INTC_INTPR2_INTLEV_SIZE 2
# define INTC_INTPR2_OFFSET_OFFSET 0
# define INTC_INTPR2_OFFSET_SIZE 24
#define INTC_INTREQ2 0x108
# define INTC_INTREQ2_IREQUEST64_OFFSET 0
# define INTC_INTREQ2_IREQUEST64_SIZE 1
# define INTC_INTREQ2_IREQUEST65_OFFSET 1
# define INTC_INTREQ2_IREQUEST65_SIZE 1
# define INTC_INTREQ2_IREQUEST66_OFFSET 2
# define INTC_INTREQ2_IREQUEST66_SIZE 1
# define INTC_INTREQ2_IREQUEST67_OFFSET 3
# define INTC_INTREQ2_IREQUEST67_SIZE 1
# define INTC_INTREQ2_IREQUEST68_OFFSET 4
# define INTC_INTREQ2_IREQUEST68_SIZE 1
#define INTC_INTPR3 0xc
# define INTC_INTPR3_INTLEV_OFFSET 30
# define INTC_INTPR3_INTLEV_SIZE 2
# define INTC_INTPR3_OFFSET_OFFSET 0
# define INTC_INTPR3_OFFSET_SIZE 24
#define INTC_INTREQ3 0x10c
# define INTC_INTREQ3_IREQUEST96_OFFSET 0
# define INTC_INTREQ3_IREQUEST96_SIZE 1
#define INTC_INTPR4 0x10
# define INTC_INTPR4_INTLEV_OFFSET 30
# define INTC_INTPR4_INTLEV_SIZE 2
# define INTC_INTPR4_OFFSET_OFFSET 0
# define INTC_INTPR4_OFFSET_SIZE 24
#define INTC_INTREQ4 0x110
# define INTC_INTREQ4_IREQUEST128_OFFSET 0
# define INTC_INTREQ4_IREQUEST128_SIZE 1
#define INTC_INTPR5 0x14
# define INTC_INTPR5_INTLEV_OFFSET 30
# define INTC_INTPR5_INTLEV_SIZE 2
# define INTC_INTPR5_OFFSET_OFFSET 0
# define INTC_INTPR5_OFFSET_SIZE 24
#define INTC_INTREQ5 0x114
# define INTC_INTREQ5_IREQUEST160_OFFSET 0
# define INTC_INTREQ5_IREQUEST160_SIZE 1
#define INTC_INTPR6 0x18
# define INTC_INTPR6_INTLEV_OFFSET 30
# define INTC_INTPR6_INTLEV_SIZE 2
# define INTC_INTPR6_OFFSET_OFFSET 0
# define INTC_INTPR6_OFFSET_SIZE 24
#define INTC_INTREQ6 0x118
# define INTC_INTREQ6_IREQUEST192_OFFSET 0
# define INTC_INTREQ6_IREQUEST192_SIZE 1
#define INTC_INTPR7 0x1c
# define INTC_INTPR7_INTLEV_OFFSET 30
# define INTC_INTPR7_INTLEV_SIZE 2
# define INTC_INTPR7_OFFSET_OFFSET 0
# define INTC_INTPR7_OFFSET_SIZE 24
#define INTC_INTREQ7 0x11c
# define INTC_INTREQ7_IREQUEST224_OFFSET 0
# define INTC_INTREQ7_IREQUEST224_SIZE 1
#define INTC_INTPR8 0x20
# define INTC_INTPR8_INTLEV_OFFSET 30
# define INTC_INTPR8_INTLEV_SIZE 2
# define INTC_INTPR8_OFFSET_OFFSET 0
# define INTC_INTPR8_OFFSET_SIZE 24
#define INTC_INTREQ8 0x120
# define INTC_INTREQ8_IREQUEST256_OFFSET 0
# define INTC_INTREQ8_IREQUEST256_SIZE 1
#define INTC_INTPR9 0x24
# define INTC_INTPR9_INTLEV_OFFSET 30
# define INTC_INTPR9_INTLEV_SIZE 2
# define INTC_INTPR9_OFFSET_OFFSET 0
# define INTC_INTPR9_OFFSET_SIZE 24
#define INTC_INTREQ9 0x124
# define INTC_INTREQ9_IREQUEST288_OFFSET 0
# define INTC_INTREQ9_IREQUEST288_SIZE 1
#define INTC_INTPR10 0x28
# define INTC_INTPR10_INTLEV_OFFSET 30
# define INTC_INTPR10_INTLEV_SIZE 2
# define INTC_INTPR10_OFFSET_OFFSET 0
# define INTC_INTPR10_OFFSET_SIZE 24
#define INTC_INTREQ10 0x128
# define INTC_INTREQ10_IREQUEST320_OFFSET 0
# define INTC_INTREQ10_IREQUEST320_SIZE 1
#define INTC_INTPR11 0x2c
# define INTC_INTPR11_INTLEV_OFFSET 30
# define INTC_INTPR11_INTLEV_SIZE 2
# define INTC_INTPR11_OFFSET_OFFSET 0
# define INTC_INTPR11_OFFSET_SIZE 24
#define INTC_INTREQ11 0x12c
# define INTC_INTREQ11_IREQUEST352_OFFSET 0
# define INTC_INTREQ11_IREQUEST352_SIZE 1
#define INTC_INTPR12 0x30
# define INTC_INTPR12_INTLEV_OFFSET 30
# define INTC_INTPR12_INTLEV_SIZE 2
# define INTC_INTPR12_OFFSET_OFFSET 0
# define INTC_INTPR12_OFFSET_SIZE 24
#define INTC_INTREQ12 0x130
# define INTC_INTREQ12_IREQUEST384_OFFSET 0
# define INTC_INTREQ12_IREQUEST384_SIZE 1
#define INTC_INTPR13 0x34
# define INTC_INTPR13_INTLEV_OFFSET 30
# define INTC_INTPR13_INTLEV_SIZE 2
# define INTC_INTPR13_OFFSET_OFFSET 0
# define INTC_INTPR13_OFFSET_SIZE 24
#define INTC_INTREQ13 0x134
# define INTC_INTREQ13_IREQUEST416_OFFSET 0
# define INTC_INTREQ13_IREQUEST416_SIZE 1
#define INTC_INTPR14 0x38
# define INTC_INTPR14_INTLEV_OFFSET 30
# define INTC_INTPR14_INTLEV_SIZE 2
# define INTC_INTPR14_OFFSET_OFFSET 0
# define INTC_INTPR14_OFFSET_SIZE 24
#define INTC_INTREQ14 0x138
# define INTC_INTREQ14_IREQUEST448_OFFSET 0
# define INTC_INTREQ14_IREQUEST448_SIZE 1
#define INTC_INTPR15 0x3c
# define INTC_INTPR15_INTLEV_OFFSET 30
# define INTC_INTPR15_INTLEV_SIZE 2
# define INTC_INTPR15_OFFSET_OFFSET 0
# define INTC_INTPR15_OFFSET_SIZE 24
#define INTC_INTREQ15 0x13c
# define INTC_INTREQ15_IREQUEST480_OFFSET 0
# define INTC_INTREQ15_IREQUEST480_SIZE 1
#define INTC_INTPR16 0x40
# define INTC_INTPR16_INTLEV_OFFSET 30
# define INTC_INTPR16_INTLEV_SIZE 2
# define INTC_INTPR16_OFFSET_OFFSET 0
# define INTC_INTPR16_OFFSET_SIZE 24
#define INTC_INTREQ16 0x140
# define INTC_INTREQ16_IREQUEST512_OFFSET 0
# define INTC_INTREQ16_IREQUEST512_SIZE 1
#define INTC_INTPR17 0x44
# define INTC_INTPR17_INTLEV_OFFSET 30
# define INTC_INTPR17_INTLEV_SIZE 2
# define INTC_INTPR17_OFFSET_OFFSET 0
# define INTC_INTPR17_OFFSET_SIZE 24
#define INTC_INTREQ17 0x144
# define INTC_INTREQ17_IREQUEST544_OFFSET 0
# define INTC_INTREQ17_IREQUEST544_SIZE 1
#define INTC_INTPR18 0x48
# define INTC_INTPR18_INTLEV_OFFSET 30
# define INTC_INTPR18_INTLEV_SIZE 2
# define INTC_INTPR18_OFFSET_OFFSET 0
# define INTC_INTPR18_OFFSET_SIZE 24
#define INTC_INTREQ18 0x148
# define INTC_INTREQ18_IREQUEST576_OFFSET 0
# define INTC_INTREQ18_IREQUEST576_SIZE 1
#define INTC_INTPR19 0x4c
# define INTC_INTPR19_INTLEV_OFFSET 30
# define INTC_INTPR19_INTLEV_SIZE 2
# define INTC_INTPR19_OFFSET_OFFSET 0
# define INTC_INTPR19_OFFSET_SIZE 24
#define INTC_INTREQ19 0x14c
# define INTC_INTREQ19_IREQUEST608_OFFSET 0
# define INTC_INTREQ19_IREQUEST608_SIZE 1
# define INTC_INTREQ19_IREQUEST609_OFFSET 1
# define INTC_INTREQ19_IREQUEST609_SIZE 1
# define INTC_INTREQ19_IREQUEST610_OFFSET 2
# define INTC_INTREQ19_IREQUEST610_SIZE 1
# define INTC_INTREQ19_IREQUEST611_OFFSET 3
# define INTC_INTREQ19_IREQUEST611_SIZE 1
#define INTC_INTPR20 0x50
# define INTC_INTPR20_INTLEV_OFFSET 30
# define INTC_INTPR20_INTLEV_SIZE 2
# define INTC_INTPR20_OFFSET_OFFSET 0
# define INTC_INTPR20_OFFSET_SIZE 24
#define INTC_INTREQ20 0x150
# define INTC_INTREQ20_IREQUEST640_OFFSET 0
# define INTC_INTREQ20_IREQUEST640_SIZE 1
#define INTC_INTPR21 0x54
# define INTC_INTPR21_INTLEV_OFFSET 30
# define INTC_INTPR21_INTLEV_SIZE 2
# define INTC_INTPR21_OFFSET_OFFSET 0
# define INTC_INTPR21_OFFSET_SIZE 24
#define INTC_INTREQ21 0x154
# define INTC_INTREQ21_IREQUEST672_OFFSET 0
# define INTC_INTREQ21_IREQUEST672_SIZE 1
#define INTC_INTPR22 0x58
# define INTC_INTPR22_INTLEV_OFFSET 30
# define INTC_INTPR22_INTLEV_SIZE 2
# define INTC_INTPR22_OFFSET_OFFSET 0
# define INTC_INTPR22_OFFSET_SIZE 24
#define INTC_INTREQ22 0x158
# define INTC_INTREQ22_IREQUEST704_OFFSET 0
# define INTC_INTREQ22_IREQUEST704_SIZE 1
# define INTC_INTREQ22_IREQUEST705_OFFSET 1
# define INTC_INTREQ22_IREQUEST705_SIZE 1
# define INTC_INTREQ22_IREQUEST706_OFFSET 2
# define INTC_INTREQ22_IREQUEST706_SIZE 1
#define INTC_INTPR23 0x5c
# define INTC_INTPR23_INTLEV_OFFSET 30
# define INTC_INTPR23_INTLEV_SIZE 2
# define INTC_INTPR23_OFFSET_OFFSET 0
# define INTC_INTPR23_OFFSET_SIZE 24
#define INTC_INTREQ23 0x15c
# define INTC_INTREQ23_IREQUEST736_OFFSET 0
# define INTC_INTREQ23_IREQUEST736_SIZE 1
# define INTC_INTREQ23_IREQUEST737_OFFSET 1
# define INTC_INTREQ23_IREQUEST737_SIZE 1
# define INTC_INTREQ23_IREQUEST738_OFFSET 2
# define INTC_INTREQ23_IREQUEST738_SIZE 1
#define INTC_INTPR24 0x60
# define INTC_INTPR24_INTLEV_OFFSET 30
# define INTC_INTPR24_INTLEV_SIZE 2
# define INTC_INTPR24_OFFSET_OFFSET 0
# define INTC_INTPR24_OFFSET_SIZE 24
#define INTC_INTREQ24 0x160
# define INTC_INTREQ24_IREQUEST768_OFFSET 0
# define INTC_INTREQ24_IREQUEST768_SIZE 1
#define INTC_INTPR25 0x64
# define INTC_INTPR25_INTLEV_OFFSET 30
# define INTC_INTPR25_INTLEV_SIZE 2
# define INTC_INTPR25_OFFSET_OFFSET 0
# define INTC_INTPR25_OFFSET_SIZE 24
#define INTC_INTREQ25 0x164
# define INTC_INTREQ25_IREQUEST800_OFFSET 0
# define INTC_INTREQ25_IREQUEST800_SIZE 1
#define INTC_INTPR26 0x68
# define INTC_INTPR26_INTLEV_OFFSET 30
# define INTC_INTPR26_INTLEV_SIZE 2
# define INTC_INTPR26_OFFSET_OFFSET 0
# define INTC_INTPR26_OFFSET_SIZE 24
#define INTC_INTREQ26 0x168
# define INTC_INTREQ26_IREQUEST832_OFFSET 0
# define INTC_INTREQ26_IREQUEST832_SIZE 1
#define INTC_INTPR27 0x6c
# define INTC_INTPR27_INTLEV_OFFSET 30
# define INTC_INTPR27_INTLEV_SIZE 2
# define INTC_INTPR27_OFFSET_OFFSET 0
# define INTC_INTPR27_OFFSET_SIZE 24
#define INTC_INTREQ27 0x16c
# define INTC_INTREQ27_IREQUEST864_OFFSET 0
# define INTC_INTREQ27_IREQUEST864_SIZE 1
#define INTC_INTPR28 0x70
# define INTC_INTPR28_INTLEV_OFFSET 30
# define INTC_INTPR28_INTLEV_SIZE 2
# define INTC_INTPR28_OFFSET_OFFSET 0
# define INTC_INTPR28_OFFSET_SIZE 24
#define INTC_INTREQ28 0x170
# define INTC_INTREQ28_IREQUEST896_OFFSET 0
# define INTC_INTREQ28_IREQUEST896_SIZE 1
#define INTC_INTPR29 0x74
# define INTC_INTPR29_INTLEV_OFFSET 30
# define INTC_INTPR29_INTLEV_SIZE 2
# define INTC_INTPR29_OFFSET_OFFSET 0
# define INTC_INTPR29_OFFSET_SIZE 24
#define INTC_INTREQ29 0x174
# define INTC_INTREQ29_IREQUEST928_OFFSET 0
# define INTC_INTREQ29_IREQUEST928_SIZE 1
#define INTC_INTPR30 0x78
# define INTC_INTPR30_INTLEV_OFFSET 30
# define INTC_INTPR30_INTLEV_SIZE 2
# define INTC_INTPR30_OFFSET_OFFSET 0
# define INTC_INTPR30_OFFSET_SIZE 24
#define INTC_INTREQ30 0x178
# define INTC_INTREQ30_IREQUEST960_OFFSET 0
# define INTC_INTREQ30_IREQUEST960_SIZE 1
#define INTC_INTPR31 0x7c
# define INTC_INTPR31_INTLEV_OFFSET 30
# define INTC_INTPR31_INTLEV_SIZE 2
# define INTC_INTPR31_OFFSET_OFFSET 0
# define INTC_INTPR31_OFFSET_SIZE 24
#define INTC_INTREQ31 0x17c
# define INTC_INTREQ31_IREQUEST992_OFFSET 0
# define INTC_INTREQ31_IREQUEST992_SIZE 1
#define INTC_INTPR32 0x80
# define INTC_INTPR32_INTLEV_OFFSET 30
# define INTC_INTPR32_INTLEV_SIZE 2
# define INTC_INTPR32_OFFSET_OFFSET 0
# define INTC_INTPR32_OFFSET_SIZE 24
#define INTC_INTREQ32 0x180
# define INTC_INTREQ32_IREQUEST1024_OFFSET 0
# define INTC_INTREQ32_IREQUEST1024_SIZE 1
#define INTC_INTCAUSE0 0x20c
# define INTC_INTCAUSE0_CAUSEGRP_OFFSET 0
# define INTC_INTCAUSE0_CAUSEGRP_SIZE 6
#define INTC_INTCAUSE1 0x208
# define INTC_INTCAUSE1_CAUSEGRP_OFFSET 0
# define INTC_INTCAUSE1_CAUSEGRP_SIZE 6
#define INTC_INTCAUSE2 0x204
# define INTC_INTCAUSE2_CAUSEGRP_OFFSET 0
# define INTC_INTCAUSE2_CAUSEGRP_SIZE 6
#define INTC_INTCAUSE3 0x200
# define INTC_INTCAUSE3_CAUSEGRP_OFFSET 0
# define INTC_INTCAUSE3_CAUSEGRP_SIZE 6
#define INTC_BIT(name) (1 << INTC_##name##_OFFSET)
#define INTC_MKBF(name, value) (((value) & ((1 << INTC_##name##_SIZE) - 1)) << INTC_##name##_OFFSET)
#define INTC_GETBF(name, value) (((value) >> INTC_##name##_OFFSET) & ((1 << INTC_##name##_SIZE) - 1))
#define intc_readl(port,reg) readl((port)->regs + INTC_##reg)
#define intc_writel(port,reg,value) writel((value), (port)->regs + INTC_##reg)
#endif /* __ASM_AVR32_PERIHP_INTC_H__ */

View file

@ -0,0 +1,118 @@
/*
* Atmel PIO2 Port Multiplexer support
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/arch/portmux.h>
#include "pio.h"
#define MAX_NR_PIO_DEVICES 8
struct pio_device {
void __iomem *regs;
const struct platform_device *pdev;
struct clk *clk;
u32 alloc_mask;
char name[32];
};
static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
unsigned int function_id)
{
struct pio_device *pio;
u32 mask = 1 << pin_id;
BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES);
pio = &pio_dev[portmux_id];
if (function_id)
pio_writel(pio, BSR, mask);
else
pio_writel(pio, ASR, mask);
pio_writel(pio, PDR, mask);
}
static int __init pio_probe(struct platform_device *pdev)
{
struct pio_device *pio = NULL;
BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES);
pio = &pio_dev[pdev->id];
BUG_ON(!pio->regs);
/* TODO: Interrupts */
platform_set_drvdata(pdev, pio);
printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n",
pio->name, pio->regs, platform_get_irq(pdev, 0));
return 0;
}
static struct platform_driver pio_driver = {
.probe = pio_probe,
.driver = {
.name = "pio",
},
};
static int __init pio_init(void)
{
return platform_driver_register(&pio_driver);
}
subsys_initcall(pio_init);
void __init at32_init_pio(struct platform_device *pdev)
{
struct resource *regs;
struct pio_device *pio;
if (pdev->id > MAX_NR_PIO_DEVICES) {
dev_err(&pdev->dev, "only %d PIO devices supported\n",
MAX_NR_PIO_DEVICES);
return;
}
pio = &pio_dev[pdev->id];
snprintf(pio->name, sizeof(pio->name), "pio%d", pdev->id);
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_err(&pdev->dev, "no mmio resource defined\n");
return;
}
pio->clk = clk_get(&pdev->dev, "mck");
if (IS_ERR(pio->clk))
/*
* This is a fatal error, but if we continue we might
* be so lucky that we manage to initialize the
* console and display this message...
*/
dev_err(&pdev->dev, "no mck clock defined\n");
else
clk_enable(pio->clk);
pio->pdev = pdev;
pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
pio_writel(pio, ODR, ~0UL);
pio_writel(pio, PER, ~0UL);
}

View file

@ -0,0 +1,178 @@
/*
* Atmel PIO2 Port Multiplexer support
*
* Copyright (C) 2004-2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ARCH_AVR32_AT32AP_PIO_H__
#define __ARCH_AVR32_AT32AP_PIO_H__
/* PIO register offsets */
#define PIO_PER 0x0000
#define PIO_PDR 0x0004
#define PIO_PSR 0x0008
#define PIO_OER 0x0010
#define PIO_ODR 0x0014
#define PIO_OSR 0x0018
#define PIO_IFER 0x0020
#define PIO_IFDR 0x0024
#define PIO_ISFR 0x0028
#define PIO_SODR 0x0030
#define PIO_CODR 0x0034
#define PIO_ODSR 0x0038
#define PIO_PDSR 0x003c
#define PIO_IER 0x0040
#define PIO_IDR 0x0044
#define PIO_IMR 0x0048
#define PIO_ISR 0x004c
#define PIO_MDER 0x0050
#define PIO_MDDR 0x0054
#define PIO_MDSR 0x0058
#define PIO_PUDR 0x0060
#define PIO_PUER 0x0064
#define PIO_PUSR 0x0068
#define PIO_ASR 0x0070
#define PIO_BSR 0x0074
#define PIO_ABSR 0x0078
#define PIO_OWER 0x00a0
#define PIO_OWDR 0x00a4
#define PIO_OWSR 0x00a8
/* Bitfields in PER */
/* Bitfields in PDR */
/* Bitfields in PSR */
/* Bitfields in OER */
/* Bitfields in ODR */
/* Bitfields in OSR */
/* Bitfields in IFER */
/* Bitfields in IFDR */
/* Bitfields in ISFR */
/* Bitfields in SODR */
/* Bitfields in CODR */
/* Bitfields in ODSR */
/* Bitfields in PDSR */
/* Bitfields in IER */
/* Bitfields in IDR */
/* Bitfields in IMR */
/* Bitfields in ISR */
/* Bitfields in MDER */
/* Bitfields in MDDR */
/* Bitfields in MDSR */
/* Bitfields in PUDR */
/* Bitfields in PUER */
/* Bitfields in PUSR */
/* Bitfields in ASR */
/* Bitfields in BSR */
/* Bitfields in ABSR */
#define PIO_P0_OFFSET 0
#define PIO_P0_SIZE 1
#define PIO_P1_OFFSET 1
#define PIO_P1_SIZE 1
#define PIO_P2_OFFSET 2
#define PIO_P2_SIZE 1
#define PIO_P3_OFFSET 3
#define PIO_P3_SIZE 1
#define PIO_P4_OFFSET 4
#define PIO_P4_SIZE 1
#define PIO_P5_OFFSET 5
#define PIO_P5_SIZE 1
#define PIO_P6_OFFSET 6
#define PIO_P6_SIZE 1
#define PIO_P7_OFFSET 7
#define PIO_P7_SIZE 1
#define PIO_P8_OFFSET 8
#define PIO_P8_SIZE 1
#define PIO_P9_OFFSET 9
#define PIO_P9_SIZE 1
#define PIO_P10_OFFSET 10
#define PIO_P10_SIZE 1
#define PIO_P11_OFFSET 11
#define PIO_P11_SIZE 1
#define PIO_P12_OFFSET 12
#define PIO_P12_SIZE 1
#define PIO_P13_OFFSET 13
#define PIO_P13_SIZE 1
#define PIO_P14_OFFSET 14
#define PIO_P14_SIZE 1
#define PIO_P15_OFFSET 15
#define PIO_P15_SIZE 1
#define PIO_P16_OFFSET 16
#define PIO_P16_SIZE 1
#define PIO_P17_OFFSET 17
#define PIO_P17_SIZE 1
#define PIO_P18_OFFSET 18
#define PIO_P18_SIZE 1
#define PIO_P19_OFFSET 19
#define PIO_P19_SIZE 1
#define PIO_P20_OFFSET 20
#define PIO_P20_SIZE 1
#define PIO_P21_OFFSET 21
#define PIO_P21_SIZE 1
#define PIO_P22_OFFSET 22
#define PIO_P22_SIZE 1
#define PIO_P23_OFFSET 23
#define PIO_P23_SIZE 1
#define PIO_P24_OFFSET 24
#define PIO_P24_SIZE 1
#define PIO_P25_OFFSET 25
#define PIO_P25_SIZE 1
#define PIO_P26_OFFSET 26
#define PIO_P26_SIZE 1
#define PIO_P27_OFFSET 27
#define PIO_P27_SIZE 1
#define PIO_P28_OFFSET 28
#define PIO_P28_SIZE 1
#define PIO_P29_OFFSET 29
#define PIO_P29_SIZE 1
#define PIO_P30_OFFSET 30
#define PIO_P30_SIZE 1
#define PIO_P31_OFFSET 31
#define PIO_P31_SIZE 1
/* Bitfields in OWER */
/* Bitfields in OWDR */
/* Bitfields in OWSR */
/* Bit manipulation macros */
#define PIO_BIT(name) (1 << PIO_##name##_OFFSET)
#define PIO_BF(name,value) (((value) & ((1 << PIO_##name##_SIZE) - 1)) << PIO_##name##_OFFSET)
#define PIO_BFEXT(name,value) (((value) >> PIO_##name##_OFFSET) & ((1 << PIO_##name##_SIZE) - 1))
#define PIO_BFINS(name,value,old) (((old) & ~(((1 << PIO_##name##_SIZE) - 1) << PIO_##name##_OFFSET)) | PIO_BF(name,value))
/* Register access macros */
#define pio_readl(port,reg) readl((port)->regs + PIO_##reg)
#define pio_writel(port,reg,value) writel((value), (port)->regs + PIO_##reg)
void at32_init_pio(struct platform_device *pdev);
#endif /* __ARCH_AVR32_AT32AP_PIO_H__ */

289
arch/avr32/mach-at32ap/sm.c Normal file
View file

@ -0,0 +1,289 @@
/*
* System Manager driver for AT32AP CPUs
*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <linux/spinlock.h>
#include <asm/intc.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/sm.h>
#include "sm.h"
#define SM_EIM_IRQ_RESOURCE 1
#define SM_PM_IRQ_RESOURCE 2
#define SM_RTC_IRQ_RESOURCE 3
#define to_eim(irqc) container_of(irqc, struct at32_sm, irqc)
struct at32_sm system_manager;
int __init at32_sm_init(void)
{
struct resource *regs;
struct at32_sm *sm = &system_manager;
int ret = -ENXIO;
regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
if (!regs)
goto fail;
spin_lock_init(&sm->lock);
sm->pdev = &at32_sm_device;
ret = -ENOMEM;
sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!sm->regs)
goto fail;
return 0;
fail:
printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
return ret;
}
/*
* External Interrupt Module (EIM).
*
* EIM gets level- or edge-triggered interrupts of either polarity
* from the outside and converts it to active-high level-triggered
* interrupts that the internal interrupt controller can handle. EIM
* also provides masking/unmasking of interrupts, as well as
* acknowledging of edge-triggered interrupts.
*/
static irqreturn_t spurious_eim_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
printk(KERN_WARNING "Spurious EIM interrupt %d\n", irq);
disable_irq(irq);
return IRQ_NONE;
}
static struct irqaction eim_spurious_action = {
.handler = spurious_eim_interrupt,
};
static irqreturn_t eim_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct irq_controller * irqc = dev_id;
struct at32_sm *sm = to_eim(irqc);
unsigned long pending;
/*
* No need to disable interrupts globally. The interrupt
* level relevant to this group must be masked all the time,
* so we know that this particular EIM instance will not be
* re-entered.
*/
spin_lock(&sm->lock);
pending = intc_get_pending(sm->irqc.irq_group);
if (unlikely(!pending)) {
printk(KERN_ERR "EIM (group %u): No interrupts pending!\n",
sm->irqc.irq_group);
goto unlock;
}
do {
struct irqaction *action;
unsigned int i;
i = fls(pending) - 1;
pending &= ~(1 << i);
action = sm->action[i];
/* Acknowledge the interrupt */
sm_writel(sm, EIM_ICR, 1 << i);
spin_unlock(&sm->lock);
if (action->flags & SA_INTERRUPT)
local_irq_disable();
action->handler(sm->irqc.first_irq + i, action->dev_id, regs);
local_irq_enable();
spin_lock(&sm->lock);
if (action->flags & SA_SAMPLE_RANDOM)
add_interrupt_randomness(sm->irqc.first_irq + i);
} while (pending);
unlock:
spin_unlock(&sm->lock);
return IRQ_HANDLED;
}
static void eim_mask(struct irq_controller *irqc, unsigned int irq)
{
struct at32_sm *sm = to_eim(irqc);
unsigned int i;
i = irq - sm->irqc.first_irq;
sm_writel(sm, EIM_IDR, 1 << i);
}
static void eim_unmask(struct irq_controller *irqc, unsigned int irq)
{
struct at32_sm *sm = to_eim(irqc);
unsigned int i;
i = irq - sm->irqc.first_irq;
sm_writel(sm, EIM_IER, 1 << i);
}
static int eim_setup(struct irq_controller *irqc, unsigned int irq,
struct irqaction *action)
{
struct at32_sm *sm = to_eim(irqc);
sm->action[irq - sm->irqc.first_irq] = action;
/* Acknowledge earlier interrupts */
sm_writel(sm, EIM_ICR, (1<<(irq - sm->irqc.first_irq)));
eim_unmask(irqc, irq);
return 0;
}
static void eim_free(struct irq_controller *irqc, unsigned int irq,
void *dev)
{
struct at32_sm *sm = to_eim(irqc);
eim_mask(irqc, irq);
sm->action[irq - sm->irqc.first_irq] = &eim_spurious_action;
}
static int eim_set_type(struct irq_controller *irqc, unsigned int irq,
unsigned int type)
{
struct at32_sm *sm = to_eim(irqc);
unsigned long flags;
u32 value, pattern;
spin_lock_irqsave(&sm->lock, flags);
pattern = 1 << (irq - sm->irqc.first_irq);
value = sm_readl(sm, EIM_MODE);
if (type & IRQ_TYPE_LEVEL)
value |= pattern;
else
value &= ~pattern;
sm_writel(sm, EIM_MODE, value);
value = sm_readl(sm, EIM_EDGE);
if (type & IRQ_EDGE_RISING)
value |= pattern;
else
value &= ~pattern;
sm_writel(sm, EIM_EDGE, value);
value = sm_readl(sm, EIM_LEVEL);
if (type & IRQ_LEVEL_HIGH)
value |= pattern;
else
value &= ~pattern;
sm_writel(sm, EIM_LEVEL, value);
spin_unlock_irqrestore(&sm->lock, flags);
return 0;
}
static unsigned int eim_get_type(struct irq_controller *irqc,
unsigned int irq)
{
struct at32_sm *sm = to_eim(irqc);
unsigned long flags;
unsigned int type = 0;
u32 mode, edge, level, pattern;
pattern = 1 << (irq - sm->irqc.first_irq);
spin_lock_irqsave(&sm->lock, flags);
mode = sm_readl(sm, EIM_MODE);
edge = sm_readl(sm, EIM_EDGE);
level = sm_readl(sm, EIM_LEVEL);
spin_unlock_irqrestore(&sm->lock, flags);
if (mode & pattern)
type |= IRQ_TYPE_LEVEL;
if (edge & pattern)
type |= IRQ_EDGE_RISING;
if (level & pattern)
type |= IRQ_LEVEL_HIGH;
return type;
}
static struct irq_controller_class eim_irq_class = {
.typename = "EIM",
.handle = eim_handle_irq,
.setup = eim_setup,
.free = eim_free,
.mask = eim_mask,
.unmask = eim_unmask,
.set_type = eim_set_type,
.get_type = eim_get_type,
};
static int __init eim_init(void)
{
struct at32_sm *sm = &system_manager;
unsigned int i;
u32 pattern;
int ret;
/*
* The EIM is really the same module as SM, so register
* mapping, etc. has been taken care of already.
*/
/*
* Find out how many interrupt lines that are actually
* implemented in hardware.
*/
sm_writel(sm, EIM_IDR, ~0UL);
sm_writel(sm, EIM_MODE, ~0UL);
pattern = sm_readl(sm, EIM_MODE);
sm->irqc.nr_irqs = fls(pattern);
ret = -ENOMEM;
sm->action = kmalloc(sizeof(*sm->action) * sm->irqc.nr_irqs,
GFP_KERNEL);
if (!sm->action)
goto out;
for (i = 0; i < sm->irqc.nr_irqs; i++)
sm->action[i] = &eim_spurious_action;
spin_lock_init(&sm->lock);
sm->irqc.irq_group = sm->pdev->resource[SM_EIM_IRQ_RESOURCE].start;
sm->irqc.class = &eim_irq_class;
ret = intc_register_controller(&sm->irqc);
if (ret < 0)
goto out_free_actions;
printk("EIM: External Interrupt Module at 0x%p, IRQ group %u\n",
sm->regs, sm->irqc.irq_group);
printk("EIM: Handling %u external IRQs, starting with IRQ%u\n",
sm->irqc.nr_irqs, sm->irqc.first_irq);
return 0;
out_free_actions:
kfree(sm->action);
out:
return ret;
}
arch_initcall(eim_init);

240
arch/avr32/mach-at32ap/sm.h Normal file
View file

@ -0,0 +1,240 @@
/*
* Register definitions for SM
*
* System Manager
*/
#ifndef __ASM_AVR32_SM_H__
#define __ASM_AVR32_SM_H__
/* SM register offsets */
#define SM_PM_MCCTRL 0x0000
#define SM_PM_CKSEL 0x0004
#define SM_PM_CPU_MASK 0x0008
#define SM_PM_HSB_MASK 0x000c
#define SM_PM_PBA_MASK 0x0010
#define SM_PM_PBB_MASK 0x0014
#define SM_PM_PLL0 0x0020
#define SM_PM_PLL1 0x0024
#define SM_PM_VCTRL 0x0030
#define SM_PM_VMREF 0x0034
#define SM_PM_VMV 0x0038
#define SM_PM_IER 0x0040
#define SM_PM_IDR 0x0044
#define SM_PM_IMR 0x0048
#define SM_PM_ISR 0x004c
#define SM_PM_ICR 0x0050
#define SM_PM_GCCTRL 0x0060
#define SM_RTC_CTRL 0x0080
#define SM_RTC_VAL 0x0084
#define SM_RTC_TOP 0x0088
#define SM_RTC_IER 0x0090
#define SM_RTC_IDR 0x0094
#define SM_RTC_IMR 0x0098
#define SM_RTC_ISR 0x009c
#define SM_RTC_ICR 0x00a0
#define SM_WDT_CTRL 0x00b0
#define SM_WDT_CLR 0x00b4
#define SM_WDT_EXT 0x00b8
#define SM_RC_RCAUSE 0x00c0
#define SM_EIM_IER 0x0100
#define SM_EIM_IDR 0x0104
#define SM_EIM_IMR 0x0108
#define SM_EIM_ISR 0x010c
#define SM_EIM_ICR 0x0110
#define SM_EIM_MODE 0x0114
#define SM_EIM_EDGE 0x0118
#define SM_EIM_LEVEL 0x011c
#define SM_EIM_TEST 0x0120
#define SM_EIM_NMIC 0x0124
/* Bitfields in PM_MCCTRL */
/* Bitfields in PM_CKSEL */
#define SM_CPUSEL_OFFSET 0
#define SM_CPUSEL_SIZE 3
#define SM_CPUDIV_OFFSET 7
#define SM_CPUDIV_SIZE 1
#define SM_HSBSEL_OFFSET 8
#define SM_HSBSEL_SIZE 3
#define SM_HSBDIV_OFFSET 15
#define SM_HSBDIV_SIZE 1
#define SM_PBASEL_OFFSET 16
#define SM_PBASEL_SIZE 3
#define SM_PBADIV_OFFSET 23
#define SM_PBADIV_SIZE 1
#define SM_PBBSEL_OFFSET 24
#define SM_PBBSEL_SIZE 3
#define SM_PBBDIV_OFFSET 31
#define SM_PBBDIV_SIZE 1
/* Bitfields in PM_CPU_MASK */
/* Bitfields in PM_HSB_MASK */
/* Bitfields in PM_PBA_MASK */
/* Bitfields in PM_PBB_MASK */
/* Bitfields in PM_PLL0 */
#define SM_PLLEN_OFFSET 0
#define SM_PLLEN_SIZE 1
#define SM_PLLOSC_OFFSET 1
#define SM_PLLOSC_SIZE 1
#define SM_PLLOPT_OFFSET 2
#define SM_PLLOPT_SIZE 3
#define SM_PLLDIV_OFFSET 8
#define SM_PLLDIV_SIZE 8
#define SM_PLLMUL_OFFSET 16
#define SM_PLLMUL_SIZE 8
#define SM_PLLCOUNT_OFFSET 24
#define SM_PLLCOUNT_SIZE 6
#define SM_PLLTEST_OFFSET 31
#define SM_PLLTEST_SIZE 1
/* Bitfields in PM_PLL1 */
/* Bitfields in PM_VCTRL */
#define SM_VAUTO_OFFSET 0
#define SM_VAUTO_SIZE 1
#define SM_PM_VCTRL_VAL_OFFSET 8
#define SM_PM_VCTRL_VAL_SIZE 7
/* Bitfields in PM_VMREF */
#define SM_REFSEL_OFFSET 0
#define SM_REFSEL_SIZE 4
/* Bitfields in PM_VMV */
#define SM_PM_VMV_VAL_OFFSET 0
#define SM_PM_VMV_VAL_SIZE 8
/* Bitfields in PM_IER */
/* Bitfields in PM_IDR */
/* Bitfields in PM_IMR */
/* Bitfields in PM_ISR */
/* Bitfields in PM_ICR */
#define SM_LOCK0_OFFSET 0
#define SM_LOCK0_SIZE 1
#define SM_LOCK1_OFFSET 1
#define SM_LOCK1_SIZE 1
#define SM_WAKE_OFFSET 2
#define SM_WAKE_SIZE 1
#define SM_VOK_OFFSET 3
#define SM_VOK_SIZE 1
#define SM_VMRDY_OFFSET 4
#define SM_VMRDY_SIZE 1
#define SM_CKRDY_OFFSET 5
#define SM_CKRDY_SIZE 1
/* Bitfields in PM_GCCTRL */
#define SM_OSCSEL_OFFSET 0
#define SM_OSCSEL_SIZE 1
#define SM_PLLSEL_OFFSET 1
#define SM_PLLSEL_SIZE 1
#define SM_CEN_OFFSET 2
#define SM_CEN_SIZE 1
#define SM_CPC_OFFSET 3
#define SM_CPC_SIZE 1
#define SM_DIVEN_OFFSET 4
#define SM_DIVEN_SIZE 1
#define SM_DIV_OFFSET 8
#define SM_DIV_SIZE 8
/* Bitfields in RTC_CTRL */
#define SM_PCLR_OFFSET 1
#define SM_PCLR_SIZE 1
#define SM_TOPEN_OFFSET 2
#define SM_TOPEN_SIZE 1
#define SM_CLKEN_OFFSET 3
#define SM_CLKEN_SIZE 1
#define SM_PSEL_OFFSET 8
#define SM_PSEL_SIZE 16
/* Bitfields in RTC_VAL */
#define SM_RTC_VAL_VAL_OFFSET 0
#define SM_RTC_VAL_VAL_SIZE 31
/* Bitfields in RTC_TOP */
#define SM_RTC_TOP_VAL_OFFSET 0
#define SM_RTC_TOP_VAL_SIZE 32
/* Bitfields in RTC_IER */
/* Bitfields in RTC_IDR */
/* Bitfields in RTC_IMR */
/* Bitfields in RTC_ISR */
/* Bitfields in RTC_ICR */
#define SM_TOPI_OFFSET 0
#define SM_TOPI_SIZE 1
/* Bitfields in WDT_CTRL */
#define SM_KEY_OFFSET 24
#define SM_KEY_SIZE 8
/* Bitfields in WDT_CLR */
/* Bitfields in WDT_EXT */
/* Bitfields in RC_RCAUSE */
#define SM_POR_OFFSET 0
#define SM_POR_SIZE 1
#define SM_BOD_OFFSET 1
#define SM_BOD_SIZE 1
#define SM_EXT_OFFSET 2
#define SM_EXT_SIZE 1
#define SM_WDT_OFFSET 3
#define SM_WDT_SIZE 1
#define SM_NTAE_OFFSET 4
#define SM_NTAE_SIZE 1
#define SM_SERP_OFFSET 5
#define SM_SERP_SIZE 1
/* Bitfields in EIM_IER */
/* Bitfields in EIM_IDR */
/* Bitfields in EIM_IMR */
/* Bitfields in EIM_ISR */
/* Bitfields in EIM_ICR */
/* Bitfields in EIM_MODE */
/* Bitfields in EIM_EDGE */
#define SM_INT0_OFFSET 0
#define SM_INT0_SIZE 1
#define SM_INT1_OFFSET 1
#define SM_INT1_SIZE 1
#define SM_INT2_OFFSET 2
#define SM_INT2_SIZE 1
#define SM_INT3_OFFSET 3
#define SM_INT3_SIZE 1
/* Bitfields in EIM_LEVEL */
/* Bitfields in EIM_TEST */
#define SM_TESTEN_OFFSET 31
#define SM_TESTEN_SIZE 1
/* Bitfields in EIM_NMIC */
#define SM_EN_OFFSET 0
#define SM_EN_SIZE 1
/* Bit manipulation macros */
#define SM_BIT(name) (1 << SM_##name##_OFFSET)
#define SM_BF(name,value) (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET)
#define SM_BFEXT(name,value) (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1))
#define SM_BFINS(name,value,old) (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value))
/* Register access macros */
#define sm_readl(port,reg) readl((port)->regs + SM_##reg)
#define sm_writel(port,reg,value) writel((value), (port)->regs + SM_##reg)
#endif /* __ASM_AVR32_SM_H__ */

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