Merge branch 'master' into gfs2
This commit is contained in:
commit
185a257f2f
1941 changed files with 87478 additions and 33031 deletions
|
@ -1,13 +1,12 @@
|
||||||
What: devfs
|
What: devfs
|
||||||
Date: July 2005
|
Date: July 2005 (scheduled), finally removed in kernel v2.6.18
|
||||||
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
Description:
|
Description:
|
||||||
devfs has been unmaintained for a number of years, has unfixable
|
devfs has been unmaintained for a number of years, has unfixable
|
||||||
races, contains a naming policy within the kernel that is
|
races, contains a naming policy within the kernel that is
|
||||||
against the LSB, and can be replaced by using udev.
|
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
|
along with the the assorted devfs function calls throughout the
|
||||||
kernel tree.
|
kernel tree.
|
||||||
|
|
||||||
Users:
|
Users:
|
||||||
|
|
88
Documentation/ABI/testing/sysfs-power
Normal file
88
Documentation/ABI/testing/sysfs-power
Normal 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.
|
|
@ -43,59 +43,52 @@
|
||||||
|
|
||||||
<para>A Universal Serial Bus (USB) is used to connect a host,
|
<para>A Universal Serial Bus (USB) is used to connect a host,
|
||||||
such as a PC or workstation, to a number of peripheral
|
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
|
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
|
Modern PCs support several such trees of USB devices, usually
|
||||||
one USB 2.0 tree (480 Mbit/sec each) with
|
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
|
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".
|
connect a USB 1.1 device directly to the machine's "root hub".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>That master/slave asymmetry was designed in part for
|
<para>That master/slave asymmetry was designed-in for a number of
|
||||||
ease of use. It is not physically possible to assemble
|
reasons, one being ease of use. It is not physically possible to
|
||||||
(legal) USB cables incorrectly: all upstream "to-the-host"
|
assemble (legal) USB cables incorrectly: all upstream "to the host"
|
||||||
connectors are the rectangular type, matching the sockets on
|
connectors are the rectangular type (matching the sockets on
|
||||||
root hubs, and the downstream type are the squarish type
|
root hubs), and all downstream connectors are the squarish type
|
||||||
(or they are built in to the peripheral).
|
(or they are built into the peripheral).
|
||||||
Software doesn't need to deal with distributed autoconfiguration
|
Also, the host software doesn't need to deal with distributed
|
||||||
since the pre-designated master node manages all that.
|
auto-configuration since the pre-designated master node manages all that.
|
||||||
At the electrical level, bus protocol overhead is reduced by
|
And finally, at the electrical level, bus protocol overhead is reduced by
|
||||||
eliminating arbitration and moving scheduling into host software.
|
eliminating arbitration and moving scheduling into the host software.
|
||||||
</para>
|
</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
|
as USB 1.1 (with improvements in hub specification and
|
||||||
support for interrupt-out transfers) in September 1998.
|
support for interrupt-out transfers) in September 1998.
|
||||||
USB 2.0 was released in April 2000, including high speed
|
USB 2.0 was released in April 2000, adding high-speed
|
||||||
transfers and transaction translating hubs (used for USB 1.1
|
transfers and transaction-translating hubs (used for USB 1.1
|
||||||
and 1.0 backward compatibility).
|
and 1.0 backward compatibility).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>USB support was added to Linux early in the 2.2 kernel series
|
<para>Kernel developers added USB support to Linux early in the 2.2 kernel
|
||||||
shortly before the 2.3 development forked off. Updates
|
series, shortly before 2.3 development forked. Updates from 2.3 were
|
||||||
from 2.3 were regularly folded back into 2.2 releases, bringing
|
regularly folded back into 2.2 releases, which improved reliability and
|
||||||
new features such as <filename>/sbin/hotplug</filename> support,
|
brought <filename>/sbin/hotplug</filename> support as well more drivers.
|
||||||
more drivers, and more robustness.
|
Such improvements were continued in the 2.5 kernel series, where they added
|
||||||
The 2.5 kernel series continued such improvements, and also
|
USB 2.0 support, improved performance, and made the host controller drivers
|
||||||
worked on USB 2.0 support,
|
(HCDs) more consistent. They also simplified the API (to make bugs less
|
||||||
higher performance,
|
likely) and added internal "kerneldoc" documentation.
|
||||||
better consistency between host controller drivers,
|
|
||||||
API simplification (to make bugs less likely),
|
|
||||||
and providing internal "kerneldoc" documentation.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>Linux can run inside USB devices as well as on
|
<para>Linux can run inside USB devices as well as on
|
||||||
the hosts that control the devices.
|
the hosts that control the devices.
|
||||||
Because the Linux 2.x USB support evolved to support mass market
|
But USB device drivers running inside those peripherals
|
||||||
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
|
|
||||||
don't do the same things as the ones running inside hosts,
|
don't do the same things as the ones running inside hosts,
|
||||||
and so they've been given a different name:
|
so they've been given a different name:
|
||||||
they're called <emphasis>gadget drivers</emphasis>.
|
<emphasis>gadget drivers</emphasis>.
|
||||||
This document does not present gadget drivers.
|
This document does not cover gadget drivers.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
@ -103,17 +96,14 @@
|
||||||
<chapter id="host">
|
<chapter id="host">
|
||||||
<title>USB Host-Side API Model</title>
|
<title>USB Host-Side API Model</title>
|
||||||
|
|
||||||
<para>Within the kernel,
|
<para>Host-side drivers for USB devices talk to the "usbcore" APIs.
|
||||||
host-side drivers for USB devices talk to the "usbcore" APIs.
|
There are two. One is intended for
|
||||||
There are two types of public "usbcore" APIs, targetted at two different
|
<emphasis>general-purpose</emphasis> drivers (exposed through
|
||||||
layers of USB driver. Those are
|
driver frameworks), and the other is for drivers that are
|
||||||
<emphasis>general purpose</emphasis> drivers, exposed through
|
<emphasis>part of the core</emphasis>.
|
||||||
driver frameworks such as block, character, or network devices;
|
Such core drivers include the <emphasis>hub</emphasis> driver
|
||||||
and drivers that are <emphasis>part of the core</emphasis>,
|
(which manages trees of USB devices) and several different kinds
|
||||||
which are involved in managing a USB bus.
|
of <emphasis>host controller drivers</emphasis>,
|
||||||
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>,
|
|
||||||
which control individual busses.
|
which control individual busses.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -122,21 +112,21 @@
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
<listitem><para>USB supports four kinds of data transfer
|
<listitem><para>USB supports four kinds of data transfers
|
||||||
(control, bulk, interrupt, and isochronous). Two transfer
|
(control, bulk, interrupt, and isochronous). Two of them (control
|
||||||
types use bandwidth as it's available (control and bulk),
|
and bulk) use bandwidth as it's available,
|
||||||
while the other two types of transfer (interrupt and isochronous)
|
while the other two (interrupt and isochronous)
|
||||||
are scheduled to provide guaranteed bandwidth.
|
are scheduled to provide guaranteed bandwidth.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>The device description model includes one or more
|
<listitem><para>The device description model includes one or more
|
||||||
"configurations" per device, only one of which is active at a time.
|
"configurations" per device, only one of which is active at a time.
|
||||||
Devices that are capable of high speed operation must also support
|
Devices that are capable of high-speed operation must also support
|
||||||
full speed configurations, along with a way to ask about the
|
full-speed configurations, along with a way to ask about the
|
||||||
"other speed" configurations that might be used.
|
"other speed" configurations which might be used.
|
||||||
</para></listitem>
|
</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
|
of which may have "alternate settings". Interfaces may be
|
||||||
standardized by USB "Class" specifications, or may be specific to
|
standardized by USB "Class" specifications, or may be specific to
|
||||||
a vendor or device.</para>
|
a vendor or device.</para>
|
||||||
|
@ -162,7 +152,7 @@
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>The Linux USB API supports synchronous calls for
|
<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,
|
It also supports asynchnous calls for all kinds of data transfer,
|
||||||
using request structures called "URBs" (USB Request Blocks).
|
using request structures called "URBs" (USB Request Blocks).
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
@ -463,14 +453,25 @@
|
||||||
file in your Linux kernel sources.
|
file in your Linux kernel sources.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>Otherwise the main use for this file from programs
|
<para>This file, in combination with the poll() system call, can
|
||||||
is to poll() it to get notifications of usb devices
|
also be used to detect when devices are added or removed:
|
||||||
as they're plugged or unplugged.
|
<programlisting>int fd;
|
||||||
To see what changed, you'd need to read the file and
|
struct pollfd pfd;
|
||||||
compare "before" and "after" contents, scan the filesystem,
|
|
||||||
or see its hotplug event.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
fd = open("/proc/bus/usb/devices", O_RDONLY);
|
||||||
|
pfd = { fd, POLLIN, 0 };
|
||||||
|
for (;;) {
|
||||||
|
/* The first time through, this call will return immediately. */
|
||||||
|
poll(&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>
|
||||||
|
|
||||||
<sect1>
|
<sect1>
|
||||||
|
|
|
@ -358,7 +358,8 @@ Here is a list of some of the different kernel trees available:
|
||||||
quilt trees:
|
quilt trees:
|
||||||
- USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de>
|
- USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
|
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
|
Bug Reporting
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -2543,6 +2543,9 @@ Your cooperation is appreciated.
|
||||||
64 = /dev/usb/rio500 Diamond Rio 500
|
64 = /dev/usb/rio500 Diamond Rio 500
|
||||||
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
|
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
|
||||||
66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
|
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
|
96 = /dev/usb/hiddev0 1st USB HID device
|
||||||
...
|
...
|
||||||
111 = /dev/usb/hiddev15 16th USB HID device
|
111 = /dev/usb/hiddev15 16th USB HID device
|
||||||
|
|
|
@ -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)
|
What: RAW driver (CONFIG_RAW_DRIVER)
|
||||||
When: December 2005
|
When: December 2005
|
||||||
Why: declared obsolete since kernel 2.6.3
|
Why: declared obsolete since kernel 2.6.3
|
||||||
|
@ -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])
|
What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
|
||||||
When: November 2005
|
When: November 2005
|
||||||
Files: drivers/pcmcia/: pcmcia_ioctl.c
|
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
|
What: Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board
|
||||||
When: September 2006
|
When: September 2006
|
||||||
Why: Does no longer build since quite some time, and was never popular,
|
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.
|
It is not clear if anyone is still using it.
|
||||||
Who: Stephen Hemminger <shemminger@osdl.org>
|
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>
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
|
|
@ -1124,11 +1124,15 @@ debugging information is displayed on console.
|
||||||
NMI switch that most IA32 servers have fires unknown NMI up, for example.
|
NMI switch that most IA32 servers have fires unknown NMI up, for example.
|
||||||
If a system hangs up, try pressing the NMI switch.
|
If a system hangs up, try pressing the NMI switch.
|
||||||
|
|
||||||
[NOTE]
|
nmi_watchdog
|
||||||
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
|
Enables/Disables the NMI watchdog on x86 systems. When the value is non-zero
|
||||||
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
|
2.4 /proc/sys/vm - The virtual memory subsystem
|
||||||
|
|
|
@ -7,9 +7,12 @@ Supported adapters:
|
||||||
* VIA Technologies, Inc. VT82C686A/B
|
* VIA Technologies, Inc. VT82C686A/B
|
||||||
Datasheet: Sometimes available at the VIA website
|
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
|
Datasheet: available on request from VIA
|
||||||
|
|
||||||
|
* VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251
|
||||||
|
Datasheet: available on request and under NDA from VIA
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
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:8235 (VT8231 function 4)
|
||||||
device 1106:3177 (VT8235)
|
device 1106:3177 (VT8235)
|
||||||
device 1106:3227 (VT8237R)
|
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
|
If none of these show up, you should look in the BIOS for settings like
|
||||||
enable ACPI / SMBus or even USB.
|
enable ACPI / SMBus or even USB.
|
||||||
|
|
|
@ -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
|
types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
|
||||||
(r/w) word data.
|
(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
|
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
|
quick commands to one address; it will respond to the other commands (also
|
||||||
to all addresses) by reading from or writing to an array in memory. It will
|
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.
|
also spam the kernel logs for every command it handles.
|
||||||
|
|
||||||
A pointer register with auto-increment is implemented for all byte
|
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
|
3. load the target sensors chip driver module
|
||||||
4. observe its behavior in the kernel log
|
4. observe its behavior in the kernel log
|
||||||
|
|
||||||
|
PARAMETERS:
|
||||||
|
|
||||||
|
int chip_addr:
|
||||||
|
The SMBus address to emulate a chip at.
|
||||||
|
|
||||||
CAVEATS:
|
CAVEATS:
|
||||||
|
|
||||||
There are independent arrays for byte/data and word/data commands. Depending
|
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
|
chips) this module will not work well - although it could be extended to
|
||||||
support that pretty easily.
|
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
|
If you spam it hard enough, printk can be lossy. This module really wants
|
||||||
something like relayfs.
|
something like relayfs.
|
||||||
|
|
||||||
|
|
|
@ -421,6 +421,11 @@ more details, with real examples.
|
||||||
The second argument is optional, and if supplied will be used
|
The second argument is optional, and if supplied will be used
|
||||||
if first argument is not supported.
|
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
|
||||||
cc-option is used to check if $(CC) supports a given option, and not
|
cc-option is used to check if $(CC) supports a given option, and not
|
||||||
supported to use an optional second option.
|
supported to use an optional second option.
|
||||||
|
|
|
@ -573,8 +573,6 @@ running once the system is up.
|
||||||
gscd= [HW,CD]
|
gscd= [HW,CD]
|
||||||
Format: <io>
|
Format: <io>
|
||||||
|
|
||||||
gt96100eth= [NET] MIPS GT96100 Advanced Communication Controller
|
|
||||||
|
|
||||||
gus= [HW,OSS]
|
gus= [HW,OSS]
|
||||||
Format: <io>,<irq>,<dma>,<dma16>
|
Format: <io>,<irq>,<dma>,<dma16>
|
||||||
|
|
||||||
|
@ -1240,7 +1238,11 @@ running once the system is up.
|
||||||
bootloader. This is currently used on
|
bootloader. This is currently used on
|
||||||
IXP2000 systems where the bus has to be
|
IXP2000 systems where the bus has to be
|
||||||
configured a certain way for adjunct CPUs.
|
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
|
pcmv= [HW,PCMCIA] BadgePAD 4
|
||||||
|
|
||||||
pd. [PARIDE]
|
pd. [PARIDE]
|
||||||
|
@ -1363,6 +1365,14 @@ running once the system is up.
|
||||||
|
|
||||||
reserve= [KNL,BUGS] Force the kernel to ignore some iomem area
|
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]
|
resume= [SWSUSP]
|
||||||
Specify the partition device for software suspend
|
Specify the partition device for software suspend
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,17 @@ or, for backwards compatibility, the option value. E.g.,
|
||||||
arp_interval
|
arp_interval
|
||||||
|
|
||||||
Specifies the ARP link monitoring frequency in milliseconds.
|
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
|
If ARP monitoring is used in an etherchannel compatible mode
|
||||||
(modes 0 and 2), the switch should be configured in a mode
|
(modes 0 and 2), the switch should be configured in a mode
|
||||||
that evenly distributes packets across all links. If the
|
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
|
maximum number of targets that can be specified is 16. The
|
||||||
default value is no IP addresses.
|
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
|
downdelay
|
||||||
|
|
||||||
Specifies the time, in milliseconds, to wait before disabling
|
Specifies the time, in milliseconds, to wait before disabling
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
DCCP protocol
|
DCCP protocol
|
||||||
============
|
============
|
||||||
|
|
||||||
Last updated: 10 November 2005
|
|
||||||
|
|
||||||
Contents
|
Contents
|
||||||
========
|
========
|
||||||
|
@ -42,8 +41,11 @@ Socket options
|
||||||
DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
|
DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
|
||||||
calculations.
|
calculations.
|
||||||
|
|
||||||
DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the
|
DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
|
||||||
specification. If you don't set it you will get EPROTO.
|
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
|
Notes
|
||||||
=====
|
=====
|
||||||
|
|
|
@ -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
|
(*) A list of all the mappings on the system is visible through /proc/maps in
|
||||||
no-MMU mode.
|
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
|
(*) Supplying MAP_FIXED or a requesting a particular mapping address will
|
||||||
result in an error.
|
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
|
error will result if they don't. This is most likely to be encountered
|
||||||
with character device files, pipes, fifos and sockets.
|
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
|
PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT
|
||||||
============================================
|
============================================
|
||||||
|
|
253
Documentation/pcieaer-howto.txt
Normal file
253
Documentation/pcieaer-howto.txt
Normal 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.
|
||||||
|
|
|
@ -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
|
Two Models for Device Power Management
|
||||||
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
|
Drivers will use one or both of these models to put devices into low-power
|
||||||
a low-power state while the system is running (and independently of
|
states:
|
||||||
any other power management activity).
|
|
||||||
|
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 {
|
struct bus_type {
|
||||||
...
|
...
|
||||||
int (*suspend)(struct device * dev, pm_message_t state);
|
int (*suspend)(struct device *dev, pm_message_t state);
|
||||||
int (*resume)(struct device * dev);
|
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
|
Bus drivers implement those methods as appropriate for the hardware and
|
||||||
the call into a bus-specific request and forwarding the call to the
|
the drivers using it; PCI works differently from USB, and so on. Not many
|
||||||
bus-specific drivers. For example, PCI drivers implement suspend() and
|
people write bus drivers; most driver code is a "device driver" that
|
||||||
resume() methods in struct pci_driver. The PCI core is simply
|
builds on top of bus-specific framework code.
|
||||||
responsible for translating the pointers to PCI-specific ones and
|
|
||||||
calling the low-level driver.
|
|
||||||
|
|
||||||
This is done to a) ease transition to the new power management methods
|
For more information on these driver calls, see the description later;
|
||||||
and leverage the existing PM code in various bus drivers; b) allow
|
they are called in phases for every device, respecting the parent-child
|
||||||
buses to implement generic and default PM routines for devices, and c)
|
sequencing in the driver model tree. Note that as this is being written,
|
||||||
make the flow of execution obvious to the reader.
|
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
|
The "can_wakeup" flag just records whether the device (and its driver) can
|
||||||
a depth-first fashion to transition each device into a low-power
|
physically support wakeup events. When that flag is clear, the sysfs
|
||||||
state. The ordering of the device tree is guaranteed by the order in
|
"wakeup" file is empty, and device_may_wakeup() returns false.
|
||||||
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.
|
|
||||||
|
|
||||||
Devices are suspended once with interrupts enabled. Drivers are
|
For devices that can issue wakeup events, a separate flag controls whether
|
||||||
expected to stop I/O transactions, save device state, and place the
|
that device should try to use its wakeup mechanism. The initial value of
|
||||||
device into a low-power state. Drivers may sleep, allocate memory,
|
device_may_wakeup() will be true, so that the device's "wakeup" file holds
|
||||||
etc. at will.
|
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
|
EXAMPLE: PCI Device Driver Methods
|
||||||
themselves back on with interrupts disabled. Once interrupts have been
|
-----------------------------------
|
||||||
re-enabled, the rest of the drivers will be called to resume their
|
PCI framework software calls these methods when the PCI device driver bound
|
||||||
devices. On resume, a driver is responsible for powering back on each
|
to a device device has provided them:
|
||||||
device, restoring state, and re-enabling I/O transactions for that
|
|
||||||
device.
|
|
||||||
|
|
||||||
|
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
|
System devices follow a slightly different API, which can be found in
|
||||||
|
|
||||||
include/linux/sysdev.h
|
include/linux/sysdev.h
|
||||||
drivers/base/sys.c
|
drivers/base/sys.c
|
||||||
|
|
||||||
System devices will only be suspended with interrupts disabled, and
|
System devices will only be suspended with interrupts disabled, and after
|
||||||
after all other devices have been suspended. On resume, they will be
|
all other devices have been suspended. On resume, they will be resumed
|
||||||
resumed before any other devices, and also with interrupts disabled.
|
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
|
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
|
However, note that if a driver puts a device into a runtime low power state
|
||||||
still running. This feature is useful for devices that are not being
|
and the system then goes into a system-wide sleep state, it normally ought
|
||||||
used, and can offer significant power savings on a running system.
|
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
|
Power Saving Techniques
|
||||||
that the device belongs to if the specified state is not 0, or
|
-----------------------
|
||||||
->resume() if it is.
|
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
|
Using information provided by other system layers
|
||||||
device is currently in.
|
- 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
|
Using fewer CPU cycles
|
||||||
is another, but different, low-power state, the ->resume() method will
|
- using DMA instead of PIO
|
||||||
first be called to power the device back on, then ->suspend() will be
|
- removing timers, or making them lower frequency
|
||||||
called again with the new state.
|
- 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
|
Reducing other resource costs
|
||||||
and putting it into the low-power state specified. If this was
|
- gating off unused clocks in software (or hardware)
|
||||||
successful, it returns 0, and the device's power_state field is
|
- switching off unused power supplies
|
||||||
updated.
|
- 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
|
Using device-specific low power states
|
||||||
properly resume the device, including all step of reinitialization
|
- using lower voltages
|
||||||
necessary. (This is the hardest part, and the one most protected by
|
- avoiding needless DMA transfers
|
||||||
NDA'd documents).
|
|
||||||
|
|
||||||
The driver must also take care not to suspend a device that is
|
Read your hardware documentation carefully to see the opportunities that
|
||||||
currently in use. It is their responsibility to provide their own
|
may be available. If you can, measure the actual power usage and check
|
||||||
exclusion mechanisms.
|
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
|
Examples: USB hosts, system timer, system CPU
|
||||||
supports a priori. This will change in the future.
|
----------------------------------------------
|
||||||
|
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
|
System devices like timers and CPUs may have special roles in the platform
|
||||||
does not know event code, it aborts the request, returning error. Some
|
power management scheme. For example, system timers using a "dynamic tick"
|
||||||
drivers may need to deal with special cases based on the actual type
|
approach don't just save CPU cycles (by eliminating needless timer IRQs),
|
||||||
of suspend operation being done at the system level. This is why
|
but they may also open the door to using lower power CPU "idle" states that
|
||||||
there are flags.
|
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
|
If the CPU can have a "cpufreq" driver, there also may be opportunities
|
||||||
HW.
|
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
|
/sys/devices/.../power/state files
|
||||||
scratch. That probably means stop accepting upstream requests, the
|
==================================
|
||||||
actual policy of what to do with them being specific to a given
|
For now you can also test some of this functionality using sysfs.
|
||||||
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.
|
|
||||||
|
|
||||||
SUSPEND -- like FREEZE, but also put hardware into low-power state. If
|
DEPRECATED: USE "power/state" ONLY FOR DRIVER TESTING, AND
|
||||||
there's need to distinguish several levels of sleep, additional flag
|
AVOID USING dev->power.power_state IN DRIVERS.
|
||||||
is probably best way to do that.
|
|
||||||
|
|
||||||
Transitions are only from a resumed state to a suspended state, never
|
THESE WILL BE REMOVED. IF THE "power/state" FILE GETS REPLACED,
|
||||||
between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen,
|
IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
|
||||||
FREEZE -> SUSPEND or SUSPEND -> FREEZE can not).
|
|
||||||
|
|
||||||
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
|
* Reading from this file displays a value corresponding to
|
||||||
should only look at event, and ignore flags.]
|
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
|
* Writing to this file initiates a transition using the
|
||||||
#enter suspend state. This gives drivers chance to load firmware from
|
specified event code number; only '0', '2', and '3' are
|
||||||
#disk and store it in memory, or do other activities taht require
|
accepted (without a newline); '2' and '3' are both
|
||||||
#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these
|
mapped to PM_EVENT_SUSPEND.
|
||||||
#are forbiden once the suspend dance is started.. event = ON, flags =
|
|
||||||
#PREPARE_TO_SUSPEND
|
|
||||||
|
|
||||||
Apm standby -- prepare for APM event. Quiesce devices to make life
|
On writes, the PM core relies on that recorded event code and the device/bus
|
||||||
easier for APM BIOS. event = FREEZE, flags = APM_STANDBY
|
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
|
- If the bus requires the irqs-disabled suspend_late()/resume_early()
|
||||||
spinning down disks. event = FREEZE, flags = APM_SUSPEND
|
phases, writes fail because those operations are not supported here.
|
||||||
|
|
||||||
System halt, reboot -- quiesce devices to make life easier for BIOS. event
|
- If the recorded value is the expected value, nothing is done.
|
||||||
= FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT
|
|
||||||
|
|
||||||
System shutdown -- at least disks need to be spun down, or data may be
|
- If the recorded value is nonzero, the device is partially resumed,
|
||||||
lost. Quiesce devices, just to make life easier for BIOS. event =
|
using the bus.resume() and/or class.resume() methods.
|
||||||
FREEZE, flags = SYSTEM_SHUTDOWN
|
|
||||||
|
|
||||||
Kexec -- turn off DMAs and put hardware into some state where new
|
- If the target value is nonzero, the device is partially suspended,
|
||||||
kernel can take over. event = FREEZE, flags = KEXEC
|
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
|
Drivers have no way to tell whether their suspend() and resume() calls
|
||||||
may need to be enabled on some devices. This actually has at least 3
|
have come through the sysfs power/state file or as part of entering a
|
||||||
subtypes, system can reboot, enter S4 and enter S5 at the end of
|
system sleep state, except that when accessed through sysfs the normal
|
||||||
swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT,
|
parent/child sequencing rules are ignored. Drivers (such as bus, bridge,
|
||||||
SYSTEM_SHUTDOWN, SYSTEM_S4
|
or hub drivers) which expose child devices may need to enforce those rules
|
||||||
|
on their own.
|
||||||
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
|
|
||||||
#
|
|
||||||
|
|
|
@ -52,3 +52,18 @@ suspend image will be as small as possible.
|
||||||
|
|
||||||
Reading from this file will display the current image size limit, which
|
Reading from this file will display the current image size limit, which
|
||||||
is set to 500 MB by default.
|
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.
|
||||||
|
|
|
@ -41,11 +41,6 @@ Board-specific code:
|
||||||
|
|
|
|
||||||
.. more boards here ...
|
.. 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:
|
Next, for companion chips:
|
||||||
.
|
.
|
||||||
`-- arch
|
`-- 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.
|
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
|
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
|
should also 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
|
board (if there are going to be more than one). In order to interoperate
|
||||||
to have this directory the same as the arch/sh/boards/ directory name,
|
seamlessly with the build system, it's best to have this directory the same
|
||||||
though if your board is again part of a family, the build system has ways
|
as the arch/sh/boards/ directory name, though if your board is again part of
|
||||||
of dealing with this, and you can feel free to name the directory after
|
a family, the build system has ways of dealing with this (via incdir-y
|
||||||
the family member itself.
|
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
|
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
|
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
|
* arch/sh/boards/vapor/setup.c - Setup code for imaginary board
|
||||||
*/
|
*/
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <asm/rtc.h> /* for board_time_init() */
|
||||||
|
|
||||||
const char *get_system_type(void)
|
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
|
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
|
to be of any use.
|
||||||
required for the time being. As such, let us take a look at what needs to be
|
|
||||||
done for the machvec assignment.
|
|
||||||
|
|
||||||
machvec functions fall into a number of categories:
|
machvec functions fall into a number of categories:
|
||||||
|
|
||||||
- I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
|
- I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
|
||||||
- I/O remapping functions (ioremap etc)
|
- I/O mapping functions (ioport_map, ioport_unmap, etc).
|
||||||
- some initialisation functions
|
- a 'heartbeat' function.
|
||||||
- a 'heartbeat' function
|
- PCI and IRQ initialization routines.
|
||||||
- some miscellaneous flags
|
- 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:
|
There are machvec functions added and removed over time, so always be sure to
|
||||||
- as a fully generic build. All drivers are linked in, and all functions
|
consult include/asm-sh/machvec.h for the current state of the machvec.
|
||||||
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 three ways in which IO can be performed:
|
The kernel will automatically wrap in generic routines for undefined function
|
||||||
- none at all. This is really only useful for the 'unknown' machine type,
|
pointers in the machvec at boot time, as machvec functions are referenced
|
||||||
which us designed to run on a machine about which we know nothing, and
|
unconditionally throughout most of the tree. Some boards have incredibly
|
||||||
so all all IO instructions do nothing.
|
sparse machvecs (such as the dreamcast and sh03), whereas others must define
|
||||||
- fully custom. In this case all IO functions go to a machine specific
|
virtually everything (rts7751r2d).
|
||||||
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.
|
|
||||||
|
|
||||||
Thus adding a new machine involves the following steps (I will assume I am
|
Adding a new machine is relatively trivial (using vapor as an example):
|
||||||
adding a machine called vapor):
|
|
||||||
|
|
||||||
- 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
|
any machine specific IO functions prefixed with the machine name, for
|
||||||
example vapor_inb. These will be needed when filling out the machine
|
example vapor_inb. These will be needed when filling out the machine
|
||||||
vector.
|
vector.
|
||||||
|
|
||||||
This is the minimum that is required, however there are ample
|
Note that these prototypes are generated automatically by setting
|
||||||
opportunities to optimise this. In particular, by making the prototypes
|
__IO_PREFIX to something sensible. A typical example would be:
|
||||||
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.
|
|
||||||
|
|
||||||
- add a new file arch/sh/boards/vapor/mach.c. This contains the definition
|
#define __IO_PREFIX vapor
|
||||||
of the machine vector. When building the machine specific version, this
|
#include <asm/io_generic.h>
|
||||||
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:
|
|
||||||
|
|
||||||
struct sh_machine_vector mv_vapor __initmv = {
|
somewhere in the board-specific header. Any boards being ported that still
|
||||||
.mv_name = "vapor",
|
have a legacy io.h should remove it entirely and switch to the new model.
|
||||||
}
|
|
||||||
ALIAS_MV(vapor)
|
|
||||||
|
|
||||||
- finally add a file arch/sh/boards/vapor/io.c, which contains
|
- Add machine vector definitions to the board's setup.c. At a bare minimum,
|
||||||
definitions of the machine specific io functions.
|
this must be defined as something like:
|
||||||
|
|
||||||
A note about initialisation functions. Three initialisation functions are
|
struct sh_machine_vector mv_vapor __initmv = {
|
||||||
provided in the machine vector:
|
.mv_name = "vapor",
|
||||||
- mv_arch_init - called very early on from setup_arch
|
};
|
||||||
- mv_init_irq - called from init_IRQ, after the generic SH interrupt
|
ALIAS_MV(vapor)
|
||||||
initialisation
|
|
||||||
- mv_init_pci - currently not used
|
|
||||||
|
|
||||||
Any other remaining functions which need to be called at start up can be
|
- finally add a file arch/sh/boards/vapor/io.c, which contains definitions of
|
||||||
added to the list using the __initcalls macro (or module_init if the code
|
the machine specific io functions (if there are enough to warrant it).
|
||||||
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.
|
|
||||||
|
|
||||||
3. Hooking into the Build System
|
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),
|
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
|
and start you on your way to having a functional kernel for your new
|
||||||
board.
|
board.
|
||||||
|
|
||||||
|
|
33
Documentation/sh/register-banks.txt
Normal file
33
Documentation/sh/register-banks.txt
Normal 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)
|
||||||
|
|
|
@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/vm:
|
||||||
- drop-caches
|
- drop-caches
|
||||||
- zone_reclaim_mode
|
- zone_reclaim_mode
|
||||||
- min_unmapped_ratio
|
- min_unmapped_ratio
|
||||||
|
- min_slab_ratio
|
||||||
- panic_on_oom
|
- panic_on_oom
|
||||||
|
|
||||||
==============================================================
|
==============================================================
|
||||||
|
@ -138,7 +139,6 @@ This is value ORed together of
|
||||||
1 = Zone reclaim on
|
1 = Zone reclaim on
|
||||||
2 = Zone reclaim writes dirty pages out
|
2 = Zone reclaim writes dirty pages out
|
||||||
4 = Zone reclaim swaps pages
|
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
|
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
|
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
|
node unless explicitly overridden by memory policies or cpuset
|
||||||
configurations.
|
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:
|
min_unmapped_ratio:
|
||||||
|
|
||||||
This is available only on NUMA kernels.
|
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.
|
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
|
This is to insure that a minimal amount of local pages is still available for
|
||||||
file I/O even if the node is overallocated.
|
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
|
panic_on_oom
|
||||||
|
|
||||||
This enables or disables panic on out-of-memory feature. If this is set to 1,
|
This enables or disables panic on out-of-memory feature. If this is set to 1,
|
||||||
|
|
|
@ -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
|
error, a failure to respond (often caused by
|
||||||
device disconnect), or some other fault.
|
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
|
bus turn-around time. This error may instead be
|
||||||
reported as -EPROTO or -EILSEQ.
|
reported as -EPROTO or -EILSEQ.
|
||||||
|
|
||||||
Note that the synchronous USB message functions
|
-ETIMEDOUT Synchronous USB message functions use this code
|
||||||
also use this code to indicate timeout expired
|
to indicate timeout expired before the transfer
|
||||||
before the transfer completed.
|
completed, and no other error was reported by HC.
|
||||||
|
|
||||||
-EPIPE (**) Endpoint stalled. For non-control endpoints,
|
-EPIPE (**) Endpoint stalled. For non-control endpoints,
|
||||||
reset this status with usb_clear_halt().
|
reset this status with usb_clear_halt().
|
||||||
|
@ -163,6 +163,3 @@ usb_get_*/usb_set_*():
|
||||||
usb_control_msg():
|
usb_control_msg():
|
||||||
usb_bulk_msg():
|
usb_bulk_msg():
|
||||||
-ETIMEDOUT Timeout expired before the transfer completed.
|
-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.
|
|
||||||
|
|
|
@ -433,6 +433,11 @@ Options supported:
|
||||||
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
|
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
|
||||||
information on this driver.
|
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
|
Generic Serial driver
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,13 @@ Debugging
|
||||||
newfallback: use new unwinder but fall back to old if it gets
|
newfallback: use new unwinder but fall back to old if it gets
|
||||||
stuck (default)
|
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
|
Misc
|
||||||
|
|
||||||
noreplacement Don't replace instructions with more appropriate ones
|
noreplacement Don't replace instructions with more appropriate ones
|
||||||
|
|
99
Documentation/x86_64/kernel-stacks
Normal file
99
Documentation/x86_64/kernel-stacks
Normal 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.
|
25
MAINTAINERS
25
MAINTAINERS
|
@ -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
|
T: git kernel.org:/pub/scm/linux/kernel/git/dwmw2/audit-2.6.git
|
||||||
S: Maintained
|
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
|
AX.25 NETWORK LAYER
|
||||||
P: Ralf Baechle
|
P: Ralf Baechle
|
||||||
M: ralf@linux-mips.org
|
M: ralf@linux-mips.org
|
||||||
|
@ -2049,6 +2066,13 @@ L: netfilter@lists.netfilter.org
|
||||||
L: netfilter-devel@lists.netfilter.org
|
L: netfilter-devel@lists.netfilter.org
|
||||||
S: Supported
|
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
|
NETROM NETWORK LAYER
|
||||||
P: Ralf Baechle
|
P: Ralf Baechle
|
||||||
M: ralf@linux-mips.org
|
M: ralf@linux-mips.org
|
||||||
|
@ -2673,7 +2697,6 @@ M: josejx@gentoo.org
|
||||||
P: Daniel Drake
|
P: Daniel Drake
|
||||||
M: dsd@gentoo.org
|
M: dsd@gentoo.org
|
||||||
W: http://softmac.sipsolutions.net/
|
W: http://softmac.sipsolutions.net/
|
||||||
L: softmac-dev@sipsolutions.net
|
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -1385,9 +1385,13 @@ endif #ifeq ($(config-targets),1)
|
||||||
endif #ifeq ($(mixed-targets),1)
|
endif #ifeq ($(mixed-targets),1)
|
||||||
|
|
||||||
PHONY += checkstack kernelrelease kernelversion
|
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:
|
checkstack:
|
||||||
$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
|
$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
|
||||||
$(PERL) $(src)/scripts/checkstack.pl $(ARCH)
|
$(PERL) $(src)/scripts/checkstack.pl $(SUBARCH)
|
||||||
|
|
||||||
kernelrelease:
|
kernelrelease:
|
||||||
$(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
|
$(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
|
||||||
|
|
|
@ -381,7 +381,7 @@ config ALPHA_EV56
|
||||||
|
|
||||||
config ALPHA_EV56
|
config ALPHA_EV56
|
||||||
prompt "EV56 CPU (speed >= 333MHz)?"
|
prompt "EV56 CPU (speed >= 333MHz)?"
|
||||||
depends on ALPHA_NORITAKE && ALPHA_PRIMO
|
depends on ALPHA_NORITAKE || ALPHA_PRIMO
|
||||||
|
|
||||||
config ALPHA_EV56
|
config ALPHA_EV56
|
||||||
prompt "EV56 CPU (speed >= 400MHz)?"
|
prompt "EV56 CPU (speed >= 400MHz)?"
|
||||||
|
|
|
@ -270,7 +270,7 @@ callback_init(void * kernel_end)
|
||||||
void
|
void
|
||||||
paging_init(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;
|
unsigned long dma_pfn, high_pfn;
|
||||||
|
|
||||||
dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
|
dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
|
||||||
|
|
|
@ -284,21 +284,9 @@ static struct pxaficp_platform_data corgi_ficp_platform_data = {
|
||||||
/*
|
/*
|
||||||
* USB Device Controller
|
* 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 = {
|
static struct pxa2xx_udc_mach_info udc_info __initdata = {
|
||||||
/* no connect GPIO; corgi can't tell connection status */
|
/* 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);
|
corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
|
||||||
|
|
||||||
pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
|
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_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
|
||||||
|
|
||||||
pxa_set_udc_info(&udc_info);
|
pxa_set_udc_info(&udc_info);
|
||||||
|
|
|
@ -177,7 +177,7 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
|
||||||
* Free the page table, if there was one.
|
* Free the page table, if there was one.
|
||||||
*/
|
*/
|
||||||
if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
|
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;
|
addr += PGDIR_SIZE;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/usb_otg.h>
|
#include <linux/usb/otg.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
|
|
196
arch/avr32/Kconfig
Normal file
196
arch/avr32/Kconfig
Normal 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
19
arch/avr32/Kconfig.debug
Normal 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
84
arch/avr32/Makefile
Normal 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
|
2
arch/avr32/boards/atstk1000/Makefile
Normal file
2
arch/avr32/boards/atstk1000/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
obj-y += setup.o spi.o flash.o
|
||||||
|
obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o
|
37
arch/avr32/boards/atstk1000/atstk1002.c
Normal file
37
arch/avr32/boards/atstk1000/atstk1002.c
Normal 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, ð0_data);
|
||||||
|
at32_add_device_spi(0);
|
||||||
|
at32_add_device_lcdc(0, &atstk1000_fb0_data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
postcore_initcall(atstk1002_init);
|
95
arch/avr32/boards/atstk1000/flash.c
Normal file
95
arch/avr32/boards/atstk1000/flash.c
Normal 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);
|
59
arch/avr32/boards/atstk1000/setup.c
Normal file
59
arch/avr32/boards/atstk1000/setup.c
Normal 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;
|
||||||
|
}
|
27
arch/avr32/boards/atstk1000/spi.c
Normal file
27
arch/avr32/boards/atstk1000/spi.c
Normal 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);
|
62
arch/avr32/boot/images/Makefile
Normal file
62
arch/avr32/boot/images/Makefile
Normal 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
|
3
arch/avr32/boot/u-boot/Makefile
Normal file
3
arch/avr32/boot/u-boot/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
extra-y := head.o
|
||||||
|
|
||||||
|
obj-y := empty.o
|
1
arch/avr32/boot/u-boot/empty.S
Normal file
1
arch/avr32/boot/u-boot/empty.S
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/* Empty file */
|
60
arch/avr32/boot/u-boot/head.S
Normal file
60
arch/avr32/boot/u-boot/head.S
Normal 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"
|
|
@ -1,158 +1,15 @@
|
||||||
#
|
#
|
||||||
# Automatically generated make config: don't edit
|
# Automatically generated make config: don't edit
|
||||||
# Linux kernel version: 2.6.18-rc1
|
# Linux kernel version: 2.6.18-rc1
|
||||||
# Thu Jul 6 10:04:05 2006
|
# Tue Jul 11 12:41:36 2006
|
||||||
#
|
#
|
||||||
CONFIG_MIPS=y
|
CONFIG_AVR32=y
|
||||||
|
CONFIG_GENERIC_HARDIRQS=y
|
||||||
#
|
CONFIG_HARDIRQS_SW_RESEND=y
|
||||||
# Machine selection
|
CONFIG_GENERIC_IRQ_PROBE=y
|
||||||
#
|
|
||||||
# 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_RWSEM_GENERIC_SPINLOCK=y
|
CONFIG_RWSEM_GENERIC_SPINLOCK=y
|
||||||
CONFIG_GENERIC_FIND_NEXT_BIT=y
|
|
||||||
CONFIG_GENERIC_HWEIGHT=y
|
CONFIG_GENERIC_HWEIGHT=y
|
||||||
CONFIG_GENERIC_CALIBRATE_DELAY=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"
|
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -166,34 +23,34 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||||
# General setup
|
# General setup
|
||||||
#
|
#
|
||||||
CONFIG_LOCALVERSION=""
|
CONFIG_LOCALVERSION=""
|
||||||
CONFIG_LOCALVERSION_AUTO=y
|
# CONFIG_LOCALVERSION_AUTO is not set
|
||||||
CONFIG_SWAP=y
|
CONFIG_SWAP=y
|
||||||
CONFIG_SYSVIPC=y
|
# CONFIG_SYSVIPC is not set
|
||||||
# CONFIG_POSIX_MQUEUE is not set
|
# CONFIG_POSIX_MQUEUE is not set
|
||||||
# CONFIG_BSD_PROCESS_ACCT is not set
|
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||||
CONFIG_SYSCTL=y
|
CONFIG_SYSCTL=y
|
||||||
# CONFIG_AUDIT is not set
|
# CONFIG_AUDIT is not set
|
||||||
# CONFIG_IKCONFIG is not set
|
# CONFIG_IKCONFIG is not set
|
||||||
CONFIG_RELAY=y
|
# CONFIG_RELAY is not set
|
||||||
CONFIG_INITRAMFS_SOURCE=""
|
CONFIG_INITRAMFS_SOURCE=""
|
||||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||||
CONFIG_EMBEDDED=y
|
CONFIG_EMBEDDED=y
|
||||||
CONFIG_KALLSYMS=y
|
CONFIG_KALLSYMS=y
|
||||||
|
# CONFIG_KALLSYMS_ALL is not set
|
||||||
# CONFIG_KALLSYMS_EXTRA_PASS is not set
|
# CONFIG_KALLSYMS_EXTRA_PASS is not set
|
||||||
# CONFIG_HOTPLUG is not set
|
CONFIG_HOTPLUG=y
|
||||||
CONFIG_PRINTK=y
|
CONFIG_PRINTK=y
|
||||||
CONFIG_BUG=y
|
CONFIG_BUG=y
|
||||||
CONFIG_ELF_CORE=y
|
CONFIG_ELF_CORE=y
|
||||||
CONFIG_BASE_FULL=y
|
# CONFIG_BASE_FULL is not set
|
||||||
CONFIG_RT_MUTEXES=y
|
# CONFIG_FUTEX is not set
|
||||||
CONFIG_FUTEX=y
|
# CONFIG_EPOLL is not set
|
||||||
CONFIG_EPOLL=y
|
|
||||||
CONFIG_SHMEM=y
|
CONFIG_SHMEM=y
|
||||||
CONFIG_SLAB=y
|
# CONFIG_SLAB is not set
|
||||||
CONFIG_VM_EVENT_COUNTERS=y
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
# CONFIG_TINY_SHMEM is not set
|
# CONFIG_TINY_SHMEM is not set
|
||||||
CONFIG_BASE_SMALL=0
|
CONFIG_BASE_SMALL=1
|
||||||
# CONFIG_SLOB is not set
|
CONFIG_SLOB=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# Loadable module support
|
# Loadable module support
|
||||||
|
@ -201,52 +58,81 @@ CONFIG_BASE_SMALL=0
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
CONFIG_MODULE_UNLOAD=y
|
CONFIG_MODULE_UNLOAD=y
|
||||||
# CONFIG_MODULE_FORCE_UNLOAD is not set
|
# CONFIG_MODULE_FORCE_UNLOAD is not set
|
||||||
CONFIG_MODVERSIONS=y
|
# CONFIG_MODVERSIONS is not set
|
||||||
CONFIG_MODULE_SRCVERSION_ALL=y
|
# CONFIG_MODULE_SRCVERSION_ALL is not set
|
||||||
# CONFIG_KMOD is not set
|
# CONFIG_KMOD is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Block layer
|
# Block layer
|
||||||
#
|
#
|
||||||
# CONFIG_LBD is not set
|
|
||||||
# CONFIG_BLK_DEV_IO_TRACE is not set
|
# CONFIG_BLK_DEV_IO_TRACE is not set
|
||||||
# CONFIG_LSF is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# IO Schedulers
|
# IO Schedulers
|
||||||
#
|
#
|
||||||
CONFIG_IOSCHED_NOOP=y
|
CONFIG_IOSCHED_NOOP=y
|
||||||
CONFIG_IOSCHED_AS=y
|
# CONFIG_IOSCHED_AS is not set
|
||||||
CONFIG_IOSCHED_DEADLINE=y
|
# CONFIG_IOSCHED_DEADLINE is not set
|
||||||
CONFIG_IOSCHED_CFQ=y
|
# CONFIG_IOSCHED_CFQ is not set
|
||||||
CONFIG_DEFAULT_AS=y
|
# CONFIG_DEFAULT_AS is not set
|
||||||
# CONFIG_DEFAULT_DEADLINE is not set
|
# CONFIG_DEFAULT_DEADLINE is not set
|
||||||
# CONFIG_DEFAULT_CFQ is not set
|
# CONFIG_DEFAULT_CFQ is not set
|
||||||
# CONFIG_DEFAULT_NOOP is not set
|
CONFIG_DEFAULT_NOOP=y
|
||||||
CONFIG_DEFAULT_IOSCHED="anticipatory"
|
CONFIG_DEFAULT_IOSCHED="noop"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
|
# System Type and features
|
||||||
#
|
#
|
||||||
CONFIG_HW_HAS_PCI=y
|
CONFIG_SUBARCH_AVR32B=y
|
||||||
# CONFIG_PCI is not set
|
|
||||||
CONFIG_MMU=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
|
# PCCARD (PCMCIA/CardBus) support
|
||||||
#
|
#
|
||||||
# CONFIG_PCCARD is not set
|
# CONFIG_PCCARD is not set
|
||||||
|
|
||||||
#
|
|
||||||
# PCI Hotplug Support
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Executable file formats
|
# Executable file formats
|
||||||
#
|
#
|
||||||
CONFIG_BINFMT_ELF=y
|
CONFIG_BINFMT_ELF=y
|
||||||
# CONFIG_BINFMT_MISC is not set
|
# CONFIG_BINFMT_MISC is not set
|
||||||
CONFIG_TRAD_SIGNALS=y
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Networking
|
# Networking
|
||||||
|
@ -257,18 +143,17 @@ CONFIG_NET=y
|
||||||
# Networking options
|
# Networking options
|
||||||
#
|
#
|
||||||
# CONFIG_NETDEBUG is not set
|
# CONFIG_NETDEBUG is not set
|
||||||
# CONFIG_PACKET is not set
|
CONFIG_PACKET=y
|
||||||
|
CONFIG_PACKET_MMAP=y
|
||||||
CONFIG_UNIX=y
|
CONFIG_UNIX=y
|
||||||
CONFIG_XFRM=y
|
# CONFIG_NET_KEY is not set
|
||||||
CONFIG_XFRM_USER=m
|
|
||||||
CONFIG_NET_KEY=y
|
|
||||||
CONFIG_INET=y
|
CONFIG_INET=y
|
||||||
# CONFIG_IP_MULTICAST is not set
|
# CONFIG_IP_MULTICAST is not set
|
||||||
# CONFIG_IP_ADVANCED_ROUTER is not set
|
# CONFIG_IP_ADVANCED_ROUTER is not set
|
||||||
CONFIG_IP_FIB_HASH=y
|
CONFIG_IP_FIB_HASH=y
|
||||||
CONFIG_IP_PNP=y
|
CONFIG_IP_PNP=y
|
||||||
# CONFIG_IP_PNP_DHCP is not set
|
CONFIG_IP_PNP_DHCP=y
|
||||||
CONFIG_IP_PNP_BOOTP=y
|
# CONFIG_IP_PNP_BOOTP is not set
|
||||||
# CONFIG_IP_PNP_RARP is not set
|
# CONFIG_IP_PNP_RARP is not set
|
||||||
# CONFIG_NET_IPIP is not set
|
# CONFIG_NET_IPIP is not set
|
||||||
# CONFIG_NET_IPGRE 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_IPCOMP is not set
|
||||||
# CONFIG_INET_XFRM_TUNNEL is not set
|
# CONFIG_INET_XFRM_TUNNEL is not set
|
||||||
# CONFIG_INET_TUNNEL is not set
|
# CONFIG_INET_TUNNEL is not set
|
||||||
CONFIG_INET_XFRM_MODE_TRANSPORT=m
|
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
|
||||||
CONFIG_INET_XFRM_MODE_TUNNEL=m
|
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
|
||||||
CONFIG_INET_DIAG=y
|
CONFIG_INET_DIAG=y
|
||||||
CONFIG_INET_TCP_DIAG=y
|
CONFIG_INET_TCP_DIAG=y
|
||||||
# CONFIG_TCP_CONG_ADVANCED is not set
|
# CONFIG_TCP_CONG_ADVANCED is not set
|
||||||
|
@ -288,7 +173,7 @@ CONFIG_TCP_CONG_BIC=y
|
||||||
# CONFIG_IPV6 is not set
|
# CONFIG_IPV6 is not set
|
||||||
# CONFIG_INET6_XFRM_TUNNEL is not set
|
# CONFIG_INET6_XFRM_TUNNEL is not set
|
||||||
# CONFIG_INET6_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
|
# CONFIG_NETFILTER is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -327,16 +212,11 @@ CONFIG_NETWORK_SECMARK=y
|
||||||
# Network testing
|
# Network testing
|
||||||
#
|
#
|
||||||
# CONFIG_NET_PKTGEN is not set
|
# CONFIG_NET_PKTGEN is not set
|
||||||
|
# CONFIG_NET_TCPPROBE is not set
|
||||||
# CONFIG_HAMRADIO is not set
|
# CONFIG_HAMRADIO is not set
|
||||||
# CONFIG_IRDA is not set
|
# CONFIG_IRDA is not set
|
||||||
# CONFIG_BT is not set
|
# CONFIG_BT is not set
|
||||||
CONFIG_IEEE80211=m
|
# CONFIG_IEEE80211 is not set
|
||||||
# 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
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Device Drivers
|
# Device Drivers
|
||||||
|
@ -346,14 +226,15 @@ CONFIG_WIRELESS_EXT=y
|
||||||
# Generic Driver Options
|
# Generic Driver Options
|
||||||
#
|
#
|
||||||
CONFIG_STANDALONE=y
|
CONFIG_STANDALONE=y
|
||||||
CONFIG_PREVENT_FIRMWARE_BUILD=y
|
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
|
||||||
# CONFIG_FW_LOADER is not set
|
# CONFIG_FW_LOADER is not set
|
||||||
|
# CONFIG_DEBUG_DRIVER is not set
|
||||||
# CONFIG_SYS_HYPERVISOR is not set
|
# CONFIG_SYS_HYPERVISOR is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Connector - unified userspace <-> kernelspace linker
|
# Connector - unified userspace <-> kernelspace linker
|
||||||
#
|
#
|
||||||
CONFIG_CONNECTOR=m
|
# CONFIG_CONNECTOR is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Memory Technology Devices (MTD)
|
# Memory Technology Devices (MTD)
|
||||||
|
@ -373,14 +254,15 @@ CONFIG_CONNECTOR=m
|
||||||
# Block devices
|
# Block devices
|
||||||
#
|
#
|
||||||
# CONFIG_BLK_DEV_COW_COMMON is not set
|
# CONFIG_BLK_DEV_COW_COMMON is not set
|
||||||
# CONFIG_BLK_DEV_LOOP is not set
|
CONFIG_BLK_DEV_LOOP=m
|
||||||
# CONFIG_BLK_DEV_NBD is not set
|
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
|
||||||
# CONFIG_BLK_DEV_RAM is not set
|
CONFIG_BLK_DEV_NBD=m
|
||||||
# CONFIG_BLK_DEV_INITRD is not set
|
CONFIG_BLK_DEV_RAM=m
|
||||||
CONFIG_CDROM_PKTCDVD=m
|
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||||
CONFIG_CDROM_PKTCDVD_BUFFERS=8
|
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||||
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
|
CONFIG_BLK_DEV_INITRD=y
|
||||||
CONFIG_ATA_OVER_ETH=m
|
# CONFIG_CDROM_PKTCDVD is not set
|
||||||
|
# CONFIG_ATA_OVER_ETH is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# ATA/ATAPI/MFM/RLL support
|
# ATA/ATAPI/MFM/RLL support
|
||||||
|
@ -390,7 +272,7 @@ CONFIG_ATA_OVER_ETH=m
|
||||||
#
|
#
|
||||||
# SCSI device support
|
# SCSI device support
|
||||||
#
|
#
|
||||||
CONFIG_RAID_ATTRS=m
|
# CONFIG_RAID_ATTRS is not set
|
||||||
# CONFIG_SCSI is not set
|
# CONFIG_SCSI is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -415,34 +297,22 @@ CONFIG_RAID_ATTRS=m
|
||||||
# Network device support
|
# Network device support
|
||||||
#
|
#
|
||||||
CONFIG_NETDEVICES=y
|
CONFIG_NETDEVICES=y
|
||||||
# CONFIG_DUMMY is not set
|
CONFIG_DUMMY=y
|
||||||
# CONFIG_BONDING is not set
|
# CONFIG_BONDING is not set
|
||||||
# CONFIG_EQUALIZER is not set
|
# CONFIG_EQUALIZER is not set
|
||||||
# CONFIG_TUN is not set
|
CONFIG_TUN=m
|
||||||
|
|
||||||
#
|
#
|
||||||
# PHY device support
|
# PHY device support
|
||||||
#
|
#
|
||||||
CONFIG_PHYLIB=m
|
# CONFIG_PHYLIB is not set
|
||||||
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ethernet (10 or 100Mbit)
|
# Ethernet (10 or 100Mbit)
|
||||||
#
|
#
|
||||||
CONFIG_NET_ETHERNET=y
|
CONFIG_NET_ETHERNET=y
|
||||||
# CONFIG_MII is not set
|
CONFIG_MII=y
|
||||||
CONFIG_MIPS_GT96100ETH=y
|
CONFIG_MACB=y
|
||||||
# CONFIG_DM9000 is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ethernet (1000 Mbit)
|
# Ethernet (1000 Mbit)
|
||||||
|
@ -465,7 +335,15 @@ CONFIG_MIPS_GT96100ETH=y
|
||||||
# Wan interfaces
|
# Wan interfaces
|
||||||
#
|
#
|
||||||
# CONFIG_WAN is not set
|
# 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_SLIP is not set
|
||||||
# CONFIG_SHAPER is not set
|
# CONFIG_SHAPER is not set
|
||||||
# CONFIG_NETCONSOLE is not set
|
# CONFIG_NETCONSOLE is not set
|
||||||
|
@ -485,65 +363,35 @@ CONFIG_MIPS_GT96100ETH=y
|
||||||
#
|
#
|
||||||
# Input device support
|
# Input device support
|
||||||
#
|
#
|
||||||
CONFIG_INPUT=y
|
# CONFIG_INPUT is not set
|
||||||
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Hardware I/O ports
|
# Hardware I/O ports
|
||||||
#
|
#
|
||||||
CONFIG_SERIO=y
|
# CONFIG_SERIO is not set
|
||||||
# CONFIG_SERIO_I8042 is not set
|
|
||||||
CONFIG_SERIO_SERPORT=y
|
|
||||||
# CONFIG_SERIO_LIBPS2 is not set
|
|
||||||
CONFIG_SERIO_RAW=m
|
|
||||||
# CONFIG_GAMEPORT is not set
|
# CONFIG_GAMEPORT is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Character devices
|
# Character devices
|
||||||
#
|
#
|
||||||
CONFIG_VT=y
|
# CONFIG_VT is not set
|
||||||
CONFIG_VT_CONSOLE=y
|
|
||||||
CONFIG_HW_CONSOLE=y
|
|
||||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
|
||||||
# CONFIG_SERIAL_NONSTANDARD is not set
|
# CONFIG_SERIAL_NONSTANDARD is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Serial drivers
|
# Serial drivers
|
||||||
#
|
#
|
||||||
CONFIG_SERIAL_8250=y
|
# CONFIG_SERIAL_8250 is not set
|
||||||
CONFIG_SERIAL_8250_CONSOLE=y
|
|
||||||
CONFIG_SERIAL_8250_NR_UARTS=4
|
|
||||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
|
|
||||||
# CONFIG_SERIAL_8250_EXTENDED is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Non-8250 serial port support
|
# 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=y
|
||||||
CONFIG_SERIAL_CORE_CONSOLE=y
|
CONFIG_SERIAL_CORE_CONSOLE=y
|
||||||
CONFIG_UNIX98_PTYS=y
|
CONFIG_UNIX98_PTYS=y
|
||||||
CONFIG_LEGACY_PTYS=y
|
# CONFIG_LEGACY_PTYS is not set
|
||||||
CONFIG_LEGACY_PTY_COUNT=256
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# IPMI
|
# IPMI
|
||||||
|
@ -579,13 +427,23 @@ CONFIG_LEGACY_PTY_COUNT=256
|
||||||
#
|
#
|
||||||
# SPI support
|
# SPI support
|
||||||
#
|
#
|
||||||
# CONFIG_SPI is not set
|
CONFIG_SPI=y
|
||||||
# CONFIG_SPI_MASTER is not set
|
# 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
|
# Dallas's 1-wire bus
|
||||||
#
|
#
|
||||||
# CONFIG_W1 is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Hardware Monitoring support
|
# Hardware Monitoring support
|
||||||
|
@ -612,13 +470,28 @@ CONFIG_VIDEO_V4L2=y
|
||||||
# Graphics support
|
# Graphics support
|
||||||
#
|
#
|
||||||
# CONFIG_FIRMWARE_EDID is not set
|
# 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_LOGO is not set
|
||||||
CONFIG_DUMMY_CONSOLE=y
|
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
|
# Sound
|
||||||
|
@ -697,15 +570,14 @@ CONFIG_EXT2_FS=y
|
||||||
# CONFIG_FS_POSIX_ACL is not set
|
# CONFIG_FS_POSIX_ACL is not set
|
||||||
# CONFIG_XFS_FS is not set
|
# CONFIG_XFS_FS is not set
|
||||||
# CONFIG_OCFS2_FS is not set
|
# CONFIG_OCFS2_FS is not set
|
||||||
# CONFIG_MINIX_FS is not set
|
CONFIG_MINIX_FS=m
|
||||||
# CONFIG_ROMFS_FS is not set
|
CONFIG_ROMFS_FS=m
|
||||||
CONFIG_INOTIFY=y
|
# CONFIG_INOTIFY is not set
|
||||||
CONFIG_INOTIFY_USER=y
|
|
||||||
# CONFIG_QUOTA is not set
|
# CONFIG_QUOTA is not set
|
||||||
CONFIG_DNOTIFY=y
|
# CONFIG_DNOTIFY is not set
|
||||||
# CONFIG_AUTOFS_FS is not set
|
# CONFIG_AUTOFS_FS is not set
|
||||||
# CONFIG_AUTOFS4_FS is not set
|
# CONFIG_AUTOFS4_FS is not set
|
||||||
CONFIG_FUSE_FS=m
|
# CONFIG_FUSE_FS is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# CD-ROM/DVD Filesystems
|
# CD-ROM/DVD Filesystems
|
||||||
|
@ -716,8 +588,11 @@ CONFIG_FUSE_FS=m
|
||||||
#
|
#
|
||||||
# DOS/FAT/NT Filesystems
|
# DOS/FAT/NT Filesystems
|
||||||
#
|
#
|
||||||
# CONFIG_MSDOS_FS is not set
|
CONFIG_FAT_FS=m
|
||||||
# CONFIG_VFAT_FS is not set
|
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
|
# CONFIG_NTFS_FS is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -726,10 +601,10 @@ CONFIG_FUSE_FS=m
|
||||||
CONFIG_PROC_FS=y
|
CONFIG_PROC_FS=y
|
||||||
CONFIG_PROC_KCORE=y
|
CONFIG_PROC_KCORE=y
|
||||||
CONFIG_SYSFS=y
|
CONFIG_SYSFS=y
|
||||||
# CONFIG_TMPFS is not set
|
CONFIG_TMPFS=y
|
||||||
# CONFIG_HUGETLB_PAGE is not set
|
# CONFIG_HUGETLB_PAGE is not set
|
||||||
CONFIG_RAMFS=y
|
CONFIG_RAMFS=y
|
||||||
# CONFIG_CONFIGFS_FS is not set
|
CONFIG_CONFIGFS_FS=m
|
||||||
|
|
||||||
#
|
#
|
||||||
# Miscellaneous filesystems
|
# Miscellaneous filesystems
|
||||||
|
@ -752,19 +627,25 @@ CONFIG_RAMFS=y
|
||||||
# Network File Systems
|
# Network File Systems
|
||||||
#
|
#
|
||||||
CONFIG_NFS_FS=y
|
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_V4 is not set
|
||||||
# CONFIG_NFS_DIRECTIO is not set
|
# CONFIG_NFS_DIRECTIO is not set
|
||||||
# CONFIG_NFSD is not set
|
# CONFIG_NFSD is not set
|
||||||
CONFIG_ROOT_NFS=y
|
CONFIG_ROOT_NFS=y
|
||||||
CONFIG_LOCKD=y
|
CONFIG_LOCKD=y
|
||||||
|
CONFIG_LOCKD_V4=y
|
||||||
CONFIG_NFS_COMMON=y
|
CONFIG_NFS_COMMON=y
|
||||||
CONFIG_SUNRPC=y
|
CONFIG_SUNRPC=y
|
||||||
# CONFIG_RPCSEC_GSS_KRB5 is not set
|
# CONFIG_RPCSEC_GSS_KRB5 is not set
|
||||||
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
||||||
# CONFIG_SMB_FS 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_DEBUG2 is not set
|
||||||
|
# CONFIG_CIFS_EXPERIMENTAL is not set
|
||||||
# CONFIG_NCP_FS is not set
|
# CONFIG_NCP_FS is not set
|
||||||
# CONFIG_CODA_FS is not set
|
# CONFIG_CODA_FS is not set
|
||||||
# CONFIG_AFS_FS is not set
|
# CONFIG_AFS_FS is not set
|
||||||
|
@ -779,60 +660,84 @@ CONFIG_MSDOS_PARTITION=y
|
||||||
#
|
#
|
||||||
# Native Language Support
|
# Native Language Support
|
||||||
#
|
#
|
||||||
# CONFIG_NLS is not set
|
CONFIG_NLS=m
|
||||||
|
CONFIG_NLS_DEFAULT="iso8859-1"
|
||||||
#
|
CONFIG_NLS_CODEPAGE_437=m
|
||||||
# Profiling support
|
# CONFIG_NLS_CODEPAGE_737 is not set
|
||||||
#
|
# CONFIG_NLS_CODEPAGE_775 is not set
|
||||||
# CONFIG_PROFILING 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
|
# Kernel hacking
|
||||||
#
|
#
|
||||||
# CONFIG_PRINTK_TIME is not set
|
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||||
# CONFIG_MAGIC_SYSRQ is not set
|
CONFIG_PRINTK_TIME=y
|
||||||
|
CONFIG_MAGIC_SYSRQ=y
|
||||||
# CONFIG_UNUSED_SYMBOLS is not set
|
# CONFIG_UNUSED_SYMBOLS is not set
|
||||||
# CONFIG_DEBUG_KERNEL is not set
|
CONFIG_DEBUG_KERNEL=y
|
||||||
CONFIG_LOG_BUF_SHIFT=14
|
CONFIG_LOG_BUF_SHIFT=14
|
||||||
# CONFIG_DEBUG_FS is not set
|
CONFIG_DETECT_SOFTLOCKUP=y
|
||||||
CONFIG_CROSSCOMPILE=y
|
# CONFIG_SCHEDSTATS is not set
|
||||||
CONFIG_CMDLINE=""
|
# 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
|
# Security options
|
||||||
#
|
#
|
||||||
CONFIG_KEYS=y
|
# CONFIG_KEYS is not set
|
||||||
CONFIG_KEYS_DEBUG_PROC_KEYS=y
|
|
||||||
# CONFIG_SECURITY is not set
|
# CONFIG_SECURITY is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cryptographic options
|
# Cryptographic options
|
||||||
#
|
#
|
||||||
CONFIG_CRYPTO=y
|
# CONFIG_CRYPTO is not set
|
||||||
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
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Hardware crypto devices
|
# Hardware crypto devices
|
||||||
|
@ -841,10 +746,9 @@ CONFIG_CRYPTO_CRC32C=m
|
||||||
#
|
#
|
||||||
# Library routines
|
# Library routines
|
||||||
#
|
#
|
||||||
# CONFIG_CRC_CCITT is not set
|
CONFIG_CRC_CCITT=m
|
||||||
CONFIG_CRC16=m
|
# CONFIG_CRC16 is not set
|
||||||
CONFIG_CRC32=m
|
CONFIG_CRC32=m
|
||||||
CONFIG_LIBCRC32C=m
|
# CONFIG_LIBCRC32C is not set
|
||||||
CONFIG_ZLIB_INFLATE=m
|
CONFIG_ZLIB_INFLATE=m
|
||||||
CONFIG_ZLIB_DEFLATE=m
|
CONFIG_ZLIB_DEFLATE=m
|
||||||
CONFIG_PLIST=y
|
|
18
arch/avr32/kernel/Makefile
Normal file
18
arch/avr32/kernel/Makefile
Normal 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)
|
25
arch/avr32/kernel/asm-offsets.c
Normal file
25
arch/avr32/kernel/asm-offsets.c
Normal 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);
|
||||||
|
}
|
55
arch/avr32/kernel/avr32_ksyms.c
Normal file
55
arch/avr32/kernel/avr32_ksyms.c
Normal 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
327
arch/avr32/kernel/cpu.c
Normal 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 */
|
678
arch/avr32/kernel/entry-avr32b.S
Normal file
678
arch/avr32/kernel/entry-avr32b.S
Normal 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
45
arch/avr32/kernel/head.S
Normal 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
|
38
arch/avr32/kernel/init_task.c
Normal file
38
arch/avr32/kernel/init_task.c
Normal 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
71
arch/avr32/kernel/irq.c
Normal 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
270
arch/avr32/kernel/kprobes.c
Normal 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
324
arch/avr32/kernel/module.c
Normal 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
276
arch/avr32/kernel/process.c
Normal 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(®s, 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, ®s, 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
371
arch/avr32/kernel/ptrace.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
148
arch/avr32/kernel/semaphore.c
Normal file
148
arch/avr32/kernel/semaphore.c
Normal 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
335
arch/avr32/kernel/setup.c
Normal 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
328
arch/avr32/kernel/signal.c
Normal 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(¤t->sighand->siglock);
|
||||||
|
current->blocked = set;
|
||||||
|
recalc_sigpending();
|
||||||
|
spin_unlock_irq(¤t->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(¤t->sighand->siglock);
|
||||||
|
sigorsets(¤t->blocked, ¤t->blocked,
|
||||||
|
&ka->sa.sa_mask);
|
||||||
|
sigaddset(¤t->blocked, sig);
|
||||||
|
recalc_sigpending();
|
||||||
|
spin_unlock_irq(¤t->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 = ¤t->saved_sigmask;
|
||||||
|
else if (!oldset)
|
||||||
|
oldset = ¤t->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, ¤t->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, ¤t->blocked, syscall);
|
||||||
|
}
|
35
arch/avr32/kernel/switch_to.S
Normal file
35
arch/avr32/kernel/switch_to.S
Normal 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
|
51
arch/avr32/kernel/sys_avr32.c
Normal file
51
arch/avr32/kernel/sys_avr32.c
Normal 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(¤t->mm->mmap_sem);
|
||||||
|
error = do_mmap_pgoff(file, addr, len, prot, flags, offset);
|
||||||
|
up_write(¤t->mm->mmap_sem);
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
fput(file);
|
||||||
|
return error;
|
||||||
|
}
|
102
arch/avr32/kernel/syscall-stubs.S
Normal file
102
arch/avr32/kernel/syscall-stubs.S
Normal 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
|
289
arch/avr32/kernel/syscall_table.S
Normal file
289
arch/avr32/kernel/syscall_table.S
Normal 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
238
arch/avr32/kernel/time.c
Normal 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
425
arch/avr32/kernel/traps.c
Normal 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
139
arch/avr32/kernel/vmlinux.lds.c
Normal file
139
arch/avr32/kernel/vmlinux.lds.c
Normal 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
10
arch/avr32/lib/Makefile
Normal 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
|
31
arch/avr32/lib/__avr32_asr64.S
Normal file
31
arch/avr32/lib/__avr32_asr64.S
Normal 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
|
31
arch/avr32/lib/__avr32_lsl64.S
Normal file
31
arch/avr32/lib/__avr32_lsl64.S
Normal 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
|
31
arch/avr32/lib/__avr32_lsr64.S
Normal file
31
arch/avr32/lib/__avr32_lsr64.S
Normal 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
|
76
arch/avr32/lib/clear_user.S
Normal file
76
arch/avr32/lib/clear_user.S
Normal 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
119
arch/avr32/lib/copy_user.S
Normal 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
|
47
arch/avr32/lib/csum_partial.S
Normal file
47
arch/avr32/lib/csum_partial.S
Normal 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
|
99
arch/avr32/lib/csum_partial_copy_generic.S
Normal file
99
arch/avr32/lib/csum_partial_copy_generic.S
Normal 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
55
arch/avr32/lib/delay.c
Normal 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
154
arch/avr32/lib/findbit.S
Normal 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
|
24
arch/avr32/lib/io-readsl.S
Normal file
24
arch/avr32/lib/io-readsl.S
Normal 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
|
43
arch/avr32/lib/io-readsw.S
Normal file
43
arch/avr32/lib/io-readsw.S
Normal 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
|
20
arch/avr32/lib/io-writesl.S
Normal file
20
arch/avr32/lib/io-writesl.S
Normal 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
|
38
arch/avr32/lib/io-writesw.S
Normal file
38
arch/avr32/lib/io-writesw.S
Normal 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
33
arch/avr32/lib/libgcc.h
Normal 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
98
arch/avr32/lib/longlong.h
Normal 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
62
arch/avr32/lib/memcpy.S
Normal 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
72
arch/avr32/lib/memset.S
Normal 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
|
60
arch/avr32/lib/strncpy_from_user.S
Normal file
60
arch/avr32/lib/strncpy_from_user.S
Normal 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
|
67
arch/avr32/lib/strnlen_user.S
Normal file
67
arch/avr32/lib/strnlen_user.S
Normal 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
|
2
arch/avr32/mach-at32ap/Makefile
Normal file
2
arch/avr32/mach-at32ap/Makefile
Normal 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
|
90
arch/avr32/mach-at32ap/at32ap.c
Normal file
90
arch/avr32/mach-at32ap/at32ap.c
Normal 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);
|
876
arch/avr32/mach-at32ap/at32ap7000.c
Normal file
876
arch/avr32/mach-at32ap/at32ap7000.c
Normal 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);
|
||||||
|
}
|
148
arch/avr32/mach-at32ap/clock.c
Normal file
148
arch/avr32/mach-at32ap/clock.c
Normal 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);
|
30
arch/avr32/mach-at32ap/clock.h
Normal file
30
arch/avr32/mach-at32ap/clock.h
Normal 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;
|
171
arch/avr32/mach-at32ap/extint.c
Normal file
171
arch/avr32/mach-at32ap/extint.c
Normal 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);
|
164
arch/avr32/mach-at32ap/hsmc.c
Normal file
164
arch/avr32/mach-at32ap/hsmc.c
Normal 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);
|
127
arch/avr32/mach-at32ap/hsmc.h
Normal file
127
arch/avr32/mach-at32ap/hsmc.h
Normal 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__ */
|
133
arch/avr32/mach-at32ap/intc.c
Normal file
133
arch/avr32/mach-at32ap/intc.c
Normal 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");
|
||||||
|
}
|
||||||
|
|
327
arch/avr32/mach-at32ap/intc.h
Normal file
327
arch/avr32/mach-at32ap/intc.h
Normal 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__ */
|
118
arch/avr32/mach-at32ap/pio.c
Normal file
118
arch/avr32/mach-at32ap/pio.c
Normal 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);
|
||||||
|
}
|
178
arch/avr32/mach-at32ap/pio.h
Normal file
178
arch/avr32/mach-at32ap/pio.h
Normal 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
289
arch/avr32/mach-at32ap/sm.c
Normal 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
240
arch/avr32/mach-at32ap/sm.h
Normal 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
Loading…
Reference in a new issue