Merge commit 'tip/perfcounters-for-linus' into oprofile/master
Conflicts: arch/x86/oprofile/op_model_ppro.c Signed-off-by: Robert Richter <robert.richter@amd.com>
This commit is contained in:
commit
1241eb8f13
|
@ -0,0 +1,18 @@
|
|||
What: /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: mark.langsdorf@amd.com
|
||||
Description: These files exist in every cpu's cache index directories.
|
||||
There are currently 2 cache_disable_# files in each
|
||||
directory. Reading from these files on a supported
|
||||
processor will return that cache disable index value
|
||||
for that processor and node. Writing to one of these
|
||||
files will cause the specificed cache index to be disabled.
|
||||
|
||||
Currently, only AMD Family 10h Processors support cache index
|
||||
disable, and only for their L3 caches. See the BIOS and
|
||||
Kernel Developer's Guide at
|
||||
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116-Public-GH-BKDG_3.20_2-4-09.pdf
|
||||
for formatting information and other details on the
|
||||
cache index disable.
|
||||
Users: joachim.deguara@amd.com
|
|
@ -704,12 +704,24 @@ this directory the following files can currently be found:
|
|||
The current number of free dma_debug_entries
|
||||
in the allocator.
|
||||
|
||||
dma-api/driver-filter
|
||||
You can write a name of a driver into this file
|
||||
to limit the debug output to requests from that
|
||||
particular driver. Write an empty string to
|
||||
that file to disable the filter and see
|
||||
all errors again.
|
||||
|
||||
If you have this code compiled into your kernel it will be enabled by default.
|
||||
If you want to boot without the bookkeeping anyway you can provide
|
||||
'dma_debug=off' as a boot parameter. This will disable DMA-API debugging.
|
||||
Notice that you can not enable it again at runtime. You have to reboot to do
|
||||
so.
|
||||
|
||||
If you want to see debug messages only for a special device driver you can
|
||||
specify the dma_debug_driver=<drivername> parameter. This will enable the
|
||||
driver filter at boot time. The debug code will only print errors for that
|
||||
driver afterwards. This filter can be disabled or changed later using debugfs.
|
||||
|
||||
When the code disables itself at runtime this is most likely because it ran
|
||||
out of dma_debug_entries. These entries are preallocated at boot. The number
|
||||
of preallocated entries is defined per architecture. If it is too low for you
|
||||
|
|
|
@ -13,7 +13,8 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
|
|||
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
|
||||
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
|
||||
mac80211.xml debugobjects.xml sh.xml regulator.xml \
|
||||
alsa-driver-api.xml writing-an-alsa-driver.xml
|
||||
alsa-driver-api.xml writing-an-alsa-driver.xml \
|
||||
tracepoint.xml
|
||||
|
||||
###
|
||||
# The build process is as follows (targets):
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
||||
|
||||
<book id="Tracepoints">
|
||||
<bookinfo>
|
||||
<title>The Linux Kernel Tracepoint API</title>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Jason</firstname>
|
||||
<surname>Baron</surname>
|
||||
<affiliation>
|
||||
<address>
|
||||
<email>jbaron@redhat.com</email>
|
||||
</address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
This documentation is free software; you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This program is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
MA 02111-1307 USA
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For more details see the file COPYING in the source
|
||||
distribution of Linux.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc></toc>
|
||||
<chapter id="intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Tracepoints are static probe points that are located in strategic points
|
||||
throughout the kernel. 'Probes' register/unregister with tracepoints
|
||||
via a callback mechanism. The 'probes' are strictly typed functions that
|
||||
are passed a unique set of parameters defined by each tracepoint.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
From this simple callback mechanism, 'probes' can be used to profile, debug,
|
||||
and understand kernel behavior. There are a number of tools that provide a
|
||||
framework for using 'probes'. These tools include Systemtap, ftrace, and
|
||||
LTTng.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Tracepoints are defined in a number of header files via various macros. Thus,
|
||||
the purpose of this document is to provide a clear accounting of the available
|
||||
tracepoints. The intention is to understand not only what tracepoints are
|
||||
available but also to understand where future tracepoints might be added.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The API presented has functions of the form:
|
||||
<function>trace_tracepointname(function parameters)</function>. These are the
|
||||
tracepoints callbacks that are found throughout the code. Registering and
|
||||
unregistering probes with these callback sites is covered in the
|
||||
<filename>Documentation/trace/*</filename> directory.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="irq">
|
||||
<title>IRQ</title>
|
||||
!Iinclude/trace/events/irq.h
|
||||
</chapter>
|
||||
|
||||
</book>
|
|
@ -192,23 +192,24 @@ rcu/rcuhier (which displays the struct rcu_node hierarchy).
|
|||
The output of "cat rcu/rcudata" looks as follows:
|
||||
|
||||
rcu:
|
||||
0 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=1 rp=3c2a dt=23301/73 dn=2 df=1882 of=0 ri=2126 ql=2 b=10
|
||||
1 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=3 rp=39a6 dt=78073/1 dn=2 df=1402 of=0 ri=1875 ql=46 b=10
|
||||
2 c=4010 g=4010 pq=1 pqc=4010 qp=0 rpfq=-5 rp=1d12 dt=16646/0 dn=2 df=3140 of=0 ri=2080 ql=0 b=10
|
||||
3 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=2b50 dt=21159/1 dn=2 df=2230 of=0 ri=1923 ql=72 b=10
|
||||
4 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1644 dt=5783/1 dn=2 df=3348 of=0 ri=2805 ql=7 b=10
|
||||
5 c=4012 g=4013 pq=0 pqc=4011 qp=1 rpfq=3 rp=1aac dt=5879/1 dn=2 df=3140 of=0 ri=2066 ql=10 b=10
|
||||
6 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=ed8 dt=5847/1 dn=2 df=3797 of=0 ri=1266 ql=10 b=10
|
||||
7 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1fa2 dt=6199/1 dn=2 df=2795 of=0 ri=2162 ql=28 b=10
|
||||
rcu:
|
||||
0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10
|
||||
1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10
|
||||
2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10
|
||||
3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10
|
||||
4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10
|
||||
5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10
|
||||
6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10
|
||||
7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10
|
||||
rcu_bh:
|
||||
0 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-145 rp=21d6 dt=23301/73 dn=2 df=0 of=0 ri=0 ql=0 b=10
|
||||
1 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-170 rp=20ce dt=78073/1 dn=2 df=26 of=0 ri=5 ql=0 b=10
|
||||
2 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-83 rp=fbd dt=16646/0 dn=2 df=28 of=0 ri=4 ql=0 b=10
|
||||
3 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-105 rp=178c dt=21159/1 dn=2 df=28 of=0 ri=2 ql=0 b=10
|
||||
4 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-30 rp=b54 dt=5783/1 dn=2 df=32 of=0 ri=0 ql=0 b=10
|
||||
5 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-29 rp=df5 dt=5879/1 dn=2 df=30 of=0 ri=3 ql=0 b=10
|
||||
6 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-28 rp=788 dt=5847/1 dn=2 df=32 of=0 ri=0 ql=0 b=10
|
||||
7 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-53 rp=1098 dt=6199/1 dn=2 df=30 of=0 ri=3 ql=0 b=10
|
||||
0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10
|
||||
1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10
|
||||
2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
|
||||
3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10
|
||||
4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
|
||||
5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
|
||||
6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
|
||||
7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
|
||||
|
||||
The first section lists the rcu_data structures for rcu, the second for
|
||||
rcu_bh. Each section has one line per CPU, or eight for this 8-CPU system.
|
||||
|
@ -253,12 +254,6 @@ o "pqc" indicates which grace period the last-observed quiescent
|
|||
o "qp" indicates that RCU still expects a quiescent state from
|
||||
this CPU.
|
||||
|
||||
o "rpfq" is the number of rcu_pending() calls on this CPU required
|
||||
to induce this CPU to invoke force_quiescent_state().
|
||||
|
||||
o "rp" is low-order four hex digits of the count of how many times
|
||||
rcu_pending() has been invoked on this CPU.
|
||||
|
||||
o "dt" is the current value of the dyntick counter that is incremented
|
||||
when entering or leaving dynticks idle state, either by the
|
||||
scheduler or by irq. The number after the "/" is the interrupt
|
||||
|
@ -305,6 +300,9 @@ o "b" is the batch limit for this CPU. If more than this number
|
|||
of RCU callbacks is ready to invoke, then the remainder will
|
||||
be deferred.
|
||||
|
||||
There is also an rcu/rcudata.csv file with the same information in
|
||||
comma-separated-variable spreadsheet format.
|
||||
|
||||
|
||||
The output of "cat rcu/rcugp" looks as follows:
|
||||
|
||||
|
@ -411,3 +409,63 @@ o Each element of the form "1/1 0:127 ^0" represents one struct
|
|||
For example, the first entry at the lowest level shows
|
||||
"^0", indicating that it corresponds to bit zero in
|
||||
the first entry at the middle level.
|
||||
|
||||
|
||||
The output of "cat rcu/rcu_pending" looks as follows:
|
||||
|
||||
rcu:
|
||||
0 np=255892 qsp=53936 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741
|
||||
1 np=261224 qsp=54638 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792
|
||||
2 np=237496 qsp=49664 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629
|
||||
3 np=236249 qsp=48766 cbr=0 cng=286 gpc=48049 gps=1218 nf=207 nn=137723
|
||||
4 np=221310 qsp=46850 cbr=0 cng=26 gpc=43161 gps=4634 nf=3529 nn=123110
|
||||
5 np=237332 qsp=48449 cbr=0 cng=54 gpc=47920 gps=3252 nf=201 nn=137456
|
||||
6 np=219995 qsp=46718 cbr=0 cng=50 gpc=42098 gps=6093 nf=4202 nn=120834
|
||||
7 np=249893 qsp=49390 cbr=0 cng=72 gpc=38400 gps=17102 nf=41 nn=144888
|
||||
rcu_bh:
|
||||
0 np=146741 qsp=1419 cbr=0 cng=6 gpc=0 gps=0 nf=2 nn=145314
|
||||
1 np=155792 qsp=12597 cbr=0 cng=0 gpc=4 gps=8 nf=3 nn=143180
|
||||
2 np=136629 qsp=18680 cbr=0 cng=0 gpc=7 gps=6 nf=0 nn=117936
|
||||
3 np=137723 qsp=2843 cbr=0 cng=0 gpc=10 gps=7 nf=0 nn=134863
|
||||
4 np=123110 qsp=12433 cbr=0 cng=0 gpc=4 gps=2 nf=0 nn=110671
|
||||
5 np=137456 qsp=4210 cbr=0 cng=0 gpc=6 gps=5 nf=0 nn=133235
|
||||
6 np=120834 qsp=9902 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921
|
||||
7 np=144888 qsp=26336 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542
|
||||
|
||||
As always, this is once again split into "rcu" and "rcu_bh" portions.
|
||||
The fields are as follows:
|
||||
|
||||
o "np" is the number of times that __rcu_pending() has been invoked
|
||||
for the corresponding flavor of RCU.
|
||||
|
||||
o "qsp" is the number of times that the RCU was waiting for a
|
||||
quiescent state from this CPU.
|
||||
|
||||
o "cbr" is the number of times that this CPU had RCU callbacks
|
||||
that had passed through a grace period, and were thus ready
|
||||
to be invoked.
|
||||
|
||||
o "cng" is the number of times that this CPU needed another
|
||||
grace period while RCU was idle.
|
||||
|
||||
o "gpc" is the number of times that an old grace period had
|
||||
completed, but this CPU was not yet aware of it.
|
||||
|
||||
o "gps" is the number of times that a new grace period had started,
|
||||
but this CPU was not yet aware of it.
|
||||
|
||||
o "nf" is the number of times that this CPU suspected that the
|
||||
current grace period had run for too long, and thus needed to
|
||||
be forced.
|
||||
|
||||
Please note that "forcing" consists of sending resched IPIs
|
||||
to holdout CPUs. If that CPU really still is in an old RCU
|
||||
read-side critical section, then we really do have to wait for it.
|
||||
The assumption behing "forcing" is that the CPU is not still in
|
||||
an old RCU read-side critical section, but has not yet responded
|
||||
for some other reason.
|
||||
|
||||
o "nn" is the number of times that this CPU needed nothing. Alert
|
||||
readers will note that the rcu "nn" number for a given CPU very
|
||||
closely matches the rcu_bh "np" number for that same CPU. This
|
||||
is due to short-circuit evaluation in rcu_pending().
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
Futex Requeue PI
|
||||
----------------
|
||||
|
||||
Requeueing of tasks from a non-PI futex to a PI futex requires
|
||||
special handling in order to ensure the underlying rt_mutex is never
|
||||
left without an owner if it has waiters; doing so would break the PI
|
||||
boosting logic [see rt-mutex-desgin.txt] For the purposes of
|
||||
brevity, this action will be referred to as "requeue_pi" throughout
|
||||
this document. Priority inheritance is abbreviated throughout as
|
||||
"PI".
|
||||
|
||||
Motivation
|
||||
----------
|
||||
|
||||
Without requeue_pi, the glibc implementation of
|
||||
pthread_cond_broadcast() must resort to waking all the tasks waiting
|
||||
on a pthread_condvar and letting them try to sort out which task
|
||||
gets to run first in classic thundering-herd formation. An ideal
|
||||
implementation would wake the highest-priority waiter, and leave the
|
||||
rest to the natural wakeup inherent in unlocking the mutex
|
||||
associated with the condvar.
|
||||
|
||||
Consider the simplified glibc calls:
|
||||
|
||||
/* caller must lock mutex */
|
||||
pthread_cond_wait(cond, mutex)
|
||||
{
|
||||
lock(cond->__data.__lock);
|
||||
unlock(mutex);
|
||||
do {
|
||||
unlock(cond->__data.__lock);
|
||||
futex_wait(cond->__data.__futex);
|
||||
lock(cond->__data.__lock);
|
||||
} while(...)
|
||||
unlock(cond->__data.__lock);
|
||||
lock(mutex);
|
||||
}
|
||||
|
||||
pthread_cond_broadcast(cond)
|
||||
{
|
||||
lock(cond->__data.__lock);
|
||||
unlock(cond->__data.__lock);
|
||||
futex_requeue(cond->data.__futex, cond->mutex);
|
||||
}
|
||||
|
||||
Once pthread_cond_broadcast() requeues the tasks, the cond->mutex
|
||||
has waiters. Note that pthread_cond_wait() attempts to lock the
|
||||
mutex only after it has returned to user space. This will leave the
|
||||
underlying rt_mutex with waiters, and no owner, breaking the
|
||||
previously mentioned PI-boosting algorithms.
|
||||
|
||||
In order to support PI-aware pthread_condvar's, the kernel needs to
|
||||
be able to requeue tasks to PI futexes. This support implies that
|
||||
upon a successful futex_wait system call, the caller would return to
|
||||
user space already holding the PI futex. The glibc implementation
|
||||
would be modified as follows:
|
||||
|
||||
|
||||
/* caller must lock mutex */
|
||||
pthread_cond_wait_pi(cond, mutex)
|
||||
{
|
||||
lock(cond->__data.__lock);
|
||||
unlock(mutex);
|
||||
do {
|
||||
unlock(cond->__data.__lock);
|
||||
futex_wait_requeue_pi(cond->__data.__futex);
|
||||
lock(cond->__data.__lock);
|
||||
} while(...)
|
||||
unlock(cond->__data.__lock);
|
||||
/* the kernel acquired the the mutex for us */
|
||||
}
|
||||
|
||||
pthread_cond_broadcast_pi(cond)
|
||||
{
|
||||
lock(cond->__data.__lock);
|
||||
unlock(cond->__data.__lock);
|
||||
futex_requeue_pi(cond->data.__futex, cond->mutex);
|
||||
}
|
||||
|
||||
The actual glibc implementation will likely test for PI and make the
|
||||
necessary changes inside the existing calls rather than creating new
|
||||
calls for the PI cases. Similar changes are needed for
|
||||
pthread_cond_timedwait() and pthread_cond_signal().
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
In order to ensure the rt_mutex has an owner if it has waiters, it
|
||||
is necessary for both the requeue code, as well as the waiting code,
|
||||
to be able to acquire the rt_mutex before returning to user space.
|
||||
The requeue code cannot simply wake the waiter and leave it to
|
||||
acquire the rt_mutex as it would open a race window between the
|
||||
requeue call returning to user space and the waiter waking and
|
||||
starting to run. This is especially true in the uncontended case.
|
||||
|
||||
The solution involves two new rt_mutex helper routines,
|
||||
rt_mutex_start_proxy_lock() and rt_mutex_finish_proxy_lock(), which
|
||||
allow the requeue code to acquire an uncontended rt_mutex on behalf
|
||||
of the waiter and to enqueue the waiter on a contended rt_mutex.
|
||||
Two new system calls provide the kernel<->user interface to
|
||||
requeue_pi: FUTEX_WAIT_REQUEUE_PI and FUTEX_REQUEUE_CMP_PI.
|
||||
|
||||
FUTEX_WAIT_REQUEUE_PI is called by the waiter (pthread_cond_wait()
|
||||
and pthread_cond_timedwait()) to block on the initial futex and wait
|
||||
to be requeued to a PI-aware futex. The implementation is the
|
||||
result of a high-speed collision between futex_wait() and
|
||||
futex_lock_pi(), with some extra logic to check for the additional
|
||||
wake-up scenarios.
|
||||
|
||||
FUTEX_REQUEUE_CMP_PI is called by the waker
|
||||
(pthread_cond_broadcast() and pthread_cond_signal()) to requeue and
|
||||
possibly wake the waiting tasks. Internally, this system call is
|
||||
still handled by futex_requeue (by passing requeue_pi=1). Before
|
||||
requeueing, futex_requeue() attempts to acquire the requeue target
|
||||
PI futex on behalf of the top waiter. If it can, this waiter is
|
||||
woken. futex_requeue() then proceeds to requeue the remaining
|
||||
nr_wake+nr_requeue tasks to the PI futex, calling
|
||||
rt_mutex_start_proxy_lock() prior to each requeue to prepare the
|
||||
task as a waiter on the underlying rt_mutex. It is possible that
|
||||
the lock can be acquired at this stage as well, if so, the next
|
||||
waiter is woken to finish the acquisition of the lock.
|
||||
|
||||
FUTEX_REQUEUE_PI accepts nr_wake and nr_requeue as arguments, but
|
||||
their sum is all that really matters. futex_requeue() will wake or
|
||||
requeue up to nr_wake + nr_requeue tasks. It will wake only as many
|
||||
tasks as it can acquire the lock for, which in the majority of cases
|
||||
should be 0 as good programming practice dictates that the caller of
|
||||
either pthread_cond_broadcast() or pthread_cond_signal() acquire the
|
||||
mutex prior to making the call. FUTEX_REQUEUE_PI requires that
|
||||
nr_wake=1. nr_requeue should be INT_MAX for broadcast and 0 for
|
||||
signal.
|
|
@ -56,7 +56,6 @@ parameter is applicable:
|
|||
ISAPNP ISA PnP code is enabled.
|
||||
ISDN Appropriate ISDN support is enabled.
|
||||
JOY Appropriate joystick support is enabled.
|
||||
KMEMTRACE kmemtrace is enabled.
|
||||
LIBATA Libata driver is enabled
|
||||
LP Printer support is enabled.
|
||||
LOOP Loopback device support is enabled.
|
||||
|
@ -329,11 +328,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
flushed before they will be reused, which
|
||||
is a lot of faster
|
||||
|
||||
amd_iommu_size= [HW,X86-64]
|
||||
Define the size of the aperture for the AMD IOMMU
|
||||
driver. Possible values are:
|
||||
'32M', '64M' (default), '128M', '256M', '512M', '1G'
|
||||
|
||||
amijoy.map= [HW,JOY] Amiga joystick support
|
||||
Map of devices attached to JOY0DAT and JOY1DAT
|
||||
Format: <a>,<b>
|
||||
|
@ -646,6 +640,13 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
DMA-API debugging code disables itself because the
|
||||
architectural default is too low.
|
||||
|
||||
dma_debug_driver=<driver_name>
|
||||
With this option the DMA-API debugging driver
|
||||
filter feature can be enabled at boot time. Just
|
||||
pass the driver to filter for as the parameter.
|
||||
The filter can be disabled or changed to another
|
||||
driver later using sysfs.
|
||||
|
||||
dscc4.setup= [NET]
|
||||
|
||||
dtc3181e= [HW,SCSI]
|
||||
|
@ -752,12 +753,25 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
|
||||
|
||||
ftrace=[tracer]
|
||||
[ftrace] will set and start the specified tracer
|
||||
[FTRACE] will set and start the specified tracer
|
||||
as early as possible in order to facilitate early
|
||||
boot debugging.
|
||||
|
||||
ftrace_dump_on_oops
|
||||
[ftrace] will dump the trace buffers on oops.
|
||||
[FTRACE] will dump the trace buffers on oops.
|
||||
|
||||
ftrace_filter=[function-list]
|
||||
[FTRACE] Limit the functions traced by the function
|
||||
tracer at boot up. function-list is a comma separated
|
||||
list of functions. This list can be changed at run
|
||||
time by the set_ftrace_filter file in the debugfs
|
||||
tracing directory.
|
||||
|
||||
ftrace_notrace=[function-list]
|
||||
[FTRACE] Do not trace the functions specified in
|
||||
function-list. This list can be changed at run time
|
||||
by the set_ftrace_notrace file in the debugfs
|
||||
tracing directory.
|
||||
|
||||
gamecon.map[2|3]=
|
||||
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
|
||||
|
@ -1054,15 +1068,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
use the HighMem zone if it exists, and the Normal
|
||||
zone if it does not.
|
||||
|
||||
kmemtrace.enable= [KNL,KMEMTRACE] Format: { yes | no }
|
||||
Controls whether kmemtrace is enabled
|
||||
at boot-time.
|
||||
|
||||
kmemtrace.subbufs=n [KNL,KMEMTRACE] Overrides the number of
|
||||
subbufs kmemtrace's relay channel has. Set this
|
||||
higher than default (KMEMTRACE_N_SUBBUFS in code) if
|
||||
you experience buffer overruns.
|
||||
|
||||
kgdboc= [HW] kgdb over consoles.
|
||||
Requires a tty driver that supports console polling.
|
||||
(only serial suported for now)
|
||||
|
@ -1575,6 +1580,9 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
noinitrd [RAM] Tells the kernel not to load any configured
|
||||
initial RAM disk.
|
||||
|
||||
nointremap [X86-64, Intel-IOMMU] Do not enable interrupt
|
||||
remapping.
|
||||
|
||||
nointroute [IA-64]
|
||||
|
||||
nojitter [IA64] Disables jitter checking for ITC timers.
|
||||
|
|
|
@ -31,6 +31,7 @@ Contents:
|
|||
|
||||
- Locking functions.
|
||||
- Interrupt disabling functions.
|
||||
- Sleep and wake-up functions.
|
||||
- Miscellaneous functions.
|
||||
|
||||
(*) Inter-CPU locking barrier effects.
|
||||
|
@ -1217,6 +1218,132 @@ barriers are required in such a situation, they must be provided from some
|
|||
other means.
|
||||
|
||||
|
||||
SLEEP AND WAKE-UP FUNCTIONS
|
||||
---------------------------
|
||||
|
||||
Sleeping and waking on an event flagged in global data can be viewed as an
|
||||
interaction between two pieces of data: the task state of the task waiting for
|
||||
the event and the global data used to indicate the event. To make sure that
|
||||
these appear to happen in the right order, the primitives to begin the process
|
||||
of going to sleep, and the primitives to initiate a wake up imply certain
|
||||
barriers.
|
||||
|
||||
Firstly, the sleeper normally follows something like this sequence of events:
|
||||
|
||||
for (;;) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
if (event_indicated)
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
|
||||
A general memory barrier is interpolated automatically by set_current_state()
|
||||
after it has altered the task state:
|
||||
|
||||
CPU 1
|
||||
===============================
|
||||
set_current_state();
|
||||
set_mb();
|
||||
STORE current->state
|
||||
<general barrier>
|
||||
LOAD event_indicated
|
||||
|
||||
set_current_state() may be wrapped by:
|
||||
|
||||
prepare_to_wait();
|
||||
prepare_to_wait_exclusive();
|
||||
|
||||
which therefore also imply a general memory barrier after setting the state.
|
||||
The whole sequence above is available in various canned forms, all of which
|
||||
interpolate the memory barrier in the right place:
|
||||
|
||||
wait_event();
|
||||
wait_event_interruptible();
|
||||
wait_event_interruptible_exclusive();
|
||||
wait_event_interruptible_timeout();
|
||||
wait_event_killable();
|
||||
wait_event_timeout();
|
||||
wait_on_bit();
|
||||
wait_on_bit_lock();
|
||||
|
||||
|
||||
Secondly, code that performs a wake up normally follows something like this:
|
||||
|
||||
event_indicated = 1;
|
||||
wake_up(&event_wait_queue);
|
||||
|
||||
or:
|
||||
|
||||
event_indicated = 1;
|
||||
wake_up_process(event_daemon);
|
||||
|
||||
A write memory barrier is implied by wake_up() and co. if and only if they wake
|
||||
something up. The barrier occurs before the task state is cleared, and so sits
|
||||
between the STORE to indicate the event and the STORE to set TASK_RUNNING:
|
||||
|
||||
CPU 1 CPU 2
|
||||
=============================== ===============================
|
||||
set_current_state(); STORE event_indicated
|
||||
set_mb(); wake_up();
|
||||
STORE current->state <write barrier>
|
||||
<general barrier> STORE current->state
|
||||
LOAD event_indicated
|
||||
|
||||
The available waker functions include:
|
||||
|
||||
complete();
|
||||
wake_up();
|
||||
wake_up_all();
|
||||
wake_up_bit();
|
||||
wake_up_interruptible();
|
||||
wake_up_interruptible_all();
|
||||
wake_up_interruptible_nr();
|
||||
wake_up_interruptible_poll();
|
||||
wake_up_interruptible_sync();
|
||||
wake_up_interruptible_sync_poll();
|
||||
wake_up_locked();
|
||||
wake_up_locked_poll();
|
||||
wake_up_nr();
|
||||
wake_up_poll();
|
||||
wake_up_process();
|
||||
|
||||
|
||||
[!] Note that the memory barriers implied by the sleeper and the waker do _not_
|
||||
order multiple stores before the wake-up with respect to loads of those stored
|
||||
values after the sleeper has called set_current_state(). For instance, if the
|
||||
sleeper does:
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (event_indicated)
|
||||
break;
|
||||
__set_current_state(TASK_RUNNING);
|
||||
do_something(my_data);
|
||||
|
||||
and the waker does:
|
||||
|
||||
my_data = value;
|
||||
event_indicated = 1;
|
||||
wake_up(&event_wait_queue);
|
||||
|
||||
there's no guarantee that the change to event_indicated will be perceived by
|
||||
the sleeper as coming after the change to my_data. In such a circumstance, the
|
||||
code on both sides must interpolate its own memory barriers between the
|
||||
separate data accesses. Thus the above sleeper ought to do:
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (event_indicated) {
|
||||
smp_rmb();
|
||||
do_something(my_data);
|
||||
}
|
||||
|
||||
and the waker should do:
|
||||
|
||||
my_data = value;
|
||||
smp_wmb();
|
||||
event_indicated = 1;
|
||||
wake_up(&event_wait_queue);
|
||||
|
||||
|
||||
MISCELLANEOUS FUNCTIONS
|
||||
-----------------------
|
||||
|
||||
|
@ -1366,7 +1493,7 @@ WHERE ARE MEMORY BARRIERS NEEDED?
|
|||
|
||||
Under normal operation, memory operation reordering is generally not going to
|
||||
be a problem as a single-threaded linear piece of code will still appear to
|
||||
work correctly, even if it's in an SMP kernel. There are, however, three
|
||||
work correctly, even if it's in an SMP kernel. There are, however, four
|
||||
circumstances in which reordering definitely _could_ be a problem:
|
||||
|
||||
(*) Interprocessor interaction.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
CONTENTS
|
||||
========
|
||||
|
||||
0. WARNING
|
||||
1. Overview
|
||||
1.1 The problem
|
||||
1.2 The solution
|
||||
|
@ -14,6 +15,23 @@ CONTENTS
|
|||
3. Future plans
|
||||
|
||||
|
||||
0. WARNING
|
||||
==========
|
||||
|
||||
Fiddling with these settings can result in an unstable system, the knobs are
|
||||
root only and assumes root knows what he is doing.
|
||||
|
||||
Most notable:
|
||||
|
||||
* very small values in sched_rt_period_us can result in an unstable
|
||||
system when the period is smaller than either the available hrtimer
|
||||
resolution, or the time it takes to handle the budget refresh itself.
|
||||
|
||||
* very small values in sched_rt_runtime_us can result in an unstable
|
||||
system when the runtime is so small the system has difficulty making
|
||||
forward progress (NOTE: the migration thread and kstopmachine both
|
||||
are real-time processes).
|
||||
|
||||
1. Overview
|
||||
===========
|
||||
|
||||
|
@ -169,7 +187,7 @@ get their allocated time.
|
|||
|
||||
Implementing SCHED_EDF might take a while to complete. Priority Inheritance is
|
||||
the biggest challenge as the current linux PI infrastructure is geared towards
|
||||
the limited static priority levels 0-139. With deadline scheduling you need to
|
||||
the limited static priority levels 0-99. With deadline scheduling you need to
|
||||
do deadline inheritance (since priority is inversely proportional to the
|
||||
deadline delta (deadline - now).
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
Event Tracing
|
||||
|
||||
Documentation written by Theodore Ts'o
|
||||
Updated by Li Zefan
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
Tracepoints (see Documentation/trace/tracepoints.txt) can be used
|
||||
without creating custom kernel modules to register probe functions
|
||||
using the event tracing infrastructure.
|
||||
|
||||
Not all tracepoints can be traced using the event tracing system;
|
||||
the kernel developer must provide code snippets which define how the
|
||||
tracing information is saved into the tracing buffer, and how the
|
||||
tracing information should be printed.
|
||||
|
||||
2. Using Event Tracing
|
||||
======================
|
||||
|
||||
2.1 Via the 'set_event' interface
|
||||
---------------------------------
|
||||
|
||||
The events which are available for tracing can be found in the file
|
||||
/debug/tracing/available_events.
|
||||
|
||||
To enable a particular event, such as 'sched_wakeup', simply echo it
|
||||
to /debug/tracing/set_event. For example:
|
||||
|
||||
# echo sched_wakeup >> /debug/tracing/set_event
|
||||
|
||||
[ Note: '>>' is necessary, otherwise it will firstly disable
|
||||
all the events. ]
|
||||
|
||||
To disable an event, echo the event name to the set_event file prefixed
|
||||
with an exclamation point:
|
||||
|
||||
# echo '!sched_wakeup' >> /debug/tracing/set_event
|
||||
|
||||
To disable all events, echo an empty line to the set_event file:
|
||||
|
||||
# echo > /debug/tracing/set_event
|
||||
|
||||
To enable all events, echo '*:*' or '*:' to the set_event file:
|
||||
|
||||
# echo *:* > /debug/tracing/set_event
|
||||
|
||||
The events are organized into subsystems, such as ext4, irq, sched,
|
||||
etc., and a full event name looks like this: <subsystem>:<event>. The
|
||||
subsystem name is optional, but it is displayed in the available_events
|
||||
file. All of the events in a subsystem can be specified via the syntax
|
||||
"<subsystem>:*"; for example, to enable all irq events, you can use the
|
||||
command:
|
||||
|
||||
# echo 'irq:*' > /debug/tracing/set_event
|
||||
|
||||
2.2 Via the 'enable' toggle
|
||||
---------------------------
|
||||
|
||||
The events available are also listed in /debug/tracing/events/ hierarchy
|
||||
of directories.
|
||||
|
||||
To enable event 'sched_wakeup':
|
||||
|
||||
# echo 1 > /debug/tracing/events/sched/sched_wakeup/enable
|
||||
|
||||
To disable it:
|
||||
|
||||
# echo 0 > /debug/tracing/events/sched/sched_wakeup/enable
|
||||
|
||||
To enable all events in sched subsystem:
|
||||
|
||||
# echo 1 > /debug/tracing/events/sched/enable
|
||||
|
||||
To eanble all events:
|
||||
|
||||
# echo 1 > /debug/tracing/events/enable
|
||||
|
||||
When reading one of these enable files, there are four results:
|
||||
|
||||
0 - all events this file affects are disabled
|
||||
1 - all events this file affects are enabled
|
||||
X - there is a mixture of events enabled and disabled
|
||||
? - this file does not affect any event
|
||||
|
||||
3. Defining an event-enabled tracepoint
|
||||
=======================================
|
||||
|
||||
See The example provided in samples/trace_events
|
||||
|
|
@ -179,7 +179,7 @@ Here is the list of current tracers that may be configured.
|
|||
|
||||
Function call tracer to trace all kernel functions.
|
||||
|
||||
"function_graph_tracer"
|
||||
"function_graph"
|
||||
|
||||
Similar to the function tracer except that the
|
||||
function tracer probes the functions on their entry
|
||||
|
@ -518,9 +518,18 @@ priority with zero (0) being the highest priority and the nice
|
|||
values starting at 100 (nice -20). Below is a quick chart to map
|
||||
the kernel priority to user land priorities.
|
||||
|
||||
Kernel priority: 0 to 99 ==> user RT priority 99 to 0
|
||||
Kernel priority: 100 to 139 ==> user nice -20 to 19
|
||||
Kernel priority: 140 ==> idle task priority
|
||||
Kernel Space User Space
|
||||
===============================================================
|
||||
0(high) to 98(low) user RT priority 99(high) to 1(low)
|
||||
with SCHED_RR or SCHED_FIFO
|
||||
---------------------------------------------------------------
|
||||
99 sched_priority is not used in scheduling
|
||||
decisions(it must be specified as 0)
|
||||
---------------------------------------------------------------
|
||||
100(high) to 139(low) user nice -20(high) to 19(low)
|
||||
---------------------------------------------------------------
|
||||
140 idle task priority
|
||||
---------------------------------------------------------------
|
||||
|
||||
The task states are:
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
The power tracer collects detailed information about C-state and P-state
|
||||
transitions, instead of just looking at the high-level "average"
|
||||
information.
|
||||
|
||||
There is a helper script found in scrips/tracing/power.pl in the kernel
|
||||
sources which can be used to parse this information and create a
|
||||
Scalable Vector Graphics (SVG) picture from the trace data.
|
||||
|
||||
To use this tracer:
|
||||
|
||||
echo 0 > /sys/kernel/debug/tracing/tracing_enabled
|
||||
echo power > /sys/kernel/debug/tracing/current_tracer
|
||||
echo 1 > /sys/kernel/debug/tracing/tracing_enabled
|
||||
sleep 1
|
||||
echo 0 > /sys/kernel/debug/tracing/tracing_enabled
|
||||
cat /sys/kernel/debug/tracing/trace | \
|
||||
perl scripts/tracing/power.pl > out.sv
|
|
@ -50,6 +50,10 @@ Protocol 2.08: (Kernel 2.6.26) Added crc32 checksum and ELF format
|
|||
Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical
|
||||
pointer to single linked list of struct setup_data.
|
||||
|
||||
Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment
|
||||
beyond the kernel_alignment added, new init_size and
|
||||
pref_address fields. Added extended boot loader IDs.
|
||||
|
||||
**** MEMORY LAYOUT
|
||||
|
||||
The traditional memory map for the kernel loader, used for Image or
|
||||
|
@ -168,12 +172,13 @@ Offset Proto Name Meaning
|
|||
021C/4 2.00+ ramdisk_size initrd size (set by boot loader)
|
||||
0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only
|
||||
0224/2 2.01+ heap_end_ptr Free memory after setup end
|
||||
0226/2 N/A pad1 Unused
|
||||
0226/1 2.02+(3 ext_loader_ver Extended boot loader version
|
||||
0227/1 2.02+(3 ext_loader_type Extended boot loader ID
|
||||
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
|
||||
022C/4 2.03+ ramdisk_max Highest legal initrd address
|
||||
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
|
||||
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
|
||||
0235/1 N/A pad2 Unused
|
||||
0235/1 2.10+ min_alignment Minimum alignment, as a power of two
|
||||
0236/2 N/A pad3 Unused
|
||||
0238/4 2.06+ cmdline_size Maximum size of the kernel command line
|
||||
023C/4 2.07+ hardware_subarch Hardware subarchitecture
|
||||
|
@ -182,6 +187,8 @@ Offset Proto Name Meaning
|
|||
024C/4 2.08+ payload_length Length of kernel payload
|
||||
0250/8 2.09+ setup_data 64-bit physical pointer to linked list
|
||||
of struct setup_data
|
||||
0258/8 2.10+ pref_address Preferred loading address
|
||||
0260/4 2.10+ init_size Linear memory required during initialization
|
||||
|
||||
(1) For backwards compatibility, if the setup_sects field contains 0, the
|
||||
real value is 4.
|
||||
|
@ -190,6 +197,8 @@ Offset Proto Name Meaning
|
|||
field are unusable, which means the size of a bzImage kernel
|
||||
cannot be determined.
|
||||
|
||||
(3) Ignored, but safe to set, for boot protocols 2.02-2.09.
|
||||
|
||||
If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
|
||||
the boot protocol version is "old". Loading an old kernel, the
|
||||
following parameters should be assumed:
|
||||
|
@ -343,18 +352,32 @@ Protocol: 2.00+
|
|||
0xTV here, where T is an identifier for the boot loader and V is
|
||||
a version number. Otherwise, enter 0xFF here.
|
||||
|
||||
For boot loader IDs above T = 0xD, write T = 0xE to this field and
|
||||
write the extended ID minus 0x10 to the ext_loader_type field.
|
||||
Similarly, the ext_loader_ver field can be used to provide more than
|
||||
four bits for the bootloader version.
|
||||
|
||||
For example, for T = 0x15, V = 0x234, write:
|
||||
|
||||
type_of_loader <- 0xE4
|
||||
ext_loader_type <- 0x05
|
||||
ext_loader_ver <- 0x23
|
||||
|
||||
Assigned boot loader ids:
|
||||
0 LILO (0x00 reserved for pre-2.00 bootloader)
|
||||
1 Loadlin
|
||||
2 bootsect-loader (0x20, all other values reserved)
|
||||
3 SYSLINUX
|
||||
4 EtherBoot
|
||||
3 Syslinux
|
||||
4 Etherboot/gPXE
|
||||
5 ELILO
|
||||
7 GRUB
|
||||
8 U-BOOT
|
||||
8 U-Boot
|
||||
9 Xen
|
||||
A Gujin
|
||||
B Qemu
|
||||
C Arcturus Networks uCbootloader
|
||||
E Extended (see ext_loader_type)
|
||||
F Special (0xFF = undefined)
|
||||
|
||||
Please contact <hpa@zytor.com> if you need a bootloader ID
|
||||
value assigned.
|
||||
|
@ -453,6 +476,35 @@ Protocol: 2.01+
|
|||
Set this field to the offset (from the beginning of the real-mode
|
||||
code) of the end of the setup stack/heap, minus 0x0200.
|
||||
|
||||
Field name: ext_loader_ver
|
||||
Type: write (optional)
|
||||
Offset/size: 0x226/1
|
||||
Protocol: 2.02+
|
||||
|
||||
This field is used as an extension of the version number in the
|
||||
type_of_loader field. The total version number is considered to be
|
||||
(type_of_loader & 0x0f) + (ext_loader_ver << 4).
|
||||
|
||||
The use of this field is boot loader specific. If not written, it
|
||||
is zero.
|
||||
|
||||
Kernels prior to 2.6.31 did not recognize this field, but it is safe
|
||||
to write for protocol version 2.02 or higher.
|
||||
|
||||
Field name: ext_loader_type
|
||||
Type: write (obligatory if (type_of_loader & 0xf0) == 0xe0)
|
||||
Offset/size: 0x227/1
|
||||
Protocol: 2.02+
|
||||
|
||||
This field is used as an extension of the type number in
|
||||
type_of_loader field. If the type in type_of_loader is 0xE, then
|
||||
the actual type is (ext_loader_type + 0x10).
|
||||
|
||||
This field is ignored if the type in type_of_loader is not 0xE.
|
||||
|
||||
Kernels prior to 2.6.31 did not recognize this field, but it is safe
|
||||
to write for protocol version 2.02 or higher.
|
||||
|
||||
Field name: cmd_line_ptr
|
||||
Type: write (obligatory)
|
||||
Offset/size: 0x228/4
|
||||
|
@ -482,11 +534,19 @@ Protocol: 2.03+
|
|||
0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
|
||||
|
||||
Field name: kernel_alignment
|
||||
Type: read (reloc)
|
||||
Type: read/modify (reloc)
|
||||
Offset/size: 0x230/4
|
||||
Protocol: 2.05+
|
||||
Protocol: 2.05+ (read), 2.10+ (modify)
|
||||
|
||||
Alignment unit required by the kernel (if relocatable_kernel is true.)
|
||||
Alignment unit required by the kernel (if relocatable_kernel is
|
||||
true.) A relocatable kernel that is loaded at an alignment
|
||||
incompatible with the value in this field will be realigned during
|
||||
kernel initialization.
|
||||
|
||||
Starting with protocol version 2.10, this reflects the kernel
|
||||
alignment preferred for optimal performance; it is possible for the
|
||||
loader to modify this field to permit a lesser alignment. See the
|
||||
min_alignment and pref_address field below.
|
||||
|
||||
Field name: relocatable_kernel
|
||||
Type: read (reloc)
|
||||
|
@ -498,6 +558,22 @@ Protocol: 2.05+
|
|||
After loading, the boot loader must set the code32_start field to
|
||||
point to the loaded code, or to a boot loader hook.
|
||||
|
||||
Field name: min_alignment
|
||||
Type: read (reloc)
|
||||
Offset/size: 0x235/1
|
||||
Protocol: 2.10+
|
||||
|
||||
This field, if nonzero, indicates as a power of two the minimum
|
||||
alignment required, as opposed to preferred, by the kernel to boot.
|
||||
If a boot loader makes use of this field, it should update the
|
||||
kernel_alignment field with the alignment unit desired; typically:
|
||||
|
||||
kernel_alignment = 1 << min_alignment
|
||||
|
||||
There may be a considerable performance cost with an excessively
|
||||
misaligned kernel. Therefore, a loader should typically try each
|
||||
power-of-two alignment from kernel_alignment down to this alignment.
|
||||
|
||||
Field name: cmdline_size
|
||||
Type: read
|
||||
Offset/size: 0x238/4
|
||||
|
@ -582,6 +658,36 @@ Protocol: 2.09+
|
|||
sure to consider the case where the linked list already contains
|
||||
entries.
|
||||
|
||||
Field name: pref_address
|
||||
Type: read (reloc)
|
||||
Offset/size: 0x258/8
|
||||
Protocol: 2.10+
|
||||
|
||||
This field, if nonzero, represents a preferred load address for the
|
||||
kernel. A relocating bootloader should attempt to load at this
|
||||
address if possible.
|
||||
|
||||
A non-relocatable kernel will unconditionally move itself and to run
|
||||
at this address.
|
||||
|
||||
Field name: init_size
|
||||
Type: read
|
||||
Offset/size: 0x25c/4
|
||||
|
||||
This field indicates the amount of linear contiguous memory starting
|
||||
at the kernel runtime start address that the kernel needs before it
|
||||
is capable of examining its memory map. This is not the same thing
|
||||
as the total amount of memory the kernel needs to boot, but it can
|
||||
be used by a relocating boot loader to help select a safe load
|
||||
address for the kernel.
|
||||
|
||||
The kernel runtime start address is determined by the following algorithm:
|
||||
|
||||
if (relocatable_kernel)
|
||||
runtime_start = align_up(load_address, kernel_alignment)
|
||||
else
|
||||
runtime_start = pref_address
|
||||
|
||||
|
||||
**** THE IMAGE CHECKSUM
|
||||
|
||||
|
|
|
@ -150,11 +150,6 @@ NUMA
|
|||
Otherwise, the remaining system RAM is allocated to an
|
||||
additional node.
|
||||
|
||||
numa=hotadd=percent
|
||||
Only allow hotadd memory to preallocate page structures upto
|
||||
percent of already available memory.
|
||||
numa=hotadd=0 will disable hotadd memory.
|
||||
|
||||
ACPI
|
||||
|
||||
acpi=off Don't enable ACPI
|
||||
|
|
|
@ -6,10 +6,11 @@ Virtual memory map with 4 level page tables:
|
|||
0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
|
||||
hole caused by [48:63] sign extension
|
||||
ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole
|
||||
ffff880000000000 - ffffc0ffffffffff (=57 TB) direct mapping of all phys. memory
|
||||
ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole
|
||||
ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space
|
||||
ffffe20000000000 - ffffe2ffffffffff (=40 bits) virtual memory map (1TB)
|
||||
ffff880000000000 - ffffc7ffffffffff (=64 TB) direct mapping of all phys. memory
|
||||
ffffc80000000000 - ffffc8ffffffffff (=40 bits) hole
|
||||
ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space
|
||||
ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
|
||||
ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
|
||||
... unused hole ...
|
||||
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
|
||||
ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space
|
||||
|
|
10
MAINTAINERS
10
MAINTAINERS
|
@ -4392,6 +4392,16 @@ S: Maintained
|
|||
F: include/linux/delayacct.h
|
||||
F: kernel/delayacct.c
|
||||
|
||||
PERFORMANCE COUNTER SUBSYSTEM
|
||||
P: Peter Zijlstra
|
||||
M: a.p.zijlstra@chello.nl
|
||||
P: Paul Mackerras
|
||||
M: paulus@samba.org
|
||||
P: Ingo Molnar
|
||||
M: mingo@elte.hu
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
|
||||
PERSONALITY HANDLING
|
||||
P: Christoph Hellwig
|
||||
M: hch@infradead.org
|
||||
|
|
|
@ -176,22 +176,26 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
dp264_set_affinity(unsigned int irq, const struct cpumask *affinity)
|
||||
{
|
||||
spin_lock(&dp264_irq_lock);
|
||||
cpu_set_irq_affinity(irq, *affinity);
|
||||
tsunami_update_irq_hw(cached_irq_mask);
|
||||
spin_unlock(&dp264_irq_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
|
||||
{
|
||||
spin_lock(&dp264_irq_lock);
|
||||
cpu_set_irq_affinity(irq - 16, *affinity);
|
||||
tsunami_update_irq_hw(cached_irq_mask);
|
||||
spin_unlock(&dp264_irq_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type dp264_irq_type = {
|
||||
|
|
|
@ -157,13 +157,15 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
|
|||
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
titan_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
|
||||
{
|
||||
spin_lock(&titan_irq_lock);
|
||||
titan_cpu_set_irq_affinity(irq - 16, *affinity);
|
||||
titan_update_irq_hw(titan_cached_irq_mask);
|
||||
spin_unlock(&titan_irq_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -109,7 +109,7 @@ static void gic_unmask_irq(unsigned int irq)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
|
||||
static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
|
||||
{
|
||||
void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3);
|
||||
unsigned int shift = (irq % 4) * 8;
|
||||
|
@ -122,6 +122,8 @@ static void gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
|
|||
val |= 1 << (cpu + shift);
|
||||
writel(val, reg);
|
||||
spin_unlock(&irq_controller_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -325,12 +325,14 @@ static void end_crisv32_irq(unsigned int irq)
|
|||
{
|
||||
}
|
||||
|
||||
void set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
|
||||
int set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&irq_lock, flags);
|
||||
irq_allocations[irq - FIRST_IRQ].mask = *dest;
|
||||
spin_unlock_irqrestore(&irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip crisv32_irq_type = {
|
||||
|
|
|
@ -21,9 +21,10 @@ hpsim_irq_noop (unsigned int irq)
|
|||
{
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
hpsim_set_affinity_noop(unsigned int a, const struct cpumask *b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type irq_type_hp_sim = {
|
||||
|
|
|
@ -636,7 +636,7 @@ void __init acpi_numa_arch_fixup(void)
|
|||
* success: return IRQ number (>=0)
|
||||
* failure: return < 0
|
||||
*/
|
||||
int acpi_register_gsi(u32 gsi, int triggering, int polarity)
|
||||
int acpi_register_gsi(struct device *dev, u32 gsi, int triggering, int polarity)
|
||||
{
|
||||
if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
|
||||
return gsi;
|
||||
|
@ -678,7 +678,8 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
|
|||
|
||||
fadt = (struct acpi_table_fadt *)fadt_header;
|
||||
|
||||
acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
|
||||
acpi_register_gsi(NULL, fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE,
|
||||
ACPI_ACTIVE_LOW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -329,7 +329,7 @@ unmask_irq (unsigned int irq)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
static int
|
||||
iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
|
@ -343,15 +343,15 @@ iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
|
||||
cpu = cpumask_first_and(cpu_online_mask, mask);
|
||||
if (cpu >= nr_cpu_ids)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (irq_prepare_move(irq, cpu))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
dest = cpu_physical_id(cpu);
|
||||
|
||||
if (!iosapic_intr_info[irq].count)
|
||||
return; /* not an IOSAPIC interrupt */
|
||||
return -1; /* not an IOSAPIC interrupt */
|
||||
|
||||
set_irq_affinity_info(irq, dest, redir);
|
||||
|
||||
|
@ -376,7 +376,9 @@ iosapic_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
|
||||
iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
static struct irq_chip ia64_msi_chip;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void ia64_set_msi_irq_affinity(unsigned int irq,
|
||||
static int ia64_set_msi_irq_affinity(unsigned int irq,
|
||||
const cpumask_t *cpu_mask)
|
||||
{
|
||||
struct msi_msg msg;
|
||||
|
@ -20,10 +20,10 @@ static void ia64_set_msi_irq_affinity(unsigned int irq,
|
|||
int cpu = first_cpu(*cpu_mask);
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (irq_prepare_move(irq, cpu))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
read_msi_msg(irq, &msg);
|
||||
|
||||
|
@ -39,6 +39,8 @@ static void ia64_set_msi_irq_affinity(unsigned int irq,
|
|||
|
||||
write_msi_msg(irq, &msg);
|
||||
cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
@ -130,17 +132,17 @@ void arch_teardown_msi_irq(unsigned int irq)
|
|||
|
||||
#ifdef CONFIG_DMAR
|
||||
#ifdef CONFIG_SMP
|
||||
static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
{
|
||||
struct irq_cfg *cfg = irq_cfg + irq;
|
||||
struct msi_msg msg;
|
||||
int cpu = cpumask_first(mask);
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (irq_prepare_move(irq, cpu))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
dmar_msi_read(irq, &msg);
|
||||
|
||||
|
@ -151,6 +153,8 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
|
||||
dmar_msi_write(irq, &msg);
|
||||
cpumask_copy(irq_desc[irq].affinity, mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
|
|
@ -227,7 +227,7 @@ finish_up:
|
|||
return new_irq_info;
|
||||
}
|
||||
|
||||
static void sn_set_affinity_irq(unsigned int irq, const struct cpumask *mask)
|
||||
static int sn_set_affinity_irq(unsigned int irq, const struct cpumask *mask)
|
||||
{
|
||||
struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
|
||||
nasid_t nasid;
|
||||
|
@ -239,6 +239,8 @@ static void sn_set_affinity_irq(unsigned int irq, const struct cpumask *mask)
|
|||
list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
|
||||
sn_irq_lh[irq], list)
|
||||
(void)sn_retarget_vector(sn_irq_info, nasid, slice);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
|
|
@ -151,7 +151,7 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void sn_set_msi_irq_affinity(unsigned int irq,
|
||||
static int sn_set_msi_irq_affinity(unsigned int irq,
|
||||
const struct cpumask *cpu_mask)
|
||||
{
|
||||
struct msi_msg msg;
|
||||
|
@ -168,7 +168,7 @@ static void sn_set_msi_irq_affinity(unsigned int irq,
|
|||
cpu = cpumask_first(cpu_mask);
|
||||
sn_irq_info = sn_msi_info[irq].sn_irq_info;
|
||||
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Release XIO resources for the old MSI PCI address
|
||||
|
@ -189,7 +189,7 @@ static void sn_set_msi_irq_affinity(unsigned int irq,
|
|||
new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
|
||||
sn_msi_info[irq].sn_irq_info = new_irq_info;
|
||||
if (new_irq_info == NULL)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Map the xio address into bus space
|
||||
|
@ -206,6 +206,8 @@ static void sn_set_msi_irq_affinity(unsigned int irq,
|
|||
|
||||
write_msi_msg(irq, &msg);
|
||||
cpumask_copy(irq_desc[irq].affinity, cpu_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
|
||||
static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
|
||||
{
|
||||
int cpu;
|
||||
int bit = irq - OCTEON_IRQ_WORKQ0; /* Bit 0-63 of EN0 */
|
||||
|
@ -199,6 +199,8 @@ static void octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask
|
|||
*/
|
||||
cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2));
|
||||
write_unlock(&octeon_irq_ciu0_rwlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -292,7 +294,7 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
|
||||
static int octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask *dest)
|
||||
{
|
||||
int cpu;
|
||||
int bit = irq - OCTEON_IRQ_WDOG0; /* Bit 0-63 of EN1 */
|
||||
|
@ -315,6 +317,8 @@ static void octeon_irq_ciu1_set_affinity(unsigned int irq, const struct cpumask
|
|||
*/
|
||||
cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num() * 2 + 1));
|
||||
write_unlock(&octeon_irq_ciu1_rwlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ static inline void smtc_im_ack_irq(unsigned int irq)
|
|||
#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
extern void plat_set_irq_affinity(unsigned int irq,
|
||||
extern int plat_set_irq_affinity(unsigned int irq,
|
||||
const struct cpumask *affinity);
|
||||
extern void smtc_forward_irq(unsigned int irq);
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ static void gic_unmask_irq(unsigned int irq)
|
|||
|
||||
static DEFINE_SPINLOCK(gic_lock);
|
||||
|
||||
static void gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
||||
static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
||||
{
|
||||
cpumask_t tmp = CPU_MASK_NONE;
|
||||
unsigned long flags;
|
||||
|
@ -166,7 +166,7 @@ static void gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
|||
|
||||
cpumask_and(&tmp, cpumask, cpu_online_mask);
|
||||
if (cpus_empty(tmp))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
/* Assumption : cpumask refers to a single CPU */
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
|
@ -190,6 +190,7 @@ static void gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
|||
cpumask_copy(irq_desc[irq].affinity, cpumask);
|
||||
spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ struct plat_smp_ops msmtc_smp_ops = {
|
|||
*/
|
||||
|
||||
|
||||
void plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
|
||||
int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
|
||||
{
|
||||
cpumask_t tmask;
|
||||
int cpu = 0;
|
||||
|
@ -156,5 +156,7 @@ void plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
|
|||
|
||||
/* Do any generic SMTC IRQ affinity setup */
|
||||
smtc_set_irq_affinity(irq, tmask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
|
||||
|
|
|
@ -50,7 +50,7 @@ static void enable_bcm1480_irq(unsigned int irq);
|
|||
static void disable_bcm1480_irq(unsigned int irq);
|
||||
static void ack_bcm1480_irq(unsigned int irq);
|
||||
#ifdef CONFIG_SMP
|
||||
static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask);
|
||||
static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
@ -109,7 +109,7 @@ void bcm1480_unmask_irq(int cpu, int irq)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
{
|
||||
int i = 0, old_cpu, cpu, int_on, k;
|
||||
u64 cur_ints;
|
||||
|
@ -118,7 +118,7 @@ static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
|
||||
if (cpumask_weight(mask) != 1) {
|
||||
printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
i = cpumask_first(mask);
|
||||
|
||||
|
@ -152,6 +152,8 @@ static void bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ static void enable_sb1250_irq(unsigned int irq);
|
|||
static void disable_sb1250_irq(unsigned int irq);
|
||||
static void ack_sb1250_irq(unsigned int irq);
|
||||
#ifdef CONFIG_SMP
|
||||
static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask);
|
||||
static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SIBYTE_HAS_LDT
|
||||
|
@ -103,7 +103,7 @@ void sb1250_unmask_irq(int cpu, int irq)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
|
||||
{
|
||||
int i = 0, old_cpu, cpu, int_on;
|
||||
u64 cur_ints;
|
||||
|
@ -113,7 +113,7 @@ static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
|
||||
if (cpumask_weight(mask) > 1) {
|
||||
printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert logical CPU to physical CPU */
|
||||
|
@ -143,6 +143,8 @@ static void sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
|
|||
R_IMR_INTERRUPT_MASK));
|
||||
}
|
||||
spin_unlock_irqrestore(&sb1250_imr_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -130,15 +130,17 @@ int cpu_check_affinity(unsigned int irq, const struct cpumask *dest)
|
|||
return cpu_dest;
|
||||
}
|
||||
|
||||
static void cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
|
||||
static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
|
||||
{
|
||||
int cpu_dest;
|
||||
|
||||
cpu_dest = cpu_check_affinity(irq, dest);
|
||||
if (cpu_dest < 0)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
cpumask_copy(&irq_desc[irq].affinity, dest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -131,5 +131,44 @@ static inline int irqs_disabled_flags(unsigned long flags)
|
|||
*/
|
||||
struct irq_chip;
|
||||
|
||||
#ifdef CONFIG_PERF_COUNTERS
|
||||
static inline unsigned long test_perf_counter_pending(void)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
asm volatile("lbz %0,%1(13)"
|
||||
: "=r" (x)
|
||||
: "i" (offsetof(struct paca_struct, perf_counter_pending)));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void set_perf_counter_pending(void)
|
||||
{
|
||||
asm volatile("stb %0,%1(13)" : :
|
||||
"r" (1),
|
||||
"i" (offsetof(struct paca_struct, perf_counter_pending)));
|
||||
}
|
||||
|
||||
static inline void clear_perf_counter_pending(void)
|
||||
{
|
||||
asm volatile("stb %0,%1(13)" : :
|
||||
"r" (0),
|
||||
"i" (offsetof(struct paca_struct, perf_counter_pending)));
|
||||
}
|
||||
|
||||
extern void perf_counter_do_pending(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline unsigned long test_perf_counter_pending(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_perf_counter_pending(void) {}
|
||||
static inline void clear_perf_counter_pending(void) {}
|
||||
static inline void perf_counter_do_pending(void) {}
|
||||
#endif /* CONFIG_PERF_COUNTERS */
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_POWERPC_HW_IRQ_H */
|
||||
|
|
|
@ -99,6 +99,7 @@ struct paca_struct {
|
|||
u8 soft_enabled; /* irq soft-enable flag */
|
||||
u8 hard_enabled; /* set if irqs are enabled in MSR */
|
||||
u8 io_sync; /* writel() needs spin_unlock sync */
|
||||
u8 perf_counter_pending; /* PM interrupt while soft-disabled */
|
||||
|
||||
/* Stuff for accurate time accounting */
|
||||
u64 user_time; /* accumulated usermode TB ticks */
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Performance counter support - PowerPC-specific definitions.
|
||||
*
|
||||
* Copyright 2008-2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MAX_HWCOUNTERS 8
|
||||
#define MAX_EVENT_ALTERNATIVES 8
|
||||
#define MAX_LIMITED_HWCOUNTERS 2
|
||||
|
||||
/*
|
||||
* This struct provides the constants and functions needed to
|
||||
* describe the PMU on a particular POWER-family CPU.
|
||||
*/
|
||||
struct power_pmu {
|
||||
int n_counter;
|
||||
int max_alternatives;
|
||||
u64 add_fields;
|
||||
u64 test_adder;
|
||||
int (*compute_mmcr)(u64 events[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[]);
|
||||
int (*get_constraint)(u64 event, u64 *mskp, u64 *valp);
|
||||
int (*get_alternatives)(u64 event, unsigned int flags,
|
||||
u64 alt[]);
|
||||
void (*disable_pmc)(unsigned int pmc, u64 mmcr[]);
|
||||
int (*limited_pmc_event)(u64 event);
|
||||
u32 flags;
|
||||
int n_generic;
|
||||
int *generic_events;
|
||||
int (*cache_events)[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX];
|
||||
};
|
||||
|
||||
extern struct power_pmu *ppmu;
|
||||
|
||||
/*
|
||||
* Values for power_pmu.flags
|
||||
*/
|
||||
#define PPMU_LIMITED_PMC5_6 1 /* PMC5/6 have limited function */
|
||||
#define PPMU_ALT_SIPR 2 /* uses alternate posn for SIPR/HV */
|
||||
|
||||
/*
|
||||
* Values for flags to get_alternatives()
|
||||
*/
|
||||
#define PPMU_LIMITED_PMC_OK 1 /* can put this on a limited PMC */
|
||||
#define PPMU_LIMITED_PMC_REQD 2 /* have to put this on a limited PMC */
|
||||
#define PPMU_ONLY_COUNT_RUN 4 /* only counting in run state */
|
||||
|
||||
struct pt_regs;
|
||||
extern unsigned long perf_misc_flags(struct pt_regs *regs);
|
||||
#define perf_misc_flags(regs) perf_misc_flags(regs)
|
||||
|
||||
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
|
||||
|
||||
/*
|
||||
* The power_pmu.get_constraint function returns a 64-bit value and
|
||||
* a 64-bit mask that express the constraints between this event and
|
||||
* other events.
|
||||
*
|
||||
* The value and mask are divided up into (non-overlapping) bitfields
|
||||
* of three different types:
|
||||
*
|
||||
* Select field: this expresses the constraint that some set of bits
|
||||
* in MMCR* needs to be set to a specific value for this event. For a
|
||||
* select field, the mask contains 1s in every bit of the field, and
|
||||
* the value contains a unique value for each possible setting of the
|
||||
* MMCR* bits. The constraint checking code will ensure that two events
|
||||
* that set the same field in their masks have the same value in their
|
||||
* value dwords.
|
||||
*
|
||||
* Add field: this expresses the constraint that there can be at most
|
||||
* N events in a particular class. A field of k bits can be used for
|
||||
* N <= 2^(k-1) - 1. The mask has the most significant bit of the field
|
||||
* set (and the other bits 0), and the value has only the least significant
|
||||
* bit of the field set. In addition, the 'add_fields' and 'test_adder'
|
||||
* in the struct power_pmu for this processor come into play. The
|
||||
* add_fields value contains 1 in the LSB of the field, and the
|
||||
* test_adder contains 2^(k-1) - 1 - N in the field.
|
||||
*
|
||||
* NAND field: this expresses the constraint that you may not have events
|
||||
* in all of a set of classes. (For example, on PPC970, you can't select
|
||||
* events from the FPU, ISU and IDU simultaneously, although any two are
|
||||
* possible.) For N classes, the field is N+1 bits wide, and each class
|
||||
* is assigned one bit from the least-significant N bits. The mask has
|
||||
* only the most-significant bit set, and the value has only the bit
|
||||
* for the event's class set. The test_adder has the least significant
|
||||
* bit set in the field.
|
||||
*
|
||||
* If an event is not subject to the constraint expressed by a particular
|
||||
* field, then it will have 0 in both the mask and value for that field.
|
||||
*/
|
|
@ -492,11 +492,13 @@
|
|||
#define MMCR0_FCHV 0x00000001UL /* freeze conditions in hypervisor mode */
|
||||
#define SPRN_MMCR1 798
|
||||
#define SPRN_MMCRA 0x312
|
||||
#define MMCRA_SDSYNC 0x80000000UL /* SDAR synced with SIAR */
|
||||
#define MMCRA_SIHV 0x10000000UL /* state of MSR HV when SIAR set */
|
||||
#define MMCRA_SIPR 0x08000000UL /* state of MSR PR when SIAR set */
|
||||
#define MMCRA_SLOT 0x07000000UL /* SLOT bits (37-39) */
|
||||
#define MMCRA_SLOT_SHIFT 24
|
||||
#define MMCRA_SAMPLE_ENABLE 0x00000001UL /* enable sampling */
|
||||
#define POWER6_MMCRA_SDSYNC 0x0000080000000000ULL /* SDAR/SIAR synced */
|
||||
#define POWER6_MMCRA_SIHV 0x0000040000000000ULL
|
||||
#define POWER6_MMCRA_SIPR 0x0000020000000000ULL
|
||||
#define POWER6_MMCRA_THRM 0x00000020UL
|
||||
|
|
|
@ -322,6 +322,6 @@ SYSCALL_SPU(epoll_create1)
|
|||
SYSCALL_SPU(dup3)
|
||||
SYSCALL_SPU(pipe2)
|
||||
SYSCALL(inotify_init1)
|
||||
SYSCALL(ni_syscall)
|
||||
SYSCALL_SPU(perf_counter_open)
|
||||
COMPAT_SYS_SPU(preadv)
|
||||
COMPAT_SYS_SPU(pwritev)
|
||||
|
|
|
@ -341,6 +341,7 @@
|
|||
#define __NR_dup3 316
|
||||
#define __NR_pipe2 317
|
||||
#define __NR_inotify_init1 318
|
||||
#define __NR_perf_counter_open 319
|
||||
#define __NR_preadv 320
|
||||
#define __NR_pwritev 321
|
||||
|
||||
|
|
|
@ -94,6 +94,9 @@ obj64-$(CONFIG_AUDIT) += compat_audit.o
|
|||
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o power4-pmu.o ppc970-pmu.o \
|
||||
power5-pmu.o power5+-pmu.o power6-pmu.o \
|
||||
power7-pmu.o
|
||||
|
||||
obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ int main(void)
|
|||
DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
|
||||
DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
|
||||
DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
|
||||
DEFINE(PACAPERFPEND, offsetof(struct paca_struct, perf_counter_pending));
|
||||
DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
|
||||
DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
|
||||
DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
|
||||
|
|
|
@ -526,6 +526,15 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
|
|||
2:
|
||||
TRACE_AND_RESTORE_IRQ(r5);
|
||||
|
||||
#ifdef CONFIG_PERF_COUNTERS
|
||||
/* check paca->perf_counter_pending if we're enabling ints */
|
||||
lbz r3,PACAPERFPEND(r13)
|
||||
and. r3,r3,r5
|
||||
beq 27f
|
||||
bl .perf_counter_do_pending
|
||||
27:
|
||||
#endif /* CONFIG_PERF_COUNTERS */
|
||||
|
||||
/* extract EE bit and use it to restore paca->hard_enabled */
|
||||
ld r3,_MSR(r1)
|
||||
rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */
|
||||
|
|
|
@ -135,6 +135,11 @@ notrace void raw_local_irq_restore(unsigned long en)
|
|||
iseries_handle_interrupts();
|
||||
}
|
||||
|
||||
if (test_perf_counter_pending()) {
|
||||
clear_perf_counter_pending();
|
||||
perf_counter_do_pending();
|
||||
}
|
||||
|
||||
/*
|
||||
* if (get_paca()->hard_enabled) return;
|
||||
* But again we need to take care that gcc gets hard_enabled directly
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* Performance counter support for POWER4 (GP) and POWER4+ (GQ) processors.
|
||||
*
|
||||
* Copyright 2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <asm/reg.h>
|
||||
|
||||
/*
|
||||
* Bits in event code for POWER4
|
||||
*/
|
||||
#define PM_PMC_SH 12 /* PMC number (1-based) for direct events */
|
||||
#define PM_PMC_MSK 0xf
|
||||
#define PM_UNIT_SH 8 /* TTMMUX number and setting - unit select */
|
||||
#define PM_UNIT_MSK 0xf
|
||||
#define PM_LOWER_SH 6
|
||||
#define PM_LOWER_MSK 1
|
||||
#define PM_LOWER_MSKS 0x40
|
||||
#define PM_BYTE_SH 4 /* Byte number of event bus to use */
|
||||
#define PM_BYTE_MSK 3
|
||||
#define PM_PMCSEL_MSK 7
|
||||
|
||||
/*
|
||||
* Unit code values
|
||||
*/
|
||||
#define PM_FPU 1
|
||||
#define PM_ISU1 2
|
||||
#define PM_IFU 3
|
||||
#define PM_IDU0 4
|
||||
#define PM_ISU1_ALT 6
|
||||
#define PM_ISU2 7
|
||||
#define PM_IFU_ALT 8
|
||||
#define PM_LSU0 9
|
||||
#define PM_LSU1 0xc
|
||||
#define PM_GPS 0xf
|
||||
|
||||
/*
|
||||
* Bits in MMCR0 for POWER4
|
||||
*/
|
||||
#define MMCR0_PMC1SEL_SH 8
|
||||
#define MMCR0_PMC2SEL_SH 1
|
||||
#define MMCR_PMCSEL_MSK 0x1f
|
||||
|
||||
/*
|
||||
* Bits in MMCR1 for POWER4
|
||||
*/
|
||||
#define MMCR1_TTM0SEL_SH 62
|
||||
#define MMCR1_TTC0SEL_SH 61
|
||||
#define MMCR1_TTM1SEL_SH 59
|
||||
#define MMCR1_TTC1SEL_SH 58
|
||||
#define MMCR1_TTM2SEL_SH 56
|
||||
#define MMCR1_TTC2SEL_SH 55
|
||||
#define MMCR1_TTM3SEL_SH 53
|
||||
#define MMCR1_TTC3SEL_SH 52
|
||||
#define MMCR1_TTMSEL_MSK 3
|
||||
#define MMCR1_TD_CP_DBG0SEL_SH 50
|
||||
#define MMCR1_TD_CP_DBG1SEL_SH 48
|
||||
#define MMCR1_TD_CP_DBG2SEL_SH 46
|
||||
#define MMCR1_TD_CP_DBG3SEL_SH 44
|
||||
#define MMCR1_DEBUG0SEL_SH 43
|
||||
#define MMCR1_DEBUG1SEL_SH 42
|
||||
#define MMCR1_DEBUG2SEL_SH 41
|
||||
#define MMCR1_DEBUG3SEL_SH 40
|
||||
#define MMCR1_PMC1_ADDER_SEL_SH 39
|
||||
#define MMCR1_PMC2_ADDER_SEL_SH 38
|
||||
#define MMCR1_PMC6_ADDER_SEL_SH 37
|
||||
#define MMCR1_PMC5_ADDER_SEL_SH 36
|
||||
#define MMCR1_PMC8_ADDER_SEL_SH 35
|
||||
#define MMCR1_PMC7_ADDER_SEL_SH 34
|
||||
#define MMCR1_PMC3_ADDER_SEL_SH 33
|
||||
#define MMCR1_PMC4_ADDER_SEL_SH 32
|
||||
#define MMCR1_PMC3SEL_SH 27
|
||||
#define MMCR1_PMC4SEL_SH 22
|
||||
#define MMCR1_PMC5SEL_SH 17
|
||||
#define MMCR1_PMC6SEL_SH 12
|
||||
#define MMCR1_PMC7SEL_SH 7
|
||||
#define MMCR1_PMC8SEL_SH 2 /* note bit 0 is in MMCRA for GP */
|
||||
|
||||
static short mmcr1_adder_bits[8] = {
|
||||
MMCR1_PMC1_ADDER_SEL_SH,
|
||||
MMCR1_PMC2_ADDER_SEL_SH,
|
||||
MMCR1_PMC3_ADDER_SEL_SH,
|
||||
MMCR1_PMC4_ADDER_SEL_SH,
|
||||
MMCR1_PMC5_ADDER_SEL_SH,
|
||||
MMCR1_PMC6_ADDER_SEL_SH,
|
||||
MMCR1_PMC7_ADDER_SEL_SH,
|
||||
MMCR1_PMC8_ADDER_SEL_SH
|
||||
};
|
||||
|
||||
/*
|
||||
* Bits in MMCRA
|
||||
*/
|
||||
#define MMCRA_PMC8SEL0_SH 17 /* PMC8SEL bit 0 for GP */
|
||||
|
||||
/*
|
||||
* Layout of constraint bits:
|
||||
* 6666555555555544444444443333333333222222222211111111110000000000
|
||||
* 3210987654321098765432109876543210987654321098765432109876543210
|
||||
* |[ >[ >[ >|||[ >[ >< >< >< >< ><><><><><><><><>
|
||||
* | UC1 UC2 UC3 ||| PS1 PS2 B0 B1 B2 B3 P1P2P3P4P5P6P7P8
|
||||
* \SMPL ||\TTC3SEL
|
||||
* |\TTC_IFU_SEL
|
||||
* \TTM2SEL0
|
||||
*
|
||||
* SMPL - SAMPLE_ENABLE constraint
|
||||
* 56: SAMPLE_ENABLE value 0x0100_0000_0000_0000
|
||||
*
|
||||
* UC1 - unit constraint 1: can't have all three of FPU/ISU1/IDU0|ISU2
|
||||
* 55: UC1 error 0x0080_0000_0000_0000
|
||||
* 54: FPU events needed 0x0040_0000_0000_0000
|
||||
* 53: ISU1 events needed 0x0020_0000_0000_0000
|
||||
* 52: IDU0|ISU2 events needed 0x0010_0000_0000_0000
|
||||
*
|
||||
* UC2 - unit constraint 2: can't have all three of FPU/IFU/LSU0
|
||||
* 51: UC2 error 0x0008_0000_0000_0000
|
||||
* 50: FPU events needed 0x0004_0000_0000_0000
|
||||
* 49: IFU events needed 0x0002_0000_0000_0000
|
||||
* 48: LSU0 events needed 0x0001_0000_0000_0000
|
||||
*
|
||||
* UC3 - unit constraint 3: can't have all four of LSU0/IFU/IDU0|ISU2/ISU1
|
||||
* 47: UC3 error 0x8000_0000_0000
|
||||
* 46: LSU0 events needed 0x4000_0000_0000
|
||||
* 45: IFU events needed 0x2000_0000_0000
|
||||
* 44: IDU0|ISU2 events needed 0x1000_0000_0000
|
||||
* 43: ISU1 events needed 0x0800_0000_0000
|
||||
*
|
||||
* TTM2SEL0
|
||||
* 42: 0 = IDU0 events needed
|
||||
* 1 = ISU2 events needed 0x0400_0000_0000
|
||||
*
|
||||
* TTC_IFU_SEL
|
||||
* 41: 0 = IFU.U events needed
|
||||
* 1 = IFU.L events needed 0x0200_0000_0000
|
||||
*
|
||||
* TTC3SEL
|
||||
* 40: 0 = LSU1.U events needed
|
||||
* 1 = LSU1.L events needed 0x0100_0000_0000
|
||||
*
|
||||
* PS1
|
||||
* 39: PS1 error 0x0080_0000_0000
|
||||
* 36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
|
||||
*
|
||||
* PS2
|
||||
* 35: PS2 error 0x0008_0000_0000
|
||||
* 32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
|
||||
*
|
||||
* B0
|
||||
* 28-31: Byte 0 event source 0xf000_0000
|
||||
* 1 = FPU
|
||||
* 2 = ISU1
|
||||
* 3 = IFU
|
||||
* 4 = IDU0
|
||||
* 7 = ISU2
|
||||
* 9 = LSU0
|
||||
* c = LSU1
|
||||
* f = GPS
|
||||
*
|
||||
* B1, B2, B3
|
||||
* 24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
|
||||
*
|
||||
* P8
|
||||
* 15: P8 error 0x8000
|
||||
* 14-15: Count of events needing PMC8
|
||||
*
|
||||
* P1..P7
|
||||
* 0-13: Count of events needing PMC1..PMC7
|
||||
*
|
||||
* Note: this doesn't allow events using IFU.U to be combined with events
|
||||
* using IFU.L, though that is feasible (using TTM0 and TTM2). However
|
||||
* there are no listed events for IFU.L (they are debug events not
|
||||
* verified for performance monitoring) so this shouldn't cause a
|
||||
* problem.
|
||||
*/
|
||||
|
||||
static struct unitinfo {
|
||||
u64 value, mask;
|
||||
int unit;
|
||||
int lowerbit;
|
||||
} p4_unitinfo[16] = {
|
||||
[PM_FPU] = { 0x44000000000000ull, 0x88000000000000ull, PM_FPU, 0 },
|
||||
[PM_ISU1] = { 0x20080000000000ull, 0x88000000000000ull, PM_ISU1, 0 },
|
||||
[PM_ISU1_ALT] =
|
||||
{ 0x20080000000000ull, 0x88000000000000ull, PM_ISU1, 0 },
|
||||
[PM_IFU] = { 0x02200000000000ull, 0x08820000000000ull, PM_IFU, 41 },
|
||||
[PM_IFU_ALT] =
|
||||
{ 0x02200000000000ull, 0x08820000000000ull, PM_IFU, 41 },
|
||||
[PM_IDU0] = { 0x10100000000000ull, 0x80840000000000ull, PM_IDU0, 1 },
|
||||
[PM_ISU2] = { 0x10140000000000ull, 0x80840000000000ull, PM_ISU2, 0 },
|
||||
[PM_LSU0] = { 0x01400000000000ull, 0x08800000000000ull, PM_LSU0, 0 },
|
||||
[PM_LSU1] = { 0x00000000000000ull, 0x00010000000000ull, PM_LSU1, 40 },
|
||||
[PM_GPS] = { 0x00000000000000ull, 0x00000000000000ull, PM_GPS, 0 }
|
||||
};
|
||||
|
||||
static unsigned char direct_marked_event[8] = {
|
||||
(1<<2) | (1<<3), /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
|
||||
(1<<3) | (1<<5), /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
|
||||
(1<<3), /* PMC3: PM_MRK_ST_CMPL_INT */
|
||||
(1<<4) | (1<<5), /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
|
||||
(1<<4) | (1<<5), /* PMC5: PM_MRK_GRP_TIMEO */
|
||||
(1<<3) | (1<<4) | (1<<5),
|
||||
/* PMC6: PM_MRK_ST_GPS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
|
||||
(1<<4) | (1<<5), /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
|
||||
(1<<4), /* PMC8: PM_MRK_LSU_FIN */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns 1 if event counts things relating to marked instructions
|
||||
* and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
|
||||
*/
|
||||
static int p4_marked_instr_event(u64 event)
|
||||
{
|
||||
int pmc, psel, unit, byte, bit;
|
||||
unsigned int mask;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
psel = event & PM_PMCSEL_MSK;
|
||||
if (pmc) {
|
||||
if (direct_marked_event[pmc - 1] & (1 << psel))
|
||||
return 1;
|
||||
if (psel == 0) /* add events */
|
||||
bit = (pmc <= 4)? pmc - 1: 8 - pmc;
|
||||
else if (psel == 6) /* decode events */
|
||||
bit = 4;
|
||||
else
|
||||
return 0;
|
||||
} else
|
||||
bit = psel;
|
||||
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
mask = 0;
|
||||
switch (unit) {
|
||||
case PM_LSU1:
|
||||
if (event & PM_LOWER_MSKS)
|
||||
mask = 1 << 28; /* byte 7 bit 4 */
|
||||
else
|
||||
mask = 6 << 24; /* byte 3 bits 1 and 2 */
|
||||
break;
|
||||
case PM_LSU0:
|
||||
/* byte 3, bit 3; byte 2 bits 0,2,3,4,5; byte 1 */
|
||||
mask = 0x083dff00;
|
||||
}
|
||||
return (mask >> (byte * 8 + bit)) & 1;
|
||||
}
|
||||
|
||||
static int p4_get_constraint(u64 event, u64 *maskp, u64 *valp)
|
||||
{
|
||||
int pmc, byte, unit, lower, sh;
|
||||
u64 mask = 0, value = 0;
|
||||
int grp = -1;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 8)
|
||||
return -1;
|
||||
sh = (pmc - 1) * 2;
|
||||
mask |= 2 << sh;
|
||||
value |= 1 << sh;
|
||||
grp = ((pmc - 1) >> 1) & 1;
|
||||
}
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
if (unit) {
|
||||
lower = (event >> PM_LOWER_SH) & PM_LOWER_MSK;
|
||||
|
||||
/*
|
||||
* Bus events on bytes 0 and 2 can be counted
|
||||
* on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
|
||||
*/
|
||||
if (!pmc)
|
||||
grp = byte & 1;
|
||||
|
||||
if (!p4_unitinfo[unit].unit)
|
||||
return -1;
|
||||
mask |= p4_unitinfo[unit].mask;
|
||||
value |= p4_unitinfo[unit].value;
|
||||
sh = p4_unitinfo[unit].lowerbit;
|
||||
if (sh > 1)
|
||||
value |= (u64)lower << sh;
|
||||
else if (lower != sh)
|
||||
return -1;
|
||||
unit = p4_unitinfo[unit].unit;
|
||||
|
||||
/* Set byte lane select field */
|
||||
mask |= 0xfULL << (28 - 4 * byte);
|
||||
value |= (u64)unit << (28 - 4 * byte);
|
||||
}
|
||||
if (grp == 0) {
|
||||
/* increment PMC1/2/5/6 field */
|
||||
mask |= 0x8000000000ull;
|
||||
value |= 0x1000000000ull;
|
||||
} else {
|
||||
/* increment PMC3/4/7/8 field */
|
||||
mask |= 0x800000000ull;
|
||||
value |= 0x100000000ull;
|
||||
}
|
||||
|
||||
/* Marked instruction events need sample_enable set */
|
||||
if (p4_marked_instr_event(event)) {
|
||||
mask |= 1ull << 56;
|
||||
value |= 1ull << 56;
|
||||
}
|
||||
|
||||
/* PMCSEL=6 decode events on byte 2 need sample_enable clear */
|
||||
if (pmc && (event & PM_PMCSEL_MSK) == 6 && byte == 2)
|
||||
mask |= 1ull << 56;
|
||||
|
||||
*maskp = mask;
|
||||
*valp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ppc_inst_cmpl[] = {
|
||||
0x1001, 0x4001, 0x6001, 0x7001, 0x8001
|
||||
};
|
||||
|
||||
static int p4_get_alternatives(u64 event, unsigned int flags, u64 alt[])
|
||||
{
|
||||
int i, j, na;
|
||||
|
||||
alt[0] = event;
|
||||
na = 1;
|
||||
|
||||
/* 2 possibilities for PM_GRP_DISP_REJECT */
|
||||
if (event == 0x8003 || event == 0x0224) {
|
||||
alt[1] = event ^ (0x8003 ^ 0x0224);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* 2 possibilities for PM_ST_MISS_L1 */
|
||||
if (event == 0x0c13 || event == 0x0c23) {
|
||||
alt[1] = event ^ (0x0c13 ^ 0x0c23);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* several possibilities for PM_INST_CMPL */
|
||||
for (i = 0; i < ARRAY_SIZE(ppc_inst_cmpl); ++i) {
|
||||
if (event == ppc_inst_cmpl[i]) {
|
||||
for (j = 0; j < ARRAY_SIZE(ppc_inst_cmpl); ++j)
|
||||
if (j != i)
|
||||
alt[na++] = ppc_inst_cmpl[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return na;
|
||||
}
|
||||
|
||||
static int p4_compute_mmcr(u64 event[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[])
|
||||
{
|
||||
u64 mmcr0 = 0, mmcr1 = 0, mmcra = 0;
|
||||
unsigned int pmc, unit, byte, psel, lower;
|
||||
unsigned int ttm, grp;
|
||||
unsigned int pmc_inuse = 0;
|
||||
unsigned int pmc_grp_use[2];
|
||||
unsigned char busbyte[4];
|
||||
unsigned char unituse[16];
|
||||
unsigned int unitlower = 0;
|
||||
int i;
|
||||
|
||||
if (n_ev > 8)
|
||||
return -1;
|
||||
|
||||
/* First pass to count resource use */
|
||||
pmc_grp_use[0] = pmc_grp_use[1] = 0;
|
||||
memset(busbyte, 0, sizeof(busbyte));
|
||||
memset(unituse, 0, sizeof(unituse));
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc_inuse & (1 << (pmc - 1)))
|
||||
return -1;
|
||||
pmc_inuse |= 1 << (pmc - 1);
|
||||
/* count 1/2/5/6 vs 3/4/7/8 use */
|
||||
++pmc_grp_use[((pmc - 1) >> 1) & 1];
|
||||
}
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
lower = (event[i] >> PM_LOWER_SH) & PM_LOWER_MSK;
|
||||
if (unit) {
|
||||
if (!pmc)
|
||||
++pmc_grp_use[byte & 1];
|
||||
if (unit == 6 || unit == 8)
|
||||
/* map alt ISU1/IFU codes: 6->2, 8->3 */
|
||||
unit = (unit >> 1) - 1;
|
||||
if (busbyte[byte] && busbyte[byte] != unit)
|
||||
return -1;
|
||||
busbyte[byte] = unit;
|
||||
lower <<= unit;
|
||||
if (unituse[unit] && lower != (unitlower & lower))
|
||||
return -1;
|
||||
unituse[unit] = 1;
|
||||
unitlower |= lower;
|
||||
}
|
||||
}
|
||||
if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Assign resources and set multiplexer selects.
|
||||
*
|
||||
* Units 1,2,3 are on TTM0, 4,6,7 on TTM1, 8,10 on TTM2.
|
||||
* Each TTMx can only select one unit, but since
|
||||
* units 2 and 6 are both ISU1, and 3 and 8 are both IFU,
|
||||
* we have some choices.
|
||||
*/
|
||||
if (unituse[2] & (unituse[1] | (unituse[3] & unituse[9]))) {
|
||||
unituse[6] = 1; /* Move 2 to 6 */
|
||||
unituse[2] = 0;
|
||||
}
|
||||
if (unituse[3] & (unituse[1] | unituse[2])) {
|
||||
unituse[8] = 1; /* Move 3 to 8 */
|
||||
unituse[3] = 0;
|
||||
unitlower = (unitlower & ~8) | ((unitlower & 8) << 5);
|
||||
}
|
||||
/* Check only one unit per TTMx */
|
||||
if (unituse[1] + unituse[2] + unituse[3] > 1 ||
|
||||
unituse[4] + unituse[6] + unituse[7] > 1 ||
|
||||
unituse[8] + unituse[9] > 1 ||
|
||||
(unituse[5] | unituse[10] | unituse[11] |
|
||||
unituse[13] | unituse[14]))
|
||||
return -1;
|
||||
|
||||
/* Set TTMxSEL fields. Note, units 1-3 => TTM0SEL codes 0-2 */
|
||||
mmcr1 |= (u64)(unituse[3] * 2 + unituse[2]) << MMCR1_TTM0SEL_SH;
|
||||
mmcr1 |= (u64)(unituse[7] * 3 + unituse[6] * 2) << MMCR1_TTM1SEL_SH;
|
||||
mmcr1 |= (u64)unituse[9] << MMCR1_TTM2SEL_SH;
|
||||
|
||||
/* Set TTCxSEL fields. */
|
||||
if (unitlower & 0xe)
|
||||
mmcr1 |= 1ull << MMCR1_TTC0SEL_SH;
|
||||
if (unitlower & 0xf0)
|
||||
mmcr1 |= 1ull << MMCR1_TTC1SEL_SH;
|
||||
if (unitlower & 0xf00)
|
||||
mmcr1 |= 1ull << MMCR1_TTC2SEL_SH;
|
||||
if (unitlower & 0x7000)
|
||||
mmcr1 |= 1ull << MMCR1_TTC3SEL_SH;
|
||||
|
||||
/* Set byte lane select fields. */
|
||||
for (byte = 0; byte < 4; ++byte) {
|
||||
unit = busbyte[byte];
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit == 0xf) {
|
||||
/* special case for GPS */
|
||||
mmcr1 |= 1ull << (MMCR1_DEBUG0SEL_SH - byte);
|
||||
} else {
|
||||
if (!unituse[unit])
|
||||
ttm = unit - 1; /* 2->1, 3->2 */
|
||||
else
|
||||
ttm = unit >> 2;
|
||||
mmcr1 |= (u64)ttm << (MMCR1_TD_CP_DBG0SEL_SH - 2*byte);
|
||||
}
|
||||
}
|
||||
|
||||
/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
psel = event[i] & PM_PMCSEL_MSK;
|
||||
if (!pmc) {
|
||||
/* Bus event or 00xxx direct event (off or cycles) */
|
||||
if (unit)
|
||||
psel |= 0x10 | ((byte & 2) << 2);
|
||||
for (pmc = 0; pmc < 8; ++pmc) {
|
||||
if (pmc_inuse & (1 << pmc))
|
||||
continue;
|
||||
grp = (pmc >> 1) & 1;
|
||||
if (unit) {
|
||||
if (grp == (byte & 1))
|
||||
break;
|
||||
} else if (pmc_grp_use[grp] < 4) {
|
||||
++pmc_grp_use[grp];
|
||||
break;
|
||||
}
|
||||
}
|
||||
pmc_inuse |= 1 << pmc;
|
||||
} else {
|
||||
/* Direct event */
|
||||
--pmc;
|
||||
if (psel == 0 && (byte & 2))
|
||||
/* add events on higher-numbered bus */
|
||||
mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
|
||||
else if (psel == 6 && byte == 3)
|
||||
/* seem to need to set sample_enable here */
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
psel |= 8;
|
||||
}
|
||||
if (pmc <= 1)
|
||||
mmcr0 |= psel << (MMCR0_PMC1SEL_SH - 7 * pmc);
|
||||
else
|
||||
mmcr1 |= psel << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
|
||||
if (pmc == 7) /* PMC8 */
|
||||
mmcra |= (psel & 1) << MMCRA_PMC8SEL0_SH;
|
||||
hwc[i] = pmc;
|
||||
if (p4_marked_instr_event(event[i]))
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
}
|
||||
|
||||
if (pmc_inuse & 1)
|
||||
mmcr0 |= MMCR0_PMC1CE;
|
||||
if (pmc_inuse & 0xfe)
|
||||
mmcr0 |= MMCR0_PMCjCE;
|
||||
|
||||
mmcra |= 0x2000; /* mark only one IOP per PPC instruction */
|
||||
|
||||
/* Return MMCRx values */
|
||||
mmcr[0] = mmcr0;
|
||||
mmcr[1] = mmcr1;
|
||||
mmcr[2] = mmcra;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void p4_disable_pmc(unsigned int pmc, u64 mmcr[])
|
||||
{
|
||||
/*
|
||||
* Setting the PMCxSEL field to 0 disables PMC x.
|
||||
* (Note that pmc is 0-based here, not 1-based.)
|
||||
*/
|
||||
if (pmc <= 1) {
|
||||
mmcr[0] &= ~(0x1fUL << (MMCR0_PMC1SEL_SH - 7 * pmc));
|
||||
} else {
|
||||
mmcr[1] &= ~(0x1fUL << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2)));
|
||||
if (pmc == 7)
|
||||
mmcr[2] &= ~(1UL << MMCRA_PMC8SEL0_SH);
|
||||
}
|
||||
}
|
||||
|
||||
static int p4_generic_events[] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 7,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 0x1001,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x8c10, /* PM_LD_REF_L1 */
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x3c10, /* PM_LD_MISS_L1 */
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x330, /* PM_BR_ISSUED */
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x331, /* PM_BR_MPRED_CR */
|
||||
};
|
||||
|
||||
#define C(x) PERF_COUNT_HW_CACHE_##x
|
||||
|
||||
/*
|
||||
* Table of generalized cache-related events.
|
||||
* 0 means not supported, -1 means nonsensical, other values
|
||||
* are event codes.
|
||||
*/
|
||||
static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
|
||||
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x8c10, 0x3c10 },
|
||||
[C(OP_WRITE)] = { 0x7c10, 0xc13 },
|
||||
[C(OP_PREFETCH)] = { 0xc35, 0 },
|
||||
},
|
||||
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { 0, 0 },
|
||||
},
|
||||
[C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { 0, 0 },
|
||||
[C(OP_PREFETCH)] = { 0xc34, 0 },
|
||||
},
|
||||
[C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x904 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x900 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x330, 0x331 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
struct power_pmu power4_pmu = {
|
||||
.n_counter = 8,
|
||||
.max_alternatives = 5,
|
||||
.add_fields = 0x0000001100005555ull,
|
||||
.test_adder = 0x0011083300000000ull,
|
||||
.compute_mmcr = p4_compute_mmcr,
|
||||
.get_constraint = p4_get_constraint,
|
||||
.get_alternatives = p4_get_alternatives,
|
||||
.disable_pmc = p4_disable_pmc,
|
||||
.n_generic = ARRAY_SIZE(p4_generic_events),
|
||||
.generic_events = p4_generic_events,
|
||||
.cache_events = &power4_cache_events,
|
||||
};
|
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* Performance counter support for POWER5+/++ (not POWER5) processors.
|
||||
*
|
||||
* Copyright 2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <asm/reg.h>
|
||||
|
||||
/*
|
||||
* Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3)
|
||||
*/
|
||||
#define PM_PMC_SH 20 /* PMC number (1-based) for direct events */
|
||||
#define PM_PMC_MSK 0xf
|
||||
#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
|
||||
#define PM_UNIT_SH 16 /* TTMMUX number and setting - unit select */
|
||||
#define PM_UNIT_MSK 0xf
|
||||
#define PM_BYTE_SH 12 /* Byte number of event bus to use */
|
||||
#define PM_BYTE_MSK 7
|
||||
#define PM_GRS_SH 8 /* Storage subsystem mux select */
|
||||
#define PM_GRS_MSK 7
|
||||
#define PM_BUSEVENT_MSK 0x80 /* Set if event uses event bus */
|
||||
#define PM_PMCSEL_MSK 0x7f
|
||||
|
||||
/* Values in PM_UNIT field */
|
||||
#define PM_FPU 0
|
||||
#define PM_ISU0 1
|
||||
#define PM_IFU 2
|
||||
#define PM_ISU1 3
|
||||
#define PM_IDU 4
|
||||
#define PM_ISU0_ALT 6
|
||||
#define PM_GRS 7
|
||||
#define PM_LSU0 8
|
||||
#define PM_LSU1 0xc
|
||||
#define PM_LASTUNIT 0xc
|
||||
|
||||
/*
|
||||
* Bits in MMCR1 for POWER5+
|
||||
*/
|
||||
#define MMCR1_TTM0SEL_SH 62
|
||||
#define MMCR1_TTM1SEL_SH 60
|
||||
#define MMCR1_TTM2SEL_SH 58
|
||||
#define MMCR1_TTM3SEL_SH 56
|
||||
#define MMCR1_TTMSEL_MSK 3
|
||||
#define MMCR1_TD_CP_DBG0SEL_SH 54
|
||||
#define MMCR1_TD_CP_DBG1SEL_SH 52
|
||||
#define MMCR1_TD_CP_DBG2SEL_SH 50
|
||||
#define MMCR1_TD_CP_DBG3SEL_SH 48
|
||||
#define MMCR1_GRS_L2SEL_SH 46
|
||||
#define MMCR1_GRS_L2SEL_MSK 3
|
||||
#define MMCR1_GRS_L3SEL_SH 44
|
||||
#define MMCR1_GRS_L3SEL_MSK 3
|
||||
#define MMCR1_GRS_MCSEL_SH 41
|
||||
#define MMCR1_GRS_MCSEL_MSK 7
|
||||
#define MMCR1_GRS_FABSEL_SH 39
|
||||
#define MMCR1_GRS_FABSEL_MSK 3
|
||||
#define MMCR1_PMC1_ADDER_SEL_SH 35
|
||||
#define MMCR1_PMC2_ADDER_SEL_SH 34
|
||||
#define MMCR1_PMC3_ADDER_SEL_SH 33
|
||||
#define MMCR1_PMC4_ADDER_SEL_SH 32
|
||||
#define MMCR1_PMC1SEL_SH 25
|
||||
#define MMCR1_PMC2SEL_SH 17
|
||||
#define MMCR1_PMC3SEL_SH 9
|
||||
#define MMCR1_PMC4SEL_SH 1
|
||||
#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
|
||||
#define MMCR1_PMCSEL_MSK 0x7f
|
||||
|
||||
/*
|
||||
* Bits in MMCRA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Layout of constraint bits:
|
||||
* 6666555555555544444444443333333333222222222211111111110000000000
|
||||
* 3210987654321098765432109876543210987654321098765432109876543210
|
||||
* [ ><><>< ><> <><>[ > < >< >< >< ><><><><><><>
|
||||
* NC G0G1G2 G3 T0T1 UC B0 B1 B2 B3 P6P5P4P3P2P1
|
||||
*
|
||||
* NC - number of counters
|
||||
* 51: NC error 0x0008_0000_0000_0000
|
||||
* 48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
|
||||
*
|
||||
* G0..G3 - GRS mux constraints
|
||||
* 46-47: GRS_L2SEL value
|
||||
* 44-45: GRS_L3SEL value
|
||||
* 41-44: GRS_MCSEL value
|
||||
* 39-40: GRS_FABSEL value
|
||||
* Note that these match up with their bit positions in MMCR1
|
||||
*
|
||||
* T0 - TTM0 constraint
|
||||
* 36-37: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0x30_0000_0000
|
||||
*
|
||||
* T1 - TTM1 constraint
|
||||
* 34-35: TTM1SEL value (0=IDU, 3=GRS) 0x0c_0000_0000
|
||||
*
|
||||
* UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
|
||||
* 33: UC3 error 0x02_0000_0000
|
||||
* 32: FPU|IFU|ISU1 events needed 0x01_0000_0000
|
||||
* 31: ISU0 events needed 0x01_8000_0000
|
||||
* 30: IDU|GRS events needed 0x00_4000_0000
|
||||
*
|
||||
* B0
|
||||
* 24-27: Byte 0 event source 0x0f00_0000
|
||||
* Encoding as for the event code
|
||||
*
|
||||
* B1, B2, B3
|
||||
* 20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
|
||||
*
|
||||
* P6
|
||||
* 11: P6 error 0x800
|
||||
* 10-11: Count of events needing PMC6
|
||||
*
|
||||
* P1..P5
|
||||
* 0-9: Count of events needing PMC1..PMC5
|
||||
*/
|
||||
|
||||
static const int grsel_shift[8] = {
|
||||
MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
|
||||
MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
|
||||
MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
|
||||
};
|
||||
|
||||
/* Masks and values for using events from the various units */
|
||||
static u64 unit_cons[PM_LASTUNIT+1][2] = {
|
||||
[PM_FPU] = { 0x3200000000ull, 0x0100000000ull },
|
||||
[PM_ISU0] = { 0x0200000000ull, 0x0080000000ull },
|
||||
[PM_ISU1] = { 0x3200000000ull, 0x3100000000ull },
|
||||
[PM_IFU] = { 0x3200000000ull, 0x2100000000ull },
|
||||
[PM_IDU] = { 0x0e00000000ull, 0x0040000000ull },
|
||||
[PM_GRS] = { 0x0e00000000ull, 0x0c40000000ull },
|
||||
};
|
||||
|
||||
static int power5p_get_constraint(u64 event, u64 *maskp, u64 *valp)
|
||||
{
|
||||
int pmc, byte, unit, sh;
|
||||
int bit, fmask;
|
||||
u64 mask = 0, value = 0;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 6)
|
||||
return -1;
|
||||
sh = (pmc - 1) * 2;
|
||||
mask |= 2 << sh;
|
||||
value |= 1 << sh;
|
||||
if (pmc >= 5 && !(event == 0x500009 || event == 0x600005))
|
||||
return -1;
|
||||
}
|
||||
if (event & PM_BUSEVENT_MSK) {
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
if (unit > PM_LASTUNIT)
|
||||
return -1;
|
||||
if (unit == PM_ISU0_ALT)
|
||||
unit = PM_ISU0;
|
||||
mask |= unit_cons[unit][0];
|
||||
value |= unit_cons[unit][1];
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
if (byte >= 4) {
|
||||
if (unit != PM_LSU1)
|
||||
return -1;
|
||||
/* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
|
||||
++unit;
|
||||
byte &= 3;
|
||||
}
|
||||
if (unit == PM_GRS) {
|
||||
bit = event & 7;
|
||||
fmask = (bit == 6)? 7: 3;
|
||||
sh = grsel_shift[bit];
|
||||
mask |= (u64)fmask << sh;
|
||||
value |= (u64)((event >> PM_GRS_SH) & fmask) << sh;
|
||||
}
|
||||
/* Set byte lane select field */
|
||||
mask |= 0xfULL << (24 - 4 * byte);
|
||||
value |= (u64)unit << (24 - 4 * byte);
|
||||
}
|
||||
if (pmc < 5) {
|
||||
/* need a counter from PMC1-4 set */
|
||||
mask |= 0x8000000000000ull;
|
||||
value |= 0x1000000000000ull;
|
||||
}
|
||||
*maskp = mask;
|
||||
*valp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int power5p_limited_pmc_event(u64 event)
|
||||
{
|
||||
int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
|
||||
return pmc == 5 || pmc == 6;
|
||||
}
|
||||
|
||||
#define MAX_ALT 3 /* at most 3 alternatives for any event */
|
||||
|
||||
static const unsigned int event_alternatives[][MAX_ALT] = {
|
||||
{ 0x100c0, 0x40001f }, /* PM_GCT_FULL_CYC */
|
||||
{ 0x120e4, 0x400002 }, /* PM_GRP_DISP_REJECT */
|
||||
{ 0x230e2, 0x323087 }, /* PM_BR_PRED_CR */
|
||||
{ 0x230e3, 0x223087, 0x3230a0 }, /* PM_BR_PRED_TA */
|
||||
{ 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */
|
||||
{ 0x800c4, 0xc20e0 }, /* PM_DTLB_MISS */
|
||||
{ 0xc50c6, 0xc60e0 }, /* PM_MRK_DTLB_MISS */
|
||||
{ 0x100005, 0x600005 }, /* PM_RUN_CYC */
|
||||
{ 0x100009, 0x200009 }, /* PM_INST_CMPL */
|
||||
{ 0x200015, 0x300015 }, /* PM_LSU_LMQ_SRQ_EMPTY_CYC */
|
||||
{ 0x300009, 0x400009 }, /* PM_INST_DISP */
|
||||
};
|
||||
|
||||
/*
|
||||
* Scan the alternatives table for a match and return the
|
||||
* index into the alternatives table if found, else -1.
|
||||
*/
|
||||
static int find_alternative(unsigned int event)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
|
||||
if (event < event_alternatives[i][0])
|
||||
break;
|
||||
for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
|
||||
if (event == event_alternatives[i][j])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const unsigned char bytedecode_alternatives[4][4] = {
|
||||
/* PMC 1 */ { 0x21, 0x23, 0x25, 0x27 },
|
||||
/* PMC 2 */ { 0x07, 0x17, 0x0e, 0x1e },
|
||||
/* PMC 3 */ { 0x20, 0x22, 0x24, 0x26 },
|
||||
/* PMC 4 */ { 0x07, 0x17, 0x0e, 0x1e }
|
||||
};
|
||||
|
||||
/*
|
||||
* Some direct events for decodes of event bus byte 3 have alternative
|
||||
* PMCSEL values on other counters. This returns the alternative
|
||||
* event code for those that do, or -1 otherwise. This also handles
|
||||
* alternative PCMSEL values for add events.
|
||||
*/
|
||||
static s64 find_alternative_bdecode(u64 event)
|
||||
{
|
||||
int pmc, altpmc, pp, j;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc == 0 || pmc > 4)
|
||||
return -1;
|
||||
altpmc = 5 - pmc; /* 1 <-> 4, 2 <-> 3 */
|
||||
pp = event & PM_PMCSEL_MSK;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
if (bytedecode_alternatives[pmc - 1][j] == pp) {
|
||||
return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
|
||||
(altpmc << PM_PMC_SH) |
|
||||
bytedecode_alternatives[altpmc - 1][j];
|
||||
}
|
||||
}
|
||||
|
||||
/* new decode alternatives for power5+ */
|
||||
if (pmc == 1 && (pp == 0x0d || pp == 0x0e))
|
||||
return event + (2 << PM_PMC_SH) + (0x2e - 0x0d);
|
||||
if (pmc == 3 && (pp == 0x2e || pp == 0x2f))
|
||||
return event - (2 << PM_PMC_SH) - (0x2e - 0x0d);
|
||||
|
||||
/* alternative add event encodings */
|
||||
if (pp == 0x10 || pp == 0x28)
|
||||
return ((event ^ (0x10 ^ 0x28)) & ~PM_PMC_MSKS) |
|
||||
(altpmc << PM_PMC_SH);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int power5p_get_alternatives(u64 event, unsigned int flags, u64 alt[])
|
||||
{
|
||||
int i, j, nalt = 1;
|
||||
int nlim;
|
||||
s64 ae;
|
||||
|
||||
alt[0] = event;
|
||||
nalt = 1;
|
||||
nlim = power5p_limited_pmc_event(event);
|
||||
i = find_alternative(event);
|
||||
if (i >= 0) {
|
||||
for (j = 0; j < MAX_ALT; ++j) {
|
||||
ae = event_alternatives[i][j];
|
||||
if (ae && ae != event)
|
||||
alt[nalt++] = ae;
|
||||
nlim += power5p_limited_pmc_event(ae);
|
||||
}
|
||||
} else {
|
||||
ae = find_alternative_bdecode(event);
|
||||
if (ae > 0)
|
||||
alt[nalt++] = ae;
|
||||
}
|
||||
|
||||
if (flags & PPMU_ONLY_COUNT_RUN) {
|
||||
/*
|
||||
* We're only counting in RUN state,
|
||||
* so PM_CYC is equivalent to PM_RUN_CYC
|
||||
* and PM_INST_CMPL === PM_RUN_INST_CMPL.
|
||||
* This doesn't include alternatives that don't provide
|
||||
* any extra flexibility in assigning PMCs (e.g.
|
||||
* 0x100005 for PM_RUN_CYC vs. 0xf for PM_CYC).
|
||||
* Note that even with these additional alternatives
|
||||
* we never end up with more than 3 alternatives for any event.
|
||||
*/
|
||||
j = nalt;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
switch (alt[i]) {
|
||||
case 0xf: /* PM_CYC */
|
||||
alt[j++] = 0x600005; /* PM_RUN_CYC */
|
||||
++nlim;
|
||||
break;
|
||||
case 0x600005: /* PM_RUN_CYC */
|
||||
alt[j++] = 0xf;
|
||||
break;
|
||||
case 0x100009: /* PM_INST_CMPL */
|
||||
alt[j++] = 0x500009; /* PM_RUN_INST_CMPL */
|
||||
++nlim;
|
||||
break;
|
||||
case 0x500009: /* PM_RUN_INST_CMPL */
|
||||
alt[j++] = 0x100009; /* PM_INST_CMPL */
|
||||
alt[j++] = 0x200009;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
}
|
||||
|
||||
if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
|
||||
/* remove the limited PMC events */
|
||||
j = 0;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
if (!power5p_limited_pmc_event(alt[i])) {
|
||||
alt[j] = alt[i];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
} else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
|
||||
/* remove all but the limited PMC events */
|
||||
j = 0;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
if (power5p_limited_pmc_event(alt[i])) {
|
||||
alt[j] = alt[i];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
}
|
||||
|
||||
return nalt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map of which direct events on which PMCs are marked instruction events.
|
||||
* Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
|
||||
* Bit 0 is set if it is marked for all PMCs.
|
||||
* The 0x80 bit indicates a byte decode PMCSEL value.
|
||||
*/
|
||||
static unsigned char direct_event_is_marked[0x28] = {
|
||||
0, /* 00 */
|
||||
0x1f, /* 01 PM_IOPS_CMPL */
|
||||
0x2, /* 02 PM_MRK_GRP_DISP */
|
||||
0xe, /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
|
||||
0, /* 04 */
|
||||
0x1c, /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
|
||||
0x80, /* 06 */
|
||||
0x80, /* 07 */
|
||||
0, 0, 0,/* 08 - 0a */
|
||||
0x18, /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
|
||||
0, /* 0c */
|
||||
0x80, /* 0d */
|
||||
0x80, /* 0e */
|
||||
0, /* 0f */
|
||||
0, /* 10 */
|
||||
0x14, /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
|
||||
0, /* 12 */
|
||||
0x10, /* 13 PM_MRK_GRP_CMPL */
|
||||
0x1f, /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
|
||||
0x2, /* 15 PM_MRK_GRP_ISSUED */
|
||||
0x80, /* 16 */
|
||||
0x80, /* 17 */
|
||||
0, 0, 0, 0, 0,
|
||||
0x80, /* 1d */
|
||||
0x80, /* 1e */
|
||||
0, /* 1f */
|
||||
0x80, /* 20 */
|
||||
0x80, /* 21 */
|
||||
0x80, /* 22 */
|
||||
0x80, /* 23 */
|
||||
0x80, /* 24 */
|
||||
0x80, /* 25 */
|
||||
0x80, /* 26 */
|
||||
0x80, /* 27 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns 1 if event counts things relating to marked instructions
|
||||
* and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
|
||||
*/
|
||||
static int power5p_marked_instr_event(u64 event)
|
||||
{
|
||||
int pmc, psel;
|
||||
int bit, byte, unit;
|
||||
u32 mask;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
psel = event & PM_PMCSEL_MSK;
|
||||
if (pmc >= 5)
|
||||
return 0;
|
||||
|
||||
bit = -1;
|
||||
if (psel < sizeof(direct_event_is_marked)) {
|
||||
if (direct_event_is_marked[psel] & (1 << pmc))
|
||||
return 1;
|
||||
if (direct_event_is_marked[psel] & 0x80)
|
||||
bit = 4;
|
||||
else if (psel == 0x08)
|
||||
bit = pmc - 1;
|
||||
else if (psel == 0x10)
|
||||
bit = 4 - pmc;
|
||||
else if (psel == 0x1b && (pmc == 1 || pmc == 3))
|
||||
bit = 4;
|
||||
} else if ((psel & 0x48) == 0x40) {
|
||||
bit = psel & 7;
|
||||
} else if (psel == 0x28) {
|
||||
bit = pmc - 1;
|
||||
} else if (pmc == 3 && (psel == 0x2e || psel == 0x2f)) {
|
||||
bit = 4;
|
||||
}
|
||||
|
||||
if (!(event & PM_BUSEVENT_MSK) || bit == -1)
|
||||
return 0;
|
||||
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
if (unit == PM_LSU0) {
|
||||
/* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
|
||||
mask = 0x5dff00;
|
||||
} else if (unit == PM_LSU1 && byte >= 4) {
|
||||
byte -= 4;
|
||||
/* byte 5 bits 6-7, byte 6 bits 0,4, byte 7 bits 0-4,6 */
|
||||
mask = 0x5f11c000;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
return (mask >> (byte * 8 + bit)) & 1;
|
||||
}
|
||||
|
||||
static int power5p_compute_mmcr(u64 event[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[])
|
||||
{
|
||||
u64 mmcr1 = 0;
|
||||
u64 mmcra = 0;
|
||||
unsigned int pmc, unit, byte, psel;
|
||||
unsigned int ttm;
|
||||
int i, isbus, bit, grsel;
|
||||
unsigned int pmc_inuse = 0;
|
||||
unsigned char busbyte[4];
|
||||
unsigned char unituse[16];
|
||||
int ttmuse;
|
||||
|
||||
if (n_ev > 6)
|
||||
return -1;
|
||||
|
||||
/* First pass to count resource use */
|
||||
memset(busbyte, 0, sizeof(busbyte));
|
||||
memset(unituse, 0, sizeof(unituse));
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 6)
|
||||
return -1;
|
||||
if (pmc_inuse & (1 << (pmc - 1)))
|
||||
return -1;
|
||||
pmc_inuse |= 1 << (pmc - 1);
|
||||
}
|
||||
if (event[i] & PM_BUSEVENT_MSK) {
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
if (unit > PM_LASTUNIT)
|
||||
return -1;
|
||||
if (unit == PM_ISU0_ALT)
|
||||
unit = PM_ISU0;
|
||||
if (byte >= 4) {
|
||||
if (unit != PM_LSU1)
|
||||
return -1;
|
||||
++unit;
|
||||
byte &= 3;
|
||||
}
|
||||
if (busbyte[byte] && busbyte[byte] != unit)
|
||||
return -1;
|
||||
busbyte[byte] = unit;
|
||||
unituse[unit] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign resources and set multiplexer selects.
|
||||
*
|
||||
* PM_ISU0 can go either on TTM0 or TTM1, but that's the only
|
||||
* choice we have to deal with.
|
||||
*/
|
||||
if (unituse[PM_ISU0] &
|
||||
(unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
|
||||
unituse[PM_ISU0_ALT] = 1; /* move ISU to TTM1 */
|
||||
unituse[PM_ISU0] = 0;
|
||||
}
|
||||
/* Set TTM[01]SEL fields. */
|
||||
ttmuse = 0;
|
||||
for (i = PM_FPU; i <= PM_ISU1; ++i) {
|
||||
if (!unituse[i])
|
||||
continue;
|
||||
if (ttmuse++)
|
||||
return -1;
|
||||
mmcr1 |= (u64)i << MMCR1_TTM0SEL_SH;
|
||||
}
|
||||
ttmuse = 0;
|
||||
for (; i <= PM_GRS; ++i) {
|
||||
if (!unituse[i])
|
||||
continue;
|
||||
if (ttmuse++)
|
||||
return -1;
|
||||
mmcr1 |= (u64)(i & 3) << MMCR1_TTM1SEL_SH;
|
||||
}
|
||||
if (ttmuse > 1)
|
||||
return -1;
|
||||
|
||||
/* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
|
||||
for (byte = 0; byte < 4; ++byte) {
|
||||
unit = busbyte[byte];
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
|
||||
/* get ISU0 through TTM1 rather than TTM0 */
|
||||
unit = PM_ISU0_ALT;
|
||||
} else if (unit == PM_LSU1 + 1) {
|
||||
/* select lower word of LSU1 for this byte */
|
||||
mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
|
||||
}
|
||||
ttm = unit >> 2;
|
||||
mmcr1 |= (u64)ttm << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
|
||||
}
|
||||
|
||||
/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
psel = event[i] & PM_PMCSEL_MSK;
|
||||
isbus = event[i] & PM_BUSEVENT_MSK;
|
||||
if (!pmc) {
|
||||
/* Bus event or any-PMC direct event */
|
||||
for (pmc = 0; pmc < 4; ++pmc) {
|
||||
if (!(pmc_inuse & (1 << pmc)))
|
||||
break;
|
||||
}
|
||||
if (pmc >= 4)
|
||||
return -1;
|
||||
pmc_inuse |= 1 << pmc;
|
||||
} else if (pmc <= 4) {
|
||||
/* Direct event */
|
||||
--pmc;
|
||||
if (isbus && (byte & 2) &&
|
||||
(psel == 8 || psel == 0x10 || psel == 0x28))
|
||||
/* add events on higher-numbered bus */
|
||||
mmcr1 |= 1ull << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
|
||||
} else {
|
||||
/* Instructions or run cycles on PMC5/6 */
|
||||
--pmc;
|
||||
}
|
||||
if (isbus && unit == PM_GRS) {
|
||||
bit = psel & 7;
|
||||
grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
|
||||
mmcr1 |= (u64)grsel << grsel_shift[bit];
|
||||
}
|
||||
if (power5p_marked_instr_event(event[i]))
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
if ((psel & 0x58) == 0x40 && (byte & 1) != ((pmc >> 1) & 1))
|
||||
/* select alternate byte lane */
|
||||
psel |= 0x10;
|
||||
if (pmc <= 3)
|
||||
mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
|
||||
hwc[i] = pmc;
|
||||
}
|
||||
|
||||
/* Return MMCRx values */
|
||||
mmcr[0] = 0;
|
||||
if (pmc_inuse & 1)
|
||||
mmcr[0] = MMCR0_PMC1CE;
|
||||
if (pmc_inuse & 0x3e)
|
||||
mmcr[0] |= MMCR0_PMCjCE;
|
||||
mmcr[1] = mmcr1;
|
||||
mmcr[2] = mmcra;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void power5p_disable_pmc(unsigned int pmc, u64 mmcr[])
|
||||
{
|
||||
if (pmc <= 3)
|
||||
mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
|
||||
}
|
||||
|
||||
static int power5p_generic_events[] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 0xf,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 0x100009,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x1c10a8, /* LD_REF_L1 */
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x3c1088, /* LD_MISS_L1 */
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x230e4, /* BR_ISSUED */
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x230e5, /* BR_MPRED_CR */
|
||||
};
|
||||
|
||||
#define C(x) PERF_COUNT_HW_CACHE_##x
|
||||
|
||||
/*
|
||||
* Table of generalized cache-related events.
|
||||
* 0 means not supported, -1 means nonsensical, other values
|
||||
* are event codes.
|
||||
*/
|
||||
static int power5p_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
|
||||
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x1c10a8, 0x3c1088 },
|
||||
[C(OP_WRITE)] = { 0x2c10a8, 0xc10c3 },
|
||||
[C(OP_PREFETCH)] = { 0xc70e7, -1 },
|
||||
},
|
||||
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { 0, 0 },
|
||||
},
|
||||
[C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { 0, 0 },
|
||||
[C(OP_PREFETCH)] = { 0xc50c3, 0 },
|
||||
},
|
||||
[C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0xc20e4, 0x800c4 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x800c0 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x230e4, 0x230e5 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
struct power_pmu power5p_pmu = {
|
||||
.n_counter = 6,
|
||||
.max_alternatives = MAX_ALT,
|
||||
.add_fields = 0x7000000000055ull,
|
||||
.test_adder = 0x3000040000000ull,
|
||||
.compute_mmcr = power5p_compute_mmcr,
|
||||
.get_constraint = power5p_get_constraint,
|
||||
.get_alternatives = power5p_get_alternatives,
|
||||
.disable_pmc = power5p_disable_pmc,
|
||||
.limited_pmc_event = power5p_limited_pmc_event,
|
||||
.flags = PPMU_LIMITED_PMC5_6,
|
||||
.n_generic = ARRAY_SIZE(power5p_generic_events),
|
||||
.generic_events = power5p_generic_events,
|
||||
.cache_events = &power5p_cache_events,
|
||||
};
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* Performance counter support for POWER5 (not POWER5++) processors.
|
||||
*
|
||||
* Copyright 2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <asm/reg.h>
|
||||
|
||||
/*
|
||||
* Bits in event code for POWER5 (not POWER5++)
|
||||
*/
|
||||
#define PM_PMC_SH 20 /* PMC number (1-based) for direct events */
|
||||
#define PM_PMC_MSK 0xf
|
||||
#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
|
||||
#define PM_UNIT_SH 16 /* TTMMUX number and setting - unit select */
|
||||
#define PM_UNIT_MSK 0xf
|
||||
#define PM_BYTE_SH 12 /* Byte number of event bus to use */
|
||||
#define PM_BYTE_MSK 7
|
||||
#define PM_GRS_SH 8 /* Storage subsystem mux select */
|
||||
#define PM_GRS_MSK 7
|
||||
#define PM_BUSEVENT_MSK 0x80 /* Set if event uses event bus */
|
||||
#define PM_PMCSEL_MSK 0x7f
|
||||
|
||||
/* Values in PM_UNIT field */
|
||||
#define PM_FPU 0
|
||||
#define PM_ISU0 1
|
||||
#define PM_IFU 2
|
||||
#define PM_ISU1 3
|
||||
#define PM_IDU 4
|
||||
#define PM_ISU0_ALT 6
|
||||
#define PM_GRS 7
|
||||
#define PM_LSU0 8
|
||||
#define PM_LSU1 0xc
|
||||
#define PM_LASTUNIT 0xc
|
||||
|
||||
/*
|
||||
* Bits in MMCR1 for POWER5
|
||||
*/
|
||||
#define MMCR1_TTM0SEL_SH 62
|
||||
#define MMCR1_TTM1SEL_SH 60
|
||||
#define MMCR1_TTM2SEL_SH 58
|
||||
#define MMCR1_TTM3SEL_SH 56
|
||||
#define MMCR1_TTMSEL_MSK 3
|
||||
#define MMCR1_TD_CP_DBG0SEL_SH 54
|
||||
#define MMCR1_TD_CP_DBG1SEL_SH 52
|
||||
#define MMCR1_TD_CP_DBG2SEL_SH 50
|
||||
#define MMCR1_TD_CP_DBG3SEL_SH 48
|
||||
#define MMCR1_GRS_L2SEL_SH 46
|
||||
#define MMCR1_GRS_L2SEL_MSK 3
|
||||
#define MMCR1_GRS_L3SEL_SH 44
|
||||
#define MMCR1_GRS_L3SEL_MSK 3
|
||||
#define MMCR1_GRS_MCSEL_SH 41
|
||||
#define MMCR1_GRS_MCSEL_MSK 7
|
||||
#define MMCR1_GRS_FABSEL_SH 39
|
||||
#define MMCR1_GRS_FABSEL_MSK 3
|
||||
#define MMCR1_PMC1_ADDER_SEL_SH 35
|
||||
#define MMCR1_PMC2_ADDER_SEL_SH 34
|
||||
#define MMCR1_PMC3_ADDER_SEL_SH 33
|
||||
#define MMCR1_PMC4_ADDER_SEL_SH 32
|
||||
#define MMCR1_PMC1SEL_SH 25
|
||||
#define MMCR1_PMC2SEL_SH 17
|
||||
#define MMCR1_PMC3SEL_SH 9
|
||||
#define MMCR1_PMC4SEL_SH 1
|
||||
#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
|
||||
#define MMCR1_PMCSEL_MSK 0x7f
|
||||
|
||||
/*
|
||||
* Bits in MMCRA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Layout of constraint bits:
|
||||
* 6666555555555544444444443333333333222222222211111111110000000000
|
||||
* 3210987654321098765432109876543210987654321098765432109876543210
|
||||
* <><>[ ><><>< ><> [ >[ >[ >< >< >< >< ><><><><><><>
|
||||
* T0T1 NC G0G1G2 G3 UC PS1PS2 B0 B1 B2 B3 P6P5P4P3P2P1
|
||||
*
|
||||
* T0 - TTM0 constraint
|
||||
* 54-55: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0xc0_0000_0000_0000
|
||||
*
|
||||
* T1 - TTM1 constraint
|
||||
* 52-53: TTM1SEL value (0=IDU, 3=GRS) 0x30_0000_0000_0000
|
||||
*
|
||||
* NC - number of counters
|
||||
* 51: NC error 0x0008_0000_0000_0000
|
||||
* 48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
|
||||
*
|
||||
* G0..G3 - GRS mux constraints
|
||||
* 46-47: GRS_L2SEL value
|
||||
* 44-45: GRS_L3SEL value
|
||||
* 41-44: GRS_MCSEL value
|
||||
* 39-40: GRS_FABSEL value
|
||||
* Note that these match up with their bit positions in MMCR1
|
||||
*
|
||||
* UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
|
||||
* 37: UC3 error 0x20_0000_0000
|
||||
* 36: FPU|IFU|ISU1 events needed 0x10_0000_0000
|
||||
* 35: ISU0 events needed 0x08_0000_0000
|
||||
* 34: IDU|GRS events needed 0x04_0000_0000
|
||||
*
|
||||
* PS1
|
||||
* 33: PS1 error 0x2_0000_0000
|
||||
* 31-32: count of events needing PMC1/2 0x1_8000_0000
|
||||
*
|
||||
* PS2
|
||||
* 30: PS2 error 0x4000_0000
|
||||
* 28-29: count of events needing PMC3/4 0x3000_0000
|
||||
*
|
||||
* B0
|
||||
* 24-27: Byte 0 event source 0x0f00_0000
|
||||
* Encoding as for the event code
|
||||
*
|
||||
* B1, B2, B3
|
||||
* 20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
|
||||
*
|
||||
* P1..P6
|
||||
* 0-11: Count of events needing PMC1..PMC6
|
||||
*/
|
||||
|
||||
static const int grsel_shift[8] = {
|
||||
MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
|
||||
MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
|
||||
MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
|
||||
};
|
||||
|
||||
/* Masks and values for using events from the various units */
|
||||
static u64 unit_cons[PM_LASTUNIT+1][2] = {
|
||||
[PM_FPU] = { 0xc0002000000000ull, 0x00001000000000ull },
|
||||
[PM_ISU0] = { 0x00002000000000ull, 0x00000800000000ull },
|
||||
[PM_ISU1] = { 0xc0002000000000ull, 0xc0001000000000ull },
|
||||
[PM_IFU] = { 0xc0002000000000ull, 0x80001000000000ull },
|
||||
[PM_IDU] = { 0x30002000000000ull, 0x00000400000000ull },
|
||||
[PM_GRS] = { 0x30002000000000ull, 0x30000400000000ull },
|
||||
};
|
||||
|
||||
static int power5_get_constraint(u64 event, u64 *maskp, u64 *valp)
|
||||
{
|
||||
int pmc, byte, unit, sh;
|
||||
int bit, fmask;
|
||||
u64 mask = 0, value = 0;
|
||||
int grp = -1;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 6)
|
||||
return -1;
|
||||
sh = (pmc - 1) * 2;
|
||||
mask |= 2 << sh;
|
||||
value |= 1 << sh;
|
||||
if (pmc <= 4)
|
||||
grp = (pmc - 1) >> 1;
|
||||
else if (event != 0x500009 && event != 0x600005)
|
||||
return -1;
|
||||
}
|
||||
if (event & PM_BUSEVENT_MSK) {
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
if (unit > PM_LASTUNIT)
|
||||
return -1;
|
||||
if (unit == PM_ISU0_ALT)
|
||||
unit = PM_ISU0;
|
||||
mask |= unit_cons[unit][0];
|
||||
value |= unit_cons[unit][1];
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
if (byte >= 4) {
|
||||
if (unit != PM_LSU1)
|
||||
return -1;
|
||||
/* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
|
||||
++unit;
|
||||
byte &= 3;
|
||||
}
|
||||
if (unit == PM_GRS) {
|
||||
bit = event & 7;
|
||||
fmask = (bit == 6)? 7: 3;
|
||||
sh = grsel_shift[bit];
|
||||
mask |= (u64)fmask << sh;
|
||||
value |= (u64)((event >> PM_GRS_SH) & fmask) << sh;
|
||||
}
|
||||
/*
|
||||
* Bus events on bytes 0 and 2 can be counted
|
||||
* on PMC1/2; bytes 1 and 3 on PMC3/4.
|
||||
*/
|
||||
if (!pmc)
|
||||
grp = byte & 1;
|
||||
/* Set byte lane select field */
|
||||
mask |= 0xfULL << (24 - 4 * byte);
|
||||
value |= (u64)unit << (24 - 4 * byte);
|
||||
}
|
||||
if (grp == 0) {
|
||||
/* increment PMC1/2 field */
|
||||
mask |= 0x200000000ull;
|
||||
value |= 0x080000000ull;
|
||||
} else if (grp == 1) {
|
||||
/* increment PMC3/4 field */
|
||||
mask |= 0x40000000ull;
|
||||
value |= 0x10000000ull;
|
||||
}
|
||||
if (pmc < 5) {
|
||||
/* need a counter from PMC1-4 set */
|
||||
mask |= 0x8000000000000ull;
|
||||
value |= 0x1000000000000ull;
|
||||
}
|
||||
*maskp = mask;
|
||||
*valp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_ALT 3 /* at most 3 alternatives for any event */
|
||||
|
||||
static const unsigned int event_alternatives[][MAX_ALT] = {
|
||||
{ 0x120e4, 0x400002 }, /* PM_GRP_DISP_REJECT */
|
||||
{ 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */
|
||||
{ 0x100005, 0x600005 }, /* PM_RUN_CYC */
|
||||
{ 0x100009, 0x200009, 0x500009 }, /* PM_INST_CMPL */
|
||||
{ 0x300009, 0x400009 }, /* PM_INST_DISP */
|
||||
};
|
||||
|
||||
/*
|
||||
* Scan the alternatives table for a match and return the
|
||||
* index into the alternatives table if found, else -1.
|
||||
*/
|
||||
static int find_alternative(u64 event)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
|
||||
if (event < event_alternatives[i][0])
|
||||
break;
|
||||
for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
|
||||
if (event == event_alternatives[i][j])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const unsigned char bytedecode_alternatives[4][4] = {
|
||||
/* PMC 1 */ { 0x21, 0x23, 0x25, 0x27 },
|
||||
/* PMC 2 */ { 0x07, 0x17, 0x0e, 0x1e },
|
||||
/* PMC 3 */ { 0x20, 0x22, 0x24, 0x26 },
|
||||
/* PMC 4 */ { 0x07, 0x17, 0x0e, 0x1e }
|
||||
};
|
||||
|
||||
/*
|
||||
* Some direct events for decodes of event bus byte 3 have alternative
|
||||
* PMCSEL values on other counters. This returns the alternative
|
||||
* event code for those that do, or -1 otherwise.
|
||||
*/
|
||||
static s64 find_alternative_bdecode(u64 event)
|
||||
{
|
||||
int pmc, altpmc, pp, j;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc == 0 || pmc > 4)
|
||||
return -1;
|
||||
altpmc = 5 - pmc; /* 1 <-> 4, 2 <-> 3 */
|
||||
pp = event & PM_PMCSEL_MSK;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
if (bytedecode_alternatives[pmc - 1][j] == pp) {
|
||||
return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
|
||||
(altpmc << PM_PMC_SH) |
|
||||
bytedecode_alternatives[altpmc - 1][j];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int power5_get_alternatives(u64 event, unsigned int flags, u64 alt[])
|
||||
{
|
||||
int i, j, nalt = 1;
|
||||
s64 ae;
|
||||
|
||||
alt[0] = event;
|
||||
nalt = 1;
|
||||
i = find_alternative(event);
|
||||
if (i >= 0) {
|
||||
for (j = 0; j < MAX_ALT; ++j) {
|
||||
ae = event_alternatives[i][j];
|
||||
if (ae && ae != event)
|
||||
alt[nalt++] = ae;
|
||||
}
|
||||
} else {
|
||||
ae = find_alternative_bdecode(event);
|
||||
if (ae > 0)
|
||||
alt[nalt++] = ae;
|
||||
}
|
||||
return nalt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map of which direct events on which PMCs are marked instruction events.
|
||||
* Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
|
||||
* Bit 0 is set if it is marked for all PMCs.
|
||||
* The 0x80 bit indicates a byte decode PMCSEL value.
|
||||
*/
|
||||
static unsigned char direct_event_is_marked[0x28] = {
|
||||
0, /* 00 */
|
||||
0x1f, /* 01 PM_IOPS_CMPL */
|
||||
0x2, /* 02 PM_MRK_GRP_DISP */
|
||||
0xe, /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
|
||||
0, /* 04 */
|
||||
0x1c, /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
|
||||
0x80, /* 06 */
|
||||
0x80, /* 07 */
|
||||
0, 0, 0,/* 08 - 0a */
|
||||
0x18, /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
|
||||
0, /* 0c */
|
||||
0x80, /* 0d */
|
||||
0x80, /* 0e */
|
||||
0, /* 0f */
|
||||
0, /* 10 */
|
||||
0x14, /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
|
||||
0, /* 12 */
|
||||
0x10, /* 13 PM_MRK_GRP_CMPL */
|
||||
0x1f, /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
|
||||
0x2, /* 15 PM_MRK_GRP_ISSUED */
|
||||
0x80, /* 16 */
|
||||
0x80, /* 17 */
|
||||
0, 0, 0, 0, 0,
|
||||
0x80, /* 1d */
|
||||
0x80, /* 1e */
|
||||
0, /* 1f */
|
||||
0x80, /* 20 */
|
||||
0x80, /* 21 */
|
||||
0x80, /* 22 */
|
||||
0x80, /* 23 */
|
||||
0x80, /* 24 */
|
||||
0x80, /* 25 */
|
||||
0x80, /* 26 */
|
||||
0x80, /* 27 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns 1 if event counts things relating to marked instructions
|
||||
* and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
|
||||
*/
|
||||
static int power5_marked_instr_event(u64 event)
|
||||
{
|
||||
int pmc, psel;
|
||||
int bit, byte, unit;
|
||||
u32 mask;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
psel = event & PM_PMCSEL_MSK;
|
||||
if (pmc >= 5)
|
||||
return 0;
|
||||
|
||||
bit = -1;
|
||||
if (psel < sizeof(direct_event_is_marked)) {
|
||||
if (direct_event_is_marked[psel] & (1 << pmc))
|
||||
return 1;
|
||||
if (direct_event_is_marked[psel] & 0x80)
|
||||
bit = 4;
|
||||
else if (psel == 0x08)
|
||||
bit = pmc - 1;
|
||||
else if (psel == 0x10)
|
||||
bit = 4 - pmc;
|
||||
else if (psel == 0x1b && (pmc == 1 || pmc == 3))
|
||||
bit = 4;
|
||||
} else if ((psel & 0x58) == 0x40)
|
||||
bit = psel & 7;
|
||||
|
||||
if (!(event & PM_BUSEVENT_MSK))
|
||||
return 0;
|
||||
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
if (unit == PM_LSU0) {
|
||||
/* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
|
||||
mask = 0x5dff00;
|
||||
} else if (unit == PM_LSU1 && byte >= 4) {
|
||||
byte -= 4;
|
||||
/* byte 4 bits 1,3,5,7, byte 5 bits 6-7, byte 7 bits 0-4,6 */
|
||||
mask = 0x5f00c0aa;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
return (mask >> (byte * 8 + bit)) & 1;
|
||||
}
|
||||
|
||||
static int power5_compute_mmcr(u64 event[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[])
|
||||
{
|
||||
u64 mmcr1 = 0;
|
||||
u64 mmcra = 0;
|
||||
unsigned int pmc, unit, byte, psel;
|
||||
unsigned int ttm, grp;
|
||||
int i, isbus, bit, grsel;
|
||||
unsigned int pmc_inuse = 0;
|
||||
unsigned int pmc_grp_use[2];
|
||||
unsigned char busbyte[4];
|
||||
unsigned char unituse[16];
|
||||
int ttmuse;
|
||||
|
||||
if (n_ev > 6)
|
||||
return -1;
|
||||
|
||||
/* First pass to count resource use */
|
||||
pmc_grp_use[0] = pmc_grp_use[1] = 0;
|
||||
memset(busbyte, 0, sizeof(busbyte));
|
||||
memset(unituse, 0, sizeof(unituse));
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 6)
|
||||
return -1;
|
||||
if (pmc_inuse & (1 << (pmc - 1)))
|
||||
return -1;
|
||||
pmc_inuse |= 1 << (pmc - 1);
|
||||
/* count 1/2 vs 3/4 use */
|
||||
if (pmc <= 4)
|
||||
++pmc_grp_use[(pmc - 1) >> 1];
|
||||
}
|
||||
if (event[i] & PM_BUSEVENT_MSK) {
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
if (unit > PM_LASTUNIT)
|
||||
return -1;
|
||||
if (unit == PM_ISU0_ALT)
|
||||
unit = PM_ISU0;
|
||||
if (byte >= 4) {
|
||||
if (unit != PM_LSU1)
|
||||
return -1;
|
||||
++unit;
|
||||
byte &= 3;
|
||||
}
|
||||
if (!pmc)
|
||||
++pmc_grp_use[byte & 1];
|
||||
if (busbyte[byte] && busbyte[byte] != unit)
|
||||
return -1;
|
||||
busbyte[byte] = unit;
|
||||
unituse[unit] = 1;
|
||||
}
|
||||
}
|
||||
if (pmc_grp_use[0] > 2 || pmc_grp_use[1] > 2)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Assign resources and set multiplexer selects.
|
||||
*
|
||||
* PM_ISU0 can go either on TTM0 or TTM1, but that's the only
|
||||
* choice we have to deal with.
|
||||
*/
|
||||
if (unituse[PM_ISU0] &
|
||||
(unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
|
||||
unituse[PM_ISU0_ALT] = 1; /* move ISU to TTM1 */
|
||||
unituse[PM_ISU0] = 0;
|
||||
}
|
||||
/* Set TTM[01]SEL fields. */
|
||||
ttmuse = 0;
|
||||
for (i = PM_FPU; i <= PM_ISU1; ++i) {
|
||||
if (!unituse[i])
|
||||
continue;
|
||||
if (ttmuse++)
|
||||
return -1;
|
||||
mmcr1 |= (u64)i << MMCR1_TTM0SEL_SH;
|
||||
}
|
||||
ttmuse = 0;
|
||||
for (; i <= PM_GRS; ++i) {
|
||||
if (!unituse[i])
|
||||
continue;
|
||||
if (ttmuse++)
|
||||
return -1;
|
||||
mmcr1 |= (u64)(i & 3) << MMCR1_TTM1SEL_SH;
|
||||
}
|
||||
if (ttmuse > 1)
|
||||
return -1;
|
||||
|
||||
/* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
|
||||
for (byte = 0; byte < 4; ++byte) {
|
||||
unit = busbyte[byte];
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
|
||||
/* get ISU0 through TTM1 rather than TTM0 */
|
||||
unit = PM_ISU0_ALT;
|
||||
} else if (unit == PM_LSU1 + 1) {
|
||||
/* select lower word of LSU1 for this byte */
|
||||
mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
|
||||
}
|
||||
ttm = unit >> 2;
|
||||
mmcr1 |= (u64)ttm << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
|
||||
}
|
||||
|
||||
/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
psel = event[i] & PM_PMCSEL_MSK;
|
||||
isbus = event[i] & PM_BUSEVENT_MSK;
|
||||
if (!pmc) {
|
||||
/* Bus event or any-PMC direct event */
|
||||
for (pmc = 0; pmc < 4; ++pmc) {
|
||||
if (pmc_inuse & (1 << pmc))
|
||||
continue;
|
||||
grp = (pmc >> 1) & 1;
|
||||
if (isbus) {
|
||||
if (grp == (byte & 1))
|
||||
break;
|
||||
} else if (pmc_grp_use[grp] < 2) {
|
||||
++pmc_grp_use[grp];
|
||||
break;
|
||||
}
|
||||
}
|
||||
pmc_inuse |= 1 << pmc;
|
||||
} else if (pmc <= 4) {
|
||||
/* Direct event */
|
||||
--pmc;
|
||||
if ((psel == 8 || psel == 0x10) && isbus && (byte & 2))
|
||||
/* add events on higher-numbered bus */
|
||||
mmcr1 |= 1ull << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
|
||||
} else {
|
||||
/* Instructions or run cycles on PMC5/6 */
|
||||
--pmc;
|
||||
}
|
||||
if (isbus && unit == PM_GRS) {
|
||||
bit = psel & 7;
|
||||
grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
|
||||
mmcr1 |= (u64)grsel << grsel_shift[bit];
|
||||
}
|
||||
if (power5_marked_instr_event(event[i]))
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
if (pmc <= 3)
|
||||
mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
|
||||
hwc[i] = pmc;
|
||||
}
|
||||
|
||||
/* Return MMCRx values */
|
||||
mmcr[0] = 0;
|
||||
if (pmc_inuse & 1)
|
||||
mmcr[0] = MMCR0_PMC1CE;
|
||||
if (pmc_inuse & 0x3e)
|
||||
mmcr[0] |= MMCR0_PMCjCE;
|
||||
mmcr[1] = mmcr1;
|
||||
mmcr[2] = mmcra;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void power5_disable_pmc(unsigned int pmc, u64 mmcr[])
|
||||
{
|
||||
if (pmc <= 3)
|
||||
mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
|
||||
}
|
||||
|
||||
static int power5_generic_events[] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 0xf,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 0x100009,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x4c1090, /* LD_REF_L1 */
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x3c1088, /* LD_MISS_L1 */
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x230e4, /* BR_ISSUED */
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x230e5, /* BR_MPRED_CR */
|
||||
};
|
||||
|
||||
#define C(x) PERF_COUNT_HW_CACHE_##x
|
||||
|
||||
/*
|
||||
* Table of generalized cache-related events.
|
||||
* 0 means not supported, -1 means nonsensical, other values
|
||||
* are event codes.
|
||||
*/
|
||||
static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
|
||||
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x4c1090, 0x3c1088 },
|
||||
[C(OP_WRITE)] = { 0x3c1090, 0xc10c3 },
|
||||
[C(OP_PREFETCH)] = { 0xc70e7, 0 },
|
||||
},
|
||||
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { 0, 0 },
|
||||
},
|
||||
[C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x3c309b },
|
||||
[C(OP_WRITE)] = { 0, 0 },
|
||||
[C(OP_PREFETCH)] = { 0xc50c3, 0 },
|
||||
},
|
||||
[C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x2c4090, 0x800c4 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x800c0 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x230e4, 0x230e5 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
struct power_pmu power5_pmu = {
|
||||
.n_counter = 6,
|
||||
.max_alternatives = MAX_ALT,
|
||||
.add_fields = 0x7000090000555ull,
|
||||
.test_adder = 0x3000490000000ull,
|
||||
.compute_mmcr = power5_compute_mmcr,
|
||||
.get_constraint = power5_get_constraint,
|
||||
.get_alternatives = power5_get_alternatives,
|
||||
.disable_pmc = power5_disable_pmc,
|
||||
.n_generic = ARRAY_SIZE(power5_generic_events),
|
||||
.generic_events = power5_generic_events,
|
||||
.cache_events = &power5_cache_events,
|
||||
};
|
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
* Performance counter support for POWER6 processors.
|
||||
*
|
||||
* Copyright 2008-2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <asm/reg.h>
|
||||
|
||||
/*
|
||||
* Bits in event code for POWER6
|
||||
*/
|
||||
#define PM_PMC_SH 20 /* PMC number (1-based) for direct events */
|
||||
#define PM_PMC_MSK 0x7
|
||||
#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
|
||||
#define PM_UNIT_SH 16 /* Unit event comes (TTMxSEL encoding) */
|
||||
#define PM_UNIT_MSK 0xf
|
||||
#define PM_UNIT_MSKS (PM_UNIT_MSK << PM_UNIT_SH)
|
||||
#define PM_LLAV 0x8000 /* Load lookahead match value */
|
||||
#define PM_LLA 0x4000 /* Load lookahead match enable */
|
||||
#define PM_BYTE_SH 12 /* Byte of event bus to use */
|
||||
#define PM_BYTE_MSK 3
|
||||
#define PM_SUBUNIT_SH 8 /* Subunit event comes from (NEST_SEL enc.) */
|
||||
#define PM_SUBUNIT_MSK 7
|
||||
#define PM_SUBUNIT_MSKS (PM_SUBUNIT_MSK << PM_SUBUNIT_SH)
|
||||
#define PM_PMCSEL_MSK 0xff /* PMCxSEL value */
|
||||
#define PM_BUSEVENT_MSK 0xf3700
|
||||
|
||||
/*
|
||||
* Bits in MMCR1 for POWER6
|
||||
*/
|
||||
#define MMCR1_TTM0SEL_SH 60
|
||||
#define MMCR1_TTMSEL_SH(n) (MMCR1_TTM0SEL_SH - (n) * 4)
|
||||
#define MMCR1_TTMSEL_MSK 0xf
|
||||
#define MMCR1_TTMSEL(m, n) (((m) >> MMCR1_TTMSEL_SH(n)) & MMCR1_TTMSEL_MSK)
|
||||
#define MMCR1_NESTSEL_SH 45
|
||||
#define MMCR1_NESTSEL_MSK 0x7
|
||||
#define MMCR1_NESTSEL(m) (((m) >> MMCR1_NESTSEL_SH) & MMCR1_NESTSEL_MSK)
|
||||
#define MMCR1_PMC1_LLA ((u64)1 << 44)
|
||||
#define MMCR1_PMC1_LLA_VALUE ((u64)1 << 39)
|
||||
#define MMCR1_PMC1_ADDR_SEL ((u64)1 << 35)
|
||||
#define MMCR1_PMC1SEL_SH 24
|
||||
#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
|
||||
#define MMCR1_PMCSEL_MSK 0xff
|
||||
|
||||
/*
|
||||
* Map of which direct events on which PMCs are marked instruction events.
|
||||
* Indexed by PMCSEL value >> 1.
|
||||
* Bottom 4 bits are a map of which PMCs are interesting,
|
||||
* top 4 bits say what sort of event:
|
||||
* 0 = direct marked event,
|
||||
* 1 = byte decode event,
|
||||
* 4 = add/and event (PMC1 -> bits 0 & 4),
|
||||
* 5 = add/and event (PMC1 -> bits 1 & 5),
|
||||
* 6 = add/and event (PMC1 -> bits 2 & 6),
|
||||
* 7 = add/and event (PMC1 -> bits 3 & 7).
|
||||
*/
|
||||
static unsigned char direct_event_is_marked[0x60 >> 1] = {
|
||||
0, /* 00 */
|
||||
0, /* 02 */
|
||||
0, /* 04 */
|
||||
0x07, /* 06 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
|
||||
0x04, /* 08 PM_MRK_DFU_FIN */
|
||||
0x06, /* 0a PM_MRK_IFU_FIN, PM_MRK_INST_FIN */
|
||||
0, /* 0c */
|
||||
0, /* 0e */
|
||||
0x02, /* 10 PM_MRK_INST_DISP */
|
||||
0x08, /* 12 PM_MRK_LSU_DERAT_MISS */
|
||||
0, /* 14 */
|
||||
0, /* 16 */
|
||||
0x0c, /* 18 PM_THRESH_TIMEO, PM_MRK_INST_FIN */
|
||||
0x0f, /* 1a PM_MRK_INST_DISP, PM_MRK_{FXU,FPU,LSU}_FIN */
|
||||
0x01, /* 1c PM_MRK_INST_ISSUED */
|
||||
0, /* 1e */
|
||||
0, /* 20 */
|
||||
0, /* 22 */
|
||||
0, /* 24 */
|
||||
0, /* 26 */
|
||||
0x15, /* 28 PM_MRK_DATA_FROM_L2MISS, PM_MRK_DATA_FROM_L3MISS */
|
||||
0, /* 2a */
|
||||
0, /* 2c */
|
||||
0, /* 2e */
|
||||
0x4f, /* 30 */
|
||||
0x7f, /* 32 */
|
||||
0x4f, /* 34 */
|
||||
0x5f, /* 36 */
|
||||
0x6f, /* 38 */
|
||||
0x4f, /* 3a */
|
||||
0, /* 3c */
|
||||
0x08, /* 3e PM_MRK_INST_TIMEO */
|
||||
0x1f, /* 40 */
|
||||
0x1f, /* 42 */
|
||||
0x1f, /* 44 */
|
||||
0x1f, /* 46 */
|
||||
0x1f, /* 48 */
|
||||
0x1f, /* 4a */
|
||||
0x1f, /* 4c */
|
||||
0x1f, /* 4e */
|
||||
0, /* 50 */
|
||||
0x05, /* 52 PM_MRK_BR_TAKEN, PM_MRK_BR_MPRED */
|
||||
0x1c, /* 54 PM_MRK_PTEG_FROM_L3MISS, PM_MRK_PTEG_FROM_L2MISS */
|
||||
0x02, /* 56 PM_MRK_LD_MISS_L1 */
|
||||
0, /* 58 */
|
||||
0, /* 5a */
|
||||
0, /* 5c */
|
||||
0, /* 5e */
|
||||
};
|
||||
|
||||
/*
|
||||
* Masks showing for each unit which bits are marked events.
|
||||
* These masks are in LE order, i.e. 0x00000001 is byte 0, bit 0.
|
||||
*/
|
||||
static u32 marked_bus_events[16] = {
|
||||
0x01000000, /* direct events set 1: byte 3 bit 0 */
|
||||
0x00010000, /* direct events set 2: byte 2 bit 0 */
|
||||
0, 0, 0, 0, /* IDU, IFU, nest: nothing */
|
||||
0x00000088, /* VMX set 1: byte 0 bits 3, 7 */
|
||||
0x000000c0, /* VMX set 2: byte 0 bits 4-7 */
|
||||
0x04010000, /* LSU set 1: byte 2 bit 0, byte 3 bit 2 */
|
||||
0xff010000u, /* LSU set 2: byte 2 bit 0, all of byte 3 */
|
||||
0, /* LSU set 3 */
|
||||
0x00000010, /* VMX set 3: byte 0 bit 4 */
|
||||
0, /* BFP set 1 */
|
||||
0x00000022, /* BFP set 2: byte 0 bits 1, 5 */
|
||||
0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns 1 if event counts things relating to marked instructions
|
||||
* and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
|
||||
*/
|
||||
static int power6_marked_instr_event(u64 event)
|
||||
{
|
||||
int pmc, psel, ptype;
|
||||
int bit, byte, unit;
|
||||
u32 mask;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
psel = (event & PM_PMCSEL_MSK) >> 1; /* drop edge/level bit */
|
||||
if (pmc >= 5)
|
||||
return 0;
|
||||
|
||||
bit = -1;
|
||||
if (psel < sizeof(direct_event_is_marked)) {
|
||||
ptype = direct_event_is_marked[psel];
|
||||
if (pmc == 0 || !(ptype & (1 << (pmc - 1))))
|
||||
return 0;
|
||||
ptype >>= 4;
|
||||
if (ptype == 0)
|
||||
return 1;
|
||||
if (ptype == 1)
|
||||
bit = 0;
|
||||
else
|
||||
bit = ptype ^ (pmc - 1);
|
||||
} else if ((psel & 0x48) == 0x40)
|
||||
bit = psel & 7;
|
||||
|
||||
if (!(event & PM_BUSEVENT_MSK) || bit == -1)
|
||||
return 0;
|
||||
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
mask = marked_bus_events[unit];
|
||||
return (mask >> (byte * 8 + bit)) & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign PMC numbers and compute MMCR1 value for a set of events
|
||||
*/
|
||||
static int p6_compute_mmcr(u64 event[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[])
|
||||
{
|
||||
u64 mmcr1 = 0;
|
||||
u64 mmcra = 0;
|
||||
int i;
|
||||
unsigned int pmc, ev, b, u, s, psel;
|
||||
unsigned int ttmset = 0;
|
||||
unsigned int pmc_inuse = 0;
|
||||
|
||||
if (n_ev > 6)
|
||||
return -1;
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc_inuse & (1 << (pmc - 1)))
|
||||
return -1; /* collision! */
|
||||
pmc_inuse |= 1 << (pmc - 1);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
ev = event[i];
|
||||
pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
--pmc;
|
||||
} else {
|
||||
/* can go on any PMC; find a free one */
|
||||
for (pmc = 0; pmc < 4; ++pmc)
|
||||
if (!(pmc_inuse & (1 << pmc)))
|
||||
break;
|
||||
if (pmc >= 4)
|
||||
return -1;
|
||||
pmc_inuse |= 1 << pmc;
|
||||
}
|
||||
hwc[i] = pmc;
|
||||
psel = ev & PM_PMCSEL_MSK;
|
||||
if (ev & PM_BUSEVENT_MSK) {
|
||||
/* this event uses the event bus */
|
||||
b = (ev >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
u = (ev >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
/* check for conflict on this byte of event bus */
|
||||
if ((ttmset & (1 << b)) && MMCR1_TTMSEL(mmcr1, b) != u)
|
||||
return -1;
|
||||
mmcr1 |= (u64)u << MMCR1_TTMSEL_SH(b);
|
||||
ttmset |= 1 << b;
|
||||
if (u == 5) {
|
||||
/* Nest events have a further mux */
|
||||
s = (ev >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
|
||||
if ((ttmset & 0x10) &&
|
||||
MMCR1_NESTSEL(mmcr1) != s)
|
||||
return -1;
|
||||
ttmset |= 0x10;
|
||||
mmcr1 |= (u64)s << MMCR1_NESTSEL_SH;
|
||||
}
|
||||
if (0x30 <= psel && psel <= 0x3d) {
|
||||
/* these need the PMCx_ADDR_SEL bits */
|
||||
if (b >= 2)
|
||||
mmcr1 |= MMCR1_PMC1_ADDR_SEL >> pmc;
|
||||
}
|
||||
/* bus select values are different for PMC3/4 */
|
||||
if (pmc >= 2 && (psel & 0x90) == 0x80)
|
||||
psel ^= 0x20;
|
||||
}
|
||||
if (ev & PM_LLA) {
|
||||
mmcr1 |= MMCR1_PMC1_LLA >> pmc;
|
||||
if (ev & PM_LLAV)
|
||||
mmcr1 |= MMCR1_PMC1_LLA_VALUE >> pmc;
|
||||
}
|
||||
if (power6_marked_instr_event(event[i]))
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
if (pmc < 4)
|
||||
mmcr1 |= (u64)psel << MMCR1_PMCSEL_SH(pmc);
|
||||
}
|
||||
mmcr[0] = 0;
|
||||
if (pmc_inuse & 1)
|
||||
mmcr[0] = MMCR0_PMC1CE;
|
||||
if (pmc_inuse & 0xe)
|
||||
mmcr[0] |= MMCR0_PMCjCE;
|
||||
mmcr[1] = mmcr1;
|
||||
mmcr[2] = mmcra;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Layout of constraint bits:
|
||||
*
|
||||
* 0-1 add field: number of uses of PMC1 (max 1)
|
||||
* 2-3, 4-5, 6-7, 8-9, 10-11: ditto for PMC2, 3, 4, 5, 6
|
||||
* 12-15 add field: number of uses of PMC1-4 (max 4)
|
||||
* 16-19 select field: unit on byte 0 of event bus
|
||||
* 20-23, 24-27, 28-31 ditto for bytes 1, 2, 3
|
||||
* 32-34 select field: nest (subunit) event selector
|
||||
*/
|
||||
static int p6_get_constraint(u64 event, u64 *maskp, u64 *valp)
|
||||
{
|
||||
int pmc, byte, sh, subunit;
|
||||
u64 mask = 0, value = 0;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 4 && !(event == 0x500009 || event == 0x600005))
|
||||
return -1;
|
||||
sh = (pmc - 1) * 2;
|
||||
mask |= 2 << sh;
|
||||
value |= 1 << sh;
|
||||
}
|
||||
if (event & PM_BUSEVENT_MSK) {
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
sh = byte * 4 + (16 - PM_UNIT_SH);
|
||||
mask |= PM_UNIT_MSKS << sh;
|
||||
value |= (u64)(event & PM_UNIT_MSKS) << sh;
|
||||
if ((event & PM_UNIT_MSKS) == (5 << PM_UNIT_SH)) {
|
||||
subunit = (event >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
|
||||
mask |= (u64)PM_SUBUNIT_MSK << 32;
|
||||
value |= (u64)subunit << 32;
|
||||
}
|
||||
}
|
||||
if (pmc <= 4) {
|
||||
mask |= 0x8000; /* add field for count of PMC1-4 uses */
|
||||
value |= 0x1000;
|
||||
}
|
||||
*maskp = mask;
|
||||
*valp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p6_limited_pmc_event(u64 event)
|
||||
{
|
||||
int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
|
||||
return pmc == 5 || pmc == 6;
|
||||
}
|
||||
|
||||
#define MAX_ALT 4 /* at most 4 alternatives for any event */
|
||||
|
||||
static const unsigned int event_alternatives[][MAX_ALT] = {
|
||||
{ 0x0130e8, 0x2000f6, 0x3000fc }, /* PM_PTEG_RELOAD_VALID */
|
||||
{ 0x080080, 0x10000d, 0x30000c, 0x4000f0 }, /* PM_LD_MISS_L1 */
|
||||
{ 0x080088, 0x200054, 0x3000f0 }, /* PM_ST_MISS_L1 */
|
||||
{ 0x10000a, 0x2000f4, 0x600005 }, /* PM_RUN_CYC */
|
||||
{ 0x10000b, 0x2000f5 }, /* PM_RUN_COUNT */
|
||||
{ 0x10000e, 0x400010 }, /* PM_PURR */
|
||||
{ 0x100010, 0x4000f8 }, /* PM_FLUSH */
|
||||
{ 0x10001a, 0x200010 }, /* PM_MRK_INST_DISP */
|
||||
{ 0x100026, 0x3000f8 }, /* PM_TB_BIT_TRANS */
|
||||
{ 0x100054, 0x2000f0 }, /* PM_ST_FIN */
|
||||
{ 0x100056, 0x2000fc }, /* PM_L1_ICACHE_MISS */
|
||||
{ 0x1000f0, 0x40000a }, /* PM_INST_IMC_MATCH_CMPL */
|
||||
{ 0x1000f8, 0x200008 }, /* PM_GCT_EMPTY_CYC */
|
||||
{ 0x1000fc, 0x400006 }, /* PM_LSU_DERAT_MISS_CYC */
|
||||
{ 0x20000e, 0x400007 }, /* PM_LSU_DERAT_MISS */
|
||||
{ 0x200012, 0x300012 }, /* PM_INST_DISP */
|
||||
{ 0x2000f2, 0x3000f2 }, /* PM_INST_DISP */
|
||||
{ 0x2000f8, 0x300010 }, /* PM_EXT_INT */
|
||||
{ 0x2000fe, 0x300056 }, /* PM_DATA_FROM_L2MISS */
|
||||
{ 0x2d0030, 0x30001a }, /* PM_MRK_FPU_FIN */
|
||||
{ 0x30000a, 0x400018 }, /* PM_MRK_INST_FIN */
|
||||
{ 0x3000f6, 0x40000e }, /* PM_L1_DCACHE_RELOAD_VALID */
|
||||
{ 0x3000fe, 0x400056 }, /* PM_DATA_FROM_L3MISS */
|
||||
};
|
||||
|
||||
/*
|
||||
* This could be made more efficient with a binary search on
|
||||
* a presorted list, if necessary
|
||||
*/
|
||||
static int find_alternatives_list(u64 event)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int alt;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
|
||||
if (event < event_alternatives[i][0])
|
||||
return -1;
|
||||
for (j = 0; j < MAX_ALT; ++j) {
|
||||
alt = event_alternatives[i][j];
|
||||
if (!alt || event < alt)
|
||||
break;
|
||||
if (event == alt)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int p6_get_alternatives(u64 event, unsigned int flags, u64 alt[])
|
||||
{
|
||||
int i, j, nlim;
|
||||
unsigned int psel, pmc;
|
||||
unsigned int nalt = 1;
|
||||
u64 aevent;
|
||||
|
||||
alt[0] = event;
|
||||
nlim = p6_limited_pmc_event(event);
|
||||
|
||||
/* check the alternatives table */
|
||||
i = find_alternatives_list(event);
|
||||
if (i >= 0) {
|
||||
/* copy out alternatives from list */
|
||||
for (j = 0; j < MAX_ALT; ++j) {
|
||||
aevent = event_alternatives[i][j];
|
||||
if (!aevent)
|
||||
break;
|
||||
if (aevent != event)
|
||||
alt[nalt++] = aevent;
|
||||
nlim += p6_limited_pmc_event(aevent);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Check for alternative ways of computing sum events */
|
||||
/* PMCSEL 0x32 counter N == PMCSEL 0x34 counter 5-N */
|
||||
psel = event & (PM_PMCSEL_MSK & ~1); /* ignore edge bit */
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc && (psel == 0x32 || psel == 0x34))
|
||||
alt[nalt++] = ((event ^ 0x6) & ~PM_PMC_MSKS) |
|
||||
((5 - pmc) << PM_PMC_SH);
|
||||
|
||||
/* PMCSEL 0x38 counter N == PMCSEL 0x3a counter N+/-2 */
|
||||
if (pmc && (psel == 0x38 || psel == 0x3a))
|
||||
alt[nalt++] = ((event ^ 0x2) & ~PM_PMC_MSKS) |
|
||||
((pmc > 2? pmc - 2: pmc + 2) << PM_PMC_SH);
|
||||
}
|
||||
|
||||
if (flags & PPMU_ONLY_COUNT_RUN) {
|
||||
/*
|
||||
* We're only counting in RUN state,
|
||||
* so PM_CYC is equivalent to PM_RUN_CYC,
|
||||
* PM_INST_CMPL === PM_RUN_INST_CMPL, PM_PURR === PM_RUN_PURR.
|
||||
* This doesn't include alternatives that don't provide
|
||||
* any extra flexibility in assigning PMCs (e.g.
|
||||
* 0x10000a for PM_RUN_CYC vs. 0x1e for PM_CYC).
|
||||
* Note that even with these additional alternatives
|
||||
* we never end up with more than 4 alternatives for any event.
|
||||
*/
|
||||
j = nalt;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
switch (alt[i]) {
|
||||
case 0x1e: /* PM_CYC */
|
||||
alt[j++] = 0x600005; /* PM_RUN_CYC */
|
||||
++nlim;
|
||||
break;
|
||||
case 0x10000a: /* PM_RUN_CYC */
|
||||
alt[j++] = 0x1e; /* PM_CYC */
|
||||
break;
|
||||
case 2: /* PM_INST_CMPL */
|
||||
alt[j++] = 0x500009; /* PM_RUN_INST_CMPL */
|
||||
++nlim;
|
||||
break;
|
||||
case 0x500009: /* PM_RUN_INST_CMPL */
|
||||
alt[j++] = 2; /* PM_INST_CMPL */
|
||||
break;
|
||||
case 0x10000e: /* PM_PURR */
|
||||
alt[j++] = 0x4000f4; /* PM_RUN_PURR */
|
||||
break;
|
||||
case 0x4000f4: /* PM_RUN_PURR */
|
||||
alt[j++] = 0x10000e; /* PM_PURR */
|
||||
break;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
}
|
||||
|
||||
if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
|
||||
/* remove the limited PMC events */
|
||||
j = 0;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
if (!p6_limited_pmc_event(alt[i])) {
|
||||
alt[j] = alt[i];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
} else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
|
||||
/* remove all but the limited PMC events */
|
||||
j = 0;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
if (p6_limited_pmc_event(alt[i])) {
|
||||
alt[j] = alt[i];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
}
|
||||
|
||||
return nalt;
|
||||
}
|
||||
|
||||
static void p6_disable_pmc(unsigned int pmc, u64 mmcr[])
|
||||
{
|
||||
/* Set PMCxSEL to 0 to disable PMCx */
|
||||
if (pmc <= 3)
|
||||
mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
|
||||
}
|
||||
|
||||
static int power6_generic_events[] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 2,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x280030, /* LD_REF_L1 */
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x30000c, /* LD_MISS_L1 */
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x410a0, /* BR_PRED */
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x400052, /* BR_MPRED */
|
||||
};
|
||||
|
||||
#define C(x) PERF_COUNT_HW_CACHE_##x
|
||||
|
||||
/*
|
||||
* Table of generalized cache-related events.
|
||||
* 0 means not supported, -1 means nonsensical, other values
|
||||
* are event codes.
|
||||
* The "DTLB" and "ITLB" events relate to the DERAT and IERAT.
|
||||
*/
|
||||
static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
|
||||
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x80082, 0x80080 },
|
||||
[C(OP_WRITE)] = { 0x80086, 0x80088 },
|
||||
[C(OP_PREFETCH)] = { 0x810a4, 0 },
|
||||
},
|
||||
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x100056 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { 0x4008c, 0 },
|
||||
},
|
||||
[C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x150730, 0x250532 },
|
||||
[C(OP_WRITE)] = { 0x250432, 0x150432 },
|
||||
[C(OP_PREFETCH)] = { 0x810a6, 0 },
|
||||
},
|
||||
[C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x20000e },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x420ce },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x430e6, 0x400052 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
struct power_pmu power6_pmu = {
|
||||
.n_counter = 6,
|
||||
.max_alternatives = MAX_ALT,
|
||||
.add_fields = 0x1555,
|
||||
.test_adder = 0x3000,
|
||||
.compute_mmcr = p6_compute_mmcr,
|
||||
.get_constraint = p6_get_constraint,
|
||||
.get_alternatives = p6_get_alternatives,
|
||||
.disable_pmc = p6_disable_pmc,
|
||||
.limited_pmc_event = p6_limited_pmc_event,
|
||||
.flags = PPMU_LIMITED_PMC5_6 | PPMU_ALT_SIPR,
|
||||
.n_generic = ARRAY_SIZE(power6_generic_events),
|
||||
.generic_events = power6_generic_events,
|
||||
.cache_events = &power6_cache_events,
|
||||
};
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* Performance counter support for POWER7 processors.
|
||||
*
|
||||
* Copyright 2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <asm/reg.h>
|
||||
|
||||
/*
|
||||
* Bits in event code for POWER7
|
||||
*/
|
||||
#define PM_PMC_SH 16 /* PMC number (1-based) for direct events */
|
||||
#define PM_PMC_MSK 0xf
|
||||
#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
|
||||
#define PM_UNIT_SH 12 /* TTMMUX number and setting - unit select */
|
||||
#define PM_UNIT_MSK 0xf
|
||||
#define PM_COMBINE_SH 11 /* Combined event bit */
|
||||
#define PM_COMBINE_MSK 1
|
||||
#define PM_COMBINE_MSKS 0x800
|
||||
#define PM_L2SEL_SH 8 /* L2 event select */
|
||||
#define PM_L2SEL_MSK 7
|
||||
#define PM_PMCSEL_MSK 0xff
|
||||
|
||||
/*
|
||||
* Bits in MMCR1 for POWER7
|
||||
*/
|
||||
#define MMCR1_TTM0SEL_SH 60
|
||||
#define MMCR1_TTM1SEL_SH 56
|
||||
#define MMCR1_TTM2SEL_SH 52
|
||||
#define MMCR1_TTM3SEL_SH 48
|
||||
#define MMCR1_TTMSEL_MSK 0xf
|
||||
#define MMCR1_L2SEL_SH 45
|
||||
#define MMCR1_L2SEL_MSK 7
|
||||
#define MMCR1_PMC1_COMBINE_SH 35
|
||||
#define MMCR1_PMC2_COMBINE_SH 34
|
||||
#define MMCR1_PMC3_COMBINE_SH 33
|
||||
#define MMCR1_PMC4_COMBINE_SH 32
|
||||
#define MMCR1_PMC1SEL_SH 24
|
||||
#define MMCR1_PMC2SEL_SH 16
|
||||
#define MMCR1_PMC3SEL_SH 8
|
||||
#define MMCR1_PMC4SEL_SH 0
|
||||
#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
|
||||
#define MMCR1_PMCSEL_MSK 0xff
|
||||
|
||||
/*
|
||||
* Bits in MMCRA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Layout of constraint bits:
|
||||
* 6666555555555544444444443333333333222222222211111111110000000000
|
||||
* 3210987654321098765432109876543210987654321098765432109876543210
|
||||
* [ ><><><><><><>
|
||||
* NC P6P5P4P3P2P1
|
||||
*
|
||||
* NC - number of counters
|
||||
* 15: NC error 0x8000
|
||||
* 12-14: number of events needing PMC1-4 0x7000
|
||||
*
|
||||
* P6
|
||||
* 11: P6 error 0x800
|
||||
* 10-11: Count of events needing PMC6
|
||||
*
|
||||
* P1..P5
|
||||
* 0-9: Count of events needing PMC1..PMC5
|
||||
*/
|
||||
|
||||
static int power7_get_constraint(u64 event, u64 *maskp, u64 *valp)
|
||||
{
|
||||
int pmc, sh;
|
||||
u64 mask = 0, value = 0;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 6)
|
||||
return -1;
|
||||
sh = (pmc - 1) * 2;
|
||||
mask |= 2 << sh;
|
||||
value |= 1 << sh;
|
||||
if (pmc >= 5 && !(event == 0x500fa || event == 0x600f4))
|
||||
return -1;
|
||||
}
|
||||
if (pmc < 5) {
|
||||
/* need a counter from PMC1-4 set */
|
||||
mask |= 0x8000;
|
||||
value |= 0x1000;
|
||||
}
|
||||
*maskp = mask;
|
||||
*valp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_ALT 2 /* at most 2 alternatives for any event */
|
||||
|
||||
static const unsigned int event_alternatives[][MAX_ALT] = {
|
||||
{ 0x200f2, 0x300f2 }, /* PM_INST_DISP */
|
||||
{ 0x200f4, 0x600f4 }, /* PM_RUN_CYC */
|
||||
{ 0x400fa, 0x500fa }, /* PM_RUN_INST_CMPL */
|
||||
};
|
||||
|
||||
/*
|
||||
* Scan the alternatives table for a match and return the
|
||||
* index into the alternatives table if found, else -1.
|
||||
*/
|
||||
static int find_alternative(u64 event)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
|
||||
if (event < event_alternatives[i][0])
|
||||
break;
|
||||
for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
|
||||
if (event == event_alternatives[i][j])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static s64 find_alternative_decode(u64 event)
|
||||
{
|
||||
int pmc, psel;
|
||||
|
||||
/* this only handles the 4x decode events */
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
psel = event & PM_PMCSEL_MSK;
|
||||
if ((pmc == 2 || pmc == 4) && (psel & ~7) == 0x40)
|
||||
return event - (1 << PM_PMC_SH) + 8;
|
||||
if ((pmc == 1 || pmc == 3) && (psel & ~7) == 0x48)
|
||||
return event + (1 << PM_PMC_SH) - 8;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int power7_get_alternatives(u64 event, unsigned int flags, u64 alt[])
|
||||
{
|
||||
int i, j, nalt = 1;
|
||||
s64 ae;
|
||||
|
||||
alt[0] = event;
|
||||
nalt = 1;
|
||||
i = find_alternative(event);
|
||||
if (i >= 0) {
|
||||
for (j = 0; j < MAX_ALT; ++j) {
|
||||
ae = event_alternatives[i][j];
|
||||
if (ae && ae != event)
|
||||
alt[nalt++] = ae;
|
||||
}
|
||||
} else {
|
||||
ae = find_alternative_decode(event);
|
||||
if (ae > 0)
|
||||
alt[nalt++] = ae;
|
||||
}
|
||||
|
||||
if (flags & PPMU_ONLY_COUNT_RUN) {
|
||||
/*
|
||||
* We're only counting in RUN state,
|
||||
* so PM_CYC is equivalent to PM_RUN_CYC
|
||||
* and PM_INST_CMPL === PM_RUN_INST_CMPL.
|
||||
* This doesn't include alternatives that don't provide
|
||||
* any extra flexibility in assigning PMCs.
|
||||
*/
|
||||
j = nalt;
|
||||
for (i = 0; i < nalt; ++i) {
|
||||
switch (alt[i]) {
|
||||
case 0x1e: /* PM_CYC */
|
||||
alt[j++] = 0x600f4; /* PM_RUN_CYC */
|
||||
break;
|
||||
case 0x600f4: /* PM_RUN_CYC */
|
||||
alt[j++] = 0x1e;
|
||||
break;
|
||||
case 0x2: /* PM_PPC_CMPL */
|
||||
alt[j++] = 0x500fa; /* PM_RUN_INST_CMPL */
|
||||
break;
|
||||
case 0x500fa: /* PM_RUN_INST_CMPL */
|
||||
alt[j++] = 0x2; /* PM_PPC_CMPL */
|
||||
break;
|
||||
}
|
||||
}
|
||||
nalt = j;
|
||||
}
|
||||
|
||||
return nalt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if event counts things relating to marked instructions
|
||||
* and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
|
||||
*/
|
||||
static int power7_marked_instr_event(u64 event)
|
||||
{
|
||||
int pmc, psel;
|
||||
int unit;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
psel = event & PM_PMCSEL_MSK & ~1; /* trim off edge/level bit */
|
||||
if (pmc >= 5)
|
||||
return 0;
|
||||
|
||||
switch (psel >> 4) {
|
||||
case 2:
|
||||
return pmc == 2 || pmc == 4;
|
||||
case 3:
|
||||
if (psel == 0x3c)
|
||||
return pmc == 1;
|
||||
if (psel == 0x3e)
|
||||
return pmc != 2;
|
||||
return 1;
|
||||
case 4:
|
||||
case 5:
|
||||
return unit == 0xd;
|
||||
case 6:
|
||||
if (psel == 0x64)
|
||||
return pmc >= 3;
|
||||
case 8:
|
||||
return unit == 0xd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int power7_compute_mmcr(u64 event[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[])
|
||||
{
|
||||
u64 mmcr1 = 0;
|
||||
u64 mmcra = 0;
|
||||
unsigned int pmc, unit, combine, l2sel, psel;
|
||||
unsigned int pmc_inuse = 0;
|
||||
int i;
|
||||
|
||||
/* First pass to count resource use */
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 6)
|
||||
return -1;
|
||||
if (pmc_inuse & (1 << (pmc - 1)))
|
||||
return -1;
|
||||
pmc_inuse |= 1 << (pmc - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Second pass: assign PMCs, set all MMCR1 fields */
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
combine = (event[i] >> PM_COMBINE_SH) & PM_COMBINE_MSK;
|
||||
l2sel = (event[i] >> PM_L2SEL_SH) & PM_L2SEL_MSK;
|
||||
psel = event[i] & PM_PMCSEL_MSK;
|
||||
if (!pmc) {
|
||||
/* Bus event or any-PMC direct event */
|
||||
for (pmc = 0; pmc < 4; ++pmc) {
|
||||
if (!(pmc_inuse & (1 << pmc)))
|
||||
break;
|
||||
}
|
||||
if (pmc >= 4)
|
||||
return -1;
|
||||
pmc_inuse |= 1 << pmc;
|
||||
} else {
|
||||
/* Direct or decoded event */
|
||||
--pmc;
|
||||
}
|
||||
if (pmc <= 3) {
|
||||
mmcr1 |= (u64) unit << (MMCR1_TTM0SEL_SH - 4 * pmc);
|
||||
mmcr1 |= (u64) combine << (MMCR1_PMC1_COMBINE_SH - pmc);
|
||||
mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
|
||||
if (unit == 6) /* L2 events */
|
||||
mmcr1 |= (u64) l2sel << MMCR1_L2SEL_SH;
|
||||
}
|
||||
if (power7_marked_instr_event(event[i]))
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
hwc[i] = pmc;
|
||||
}
|
||||
|
||||
/* Return MMCRx values */
|
||||
mmcr[0] = 0;
|
||||
if (pmc_inuse & 1)
|
||||
mmcr[0] = MMCR0_PMC1CE;
|
||||
if (pmc_inuse & 0x3e)
|
||||
mmcr[0] |= MMCR0_PMCjCE;
|
||||
mmcr[1] = mmcr1;
|
||||
mmcr[2] = mmcra;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void power7_disable_pmc(unsigned int pmc, u64 mmcr[])
|
||||
{
|
||||
if (pmc <= 3)
|
||||
mmcr[1] &= ~(0xffULL << MMCR1_PMCSEL_SH(pmc));
|
||||
}
|
||||
|
||||
static int power7_generic_events[] = {
|
||||
[PERF_COUNT_CPU_CYCLES] = 0x1e,
|
||||
[PERF_COUNT_INSTRUCTIONS] = 2,
|
||||
[PERF_COUNT_CACHE_REFERENCES] = 0xc880, /* LD_REF_L1_LSU */
|
||||
[PERF_COUNT_CACHE_MISSES] = 0x400f0, /* LD_MISS_L1 */
|
||||
[PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x10068, /* BRU_FIN */
|
||||
[PERF_COUNT_BRANCH_MISSES] = 0x400f6, /* BR_MPRED */
|
||||
};
|
||||
|
||||
#define C(x) PERF_COUNT_HW_CACHE_##x
|
||||
|
||||
/*
|
||||
* Table of generalized cache-related events.
|
||||
* 0 means not supported, -1 means nonsensical, other values
|
||||
* are event codes.
|
||||
*/
|
||||
static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
|
||||
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x400f0, 0xc880 },
|
||||
[C(OP_WRITE)] = { 0, 0x300f0 },
|
||||
[C(OP_PREFETCH)] = { 0xd8b8, 0 },
|
||||
},
|
||||
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x200fc },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { 0x408a, 0 },
|
||||
},
|
||||
[C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x6080, 0x6084 },
|
||||
[C(OP_WRITE)] = { 0x6082, 0x6086 },
|
||||
[C(OP_PREFETCH)] = { 0, 0 },
|
||||
},
|
||||
[C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x300fc },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x400fc },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x10068, 0x400f6 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
struct power_pmu power7_pmu = {
|
||||
.n_counter = 6,
|
||||
.max_alternatives = MAX_ALT + 1,
|
||||
.add_fields = 0x1555ull,
|
||||
.test_adder = 0x3000ull,
|
||||
.compute_mmcr = power7_compute_mmcr,
|
||||
.get_constraint = power7_get_constraint,
|
||||
.get_alternatives = power7_get_alternatives,
|
||||
.disable_pmc = power7_disable_pmc,
|
||||
.n_generic = ARRAY_SIZE(power7_generic_events),
|
||||
.generic_events = power7_generic_events,
|
||||
.cache_events = &power7_cache_events,
|
||||
};
|
|
@ -0,0 +1,482 @@
|
|||
/*
|
||||
* Performance counter support for PPC970-family processors.
|
||||
*
|
||||
* Copyright 2008-2009 Paul Mackerras, IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/string.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <asm/reg.h>
|
||||
|
||||
/*
|
||||
* Bits in event code for PPC970
|
||||
*/
|
||||
#define PM_PMC_SH 12 /* PMC number (1-based) for direct events */
|
||||
#define PM_PMC_MSK 0xf
|
||||
#define PM_UNIT_SH 8 /* TTMMUX number and setting - unit select */
|
||||
#define PM_UNIT_MSK 0xf
|
||||
#define PM_SPCSEL_SH 6
|
||||
#define PM_SPCSEL_MSK 3
|
||||
#define PM_BYTE_SH 4 /* Byte number of event bus to use */
|
||||
#define PM_BYTE_MSK 3
|
||||
#define PM_PMCSEL_MSK 0xf
|
||||
|
||||
/* Values in PM_UNIT field */
|
||||
#define PM_NONE 0
|
||||
#define PM_FPU 1
|
||||
#define PM_VPU 2
|
||||
#define PM_ISU 3
|
||||
#define PM_IFU 4
|
||||
#define PM_IDU 5
|
||||
#define PM_STS 6
|
||||
#define PM_LSU0 7
|
||||
#define PM_LSU1U 8
|
||||
#define PM_LSU1L 9
|
||||
#define PM_LASTUNIT 9
|
||||
|
||||
/*
|
||||
* Bits in MMCR0 for PPC970
|
||||
*/
|
||||
#define MMCR0_PMC1SEL_SH 8
|
||||
#define MMCR0_PMC2SEL_SH 1
|
||||
#define MMCR_PMCSEL_MSK 0x1f
|
||||
|
||||
/*
|
||||
* Bits in MMCR1 for PPC970
|
||||
*/
|
||||
#define MMCR1_TTM0SEL_SH 62
|
||||
#define MMCR1_TTM1SEL_SH 59
|
||||
#define MMCR1_TTM3SEL_SH 53
|
||||
#define MMCR1_TTMSEL_MSK 3
|
||||
#define MMCR1_TD_CP_DBG0SEL_SH 50
|
||||
#define MMCR1_TD_CP_DBG1SEL_SH 48
|
||||
#define MMCR1_TD_CP_DBG2SEL_SH 46
|
||||
#define MMCR1_TD_CP_DBG3SEL_SH 44
|
||||
#define MMCR1_PMC1_ADDER_SEL_SH 39
|
||||
#define MMCR1_PMC2_ADDER_SEL_SH 38
|
||||
#define MMCR1_PMC6_ADDER_SEL_SH 37
|
||||
#define MMCR1_PMC5_ADDER_SEL_SH 36
|
||||
#define MMCR1_PMC8_ADDER_SEL_SH 35
|
||||
#define MMCR1_PMC7_ADDER_SEL_SH 34
|
||||
#define MMCR1_PMC3_ADDER_SEL_SH 33
|
||||
#define MMCR1_PMC4_ADDER_SEL_SH 32
|
||||
#define MMCR1_PMC3SEL_SH 27
|
||||
#define MMCR1_PMC4SEL_SH 22
|
||||
#define MMCR1_PMC5SEL_SH 17
|
||||
#define MMCR1_PMC6SEL_SH 12
|
||||
#define MMCR1_PMC7SEL_SH 7
|
||||
#define MMCR1_PMC8SEL_SH 2
|
||||
|
||||
static short mmcr1_adder_bits[8] = {
|
||||
MMCR1_PMC1_ADDER_SEL_SH,
|
||||
MMCR1_PMC2_ADDER_SEL_SH,
|
||||
MMCR1_PMC3_ADDER_SEL_SH,
|
||||
MMCR1_PMC4_ADDER_SEL_SH,
|
||||
MMCR1_PMC5_ADDER_SEL_SH,
|
||||
MMCR1_PMC6_ADDER_SEL_SH,
|
||||
MMCR1_PMC7_ADDER_SEL_SH,
|
||||
MMCR1_PMC8_ADDER_SEL_SH
|
||||
};
|
||||
|
||||
/*
|
||||
* Bits in MMCRA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Layout of constraint bits:
|
||||
* 6666555555555544444444443333333333222222222211111111110000000000
|
||||
* 3210987654321098765432109876543210987654321098765432109876543210
|
||||
* <><><>[ >[ >[ >< >< >< >< ><><><><><><><><>
|
||||
* SPT0T1 UC PS1 PS2 B0 B1 B2 B3 P1P2P3P4P5P6P7P8
|
||||
*
|
||||
* SP - SPCSEL constraint
|
||||
* 48-49: SPCSEL value 0x3_0000_0000_0000
|
||||
*
|
||||
* T0 - TTM0 constraint
|
||||
* 46-47: TTM0SEL value (0=FPU, 2=IFU, 3=VPU) 0xC000_0000_0000
|
||||
*
|
||||
* T1 - TTM1 constraint
|
||||
* 44-45: TTM1SEL value (0=IDU, 3=STS) 0x3000_0000_0000
|
||||
*
|
||||
* UC - unit constraint: can't have all three of FPU|IFU|VPU, ISU, IDU|STS
|
||||
* 43: UC3 error 0x0800_0000_0000
|
||||
* 42: FPU|IFU|VPU events needed 0x0400_0000_0000
|
||||
* 41: ISU events needed 0x0200_0000_0000
|
||||
* 40: IDU|STS events needed 0x0100_0000_0000
|
||||
*
|
||||
* PS1
|
||||
* 39: PS1 error 0x0080_0000_0000
|
||||
* 36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
|
||||
*
|
||||
* PS2
|
||||
* 35: PS2 error 0x0008_0000_0000
|
||||
* 32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
|
||||
*
|
||||
* B0
|
||||
* 28-31: Byte 0 event source 0xf000_0000
|
||||
* Encoding as for the event code
|
||||
*
|
||||
* B1, B2, B3
|
||||
* 24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
|
||||
*
|
||||
* P1
|
||||
* 15: P1 error 0x8000
|
||||
* 14-15: Count of events needing PMC1
|
||||
*
|
||||
* P2..P8
|
||||
* 0-13: Count of events needing PMC2..PMC8
|
||||
*/
|
||||
|
||||
static unsigned char direct_marked_event[8] = {
|
||||
(1<<2) | (1<<3), /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
|
||||
(1<<3) | (1<<5), /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
|
||||
(1<<3) | (1<<5), /* PMC3: PM_MRK_ST_CMPL_INT, PM_MRK_VMX_FIN */
|
||||
(1<<4) | (1<<5), /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
|
||||
(1<<4) | (1<<5), /* PMC5: PM_GRP_MRK, PM_MRK_GRP_TIMEO */
|
||||
(1<<3) | (1<<4) | (1<<5),
|
||||
/* PMC6: PM_MRK_ST_STS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
|
||||
(1<<4) | (1<<5), /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
|
||||
(1<<4) /* PMC8: PM_MRK_LSU_FIN */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns 1 if event counts things relating to marked instructions
|
||||
* and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
|
||||
*/
|
||||
static int p970_marked_instr_event(u64 event)
|
||||
{
|
||||
int pmc, psel, unit, byte, bit;
|
||||
unsigned int mask;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
psel = event & PM_PMCSEL_MSK;
|
||||
if (pmc) {
|
||||
if (direct_marked_event[pmc - 1] & (1 << psel))
|
||||
return 1;
|
||||
if (psel == 0) /* add events */
|
||||
bit = (pmc <= 4)? pmc - 1: 8 - pmc;
|
||||
else if (psel == 7 || psel == 13) /* decode events */
|
||||
bit = 4;
|
||||
else
|
||||
return 0;
|
||||
} else
|
||||
bit = psel;
|
||||
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
mask = 0;
|
||||
switch (unit) {
|
||||
case PM_VPU:
|
||||
mask = 0x4c; /* byte 0 bits 2,3,6 */
|
||||
case PM_LSU0:
|
||||
/* byte 2 bits 0,2,3,4,6; all of byte 1 */
|
||||
mask = 0x085dff00;
|
||||
case PM_LSU1L:
|
||||
mask = 0x50 << 24; /* byte 3 bits 4,6 */
|
||||
break;
|
||||
}
|
||||
return (mask >> (byte * 8 + bit)) & 1;
|
||||
}
|
||||
|
||||
/* Masks and values for using events from the various units */
|
||||
static u64 unit_cons[PM_LASTUNIT+1][2] = {
|
||||
[PM_FPU] = { 0xc80000000000ull, 0x040000000000ull },
|
||||
[PM_VPU] = { 0xc80000000000ull, 0xc40000000000ull },
|
||||
[PM_ISU] = { 0x080000000000ull, 0x020000000000ull },
|
||||
[PM_IFU] = { 0xc80000000000ull, 0x840000000000ull },
|
||||
[PM_IDU] = { 0x380000000000ull, 0x010000000000ull },
|
||||
[PM_STS] = { 0x380000000000ull, 0x310000000000ull },
|
||||
};
|
||||
|
||||
static int p970_get_constraint(u64 event, u64 *maskp, u64 *valp)
|
||||
{
|
||||
int pmc, byte, unit, sh, spcsel;
|
||||
u64 mask = 0, value = 0;
|
||||
int grp = -1;
|
||||
|
||||
pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc > 8)
|
||||
return -1;
|
||||
sh = (pmc - 1) * 2;
|
||||
mask |= 2 << sh;
|
||||
value |= 1 << sh;
|
||||
grp = ((pmc - 1) >> 1) & 1;
|
||||
}
|
||||
unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
if (unit) {
|
||||
if (unit > PM_LASTUNIT)
|
||||
return -1;
|
||||
mask |= unit_cons[unit][0];
|
||||
value |= unit_cons[unit][1];
|
||||
byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
/*
|
||||
* Bus events on bytes 0 and 2 can be counted
|
||||
* on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
|
||||
*/
|
||||
if (!pmc)
|
||||
grp = byte & 1;
|
||||
/* Set byte lane select field */
|
||||
mask |= 0xfULL << (28 - 4 * byte);
|
||||
value |= (u64)unit << (28 - 4 * byte);
|
||||
}
|
||||
if (grp == 0) {
|
||||
/* increment PMC1/2/5/6 field */
|
||||
mask |= 0x8000000000ull;
|
||||
value |= 0x1000000000ull;
|
||||
} else if (grp == 1) {
|
||||
/* increment PMC3/4/7/8 field */
|
||||
mask |= 0x800000000ull;
|
||||
value |= 0x100000000ull;
|
||||
}
|
||||
spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
|
||||
if (spcsel) {
|
||||
mask |= 3ull << 48;
|
||||
value |= (u64)spcsel << 48;
|
||||
}
|
||||
*maskp = mask;
|
||||
*valp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
|
||||
{
|
||||
alt[0] = event;
|
||||
|
||||
/* 2 alternatives for LSU empty */
|
||||
if (event == 0x2002 || event == 0x3002) {
|
||||
alt[1] = event ^ 0x1000;
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int p970_compute_mmcr(u64 event[], int n_ev,
|
||||
unsigned int hwc[], u64 mmcr[])
|
||||
{
|
||||
u64 mmcr0 = 0, mmcr1 = 0, mmcra = 0;
|
||||
unsigned int pmc, unit, byte, psel;
|
||||
unsigned int ttm, grp;
|
||||
unsigned int pmc_inuse = 0;
|
||||
unsigned int pmc_grp_use[2];
|
||||
unsigned char busbyte[4];
|
||||
unsigned char unituse[16];
|
||||
unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
|
||||
unsigned char ttmuse[2];
|
||||
unsigned char pmcsel[8];
|
||||
int i;
|
||||
int spcsel;
|
||||
|
||||
if (n_ev > 8)
|
||||
return -1;
|
||||
|
||||
/* First pass to count resource use */
|
||||
pmc_grp_use[0] = pmc_grp_use[1] = 0;
|
||||
memset(busbyte, 0, sizeof(busbyte));
|
||||
memset(unituse, 0, sizeof(unituse));
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
if (pmc) {
|
||||
if (pmc_inuse & (1 << (pmc - 1)))
|
||||
return -1;
|
||||
pmc_inuse |= 1 << (pmc - 1);
|
||||
/* count 1/2/5/6 vs 3/4/7/8 use */
|
||||
++pmc_grp_use[((pmc - 1) >> 1) & 1];
|
||||
}
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
if (unit) {
|
||||
if (unit > PM_LASTUNIT)
|
||||
return -1;
|
||||
if (!pmc)
|
||||
++pmc_grp_use[byte & 1];
|
||||
if (busbyte[byte] && busbyte[byte] != unit)
|
||||
return -1;
|
||||
busbyte[byte] = unit;
|
||||
unituse[unit] = 1;
|
||||
}
|
||||
}
|
||||
if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Assign resources and set multiplexer selects.
|
||||
*
|
||||
* PM_ISU can go either on TTM0 or TTM1, but that's the only
|
||||
* choice we have to deal with.
|
||||
*/
|
||||
if (unituse[PM_ISU] &
|
||||
(unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
|
||||
unitmap[PM_ISU] = 2 | 4; /* move ISU to TTM1 */
|
||||
/* Set TTM[01]SEL fields. */
|
||||
ttmuse[0] = ttmuse[1] = 0;
|
||||
for (i = PM_FPU; i <= PM_STS; ++i) {
|
||||
if (!unituse[i])
|
||||
continue;
|
||||
ttm = unitmap[i];
|
||||
++ttmuse[(ttm >> 2) & 1];
|
||||
mmcr1 |= (u64)(ttm & ~4) << MMCR1_TTM1SEL_SH;
|
||||
}
|
||||
/* Check only one unit per TTMx */
|
||||
if (ttmuse[0] > 1 || ttmuse[1] > 1)
|
||||
return -1;
|
||||
|
||||
/* Set byte lane select fields and TTM3SEL. */
|
||||
for (byte = 0; byte < 4; ++byte) {
|
||||
unit = busbyte[byte];
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit <= PM_STS)
|
||||
ttm = (unitmap[unit] >> 2) & 1;
|
||||
else if (unit == PM_LSU0)
|
||||
ttm = 2;
|
||||
else {
|
||||
ttm = 3;
|
||||
if (unit == PM_LSU1L && byte >= 2)
|
||||
mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
|
||||
}
|
||||
mmcr1 |= (u64)ttm << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
|
||||
}
|
||||
|
||||
/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
|
||||
memset(pmcsel, 0x8, sizeof(pmcsel)); /* 8 means don't count */
|
||||
for (i = 0; i < n_ev; ++i) {
|
||||
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
|
||||
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
|
||||
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
|
||||
psel = event[i] & PM_PMCSEL_MSK;
|
||||
if (!pmc) {
|
||||
/* Bus event or any-PMC direct event */
|
||||
if (unit)
|
||||
psel |= 0x10 | ((byte & 2) << 2);
|
||||
else
|
||||
psel |= 8;
|
||||
for (pmc = 0; pmc < 8; ++pmc) {
|
||||
if (pmc_inuse & (1 << pmc))
|
||||
continue;
|
||||
grp = (pmc >> 1) & 1;
|
||||
if (unit) {
|
||||
if (grp == (byte & 1))
|
||||
break;
|
||||
} else if (pmc_grp_use[grp] < 4) {
|
||||
++pmc_grp_use[grp];
|
||||
break;
|
||||
}
|
||||
}
|
||||
pmc_inuse |= 1 << pmc;
|
||||
} else {
|
||||
/* Direct event */
|
||||
--pmc;
|
||||
if (psel == 0 && (byte & 2))
|
||||
/* add events on higher-numbered bus */
|
||||
mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
|
||||
}
|
||||
pmcsel[pmc] = psel;
|
||||
hwc[i] = pmc;
|
||||
spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
|
||||
mmcr1 |= spcsel;
|
||||
if (p970_marked_instr_event(event[i]))
|
||||
mmcra |= MMCRA_SAMPLE_ENABLE;
|
||||
}
|
||||
for (pmc = 0; pmc < 2; ++pmc)
|
||||
mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
|
||||
for (; pmc < 8; ++pmc)
|
||||
mmcr1 |= (u64)pmcsel[pmc] << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
|
||||
if (pmc_inuse & 1)
|
||||
mmcr0 |= MMCR0_PMC1CE;
|
||||
if (pmc_inuse & 0xfe)
|
||||
mmcr0 |= MMCR0_PMCjCE;
|
||||
|
||||
mmcra |= 0x2000; /* mark only one IOP per PPC instruction */
|
||||
|
||||
/* Return MMCRx values */
|
||||
mmcr[0] = mmcr0;
|
||||
mmcr[1] = mmcr1;
|
||||
mmcr[2] = mmcra;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void p970_disable_pmc(unsigned int pmc, u64 mmcr[])
|
||||
{
|
||||
int shift, i;
|
||||
|
||||
if (pmc <= 1) {
|
||||
shift = MMCR0_PMC1SEL_SH - 7 * pmc;
|
||||
i = 0;
|
||||
} else {
|
||||
shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
|
||||
i = 1;
|
||||
}
|
||||
/*
|
||||
* Setting the PMCxSEL field to 0x08 disables PMC x.
|
||||
*/
|
||||
mmcr[i] = (mmcr[i] & ~(0x1fUL << shift)) | (0x08UL << shift);
|
||||
}
|
||||
|
||||
static int ppc970_generic_events[] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = 7,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = 1,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x8810, /* PM_LD_REF_L1 */
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = 0x3810, /* PM_LD_MISS_L1 */
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x431, /* PM_BR_ISSUED */
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = 0x327, /* PM_GRP_BR_MPRED */
|
||||
};
|
||||
|
||||
#define C(x) PERF_COUNT_HW_CACHE_##x
|
||||
|
||||
/*
|
||||
* Table of generalized cache-related events.
|
||||
* 0 means not supported, -1 means nonsensical, other values
|
||||
* are event codes.
|
||||
*/
|
||||
static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
|
||||
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x8810, 0x3810 },
|
||||
[C(OP_WRITE)] = { 0x7810, 0x813 },
|
||||
[C(OP_PREFETCH)] = { 0x731, 0 },
|
||||
},
|
||||
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { 0, 0 },
|
||||
},
|
||||
[C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0 },
|
||||
[C(OP_WRITE)] = { 0, 0 },
|
||||
[C(OP_PREFETCH)] = { 0x733, 0 },
|
||||
},
|
||||
[C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x704 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0, 0x700 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
[C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
|
||||
[C(OP_READ)] = { 0x431, 0x327 },
|
||||
[C(OP_WRITE)] = { -1, -1 },
|
||||
[C(OP_PREFETCH)] = { -1, -1 },
|
||||
},
|
||||
};
|
||||
|
||||
struct power_pmu ppc970_pmu = {
|
||||
.n_counter = 8,
|
||||
.max_alternatives = 2,
|
||||
.add_fields = 0x001100005555ull,
|
||||
.test_adder = 0x013300000000ull,
|
||||
.compute_mmcr = p970_compute_mmcr,
|
||||
.get_constraint = p970_get_constraint,
|
||||
.get_alternatives = p970_get_alternatives,
|
||||
.disable_pmc = p970_disable_pmc,
|
||||
.n_generic = ARRAY_SIZE(ppc970_generic_events),
|
||||
.generic_events = ppc970_generic_events,
|
||||
.cache_events = &ppc970_cache_events,
|
||||
};
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/perf_counter.h>
|
||||
|
||||
#include <asm/firmware.h>
|
||||
#include <asm/page.h>
|
||||
|
@ -170,6 +171,8 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
|
|||
die("Weird page fault", regs, SIGSEGV);
|
||||
}
|
||||
|
||||
perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
|
||||
|
||||
/* When running in the kernel we expect faults to occur only to
|
||||
* addresses in user space. All other faults represent errors in the
|
||||
* kernel and should generate an OOPS. Unfortunately, in the case of an
|
||||
|
@ -309,6 +312,8 @@ good_area:
|
|||
}
|
||||
if (ret & VM_FAULT_MAJOR) {
|
||||
current->maj_flt++;
|
||||
perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
|
||||
regs, address);
|
||||
#ifdef CONFIG_PPC_SMLPAR
|
||||
if (firmware_has_feature(FW_FEATURE_CMO)) {
|
||||
preempt_disable();
|
||||
|
@ -316,8 +321,11 @@ good_area:
|
|||
preempt_enable();
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
} else {
|
||||
current->min_flt++;
|
||||
perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
|
||||
regs, address);
|
||||
}
|
||||
up_read(&mm->mmap_sem);
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
config PPC64
|
||||
bool "64-bit kernel"
|
||||
default n
|
||||
select HAVE_PERF_COUNTERS
|
||||
help
|
||||
This option selects whether a 32-bit or a 64-bit kernel
|
||||
will be built.
|
||||
|
|
|
@ -333,7 +333,7 @@ static void xics_eoi_lpar(unsigned int virq)
|
|||
lpar_xirr_info_set((0xff << 24) | irq);
|
||||
}
|
||||
|
||||
static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
|
||||
static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
|
||||
{
|
||||
unsigned int irq;
|
||||
int status;
|
||||
|
@ -342,14 +342,14 @@ static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
|
|||
|
||||
irq = (unsigned int)irq_map[virq].hwirq;
|
||||
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
|
||||
|
||||
if (status) {
|
||||
printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
|
||||
__func__, irq, status);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -363,7 +363,7 @@ static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
|
|||
printk(KERN_WARNING
|
||||
"%s: No online cpus in the mask %s for irq %d\n",
|
||||
__func__, cpulist, virq);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = rtas_call(ibm_set_xive, 3, 1, NULL,
|
||||
|
@ -372,8 +372,10 @@ static void xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
|
|||
if (status) {
|
||||
printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
|
||||
__func__, irq, status);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip xics_pic_direct = {
|
||||
|
|
|
@ -807,7 +807,7 @@ static void mpic_end_ipi(unsigned int irq)
|
|||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
||||
int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
||||
{
|
||||
struct mpic *mpic = mpic_from_irq(irq);
|
||||
unsigned int src = mpic_irq_to_hw(irq);
|
||||
|
@ -824,6 +824,8 @@ void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
|||
mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
|
||||
mpic_physmask(cpus_addr(tmp)[0]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
|
||||
|
|
|
@ -36,6 +36,6 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic)
|
|||
|
||||
extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
|
||||
extern void mpic_set_vector(unsigned int virq, unsigned int vector);
|
||||
extern void mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
|
||||
extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
|
||||
|
||||
#endif /* _POWERPC_SYSDEV_MPIC_H */
|
||||
|
|
|
@ -102,8 +102,8 @@ struct thread_info {
|
|||
#define TI_KERN_CNTD1 0x00000488
|
||||
#define TI_PCR 0x00000490
|
||||
#define TI_RESTART_BLOCK 0x00000498
|
||||
#define TI_KUNA_REGS 0x000004c0
|
||||
#define TI_KUNA_INSN 0x000004c8
|
||||
#define TI_KUNA_REGS 0x000004c8
|
||||
#define TI_KUNA_INSN 0x000004d0
|
||||
#define TI_FPREGS 0x00000500
|
||||
|
||||
/* We embed this in the uppermost byte of thread_info->flags */
|
||||
|
|
|
@ -318,10 +318,12 @@ static void sun4u_irq_enable(unsigned int virt_irq)
|
|||
}
|
||||
}
|
||||
|
||||
static void sun4u_set_affinity(unsigned int virt_irq,
|
||||
static int sun4u_set_affinity(unsigned int virt_irq,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
sun4u_irq_enable(virt_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't do anything. The desc->status check for IRQ_DISABLED in
|
||||
|
@ -377,7 +379,7 @@ static void sun4v_irq_enable(unsigned int virt_irq)
|
|||
ino, err);
|
||||
}
|
||||
|
||||
static void sun4v_set_affinity(unsigned int virt_irq,
|
||||
static int sun4v_set_affinity(unsigned int virt_irq,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
unsigned int ino = virt_irq_table[virt_irq].dev_ino;
|
||||
|
@ -388,6 +390,8 @@ static void sun4v_set_affinity(unsigned int virt_irq,
|
|||
if (err != HV_EOK)
|
||||
printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
|
||||
"err(%d)\n", ino, cpuid, err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sun4v_irq_disable(unsigned int virt_irq)
|
||||
|
@ -445,7 +449,7 @@ static void sun4v_virq_enable(unsigned int virt_irq)
|
|||
dev_handle, dev_ino, err);
|
||||
}
|
||||
|
||||
static void sun4v_virt_set_affinity(unsigned int virt_irq,
|
||||
static int sun4v_virt_set_affinity(unsigned int virt_irq,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
unsigned long cpuid, dev_handle, dev_ino;
|
||||
|
@ -461,6 +465,8 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq,
|
|||
printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
|
||||
"err(%d)\n",
|
||||
dev_handle, dev_ino, cpuid, err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sun4v_virq_disable(unsigned int virt_irq)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
obj-$(CONFIG_KVM) += kvm/
|
||||
|
||||
# Xen paravirtualization support
|
||||
obj-$(CONFIG_XEN) += xen/
|
||||
|
||||
# lguest paravirtualization support
|
||||
obj-$(CONFIG_LGUEST_GUEST) += lguest/
|
||||
|
||||
obj-y += kernel/
|
||||
obj-y += mm/
|
||||
|
||||
obj-y += crypto/
|
||||
obj-y += vdso/
|
||||
obj-$(CONFIG_IA32_EMULATION) += ia32/
|
||||
|
|
@ -47,6 +47,11 @@ config X86
|
|||
select HAVE_KERNEL_BZIP2
|
||||
select HAVE_KERNEL_LZMA
|
||||
|
||||
config OUTPUT_FORMAT
|
||||
string
|
||||
default "elf32-i386" if X86_32
|
||||
default "elf64-x86-64" if X86_64
|
||||
|
||||
config ARCH_DEFCONFIG
|
||||
string
|
||||
default "arch/x86/configs/i386_defconfig" if X86_32
|
||||
|
@ -274,15 +279,9 @@ config SPARSE_IRQ
|
|||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
config NUMA_MIGRATE_IRQ_DESC
|
||||
bool "Move irq desc when changing irq smp_affinity"
|
||||
config NUMA_IRQ_DESC
|
||||
def_bool y
|
||||
depends on SPARSE_IRQ && NUMA
|
||||
depends on BROKEN
|
||||
default n
|
||||
---help---
|
||||
This enables moving irq_desc to cpu/node that irq will use handled.
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
config X86_MPPARSE
|
||||
bool "Enable MPS table" if ACPI
|
||||
|
@ -355,7 +354,7 @@ config X86_UV
|
|||
depends on X86_64
|
||||
depends on X86_EXTENDED_PLATFORM
|
||||
depends on NUMA
|
||||
select X86_X2APIC
|
||||
depends on X86_X2APIC
|
||||
---help---
|
||||
This option is needed in order to support SGI Ultraviolet systems.
|
||||
If you don't have one of these, you should say N here.
|
||||
|
@ -740,6 +739,7 @@ config X86_UP_IOAPIC
|
|||
config X86_LOCAL_APIC
|
||||
def_bool y
|
||||
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC
|
||||
select HAVE_PERF_COUNTERS if (!M386 && !M486)
|
||||
|
||||
config X86_IO_APIC
|
||||
def_bool y
|
||||
|
@ -1466,9 +1466,7 @@ config KEXEC_JUMP
|
|||
|
||||
config PHYSICAL_START
|
||||
hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
|
||||
default "0x1000000" if X86_NUMAQ
|
||||
default "0x200000" if X86_64
|
||||
default "0x100000"
|
||||
default "0x1000000"
|
||||
---help---
|
||||
This gives the physical address where the kernel is loaded.
|
||||
|
||||
|
@ -1487,15 +1485,15 @@ config PHYSICAL_START
|
|||
to be specifically compiled to run from a specific memory area
|
||||
(normally a reserved region) and this option comes handy.
|
||||
|
||||
So if you are using bzImage for capturing the crash dump, leave
|
||||
the value here unchanged to 0x100000 and set CONFIG_RELOCATABLE=y.
|
||||
Otherwise if you plan to use vmlinux for capturing the crash dump
|
||||
change this value to start of the reserved region (Typically 16MB
|
||||
0x1000000). In other words, it can be set based on the "X" value as
|
||||
specified in the "crashkernel=YM@XM" command line boot parameter
|
||||
passed to the panic-ed kernel. Typically this parameter is set as
|
||||
crashkernel=64M@16M. Please take a look at
|
||||
Documentation/kdump/kdump.txt for more details about crash dumps.
|
||||
So if you are using bzImage for capturing the crash dump,
|
||||
leave the value here unchanged to 0x1000000 and set
|
||||
CONFIG_RELOCATABLE=y. Otherwise if you plan to use vmlinux
|
||||
for capturing the crash dump change this value to start of
|
||||
the reserved region. In other words, it can be set based on
|
||||
the "X" value as specified in the "crashkernel=YM@XM"
|
||||
command line boot parameter passed to the panic-ed
|
||||
kernel. Please take a look at Documentation/kdump/kdump.txt
|
||||
for more details about crash dumps.
|
||||
|
||||
Usage of bzImage for capturing the crash dump is recommended as
|
||||
one does not have to build two kernels. Same kernel can be used
|
||||
|
@ -1508,8 +1506,8 @@ config PHYSICAL_START
|
|||
Don't change this unless you know what you are doing.
|
||||
|
||||
config RELOCATABLE
|
||||
bool "Build a relocatable kernel (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
bool "Build a relocatable kernel"
|
||||
default y
|
||||
---help---
|
||||
This builds a kernel image that retains relocation information
|
||||
so it can be loaded someplace besides the default 1MB.
|
||||
|
@ -1524,12 +1522,16 @@ config RELOCATABLE
|
|||
it has been loaded at and the compile time physical address
|
||||
(CONFIG_PHYSICAL_START) is ignored.
|
||||
|
||||
# Relocation on x86-32 needs some additional build support
|
||||
config X86_NEED_RELOCS
|
||||
def_bool y
|
||||
depends on X86_32 && RELOCATABLE
|
||||
|
||||
config PHYSICAL_ALIGN
|
||||
hex
|
||||
prompt "Alignment value to which kernel should be aligned" if X86_32
|
||||
default "0x100000" if X86_32
|
||||
default "0x200000" if X86_64
|
||||
range 0x2000 0x400000
|
||||
default "0x1000000"
|
||||
range 0x2000 0x1000000
|
||||
---help---
|
||||
This value puts the alignment restrictions on physical address
|
||||
where kernel is loaded and run from. Kernel is compiled for an
|
||||
|
|
|
@ -159,14 +159,30 @@ config IOMMU_DEBUG
|
|||
options. See Documentation/x86_64/boot-options.txt for more
|
||||
details.
|
||||
|
||||
config IOMMU_STRESS
|
||||
bool "Enable IOMMU stress-test mode"
|
||||
---help---
|
||||
This option disables various optimizations in IOMMU related
|
||||
code to do real stress testing of the IOMMU code. This option
|
||||
will cause a performance drop and should only be enabled for
|
||||
testing.
|
||||
|
||||
config IOMMU_LEAK
|
||||
bool "IOMMU leak tracing"
|
||||
depends on DEBUG_KERNEL
|
||||
depends on IOMMU_DEBUG
|
||||
depends on IOMMU_DEBUG && DMA_API_DEBUG
|
||||
---help---
|
||||
Add a simple leak tracer to the IOMMU code. This is useful when you
|
||||
are debugging a buggy device driver that leaks IOMMU mappings.
|
||||
|
||||
config X86_DS_SELFTEST
|
||||
bool "DS selftest"
|
||||
default y
|
||||
depends on DEBUG_KERNEL
|
||||
depends on X86_DS
|
||||
---help---
|
||||
Perform Debug Store selftests at boot time.
|
||||
If in doubt, say "N".
|
||||
|
||||
config HAVE_MMIOTRACE_SUPPORT
|
||||
def_bool y
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ else
|
|||
KBUILD_DEFCONFIG := $(ARCH)_defconfig
|
||||
endif
|
||||
|
||||
core-$(CONFIG_KVM) += arch/x86/kvm/
|
||||
|
||||
# BITS is used as extension for files which are available in a 32 bit
|
||||
# and a 64 bit version to simplify shared Makefiles.
|
||||
# e.g.: obj-y += foo_$(BITS).o
|
||||
|
@ -118,21 +116,8 @@ head-y += arch/x86/kernel/init_task.o
|
|||
|
||||
libs-y += arch/x86/lib/
|
||||
|
||||
# Sub architecture files that needs linking first
|
||||
core-y += $(fcore-y)
|
||||
|
||||
# Xen paravirtualization support
|
||||
core-$(CONFIG_XEN) += arch/x86/xen/
|
||||
|
||||
# lguest paravirtualization support
|
||||
core-$(CONFIG_LGUEST_GUEST) += arch/x86/lguest/
|
||||
|
||||
core-y += arch/x86/kernel/
|
||||
core-y += arch/x86/mm/
|
||||
|
||||
core-y += arch/x86/crypto/
|
||||
core-y += arch/x86/vdso/
|
||||
core-$(CONFIG_IA32_EMULATION) += arch/x86/ia32/
|
||||
# See arch/x86/Kbuild for content of core part of the kernel
|
||||
core-y += arch/x86/
|
||||
|
||||
# drivers-y are linked after core-y
|
||||
drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/
|
||||
|
|
|
@ -3,6 +3,8 @@ bzImage
|
|||
cpustr.h
|
||||
mkcpustr
|
||||
offsets.h
|
||||
voffset.h
|
||||
zoffset.h
|
||||
setup
|
||||
setup.bin
|
||||
setup.elf
|
||||
|
|
|
@ -26,9 +26,10 @@ targets := vmlinux.bin setup.bin setup.elf bzImage
|
|||
targets += fdimage fdimage144 fdimage288 image.iso mtools.conf
|
||||
subdir- := compressed
|
||||
|
||||
setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
|
||||
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o edd.o
|
||||
setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
|
||||
setup-y += printf.o string.o tty.o video.o video-mode.o version.o
|
||||
setup-y += printf.o regs.o string.o tty.o video.o video-mode.o
|
||||
setup-y += version.o
|
||||
setup-$(CONFIG_X86_APM_BOOT) += apm.o
|
||||
|
||||
# The link order of the video-*.o modules can matter. In particular,
|
||||
|
@ -86,19 +87,27 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
|
|||
|
||||
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
|
||||
|
||||
sed-offsets := -e 's/^00*/0/' \
|
||||
-e 's/^\([0-9a-fA-F]*\) . \(input_data\|input_data_end\)$$/\#define \2 0x\1/p'
|
||||
sed-voffset := -e 's/^\([0-9a-fA-F]*\) . \(_text\|_end\)$$/\#define VO_\2 0x\1/p'
|
||||
|
||||
quiet_cmd_offsets = OFFSETS $@
|
||||
cmd_offsets = $(NM) $< | sed -n $(sed-offsets) > $@
|
||||
quiet_cmd_voffset = VOFFSET $@
|
||||
cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
|
||||
|
||||
$(obj)/offsets.h: $(obj)/compressed/vmlinux FORCE
|
||||
$(call if_changed,offsets)
|
||||
targets += voffset.h
|
||||
$(obj)/voffset.h: vmlinux FORCE
|
||||
$(call if_changed,voffset)
|
||||
|
||||
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
|
||||
|
||||
quiet_cmd_zoffset = ZOFFSET $@
|
||||
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
|
||||
|
||||
targets += zoffset.h
|
||||
$(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
|
||||
$(call if_changed,zoffset)
|
||||
|
||||
targets += offsets.h
|
||||
|
||||
AFLAGS_header.o += -I$(obj)
|
||||
$(obj)/header.o: $(obj)/offsets.h
|
||||
$(obj)/header.o: $(obj)/voffset.h $(obj)/zoffset.h
|
||||
|
||||
LDFLAGS_setup.elf := -T
|
||||
$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007-2008 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -90,8 +90,11 @@ static int a20_test_long(void)
|
|||
|
||||
static void enable_a20_bios(void)
|
||||
{
|
||||
asm volatile("pushfl; int $0x15; popfl"
|
||||
: : "a" ((u16)0x2401));
|
||||
struct biosregs ireg;
|
||||
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x2401;
|
||||
intcall(0x15, &ireg, NULL);
|
||||
}
|
||||
|
||||
static void enable_a20_kbc(void)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* Original APM BIOS checking by Stephen Rothwell, May 1994
|
||||
* (sfr@canb.auug.org.au)
|
||||
|
@ -19,75 +20,56 @@
|
|||
|
||||
int query_apm_bios(void)
|
||||
{
|
||||
u16 ax, bx, cx, dx, di;
|
||||
u32 ebx, esi;
|
||||
u8 err;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
/* APM BIOS installation check */
|
||||
ax = 0x5300;
|
||||
bx = cx = 0;
|
||||
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
|
||||
: "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
|
||||
: : "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x53;
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
if (err)
|
||||
if (oreg.flags & X86_EFLAGS_CF)
|
||||
return -1; /* No APM BIOS */
|
||||
|
||||
if (bx != 0x504d) /* "PM" signature */
|
||||
if (oreg.bx != 0x504d) /* "PM" signature */
|
||||
return -1;
|
||||
|
||||
if (!(cx & 0x02)) /* 32 bits supported? */
|
||||
if (!(oreg.cx & 0x02)) /* 32 bits supported? */
|
||||
return -1;
|
||||
|
||||
/* Disconnect first, just in case */
|
||||
ax = 0x5304;
|
||||
bx = 0;
|
||||
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
|
||||
: "+a" (ax), "+b" (bx)
|
||||
: : "ecx", "edx", "esi", "edi");
|
||||
|
||||
/* Paranoia */
|
||||
ebx = esi = 0;
|
||||
cx = dx = di = 0;
|
||||
ireg.al = 0x04;
|
||||
intcall(0x15, &ireg, NULL);
|
||||
|
||||
/* 32-bit connect */
|
||||
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6"
|
||||
: "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx),
|
||||
"+S" (esi), "+D" (di), "=m" (err)
|
||||
: "a" (0x5303));
|
||||
ireg.al = 0x03;
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
boot_params.apm_bios_info.cseg = ax;
|
||||
boot_params.apm_bios_info.offset = ebx;
|
||||
boot_params.apm_bios_info.cseg_16 = cx;
|
||||
boot_params.apm_bios_info.dseg = dx;
|
||||
boot_params.apm_bios_info.cseg_len = (u16)esi;
|
||||
boot_params.apm_bios_info.cseg_16_len = esi >> 16;
|
||||
boot_params.apm_bios_info.dseg_len = di;
|
||||
boot_params.apm_bios_info.cseg = oreg.ax;
|
||||
boot_params.apm_bios_info.offset = oreg.ebx;
|
||||
boot_params.apm_bios_info.cseg_16 = oreg.cx;
|
||||
boot_params.apm_bios_info.dseg = oreg.dx;
|
||||
boot_params.apm_bios_info.cseg_len = oreg.si;
|
||||
boot_params.apm_bios_info.cseg_16_len = oreg.hsi;
|
||||
boot_params.apm_bios_info.dseg_len = oreg.di;
|
||||
|
||||
if (err)
|
||||
if (oreg.flags & X86_EFLAGS_CF)
|
||||
return -1;
|
||||
|
||||
/* Redo the installation check as the 32-bit connect;
|
||||
some BIOSes return different flags this way... */
|
||||
|
||||
ax = 0x5300;
|
||||
bx = cx = 0;
|
||||
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
|
||||
: "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
|
||||
: : "esi", "edi");
|
||||
ireg.al = 0x00;
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
if (err || bx != 0x504d) {
|
||||
if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) {
|
||||
/* Failure with 32-bit connect, try to disconect and ignore */
|
||||
ax = 0x5304;
|
||||
bx = 0;
|
||||
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
|
||||
: "+a" (ax), "+b" (bx)
|
||||
: : "ecx", "edx", "esi", "edi");
|
||||
ireg.al = 0x04;
|
||||
intcall(0x15, &ireg, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
boot_params.apm_bios_info.version = ax;
|
||||
boot_params.apm_bios_info.flags = cx;
|
||||
boot_params.apm_bios_info.version = oreg.ax;
|
||||
boot_params.apm_bios_info.flags = oreg.cx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
*
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2 or (at your
|
||||
* option) any later version; incorporated herein by reference.
|
||||
*
|
||||
* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* "Glove box" for BIOS calls. Avoids the constant problems with BIOSes
|
||||
* touching registers they shouldn't be.
|
||||
*/
|
||||
|
||||
.code16
|
||||
.text
|
||||
.globl intcall
|
||||
.type intcall, @function
|
||||
intcall:
|
||||
/* Self-modify the INT instruction. Ugly, but works. */
|
||||
cmpb %al, 3f
|
||||
je 1f
|
||||
movb %al, 3f
|
||||
jmp 1f /* Synchronize pipeline */
|
||||
1:
|
||||
/* Save state */
|
||||
pushfl
|
||||
pushw %fs
|
||||
pushw %gs
|
||||
pushal
|
||||
|
||||
/* Copy input state to stack frame */
|
||||
subw $44, %sp
|
||||
movw %dx, %si
|
||||
movw %sp, %di
|
||||
movw $11, %cx
|
||||
rep; movsd
|
||||
|
||||
/* Pop full state from the stack */
|
||||
popal
|
||||
popw %gs
|
||||
popw %fs
|
||||
popw %es
|
||||
popw %ds
|
||||
popfl
|
||||
|
||||
/* Actual INT */
|
||||
.byte 0xcd /* INT opcode */
|
||||
3: .byte 0
|
||||
|
||||
/* Push full state to the stack */
|
||||
pushfl
|
||||
pushw %ds
|
||||
pushw %es
|
||||
pushw %fs
|
||||
pushw %gs
|
||||
pushal
|
||||
|
||||
/* Re-establish C environment invariants */
|
||||
cld
|
||||
movzwl %sp, %esp
|
||||
movw %cs, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
|
||||
/* Copy output state from stack frame */
|
||||
movw 68(%esp), %di /* Original %cx == 3rd argument */
|
||||
andw %di, %di
|
||||
jz 4f
|
||||
movw %sp, %si
|
||||
movw $11, %cx
|
||||
rep; movsd
|
||||
4: addw $44, %sp
|
||||
|
||||
/* Restore state and return */
|
||||
popal
|
||||
popw %gs
|
||||
popw %fs
|
||||
popfl
|
||||
retl
|
||||
.size intcall, .-intcall
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include <asm/setup.h>
|
||||
#include "bitops.h"
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
/* Useful macros */
|
||||
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
|
||||
|
@ -241,6 +243,49 @@ int enable_a20(void);
|
|||
/* apm.c */
|
||||
int query_apm_bios(void);
|
||||
|
||||
/* bioscall.c */
|
||||
struct biosregs {
|
||||
union {
|
||||
struct {
|
||||
u32 edi;
|
||||
u32 esi;
|
||||
u32 ebp;
|
||||
u32 _esp;
|
||||
u32 ebx;
|
||||
u32 edx;
|
||||
u32 ecx;
|
||||
u32 eax;
|
||||
u32 _fsgs;
|
||||
u32 _dses;
|
||||
u32 eflags;
|
||||
};
|
||||
struct {
|
||||
u16 di, hdi;
|
||||
u16 si, hsi;
|
||||
u16 bp, hbp;
|
||||
u16 _sp, _hsp;
|
||||
u16 bx, hbx;
|
||||
u16 dx, hdx;
|
||||
u16 cx, hcx;
|
||||
u16 ax, hax;
|
||||
u16 gs, fs;
|
||||
u16 es, ds;
|
||||
u16 flags, hflags;
|
||||
};
|
||||
struct {
|
||||
u8 dil, dih, edi2, edi3;
|
||||
u8 sil, sih, esi2, esi3;
|
||||
u8 bpl, bph, ebp2, ebp3;
|
||||
u8 _spl, _sph, _esp2, _esp3;
|
||||
u8 bl, bh, ebx2, ebx3;
|
||||
u8 dl, dh, edx2, edx3;
|
||||
u8 cl, ch, ecx2, ecx3;
|
||||
u8 al, ah, eax2, eax3;
|
||||
};
|
||||
};
|
||||
};
|
||||
void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
|
||||
|
||||
/* cmdline.c */
|
||||
int cmdline_find_option(const char *option, char *buffer, int bufsize);
|
||||
int cmdline_find_option_bool(const char *option);
|
||||
|
@ -279,6 +324,9 @@ int sprintf(char *buf, const char *fmt, ...);
|
|||
int vsprintf(char *buf, const char *fmt, va_list args);
|
||||
int printf(const char *fmt, ...);
|
||||
|
||||
/* regs.c */
|
||||
void initregs(struct biosregs *regs);
|
||||
|
||||
/* string.c */
|
||||
int strcmp(const char *str1, const char *str2);
|
||||
size_t strnlen(const char *s, size_t maxlen);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
relocs
|
||||
vmlinux.bin.all
|
||||
vmlinux.relocs
|
||||
vmlinux.lds
|
||||
mkpiggy
|
||||
piggy.S
|
||||
|
|
|
@ -19,7 +19,9 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
|
|||
LDFLAGS := -m elf_$(UTS_MACHINE)
|
||||
LDFLAGS_vmlinux := -T
|
||||
|
||||
$(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE
|
||||
hostprogs-y := mkpiggy
|
||||
|
||||
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE
|
||||
$(call if_changed,ld)
|
||||
@:
|
||||
|
||||
|
@ -29,7 +31,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
|||
|
||||
|
||||
targets += vmlinux.bin.all vmlinux.relocs relocs
|
||||
hostprogs-$(CONFIG_X86_32) += relocs
|
||||
hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs
|
||||
|
||||
quiet_cmd_relocs = RELOCS $@
|
||||
cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
|
||||
|
@ -37,46 +39,22 @@ $(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE
|
|||
$(call if_changed,relocs)
|
||||
|
||||
vmlinux.bin.all-y := $(obj)/vmlinux.bin
|
||||
vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs
|
||||
quiet_cmd_relocbin = BUILD $@
|
||||
cmd_relocbin = cat $(filter-out FORCE,$^) > $@
|
||||
$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,relocbin)
|
||||
vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs
|
||||
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
|
||||
ifdef CONFIG_RELOCATABLE
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
|
||||
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin.all FORCE
|
||||
$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,bzip2)
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin.all FORCE
|
||||
$(call if_changed,lzma)
|
||||
else
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2)
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,lzma)
|
||||
endif
|
||||
LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
|
||||
|
||||
else
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2)
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
|
||||
$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,lzma)
|
||||
|
||||
LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
|
||||
endif
|
||||
suffix-$(CONFIG_KERNEL_GZIP) := gz
|
||||
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
|
||||
suffix-$(CONFIG_KERNEL_LZMA) := lzma
|
||||
|
||||
suffix_$(CONFIG_KERNEL_GZIP) = gz
|
||||
suffix_$(CONFIG_KERNEL_BZIP2) = bz2
|
||||
suffix_$(CONFIG_KERNEL_LZMA) = lzma
|
||||
quiet_cmd_mkpiggy = MKPIGGY $@
|
||||
cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )
|
||||
|
||||
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix_y) FORCE
|
||||
$(call if_changed,ld)
|
||||
targets += piggy.S
|
||||
$(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
|
||||
$(call if_changed,mkpiggy)
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
* the page directory. [According to comments etc elsewhere on a compressed
|
||||
* kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
|
||||
*
|
||||
* Page 0 is deliberately kept safe, since System Management Mode code in
|
||||
* Page 0 is deliberately kept safe, since System Management Mode code in
|
||||
* laptops may need to access the BIOS data stored there. This is also
|
||||
* useful for future device drivers that either access the BIOS via VM86
|
||||
* useful for future device drivers that either access the BIOS via VM86
|
||||
* mode.
|
||||
*/
|
||||
|
||||
/*
|
||||
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
|
||||
*/
|
||||
.text
|
||||
.text
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/segment.h>
|
||||
|
@ -29,161 +29,151 @@
|
|||
#include <asm/boot.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
.section ".text.head","ax",@progbits
|
||||
.section ".text.head","ax",@progbits
|
||||
ENTRY(startup_32)
|
||||
cld
|
||||
/* test KEEP_SEGMENTS flag to see if the bootloader is asking
|
||||
* us to not reload segments */
|
||||
testb $(1<<6), BP_loadflags(%esi)
|
||||
jnz 1f
|
||||
/*
|
||||
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
|
||||
* us to not reload segments
|
||||
*/
|
||||
testb $(1<<6), BP_loadflags(%esi)
|
||||
jnz 1f
|
||||
|
||||
cli
|
||||
movl $(__BOOT_DS),%eax
|
||||
movl %eax,%ds
|
||||
movl %eax,%es
|
||||
movl %eax,%fs
|
||||
movl %eax,%gs
|
||||
movl %eax,%ss
|
||||
movl $__BOOT_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
movl %eax, %ss
|
||||
1:
|
||||
|
||||
/* Calculate the delta between where we were compiled to run
|
||||
/*
|
||||
* Calculate the delta between where we were compiled to run
|
||||
* at and where we were actually loaded at. This can only be done
|
||||
* with a short local call on x86. Nothing else will tell us what
|
||||
* address we are running at. The reserved chunk of the real-mode
|
||||
* data at 0x1e4 (defined as a scratch field) are used as the stack
|
||||
* for this calculation. Only 4 bytes are needed.
|
||||
*/
|
||||
leal (0x1e4+4)(%esi), %esp
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
subl $1b, %ebp
|
||||
leal (BP_scratch+4)(%esi), %esp
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
subl $1b, %ebp
|
||||
|
||||
/* %ebp contains the address we are loaded at by the boot loader and %ebx
|
||||
/*
|
||||
* %ebp contains the address we are loaded at by the boot loader and %ebx
|
||||
* contains the address where we should move the kernel image temporarily
|
||||
* for safe in-place decompression.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
movl %ebp, %ebx
|
||||
addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx
|
||||
andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx
|
||||
movl %ebp, %ebx
|
||||
movl BP_kernel_alignment(%esi), %eax
|
||||
decl %eax
|
||||
addl %eax, %ebx
|
||||
notl %eax
|
||||
andl %eax, %ebx
|
||||
#else
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
#endif
|
||||
|
||||
/* Replace the compressed data size with the uncompressed size */
|
||||
subl input_len(%ebp), %ebx
|
||||
movl output_len(%ebp), %eax
|
||||
addl %eax, %ebx
|
||||
/* Add 8 bytes for every 32K input block */
|
||||
shrl $12, %eax
|
||||
addl %eax, %ebx
|
||||
/* Add 32K + 18 bytes of extra slack */
|
||||
addl $(32768 + 18), %ebx
|
||||
/* Align on a 4K boundary */
|
||||
addl $4095, %ebx
|
||||
andl $~4095, %ebx
|
||||
/* Target address to relocate to for decompression */
|
||||
addl $z_extract_offset, %ebx
|
||||
|
||||
/* Copy the compressed kernel to the end of our buffer
|
||||
/* Set up the stack */
|
||||
leal boot_stack_end(%ebx), %esp
|
||||
|
||||
/* Zero EFLAGS */
|
||||
pushl $0
|
||||
popfl
|
||||
|
||||
/*
|
||||
* Copy the compressed kernel to the end of our buffer
|
||||
* where decompression in place becomes safe.
|
||||
*/
|
||||
pushl %esi
|
||||
leal _end(%ebp), %esi
|
||||
leal _end(%ebx), %edi
|
||||
movl $(_end - startup_32), %ecx
|
||||
pushl %esi
|
||||
leal (_bss-4)(%ebp), %esi
|
||||
leal (_bss-4)(%ebx), %edi
|
||||
movl $(_bss - startup_32), %ecx
|
||||
shrl $2, %ecx
|
||||
std
|
||||
rep
|
||||
movsb
|
||||
rep movsl
|
||||
cld
|
||||
popl %esi
|
||||
|
||||
/* Compute the kernel start address.
|
||||
*/
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp
|
||||
andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp
|
||||
#else
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebp
|
||||
#endif
|
||||
popl %esi
|
||||
|
||||
/*
|
||||
* Jump to the relocated address.
|
||||
*/
|
||||
leal relocated(%ebx), %eax
|
||||
jmp *%eax
|
||||
leal relocated(%ebx), %eax
|
||||
jmp *%eax
|
||||
ENDPROC(startup_32)
|
||||
|
||||
.section ".text"
|
||||
.text
|
||||
relocated:
|
||||
|
||||
/*
|
||||
* Clear BSS
|
||||
* Clear BSS (stack is currently empty)
|
||||
*/
|
||||
xorl %eax,%eax
|
||||
leal _edata(%ebx),%edi
|
||||
leal _end(%ebx), %ecx
|
||||
subl %edi,%ecx
|
||||
cld
|
||||
rep
|
||||
stosb
|
||||
|
||||
/*
|
||||
* Setup the stack for the decompressor
|
||||
*/
|
||||
leal boot_stack_end(%ebx), %esp
|
||||
xorl %eax, %eax
|
||||
leal _bss(%ebx), %edi
|
||||
leal _ebss(%ebx), %ecx
|
||||
subl %edi, %ecx
|
||||
shrl $2, %ecx
|
||||
rep stosl
|
||||
|
||||
/*
|
||||
* Do the decompression, and jump to the new kernel..
|
||||
*/
|
||||
movl output_len(%ebx), %eax
|
||||
pushl %eax
|
||||
# push arguments for decompress_kernel:
|
||||
pushl %ebp # output address
|
||||
movl input_len(%ebx), %eax
|
||||
pushl %eax # input_len
|
||||
leal input_data(%ebx), %eax
|
||||
pushl %eax # input_data
|
||||
leal boot_heap(%ebx), %eax
|
||||
pushl %eax # heap area
|
||||
pushl %esi # real mode pointer
|
||||
call decompress_kernel
|
||||
addl $20, %esp
|
||||
popl %ecx
|
||||
leal z_extract_offset_negative(%ebx), %ebp
|
||||
/* push arguments for decompress_kernel: */
|
||||
pushl %ebp /* output address */
|
||||
pushl $z_input_len /* input_len */
|
||||
leal input_data(%ebx), %eax
|
||||
pushl %eax /* input_data */
|
||||
leal boot_heap(%ebx), %eax
|
||||
pushl %eax /* heap area */
|
||||
pushl %esi /* real mode pointer */
|
||||
call decompress_kernel
|
||||
addl $20, %esp
|
||||
|
||||
#if CONFIG_RELOCATABLE
|
||||
/* Find the address of the relocations.
|
||||
/*
|
||||
* Find the address of the relocations.
|
||||
*/
|
||||
movl %ebp, %edi
|
||||
addl %ecx, %edi
|
||||
leal z_output_len(%ebp), %edi
|
||||
|
||||
/* Calculate the delta between where vmlinux was compiled to run
|
||||
/*
|
||||
* Calculate the delta between where vmlinux was compiled to run
|
||||
* and where it was actually loaded.
|
||||
*/
|
||||
movl %ebp, %ebx
|
||||
subl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
jz 2f /* Nothing to be done if loaded at compiled addr. */
|
||||
movl %ebp, %ebx
|
||||
subl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
jz 2f /* Nothing to be done if loaded at compiled addr. */
|
||||
/*
|
||||
* Process relocations.
|
||||
*/
|
||||
|
||||
1: subl $4, %edi
|
||||
movl 0(%edi), %ecx
|
||||
testl %ecx, %ecx
|
||||
jz 2f
|
||||
addl %ebx, -__PAGE_OFFSET(%ebx, %ecx)
|
||||
jmp 1b
|
||||
1: subl $4, %edi
|
||||
movl (%edi), %ecx
|
||||
testl %ecx, %ecx
|
||||
jz 2f
|
||||
addl %ebx, -__PAGE_OFFSET(%ebx, %ecx)
|
||||
jmp 1b
|
||||
2:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Jump to the decompressed kernel.
|
||||
*/
|
||||
xorl %ebx,%ebx
|
||||
jmp *%ebp
|
||||
xorl %ebx, %ebx
|
||||
jmp *%ebp
|
||||
|
||||
.bss
|
||||
/* Stack and heap for uncompression */
|
||||
.balign 4
|
||||
/*
|
||||
* Stack and heap for uncompression
|
||||
*/
|
||||
.bss
|
||||
.balign 4
|
||||
boot_heap:
|
||||
.fill BOOT_HEAP_SIZE, 1, 0
|
||||
boot_stack:
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
/*
|
||||
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
|
||||
*/
|
||||
.code32
|
||||
.text
|
||||
.code32
|
||||
.text
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/segment.h>
|
||||
|
@ -33,12 +33,14 @@
|
|||
#include <asm/processor-flags.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
.section ".text.head"
|
||||
.section ".text.head"
|
||||
.code32
|
||||
ENTRY(startup_32)
|
||||
cld
|
||||
/* test KEEP_SEGMENTS flag to see if the bootloader is asking
|
||||
* us to not reload segments */
|
||||
/*
|
||||
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
|
||||
* us to not reload segments
|
||||
*/
|
||||
testb $(1<<6), BP_loadflags(%esi)
|
||||
jnz 1f
|
||||
|
||||
|
@ -49,14 +51,15 @@ ENTRY(startup_32)
|
|||
movl %eax, %ss
|
||||
1:
|
||||
|
||||
/* Calculate the delta between where we were compiled to run
|
||||
/*
|
||||
* Calculate the delta between where we were compiled to run
|
||||
* at and where we were actually loaded at. This can only be done
|
||||
* with a short local call on x86. Nothing else will tell us what
|
||||
* address we are running at. The reserved chunk of the real-mode
|
||||
* data at 0x1e4 (defined as a scratch field) are used as the stack
|
||||
* for this calculation. Only 4 bytes are needed.
|
||||
*/
|
||||
leal (0x1e4+4)(%esi), %esp
|
||||
leal (BP_scratch+4)(%esi), %esp
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
subl $1b, %ebp
|
||||
|
@ -70,32 +73,28 @@ ENTRY(startup_32)
|
|||
testl %eax, %eax
|
||||
jnz no_longmode
|
||||
|
||||
/* Compute the delta between where we were compiled to run at
|
||||
/*
|
||||
* Compute the delta between where we were compiled to run at
|
||||
* and where the code will actually run at.
|
||||
*/
|
||||
/* %ebp contains the address we are loaded at by the boot loader and %ebx
|
||||
*
|
||||
* %ebp contains the address we are loaded at by the boot loader and %ebx
|
||||
* contains the address where we should move the kernel image temporarily
|
||||
* for safe in-place decompression.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
movl %ebp, %ebx
|
||||
addl $(PMD_PAGE_SIZE -1), %ebx
|
||||
andl $PMD_PAGE_MASK, %ebx
|
||||
movl BP_kernel_alignment(%esi), %eax
|
||||
decl %eax
|
||||
addl %eax, %ebx
|
||||
notl %eax
|
||||
andl %eax, %ebx
|
||||
#else
|
||||
movl $CONFIG_PHYSICAL_START, %ebx
|
||||
movl $LOAD_PHYSICAL_ADDR, %ebx
|
||||
#endif
|
||||
|
||||
/* Replace the compressed data size with the uncompressed size */
|
||||
subl input_len(%ebp), %ebx
|
||||
movl output_len(%ebp), %eax
|
||||
addl %eax, %ebx
|
||||
/* Add 8 bytes for every 32K input block */
|
||||
shrl $12, %eax
|
||||
addl %eax, %ebx
|
||||
/* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
|
||||
addl $(32768 + 18 + 4095), %ebx
|
||||
andl $~4095, %ebx
|
||||
/* Target address to relocate to for decompression */
|
||||
addl $z_extract_offset, %ebx
|
||||
|
||||
/*
|
||||
* Prepare for entering 64 bit mode
|
||||
|
@ -114,7 +113,7 @@ ENTRY(startup_32)
|
|||
/*
|
||||
* Build early 4G boot pagetable
|
||||
*/
|
||||
/* Initialize Page tables to 0*/
|
||||
/* Initialize Page tables to 0 */
|
||||
leal pgtable(%ebx), %edi
|
||||
xorl %eax, %eax
|
||||
movl $((4096*6)/4), %ecx
|
||||
|
@ -155,7 +154,8 @@ ENTRY(startup_32)
|
|||
btsl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
/* Setup for the jump to 64bit mode
|
||||
/*
|
||||
* Setup for the jump to 64bit mode
|
||||
*
|
||||
* When the jump is performend we will be in long mode but
|
||||
* in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
|
||||
|
@ -184,7 +184,8 @@ no_longmode:
|
|||
|
||||
#include "../../kernel/verify_cpu_64.S"
|
||||
|
||||
/* Be careful here startup_64 needs to be at a predictable
|
||||
/*
|
||||
* Be careful here startup_64 needs to be at a predictable
|
||||
* address so I can export it in an ELF header. Bootloaders
|
||||
* should look at the ELF header to find this address, as
|
||||
* it may change in the future.
|
||||
|
@ -192,7 +193,8 @@ no_longmode:
|
|||
.code64
|
||||
.org 0x200
|
||||
ENTRY(startup_64)
|
||||
/* We come here either from startup_32 or directly from a
|
||||
/*
|
||||
* We come here either from startup_32 or directly from a
|
||||
* 64bit bootloader. If we come here from a bootloader we depend on
|
||||
* an identity mapped page table being provied that maps our
|
||||
* entire text+data+bss and hopefully all of memory.
|
||||
|
@ -209,50 +211,54 @@ ENTRY(startup_64)
|
|||
movl $0x20, %eax
|
||||
ltr %ax
|
||||
|
||||
/* Compute the decompressed kernel start address. It is where
|
||||
/*
|
||||
* Compute the decompressed kernel start address. It is where
|
||||
* we were loaded at aligned to a 2M boundary. %rbp contains the
|
||||
* decompressed kernel start address.
|
||||
*
|
||||
* If it is a relocatable kernel then decompress and run the kernel
|
||||
* from load address aligned to 2MB addr, otherwise decompress and
|
||||
* run the kernel from CONFIG_PHYSICAL_START
|
||||
* run the kernel from LOAD_PHYSICAL_ADDR
|
||||
*
|
||||
* We cannot rely on the calculation done in 32-bit mode, since we
|
||||
* may have been invoked via the 64-bit entry point.
|
||||
*/
|
||||
|
||||
/* Start with the delta to where the kernel will run at. */
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
leaq startup_32(%rip) /* - $startup_32 */, %rbp
|
||||
addq $(PMD_PAGE_SIZE - 1), %rbp
|
||||
andq $PMD_PAGE_MASK, %rbp
|
||||
movq %rbp, %rbx
|
||||
movl BP_kernel_alignment(%rsi), %eax
|
||||
decl %eax
|
||||
addq %rax, %rbp
|
||||
notq %rax
|
||||
andq %rax, %rbp
|
||||
#else
|
||||
movq $CONFIG_PHYSICAL_START, %rbp
|
||||
movq %rbp, %rbx
|
||||
movq $LOAD_PHYSICAL_ADDR, %rbp
|
||||
#endif
|
||||
|
||||
/* Replace the compressed data size with the uncompressed size */
|
||||
movl input_len(%rip), %eax
|
||||
subq %rax, %rbx
|
||||
movl output_len(%rip), %eax
|
||||
addq %rax, %rbx
|
||||
/* Add 8 bytes for every 32K input block */
|
||||
shrq $12, %rax
|
||||
addq %rax, %rbx
|
||||
/* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
|
||||
addq $(32768 + 18 + 4095), %rbx
|
||||
andq $~4095, %rbx
|
||||
/* Target address to relocate to for decompression */
|
||||
leaq z_extract_offset(%rbp), %rbx
|
||||
|
||||
/* Copy the compressed kernel to the end of our buffer
|
||||
/* Set up the stack */
|
||||
leaq boot_stack_end(%rbx), %rsp
|
||||
|
||||
/* Zero EFLAGS */
|
||||
pushq $0
|
||||
popfq
|
||||
|
||||
/*
|
||||
* Copy the compressed kernel to the end of our buffer
|
||||
* where decompression in place becomes safe.
|
||||
*/
|
||||
leaq _end_before_pgt(%rip), %r8
|
||||
leaq _end_before_pgt(%rbx), %r9
|
||||
movq $_end_before_pgt /* - $startup_32 */, %rcx
|
||||
1: subq $8, %r8
|
||||
subq $8, %r9
|
||||
movq 0(%r8), %rax
|
||||
movq %rax, 0(%r9)
|
||||
subq $8, %rcx
|
||||
jnz 1b
|
||||
pushq %rsi
|
||||
leaq (_bss-8)(%rip), %rsi
|
||||
leaq (_bss-8)(%rbx), %rdi
|
||||
movq $_bss /* - $startup_32 */, %rcx
|
||||
shrq $3, %rcx
|
||||
std
|
||||
rep movsq
|
||||
cld
|
||||
popq %rsi
|
||||
|
||||
/*
|
||||
* Jump to the relocated address.
|
||||
|
@ -260,37 +266,28 @@ ENTRY(startup_64)
|
|||
leaq relocated(%rbx), %rax
|
||||
jmp *%rax
|
||||
|
||||
.section ".text"
|
||||
.text
|
||||
relocated:
|
||||
|
||||
/*
|
||||
* Clear BSS
|
||||
* Clear BSS (stack is currently empty)
|
||||
*/
|
||||
xorq %rax, %rax
|
||||
leaq _edata(%rbx), %rdi
|
||||
leaq _end_before_pgt(%rbx), %rcx
|
||||
xorl %eax, %eax
|
||||
leaq _bss(%rip), %rdi
|
||||
leaq _ebss(%rip), %rcx
|
||||
subq %rdi, %rcx
|
||||
cld
|
||||
rep
|
||||
stosb
|
||||
|
||||
/* Setup the stack */
|
||||
leaq boot_stack_end(%rip), %rsp
|
||||
|
||||
/* zero EFLAGS after setting rsp */
|
||||
pushq $0
|
||||
popfq
|
||||
shrq $3, %rcx
|
||||
rep stosq
|
||||
|
||||
/*
|
||||
* Do the decompression, and jump to the new kernel..
|
||||
*/
|
||||
pushq %rsi # Save the real mode argument
|
||||
movq %rsi, %rdi # real mode address
|
||||
leaq boot_heap(%rip), %rsi # malloc area for uncompression
|
||||
leaq input_data(%rip), %rdx # input_data
|
||||
movl input_len(%rip), %eax
|
||||
movq %rax, %rcx # input_len
|
||||
movq %rbp, %r8 # output
|
||||
pushq %rsi /* Save the real mode argument */
|
||||
movq %rsi, %rdi /* real mode address */
|
||||
leaq boot_heap(%rip), %rsi /* malloc area for uncompression */
|
||||
leaq input_data(%rip), %rdx /* input_data */
|
||||
movl $z_input_len, %ecx /* input_len */
|
||||
movq %rbp, %r8 /* output target address */
|
||||
call decompress_kernel
|
||||
popq %rsi
|
||||
|
||||
|
@ -311,11 +308,21 @@ gdt:
|
|||
.quad 0x0000000000000000 /* TS continued */
|
||||
gdt_end:
|
||||
|
||||
.bss
|
||||
/* Stack and heap for uncompression */
|
||||
.balign 4
|
||||
/*
|
||||
* Stack and heap for uncompression
|
||||
*/
|
||||
.bss
|
||||
.balign 4
|
||||
boot_heap:
|
||||
.fill BOOT_HEAP_SIZE, 1, 0
|
||||
boot_stack:
|
||||
.fill BOOT_STACK_SIZE, 1, 0
|
||||
boot_stack_end:
|
||||
|
||||
/*
|
||||
* Space for page tables (not in .bss so not zeroed)
|
||||
*/
|
||||
.section ".pgtable","a",@nobits
|
||||
.balign 4096
|
||||
pgtable:
|
||||
.fill 6*4096, 1, 0
|
||||
|
|
|
@ -325,20 +325,18 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
|
|||
free_mem_ptr = heap; /* Heap */
|
||||
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
|
||||
|
||||
if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
|
||||
error("Destination address inappropriately aligned");
|
||||
#ifdef CONFIG_X86_64
|
||||
if ((unsigned long)output & (__KERNEL_ALIGN - 1))
|
||||
error("Destination address not 2M aligned");
|
||||
if ((unsigned long)output >= 0xffffffffffUL)
|
||||
if (heap > 0x3fffffffffffUL)
|
||||
error("Destination address too large");
|
||||
#else
|
||||
if ((u32)output & (CONFIG_PHYSICAL_ALIGN - 1))
|
||||
error("Destination address not CONFIG_PHYSICAL_ALIGN aligned");
|
||||
if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff))
|
||||
error("Destination address too large");
|
||||
#ifndef CONFIG_RELOCATABLE
|
||||
if ((u32)output != LOAD_PHYSICAL_ADDR)
|
||||
error("Wrong destination address");
|
||||
#endif
|
||||
#ifndef CONFIG_RELOCATABLE
|
||||
if ((unsigned long)output != LOAD_PHYSICAL_ADDR)
|
||||
error("Wrong destination address");
|
||||
#endif
|
||||
|
||||
if (!quiet)
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/* ----------------------------------------------------------------------- *
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* H. Peter Anvin <hpa@linux.intel.com>
|
||||
*
|
||||
* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Compute the desired load offset from a compressed program; outputs
|
||||
* a small assembly wrapper with the appropriate symbols defined.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static uint32_t getle32(const void *p)
|
||||
{
|
||||
const uint8_t *cp = p;
|
||||
|
||||
return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) +
|
||||
((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t olen;
|
||||
long ilen;
|
||||
unsigned long offs;
|
||||
FILE *f;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s compressed_file\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get the information for the compressed kernel image first */
|
||||
|
||||
f = fopen(argv[1], "r");
|
||||
if (!f) {
|
||||
perror(argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (fseek(f, -4L, SEEK_END)) {
|
||||
perror(argv[1]);
|
||||
}
|
||||
fread(&olen, sizeof olen, 1, f);
|
||||
ilen = ftell(f);
|
||||
olen = getle32(&olen);
|
||||
fclose(f);
|
||||
|
||||
/*
|
||||
* Now we have the input (compressed) and output (uncompressed)
|
||||
* sizes, compute the necessary decompression offset...
|
||||
*/
|
||||
|
||||
offs = (olen > ilen) ? olen - ilen : 0;
|
||||
offs += olen >> 12; /* Add 8 bytes for each 32K block */
|
||||
offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */
|
||||
offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
|
||||
|
||||
printf(".section \".rodata.compressed\",\"a\",@progbits\n");
|
||||
printf(".globl z_input_len\n");
|
||||
printf("z_input_len = %lu\n", ilen);
|
||||
printf(".globl z_output_len\n");
|
||||
printf("z_output_len = %lu\n", (unsigned long)olen);
|
||||
printf(".globl z_extract_offset\n");
|
||||
printf("z_extract_offset = 0x%lx\n", offs);
|
||||
/* z_extract_offset_negative allows simplification of head_32.S */
|
||||
printf(".globl z_extract_offset_negative\n");
|
||||
printf("z_extract_offset_negative = -0x%lx\n", offs);
|
||||
|
||||
printf(".globl input_data, input_data_end\n");
|
||||
printf("input_data:\n");
|
||||
printf(".incbin \"%s\"\n", argv[1]);
|
||||
printf("input_data_end:\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,17 @@
|
|||
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
|
||||
OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT)
|
||||
|
||||
#undef i386
|
||||
|
||||
#include <asm/page_types.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
ENTRY(startup_64)
|
||||
#else
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(startup_32)
|
||||
#endif
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Be careful parts of head_64.S assume startup_32 is at
|
||||
|
@ -33,16 +44,22 @@ SECTIONS
|
|||
*(.data.*)
|
||||
_edata = . ;
|
||||
}
|
||||
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
|
||||
.bss : {
|
||||
_bss = . ;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(8);
|
||||
_end_before_pgt = . ;
|
||||
. = ALIGN(4096);
|
||||
pgtable = . ;
|
||||
. = . + 4096 * 6;
|
||||
. = ALIGN(8); /* For convenience during zeroing */
|
||||
_ebss = .;
|
||||
}
|
||||
#ifdef CONFIG_X86_64
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
.pgtable : {
|
||||
_pgtable = . ;
|
||||
*(.pgtable)
|
||||
_epgtable = . ;
|
||||
}
|
||||
#endif
|
||||
_end = .;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
SECTIONS
|
||||
{
|
||||
.rodata.compressed : {
|
||||
input_len = .;
|
||||
LONG(input_data_end - input_data) input_data = .;
|
||||
*(.data)
|
||||
output_len = . - 4;
|
||||
input_data_end = .;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(startup_32)
|
||||
SECTIONS
|
||||
{
|
||||
/* Be careful parts of head_32.S assume startup_32 is at
|
||||
* address 0.
|
||||
*/
|
||||
. = 0;
|
||||
.text.head : {
|
||||
_head = . ;
|
||||
*(.text.head)
|
||||
_ehead = . ;
|
||||
}
|
||||
.rodata.compressed : {
|
||||
*(.rodata.compressed)
|
||||
}
|
||||
.text : {
|
||||
_text = .; /* Text */
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
_etext = . ;
|
||||
}
|
||||
.rodata : {
|
||||
_rodata = . ;
|
||||
*(.rodata) /* read-only data */
|
||||
*(.rodata.*)
|
||||
_erodata = . ;
|
||||
}
|
||||
.data : {
|
||||
_data = . ;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
_edata = . ;
|
||||
}
|
||||
.bss : {
|
||||
_bss = . ;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
_end = . ;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -22,17 +23,17 @@
|
|||
*/
|
||||
static int read_mbr(u8 devno, void *buf)
|
||||
{
|
||||
u16 ax, bx, cx, dx;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
ax = 0x0201; /* Legacy Read, one sector */
|
||||
cx = 0x0001; /* Sector 0-0-1 */
|
||||
dx = devno;
|
||||
bx = (size_t)buf;
|
||||
asm volatile("pushfl; stc; int $0x13; setc %%al; popfl"
|
||||
: "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx)
|
||||
: : "esi", "edi", "memory");
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x0201; /* Legacy Read, one sector */
|
||||
ireg.cx = 0x0001; /* Sector 0-0-1 */
|
||||
ireg.dl = devno;
|
||||
ireg.bx = (size_t)buf;
|
||||
|
||||
return -(u8)ax; /* 0 or -1 */
|
||||
intcall(0x13, &ireg, &oreg);
|
||||
|
||||
return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
|
||||
}
|
||||
|
||||
static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
|
||||
|
@ -72,56 +73,46 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
|
|||
|
||||
static int get_edd_info(u8 devno, struct edd_info *ei)
|
||||
{
|
||||
u16 ax, bx, cx, dx, di;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
memset(ei, 0, sizeof *ei);
|
||||
|
||||
/* Check Extensions Present */
|
||||
|
||||
ax = 0x4100;
|
||||
bx = EDDMAGIC1;
|
||||
dx = devno;
|
||||
asm("pushfl; stc; int $0x13; setc %%al; popfl"
|
||||
: "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx)
|
||||
: : "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x41;
|
||||
ireg.bx = EDDMAGIC1;
|
||||
ireg.dl = devno;
|
||||
intcall(0x13, &ireg, &oreg);
|
||||
|
||||
if ((u8)ax)
|
||||
if (oreg.eflags & X86_EFLAGS_CF)
|
||||
return -1; /* No extended information */
|
||||
|
||||
if (bx != EDDMAGIC2)
|
||||
if (oreg.bx != EDDMAGIC2)
|
||||
return -1;
|
||||
|
||||
ei->device = devno;
|
||||
ei->version = ax >> 8; /* EDD version number */
|
||||
ei->interface_support = cx; /* EDD functionality subsets */
|
||||
ei->version = oreg.ah; /* EDD version number */
|
||||
ei->interface_support = oreg.cx; /* EDD functionality subsets */
|
||||
|
||||
/* Extended Get Device Parameters */
|
||||
|
||||
ei->params.length = sizeof(ei->params);
|
||||
ax = 0x4800;
|
||||
dx = devno;
|
||||
asm("pushfl; int $0x13; popfl"
|
||||
: "+a" (ax), "+d" (dx), "=m" (ei->params)
|
||||
: "S" (&ei->params)
|
||||
: "ebx", "ecx", "edi");
|
||||
ireg.ah = 0x48;
|
||||
ireg.si = (size_t)&ei->params;
|
||||
intcall(0x13, &ireg, &oreg);
|
||||
|
||||
/* Get legacy CHS parameters */
|
||||
|
||||
/* Ralf Brown recommends setting ES:DI to 0:0 */
|
||||
ax = 0x0800;
|
||||
dx = devno;
|
||||
di = 0;
|
||||
asm("pushw %%es; "
|
||||
"movw %%di,%%es; "
|
||||
"pushfl; stc; int $0x13; setc %%al; popfl; "
|
||||
"popw %%es"
|
||||
: "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di)
|
||||
: : "esi");
|
||||
ireg.ah = 0x08;
|
||||
ireg.es = 0;
|
||||
intcall(0x13, &ireg, &oreg);
|
||||
|
||||
if ((u8)ax == 0) {
|
||||
ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2);
|
||||
ei->legacy_max_head = dx >> 8;
|
||||
ei->legacy_sectors_per_track = cx & 0x3f;
|
||||
if (!(oreg.eflags & X86_EFLAGS_CF)) {
|
||||
ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2);
|
||||
ei->legacy_max_head = oreg.dh;
|
||||
ei->legacy_sectors_per_track = oreg.cl & 0x3f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include <asm/page_types.h>
|
||||
#include <asm/setup.h>
|
||||
#include "boot.h"
|
||||
#include "offsets.h"
|
||||
#include "voffset.h"
|
||||
#include "zoffset.h"
|
||||
|
||||
BOOTSEG = 0x07C0 /* original address of boot-sector */
|
||||
SYSSEG = 0x1000 /* historical load address >> 4 */
|
||||
|
@ -115,7 +116,7 @@ _start:
|
|||
# Part 2 of the header, from the old setup.S
|
||||
|
||||
.ascii "HdrS" # header signature
|
||||
.word 0x0209 # header version number (>= 0x0105)
|
||||
.word 0x020a # header version number (>= 0x0105)
|
||||
# or else old loadlin-1.5 will fail)
|
||||
.globl realmode_swtch
|
||||
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
|
||||
|
@ -168,7 +169,11 @@ heap_end_ptr: .word _end+STACK_SIZE-512
|
|||
# end of setup code can be used by setup
|
||||
# for local heap purposes.
|
||||
|
||||
pad1: .word 0
|
||||
ext_loader_ver:
|
||||
.byte 0 # Extended boot loader version
|
||||
ext_loader_type:
|
||||
.byte 0 # Extended boot loader type
|
||||
|
||||
cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
|
||||
# If nonzero, a 32-bit pointer
|
||||
# to the kernel command line.
|
||||
|
@ -200,7 +205,7 @@ relocatable_kernel: .byte 1
|
|||
#else
|
||||
relocatable_kernel: .byte 0
|
||||
#endif
|
||||
pad2: .byte 0
|
||||
min_alignment: .byte MIN_KERNEL_ALIGN_LG2 # minimum alignment
|
||||
pad3: .word 0
|
||||
|
||||
cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
|
||||
|
@ -212,16 +217,27 @@ hardware_subarch: .long 0 # subarchitecture, added with 2.07
|
|||
|
||||
hardware_subarch_data: .quad 0
|
||||
|
||||
payload_offset: .long input_data
|
||||
payload_length: .long input_data_end-input_data
|
||||
payload_offset: .long ZO_input_data
|
||||
payload_length: .long ZO_z_input_len
|
||||
|
||||
setup_data: .quad 0 # 64-bit physical pointer to
|
||||
# single linked list of
|
||||
# struct setup_data
|
||||
|
||||
pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
|
||||
|
||||
#define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_extract_offset)
|
||||
#define VO_INIT_SIZE (VO__end - VO__text)
|
||||
#if ZO_INIT_SIZE > VO_INIT_SIZE
|
||||
#define INIT_SIZE ZO_INIT_SIZE
|
||||
#else
|
||||
#define INIT_SIZE VO_INIT_SIZE
|
||||
#endif
|
||||
init_size: .long INIT_SIZE # kernel initialization size
|
||||
|
||||
# End of setup header #####################################################
|
||||
|
||||
.section ".inittext", "ax"
|
||||
.section ".entrytext", "ax"
|
||||
start_of_setup:
|
||||
#ifdef SAFE_RESET_DISK_CONTROLLER
|
||||
# Reset the disk controller.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -61,11 +62,10 @@ static void copy_boot_params(void)
|
|||
*/
|
||||
static void keyboard_set_repeat(void)
|
||||
{
|
||||
u16 ax = 0x0305;
|
||||
u16 bx = 0;
|
||||
asm volatile("int $0x16"
|
||||
: "+a" (ax), "+b" (bx)
|
||||
: : "ecx", "edx", "esi", "edi");
|
||||
struct biosregs ireg;
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x0305;
|
||||
intcall(0x16, &ireg, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -73,18 +73,22 @@ static void keyboard_set_repeat(void)
|
|||
*/
|
||||
static void query_ist(void)
|
||||
{
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
/* Some older BIOSes apparently crash on this call, so filter
|
||||
it from machines too old to have SpeedStep at all. */
|
||||
if (cpu.level < 6)
|
||||
return;
|
||||
|
||||
asm("int $0x15"
|
||||
: "=a" (boot_params.ist_info.signature),
|
||||
"=b" (boot_params.ist_info.command),
|
||||
"=c" (boot_params.ist_info.event),
|
||||
"=d" (boot_params.ist_info.perf_level)
|
||||
: "a" (0x0000e980), /* IST Support */
|
||||
"d" (0x47534943)); /* Request value */
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0xe980; /* IST Support */
|
||||
ireg.edx = 0x47534943; /* Request value */
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
boot_params.ist_info.signature = oreg.eax;
|
||||
boot_params.ist_info.command = oreg.ebx;
|
||||
boot_params.ist_info.event = oreg.ecx;
|
||||
boot_params.ist_info.perf_level = oreg.edx;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -93,13 +97,12 @@ static void query_ist(void)
|
|||
static void set_bios_mode(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
u32 eax, ebx;
|
||||
struct biosregs ireg;
|
||||
|
||||
eax = 0xec00;
|
||||
ebx = 2;
|
||||
asm volatile("int $0x15"
|
||||
: "+a" (eax), "+b" (ebx)
|
||||
: : "ecx", "edx", "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0xec00;
|
||||
ireg.bx = 2;
|
||||
intcall(0x15, &ireg, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -16,26 +17,22 @@
|
|||
|
||||
int query_mca(void)
|
||||
{
|
||||
u8 err;
|
||||
u16 es, bx, len;
|
||||
struct biosregs ireg, oreg;
|
||||
u16 len;
|
||||
|
||||
asm("pushw %%es ; "
|
||||
"int $0x15 ; "
|
||||
"setc %0 ; "
|
||||
"movw %%es, %1 ; "
|
||||
"popw %%es"
|
||||
: "=acd" (err), "=acdSD" (es), "=b" (bx)
|
||||
: "a" (0xc000));
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0xc0;
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
if (err)
|
||||
if (oreg.eflags & X86_EFLAGS_CF)
|
||||
return -1; /* No MCA present */
|
||||
|
||||
set_fs(es);
|
||||
len = rdfs16(bx);
|
||||
set_fs(oreg.es);
|
||||
len = rdfs16(oreg.bx);
|
||||
|
||||
if (len > sizeof(boot_params.sys_desc_table))
|
||||
len = sizeof(boot_params.sys_desc_table);
|
||||
|
||||
copy_from_fs(&boot_params.sys_desc_table, bx, len);
|
||||
copy_from_fs(&boot_params.sys_desc_table, oreg.bx, len);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,12 +20,16 @@
|
|||
static int detect_memory_e820(void)
|
||||
{
|
||||
int count = 0;
|
||||
u32 next = 0;
|
||||
u32 size, id, edi;
|
||||
u8 err;
|
||||
struct biosregs ireg, oreg;
|
||||
struct e820entry *desc = boot_params.e820_map;
|
||||
static struct e820entry buf; /* static so it is zeroed */
|
||||
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0xe820;
|
||||
ireg.cx = sizeof buf;
|
||||
ireg.edx = SMAP;
|
||||
ireg.di = (size_t)&buf;
|
||||
|
||||
/*
|
||||
* Note: at least one BIOS is known which assumes that the
|
||||
* buffer pointed to by one e820 call is the same one as
|
||||
|
@ -41,22 +45,13 @@ static int detect_memory_e820(void)
|
|||
*/
|
||||
|
||||
do {
|
||||
size = sizeof buf;
|
||||
|
||||
/* Important: %edx and %esi are clobbered by some BIOSes,
|
||||
so they must be either used for the error output
|
||||
or explicitly marked clobbered. Given that, assume there
|
||||
is something out there clobbering %ebp and %edi, too. */
|
||||
asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0"
|
||||
: "=d" (err), "+b" (next), "=a" (id), "+c" (size),
|
||||
"=D" (edi), "+m" (buf)
|
||||
: "D" (&buf), "d" (SMAP), "a" (0xe820)
|
||||
: "esi");
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
ireg.ebx = oreg.ebx; /* for next iteration... */
|
||||
|
||||
/* BIOSes which terminate the chain with CF = 1 as opposed
|
||||
to %ebx = 0 don't always report the SMAP signature on
|
||||
the final, failing, probe. */
|
||||
if (err)
|
||||
if (oreg.eflags & X86_EFLAGS_CF)
|
||||
break;
|
||||
|
||||
/* Some BIOSes stop returning SMAP in the middle of
|
||||
|
@ -64,60 +59,64 @@ static int detect_memory_e820(void)
|
|||
screwed up the map at that point, we might have a
|
||||
partial map, the full map, or complete garbage, so
|
||||
just return failure. */
|
||||
if (id != SMAP) {
|
||||
if (oreg.eax != SMAP) {
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*desc++ = buf;
|
||||
count++;
|
||||
} while (next && count < ARRAY_SIZE(boot_params.e820_map));
|
||||
} while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));
|
||||
|
||||
return boot_params.e820_entries = count;
|
||||
}
|
||||
|
||||
static int detect_memory_e801(void)
|
||||
{
|
||||
u16 ax, bx, cx, dx;
|
||||
u8 err;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
bx = cx = dx = 0;
|
||||
ax = 0xe801;
|
||||
asm("stc; int $0x15; setc %0"
|
||||
: "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0xe801;
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
if (err)
|
||||
if (oreg.eflags & X86_EFLAGS_CF)
|
||||
return -1;
|
||||
|
||||
/* Do we really need to do this? */
|
||||
if (cx || dx) {
|
||||
ax = cx;
|
||||
bx = dx;
|
||||
if (oreg.cx || oreg.dx) {
|
||||
oreg.ax = oreg.cx;
|
||||
oreg.bx = oreg.dx;
|
||||
}
|
||||
|
||||
if (ax > 15*1024)
|
||||
if (oreg.ax > 15*1024) {
|
||||
return -1; /* Bogus! */
|
||||
|
||||
/* This ignores memory above 16MB if we have a memory hole
|
||||
there. If someone actually finds a machine with a memory
|
||||
hole at 16MB and no support for 0E820h they should probably
|
||||
generate a fake e820 map. */
|
||||
boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax;
|
||||
} else if (oreg.ax == 15*1024) {
|
||||
boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax;
|
||||
} else {
|
||||
/*
|
||||
* This ignores memory above 16MB if we have a memory
|
||||
* hole there. If someone actually finds a machine
|
||||
* with a memory hole at 16MB and no support for
|
||||
* 0E820h they should probably generate a fake e820
|
||||
* map.
|
||||
*/
|
||||
boot_params.alt_mem_k = oreg.ax;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int detect_memory_88(void)
|
||||
{
|
||||
u16 ax;
|
||||
u8 err;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
ax = 0x8800;
|
||||
asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x88;
|
||||
intcall(0x15, &ireg, &oreg);
|
||||
|
||||
boot_params.screen_info.ext_mem_k = ax;
|
||||
boot_params.screen_info.ext_mem_k = oreg.ax;
|
||||
|
||||
return -err;
|
||||
return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
|
||||
}
|
||||
|
||||
int detect_memory(void)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* -----------------------------------------------------------------------
|
||||
*
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2 or (at your
|
||||
* option) any later version; incorporated herein by reference.
|
||||
*
|
||||
* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Simple helper function for initializing a register set.
|
||||
*
|
||||
* Note that this sets EFLAGS_CF in the input register set; this
|
||||
* makes it easier to catch functions which do nothing but don't
|
||||
* explicitly set CF.
|
||||
*/
|
||||
|
||||
#include "boot.h"
|
||||
|
||||
void initregs(struct biosregs *reg)
|
||||
{
|
||||
memset(reg, 0, sizeof *reg);
|
||||
reg->eflags |= X86_EFLAGS_CF;
|
||||
reg->ds = ds();
|
||||
reg->es = ds();
|
||||
reg->fs = fs();
|
||||
reg->gs = gs();
|
||||
}
|
|
@ -15,8 +15,11 @@ SECTIONS
|
|||
|
||||
. = 497;
|
||||
.header : { *(.header) }
|
||||
.entrytext : { *(.entrytext) }
|
||||
.inittext : { *(.inittext) }
|
||||
.initdata : { *(.initdata) }
|
||||
__end_init = .;
|
||||
|
||||
.text : { *(.text) }
|
||||
.text32 : { *(.text32) }
|
||||
|
||||
|
@ -52,4 +55,7 @@ SECTIONS
|
|||
|
||||
. = ASSERT(_end <= 0x8000, "Setup too big!");
|
||||
. = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
|
||||
/* Necessary for the very-old-loader check to work... */
|
||||
. = ASSERT(__end_init <= 5*512, "init sections too big!");
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -22,24 +23,23 @@
|
|||
|
||||
void __attribute__((section(".inittext"))) putchar(int ch)
|
||||
{
|
||||
unsigned char c = ch;
|
||||
struct biosregs ireg;
|
||||
|
||||
if (c == '\n')
|
||||
if (ch == '\n')
|
||||
putchar('\r'); /* \n -> \r\n */
|
||||
|
||||
/* int $0x10 is known to have bugs involving touching registers
|
||||
it shouldn't. Be extra conservative... */
|
||||
asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
|
||||
: : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
|
||||
initregs(&ireg);
|
||||
ireg.bx = 0x0007;
|
||||
ireg.cx = 0x0001;
|
||||
ireg.ah = 0x0e;
|
||||
ireg.al = ch;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
}
|
||||
|
||||
void __attribute__((section(".inittext"))) puts(const char *str)
|
||||
{
|
||||
int n = 0;
|
||||
while (*str) {
|
||||
while (*str)
|
||||
putchar(*str++);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -49,14 +49,13 @@ void __attribute__((section(".inittext"))) puts(const char *str)
|
|||
|
||||
static u8 gettime(void)
|
||||
{
|
||||
u16 ax = 0x0200;
|
||||
u16 cx, dx;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
asm volatile("int $0x1a"
|
||||
: "+a" (ax), "=c" (cx), "=d" (dx)
|
||||
: : "ebx", "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x02;
|
||||
intcall(0x1a, &ireg, &oreg);
|
||||
|
||||
return dx >> 8;
|
||||
return oreg.dh;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -64,19 +63,24 @@ static u8 gettime(void)
|
|||
*/
|
||||
int getchar(void)
|
||||
{
|
||||
u16 ax = 0;
|
||||
asm volatile("int $0x16" : "+a" (ax));
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
return ax & 0xff;
|
||||
initregs(&ireg);
|
||||
/* ireg.ah = 0x00; */
|
||||
intcall(0x16, &ireg, &oreg);
|
||||
|
||||
return oreg.al;
|
||||
}
|
||||
|
||||
static int kbd_pending(void)
|
||||
{
|
||||
u8 pending;
|
||||
asm volatile("int $0x16; setnz %0"
|
||||
: "=qm" (pending)
|
||||
: "a" (0x0100));
|
||||
return pending;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x01;
|
||||
intcall(0x16, &ireg, &oreg);
|
||||
|
||||
return !(oreg.eflags & X86_EFLAGS_ZF);
|
||||
}
|
||||
|
||||
void kbd_flush(void)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -29,21 +30,21 @@ static int bios_set_mode(struct mode_info *mi)
|
|||
|
||||
static int set_bios_mode(u8 mode)
|
||||
{
|
||||
u16 ax;
|
||||
struct biosregs ireg, oreg;
|
||||
u8 new_mode;
|
||||
|
||||
ax = mode; /* AH=0x00 Set Video Mode */
|
||||
asm volatile(INT10
|
||||
: "+a" (ax)
|
||||
: : "ebx", "ecx", "edx", "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.al = mode; /* AH=0x00 Set Video Mode */
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
ax = 0x0f00; /* Get Current Video Mode */
|
||||
asm volatile(INT10
|
||||
: "+a" (ax)
|
||||
: : "ebx", "ecx", "edx", "esi", "edi");
|
||||
|
||||
ireg.ah = 0x0f; /* Get Current Video Mode */
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
do_restore = 1; /* Assume video contents were lost */
|
||||
new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */
|
||||
|
||||
/* Not all BIOSes are clean with the top bit */
|
||||
new_mode = ireg.al & 0x7f;
|
||||
|
||||
if (new_mode == mode)
|
||||
return 0; /* Mode change OK */
|
||||
|
@ -53,10 +54,8 @@ static int set_bios_mode(u8 mode)
|
|||
/* Mode setting failed, but we didn't end up where we
|
||||
started. That's bad. Try to revert to the original
|
||||
video mode. */
|
||||
ax = boot_params.screen_info.orig_video_mode;
|
||||
asm volatile(INT10
|
||||
: "+a" (ax)
|
||||
: : "ebx", "ecx", "edx", "esi", "edi");
|
||||
ireg.ax = boot_params.screen_info.orig_video_mode;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -31,7 +32,7 @@ static inline void vesa_store_mode_params_graphics(void) {}
|
|||
static int vesa_probe(void)
|
||||
{
|
||||
#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
|
||||
u16 ax, cx, di;
|
||||
struct biosregs ireg, oreg;
|
||||
u16 mode;
|
||||
addr_t mode_ptr;
|
||||
struct mode_info *mi;
|
||||
|
@ -39,13 +40,12 @@ static int vesa_probe(void)
|
|||
|
||||
video_vesa.modes = GET_HEAP(struct mode_info, 0);
|
||||
|
||||
ax = 0x4f00;
|
||||
di = (size_t)&vginfo;
|
||||
asm(INT10
|
||||
: "+a" (ax), "+D" (di), "=m" (vginfo)
|
||||
: : "ebx", "ecx", "edx", "esi");
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x4f00;
|
||||
ireg.di = (size_t)&vginfo;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
if (ax != 0x004f ||
|
||||
if (ireg.ax != 0x004f ||
|
||||
vginfo.signature != VESA_MAGIC ||
|
||||
vginfo.version < 0x0102)
|
||||
return 0; /* Not present */
|
||||
|
@ -65,14 +65,12 @@ static int vesa_probe(void)
|
|||
|
||||
memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
|
||||
|
||||
ax = 0x4f01;
|
||||
cx = mode;
|
||||
di = (size_t)&vminfo;
|
||||
asm(INT10
|
||||
: "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
|
||||
: : "ebx", "edx", "esi");
|
||||
ireg.ax = 0x4f01;
|
||||
ireg.cx = mode;
|
||||
ireg.di = (size_t)&vminfo;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
if (ax != 0x004f)
|
||||
if (ireg.ax != 0x004f)
|
||||
continue;
|
||||
|
||||
if ((vminfo.mode_attr & 0x15) == 0x05) {
|
||||
|
@ -111,20 +109,19 @@ static int vesa_probe(void)
|
|||
|
||||
static int vesa_set_mode(struct mode_info *mode)
|
||||
{
|
||||
u16 ax, bx, cx, di;
|
||||
struct biosregs ireg, oreg;
|
||||
int is_graphic;
|
||||
u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA;
|
||||
|
||||
memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
|
||||
|
||||
ax = 0x4f01;
|
||||
cx = vesa_mode;
|
||||
di = (size_t)&vminfo;
|
||||
asm(INT10
|
||||
: "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
|
||||
: : "ebx", "edx", "esi");
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x4f01;
|
||||
ireg.cx = vesa_mode;
|
||||
ireg.di = (size_t)&vminfo;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
if (ax != 0x004f)
|
||||
if (oreg.ax != 0x004f)
|
||||
return -1;
|
||||
|
||||
if ((vminfo.mode_attr & 0x15) == 0x05) {
|
||||
|
@ -141,14 +138,12 @@ static int vesa_set_mode(struct mode_info *mode)
|
|||
}
|
||||
|
||||
|
||||
ax = 0x4f02;
|
||||
bx = vesa_mode;
|
||||
di = 0;
|
||||
asm volatile(INT10
|
||||
: "+a" (ax), "+b" (bx), "+D" (di)
|
||||
: : "ecx", "edx", "esi");
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x4f02;
|
||||
ireg.bx = vesa_mode;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
if (ax != 0x004f)
|
||||
if (oreg.ax != 0x004f)
|
||||
return -1;
|
||||
|
||||
graphic_mode = is_graphic;
|
||||
|
@ -171,50 +166,45 @@ static int vesa_set_mode(struct mode_info *mode)
|
|||
/* Switch DAC to 8-bit mode */
|
||||
static void vesa_dac_set_8bits(void)
|
||||
{
|
||||
struct biosregs ireg, oreg;
|
||||
u8 dac_size = 6;
|
||||
|
||||
/* If possible, switch the DAC to 8-bit mode */
|
||||
if (vginfo.capabilities & 1) {
|
||||
u16 ax, bx;
|
||||
|
||||
ax = 0x4f08;
|
||||
bx = 0x0800;
|
||||
asm volatile(INT10
|
||||
: "+a" (ax), "+b" (bx)
|
||||
: : "ecx", "edx", "esi", "edi");
|
||||
|
||||
if (ax == 0x004f)
|
||||
dac_size = bx >> 8;
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x4f08;
|
||||
ireg.bh = 0x08;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
if (oreg.ax == 0x004f)
|
||||
dac_size = oreg.bh;
|
||||
}
|
||||
|
||||
/* Set the color sizes to the DAC size, and offsets to 0 */
|
||||
boot_params.screen_info.red_size = dac_size;
|
||||
boot_params.screen_info.red_size = dac_size;
|
||||
boot_params.screen_info.green_size = dac_size;
|
||||
boot_params.screen_info.blue_size = dac_size;
|
||||
boot_params.screen_info.rsvd_size = dac_size;
|
||||
boot_params.screen_info.blue_size = dac_size;
|
||||
boot_params.screen_info.rsvd_size = dac_size;
|
||||
|
||||
boot_params.screen_info.red_pos = 0;
|
||||
boot_params.screen_info.green_pos = 0;
|
||||
boot_params.screen_info.blue_pos = 0;
|
||||
boot_params.screen_info.rsvd_pos = 0;
|
||||
boot_params.screen_info.red_pos = 0;
|
||||
boot_params.screen_info.green_pos = 0;
|
||||
boot_params.screen_info.blue_pos = 0;
|
||||
boot_params.screen_info.rsvd_pos = 0;
|
||||
}
|
||||
|
||||
/* Save the VESA protected mode info */
|
||||
static void vesa_store_pm_info(void)
|
||||
{
|
||||
u16 ax, bx, di, es;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
ax = 0x4f0a;
|
||||
bx = di = 0;
|
||||
asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es"
|
||||
: "=d" (es), "+a" (ax), "+b" (bx), "+D" (di)
|
||||
: : "ecx", "esi");
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x4f0a;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
if (ax != 0x004f)
|
||||
if (oreg.ax != 0x004f)
|
||||
return;
|
||||
|
||||
boot_params.screen_info.vesapm_seg = es;
|
||||
boot_params.screen_info.vesapm_off = di;
|
||||
boot_params.screen_info.vesapm_seg = oreg.es;
|
||||
boot_params.screen_info.vesapm_off = oreg.di;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -252,7 +242,7 @@ static void vesa_store_mode_params_graphics(void)
|
|||
void vesa_store_edid(void)
|
||||
{
|
||||
#ifdef CONFIG_FIRMWARE_EDID
|
||||
u16 ax, bx, cx, dx, di;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
/* Apparently used as a nonsense token... */
|
||||
memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info);
|
||||
|
@ -260,33 +250,26 @@ void vesa_store_edid(void)
|
|||
if (vginfo.version < 0x0200)
|
||||
return; /* EDID requires VBE 2.0+ */
|
||||
|
||||
ax = 0x4f15; /* VBE DDC */
|
||||
bx = 0x0000; /* Report DDC capabilities */
|
||||
cx = 0; /* Controller 0 */
|
||||
di = 0; /* ES:DI must be 0 by spec */
|
||||
initregs(&ireg);
|
||||
ireg.ax = 0x4f15; /* VBE DDC */
|
||||
/* ireg.bx = 0x0000; */ /* Report DDC capabilities */
|
||||
/* ireg.cx = 0; */ /* Controller 0 */
|
||||
ireg.es = 0; /* ES:DI must be 0 by spec */
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
/* Note: The VBE DDC spec is different from the main VESA spec;
|
||||
we genuinely have to assume all registers are destroyed here. */
|
||||
|
||||
asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
|
||||
: "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di)
|
||||
: : "esi", "edx");
|
||||
|
||||
if (ax != 0x004f)
|
||||
if (oreg.ax != 0x004f)
|
||||
return; /* No EDID */
|
||||
|
||||
/* BH = time in seconds to transfer EDD information */
|
||||
/* BL = DDC level supported */
|
||||
|
||||
ax = 0x4f15; /* VBE DDC */
|
||||
bx = 0x0001; /* Read EDID */
|
||||
cx = 0; /* Controller 0 */
|
||||
dx = 0; /* EDID block number */
|
||||
di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
|
||||
asm(INT10
|
||||
: "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info),
|
||||
"+c" (cx), "+D" (di)
|
||||
: : "esi");
|
||||
ireg.ax = 0x4f15; /* VBE DDC */
|
||||
ireg.bx = 0x0001; /* Read EDID */
|
||||
/* ireg.cx = 0; */ /* Controller 0 */
|
||||
/* ireg.dx = 0; */ /* EDID block number */
|
||||
ireg.es = ds();
|
||||
ireg.di =(size_t)&boot_params.edid_info; /* (ES:)Pointer to block */
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
#endif /* CONFIG_FIRMWARE_EDID */
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -39,30 +40,30 @@ static __videocard video_vga;
|
|||
/* Set basic 80x25 mode */
|
||||
static u8 vga_set_basic_mode(void)
|
||||
{
|
||||
struct biosregs ireg, oreg;
|
||||
u16 ax;
|
||||
u8 rows;
|
||||
u8 mode;
|
||||
|
||||
initregs(&ireg);
|
||||
|
||||
#ifdef CONFIG_VIDEO_400_HACK
|
||||
if (adapter >= ADAPTER_VGA) {
|
||||
asm volatile(INT10
|
||||
: : "a" (0x1202), "b" (0x0030)
|
||||
: "ecx", "edx", "esi", "edi");
|
||||
ireg.ax = 0x1202;
|
||||
ireg.bx = 0x0030;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
ax = 0x0f00;
|
||||
asm volatile(INT10
|
||||
: "+a" (ax)
|
||||
: : "ebx", "ecx", "edx", "esi", "edi");
|
||||
|
||||
mode = (u8)ax;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
mode = oreg.al;
|
||||
|
||||
set_fs(0);
|
||||
rows = rdfs8(0x484); /* rows minus one */
|
||||
|
||||
#ifndef CONFIG_VIDEO_400_HACK
|
||||
if ((ax == 0x5003 || ax == 0x5007) &&
|
||||
if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) &&
|
||||
(rows == 0 || rows == 24))
|
||||
return mode;
|
||||
#endif
|
||||
|
@ -71,10 +72,8 @@ static u8 vga_set_basic_mode(void)
|
|||
mode = 3;
|
||||
|
||||
/* Set the mode */
|
||||
ax = mode;
|
||||
asm volatile(INT10
|
||||
: "+a" (ax)
|
||||
: : "ebx", "ecx", "edx", "esi", "edi");
|
||||
ireg.ax = mode; /* AH=0: set mode */
|
||||
intcall(0x10, &ireg, NULL);
|
||||
do_restore = 1;
|
||||
return mode;
|
||||
}
|
||||
|
@ -82,43 +81,69 @@ static u8 vga_set_basic_mode(void)
|
|||
static void vga_set_8font(void)
|
||||
{
|
||||
/* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
|
||||
struct biosregs ireg;
|
||||
|
||||
initregs(&ireg);
|
||||
|
||||
/* Set 8x8 font */
|
||||
asm volatile(INT10 : : "a" (0x1112), "b" (0));
|
||||
ireg.ax = 0x1112;
|
||||
/* ireg.bl = 0; */
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
/* Use alternate print screen */
|
||||
asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
|
||||
ireg.ax = 0x1200;
|
||||
ireg.bl = 0x20;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
/* Turn off cursor emulation */
|
||||
asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
|
||||
ireg.ax = 0x1201;
|
||||
ireg.bl = 0x34;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
/* Cursor is scan lines 6-7 */
|
||||
asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
|
||||
ireg.ax = 0x0100;
|
||||
ireg.cx = 0x0607;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
}
|
||||
|
||||
static void vga_set_14font(void)
|
||||
{
|
||||
/* Set 9x14 font - 80x28 on VGA */
|
||||
struct biosregs ireg;
|
||||
|
||||
initregs(&ireg);
|
||||
|
||||
/* Set 9x14 font */
|
||||
asm volatile(INT10 : : "a" (0x1111), "b" (0));
|
||||
ireg.ax = 0x1111;
|
||||
/* ireg.bl = 0; */
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
/* Turn off cursor emulation */
|
||||
asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
|
||||
ireg.ax = 0x1201;
|
||||
ireg.bl = 0x34;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
/* Cursor is scan lines 11-12 */
|
||||
asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
|
||||
ireg.ax = 0x0100;
|
||||
ireg.cx = 0x0b0c;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
}
|
||||
|
||||
static void vga_set_80x43(void)
|
||||
{
|
||||
/* Set 80x43 mode on VGA (not EGA) */
|
||||
struct biosregs ireg;
|
||||
|
||||
initregs(&ireg);
|
||||
|
||||
/* Set 350 scans */
|
||||
asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
|
||||
ireg.ax = 0x1201;
|
||||
ireg.bl = 0x30;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
/* Reset video mode */
|
||||
asm volatile(INT10 : : "a" (0x0003));
|
||||
ireg.ax = 0x0003;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
|
||||
vga_set_8font();
|
||||
}
|
||||
|
@ -225,8 +250,6 @@ static int vga_set_mode(struct mode_info *mode)
|
|||
*/
|
||||
static int vga_probe(void)
|
||||
{
|
||||
u16 ega_bx;
|
||||
|
||||
static const char *card_name[] = {
|
||||
"CGA/MDA/HGC", "EGA", "VGA"
|
||||
};
|
||||
|
@ -240,26 +263,26 @@ static int vga_probe(void)
|
|||
sizeof(ega_modes)/sizeof(struct mode_info),
|
||||
sizeof(vga_modes)/sizeof(struct mode_info),
|
||||
};
|
||||
u8 vga_flag;
|
||||
|
||||
asm(INT10
|
||||
: "=b" (ega_bx)
|
||||
: "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
|
||||
: "ecx", "edx", "esi", "edi");
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
initregs(&ireg);
|
||||
|
||||
ireg.ax = 0x1200;
|
||||
ireg.bl = 0x10; /* Check EGA/VGA */
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
#ifndef _WAKEUP
|
||||
boot_params.screen_info.orig_video_ega_bx = ega_bx;
|
||||
boot_params.screen_info.orig_video_ega_bx = oreg.bx;
|
||||
#endif
|
||||
|
||||
/* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
|
||||
if ((u8)ega_bx != 0x10) {
|
||||
if (oreg.bl != 0x10) {
|
||||
/* EGA/VGA */
|
||||
asm(INT10
|
||||
: "=a" (vga_flag)
|
||||
: "a" (0x1a00)
|
||||
: "ebx", "ecx", "edx", "esi", "edi");
|
||||
ireg.ax = 0x1a00;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
if (vga_flag == 0x1a) {
|
||||
if (oreg.al == 0x1a) {
|
||||
adapter = ADAPTER_VGA;
|
||||
#ifndef _WAKEUP
|
||||
boot_params.screen_info.orig_video_isVGA = 1;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
* Copyright 2009 Intel Corporation; author H. Peter Anvin
|
||||
*
|
||||
* This file is part of the Linux kernel, and is made available under
|
||||
* the terms of the GNU General Public License version 2.
|
||||
|
@ -18,33 +19,29 @@
|
|||
|
||||
static void store_cursor_position(void)
|
||||
{
|
||||
u16 curpos;
|
||||
u16 ax, bx;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
ax = 0x0300;
|
||||
bx = 0;
|
||||
asm(INT10
|
||||
: "=d" (curpos), "+a" (ax), "+b" (bx)
|
||||
: : "ecx", "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x03;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
boot_params.screen_info.orig_x = curpos;
|
||||
boot_params.screen_info.orig_y = curpos >> 8;
|
||||
boot_params.screen_info.orig_x = oreg.dl;
|
||||
boot_params.screen_info.orig_y = oreg.dh;
|
||||
}
|
||||
|
||||
static void store_video_mode(void)
|
||||
{
|
||||
u16 ax, page;
|
||||
struct biosregs ireg, oreg;
|
||||
|
||||
/* N.B.: the saving of the video page here is a bit silly,
|
||||
since we pretty much assume page 0 everywhere. */
|
||||
ax = 0x0f00;
|
||||
asm(INT10
|
||||
: "+a" (ax), "=b" (page)
|
||||
: : "ecx", "edx", "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x0f;
|
||||
intcall(0x10, &ireg, &oreg);
|
||||
|
||||
/* Not all BIOSes are clean with respect to the top bit */
|
||||
boot_params.screen_info.orig_video_mode = ax & 0x7f;
|
||||
boot_params.screen_info.orig_video_page = page >> 8;
|
||||
boot_params.screen_info.orig_video_mode = oreg.al & 0x7f;
|
||||
boot_params.screen_info.orig_video_page = oreg.bh;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -257,7 +254,7 @@ static void restore_screen(void)
|
|||
int y;
|
||||
addr_t dst = 0;
|
||||
u16 *src = saved.data;
|
||||
u16 ax, bx, dx;
|
||||
struct biosregs ireg;
|
||||
|
||||
if (graphic_mode)
|
||||
return; /* Can't restore onto a graphic mode */
|
||||
|
@ -296,12 +293,11 @@ static void restore_screen(void)
|
|||
}
|
||||
|
||||
/* Restore cursor position */
|
||||
ax = 0x0200; /* Set cursor position */
|
||||
bx = 0; /* Page number (<< 8) */
|
||||
dx = (saved.cury << 8)+saved.curx;
|
||||
asm volatile(INT10
|
||||
: "+a" (ax), "+b" (bx), "+d" (dx)
|
||||
: : "ecx", "esi", "edi");
|
||||
initregs(&ireg);
|
||||
ireg.ah = 0x02; /* Set cursor position */
|
||||
ireg.dh = saved.cury;
|
||||
ireg.dl = saved.curx;
|
||||
intcall(0x10, &ireg, NULL);
|
||||
}
|
||||
#else
|
||||
#define save_screen() ((void)0)
|
||||
|
|
|
@ -112,20 +112,6 @@ extern int force_x, force_y; /* Don't query the BIOS for cols/rows */
|
|||
extern int do_restore; /* Restore screen contents */
|
||||
extern int graphic_mode; /* Graphics mode with linear frame buffer */
|
||||
|
||||
/*
|
||||
* int $0x10 is notorious for touching registers it shouldn't.
|
||||
* gcc doesn't like %ebp being clobbered, so define it as a push/pop
|
||||
* sequence here.
|
||||
*
|
||||
* A number of systems, including the original PC can clobber %bp in
|
||||
* certain circumstances, like when scrolling. There exists at least
|
||||
* one Trident video card which could clobber DS under a set of
|
||||
* circumstances that we are unlikely to encounter (scrolling when
|
||||
* using an extended graphics mode of more than 800x600 pixels), but
|
||||
* it's cheap insurance to deal with that here.
|
||||
*/
|
||||
#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
|
||||
|
||||
/* Accessing VGA indexed registers */
|
||||
static inline u8 in_idx(u16 port, u8 index)
|
||||
{
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.29-rc4
|
||||
# Tue Feb 24 15:50:58 2009
|
||||
# Linux kernel version: 2.6.30-rc2
|
||||
# Mon May 11 16:21:55 2009
|
||||
#
|
||||
# CONFIG_64BIT is not set
|
||||
CONFIG_X86_32=y
|
||||
# CONFIG_X86_64 is not set
|
||||
CONFIG_X86=y
|
||||
CONFIG_OUTPUT_FORMAT="elf32-i386"
|
||||
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
|
||||
CONFIG_GENERIC_TIME=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
|
@ -33,6 +34,7 @@ CONFIG_ARCH_HAS_CPU_RELAX=y
|
|||
CONFIG_ARCH_HAS_DEFAULT_IDLE=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
|
||||
CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y
|
||||
# CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
|
@ -40,15 +42,16 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
|||
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
||||
# CONFIG_AUDIT_ARCH is not set
|
||||
CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
|
||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||
CONFIG_GENERIC_HARDIRQS=y
|
||||
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
|
||||
CONFIG_GENERIC_IRQ_PROBE=y
|
||||
CONFIG_GENERIC_PENDING_IRQ=y
|
||||
CONFIG_X86_SMP=y
|
||||
CONFIG_USE_GENERIC_SMP_HELPERS=y
|
||||
CONFIG_X86_32_SMP=y
|
||||
CONFIG_X86_HT=y
|
||||
CONFIG_X86_BIOS_REBOOT=y
|
||||
CONFIG_X86_TRAMPOLINE=y
|
||||
CONFIG_X86_32_LAZY_GS=y
|
||||
CONFIG_KTIME_SCALAR=y
|
||||
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
|
||||
|
||||
|
@ -60,10 +63,17 @@ CONFIG_LOCK_KERNEL=y
|
|||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||
CONFIG_LOCALVERSION=""
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_HAVE_KERNEL_GZIP=y
|
||||
CONFIG_HAVE_KERNEL_BZIP2=y
|
||||
CONFIG_HAVE_KERNEL_LZMA=y
|
||||
CONFIG_KERNEL_GZIP=y
|
||||
# CONFIG_KERNEL_BZIP2 is not set
|
||||
# CONFIG_KERNEL_LZMA is not set
|
||||
CONFIG_SWAP=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_SYSVIPC_SYSCTL=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_POSIX_MQUEUE_SYSCTL=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
|
||||
CONFIG_TASKSTATS=y
|
||||
|
@ -113,23 +123,26 @@ CONFIG_PID_NS=y
|
|||
CONFIG_NET_NS=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_RD_GZIP=y
|
||||
CONFIG_RD_BZIP2=y
|
||||
CONFIG_RD_LZMA=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_ANON_INODES=y
|
||||
# CONFIG_EMBEDDED is not set
|
||||
CONFIG_UID16=y
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_KALLSYMS=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_KALLSYMS_EXTRA_PASS=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_HOTPLUG=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_BUG=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_PCSPKR_PLATFORM=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_BASE_FULL=y
|
||||
CONFIG_FUTEX=y
|
||||
CONFIG_ANON_INODES=y
|
||||
CONFIG_EPOLL=y
|
||||
CONFIG_SIGNALFD=y
|
||||
CONFIG_TIMERFD=y
|
||||
|
@ -139,6 +152,7 @@ CONFIG_AIO=y
|
|||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
CONFIG_PCI_QUIRKS=y
|
||||
CONFIG_SLUB_DEBUG=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
# CONFIG_SLAB is not set
|
||||
CONFIG_SLUB=y
|
||||
# CONFIG_SLOB is not set
|
||||
|
@ -154,6 +168,8 @@ CONFIG_HAVE_IOREMAP_PROT=y
|
|||
CONFIG_HAVE_KPROBES=y
|
||||
CONFIG_HAVE_KRETPROBES=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
# CONFIG_SLOW_WORK is not set
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
CONFIG_SLABINFO=y
|
||||
CONFIG_RT_MUTEXES=y
|
||||
|
@ -167,7 +183,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
|
|||
CONFIG_STOP_MACHINE=y
|
||||
CONFIG_BLOCK=y
|
||||
# CONFIG_LBD is not set
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_BLK_DEV_BSG=y
|
||||
# CONFIG_BLK_DEV_INTEGRITY is not set
|
||||
|
||||
|
@ -194,12 +209,12 @@ CONFIG_HIGH_RES_TIMERS=y
|
|||
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_X86_FIND_SMP_CONFIG=y
|
||||
CONFIG_X86_MPPARSE=y
|
||||
# CONFIG_X86_BIGSMP is not set
|
||||
CONFIG_X86_EXTENDED_PLATFORM=y
|
||||
# CONFIG_X86_ELAN is not set
|
||||
# CONFIG_X86_GENERICARCH is not set
|
||||
# CONFIG_X86_VSMP is not set
|
||||
# CONFIG_X86_RDC321X is not set
|
||||
# CONFIG_X86_32_NON_STANDARD is not set
|
||||
CONFIG_SCHED_OMIT_FRAME_POINTER=y
|
||||
# CONFIG_PARAVIRT_GUEST is not set
|
||||
# CONFIG_MEMTEST is not set
|
||||
|
@ -230,8 +245,10 @@ CONFIG_M686=y
|
|||
# CONFIG_GENERIC_CPU is not set
|
||||
CONFIG_X86_GENERIC=y
|
||||
CONFIG_X86_CPU=y
|
||||
CONFIG_X86_L1_CACHE_BYTES=64
|
||||
CONFIG_X86_INTERNODE_CACHE_BYTES=64
|
||||
CONFIG_X86_CMPXCHG=y
|
||||
CONFIG_X86_L1_CACHE_SHIFT=7
|
||||
CONFIG_X86_L1_CACHE_SHIFT=5
|
||||
CONFIG_X86_XADD=y
|
||||
# CONFIG_X86_PPRO_FENCE is not set
|
||||
CONFIG_X86_WP_WORKS_OK=y
|
||||
|
@ -247,7 +264,7 @@ CONFIG_X86_DEBUGCTLMSR=y
|
|||
CONFIG_CPU_SUP_INTEL=y
|
||||
CONFIG_CPU_SUP_CYRIX_32=y
|
||||
CONFIG_CPU_SUP_AMD=y
|
||||
CONFIG_CPU_SUP_CENTAUR_32=y
|
||||
CONFIG_CPU_SUP_CENTAUR=y
|
||||
CONFIG_CPU_SUP_TRANSMETA_32=y
|
||||
CONFIG_CPU_SUP_UMC_32=y
|
||||
CONFIG_X86_DS=y
|
||||
|
@ -279,6 +296,7 @@ CONFIG_MICROCODE_AMD=y
|
|||
CONFIG_MICROCODE_OLD_INTERFACE=y
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
# CONFIG_X86_CPU_DEBUG is not set
|
||||
# CONFIG_NOHIGHMEM is not set
|
||||
CONFIG_HIGHMEM4G=y
|
||||
# CONFIG_HIGHMEM64G is not set
|
||||
|
@ -302,6 +320,8 @@ CONFIG_ZONE_DMA_FLAG=1
|
|||
CONFIG_BOUNCE=y
|
||||
CONFIG_VIRT_TO_BUS=y
|
||||
CONFIG_UNEVICTABLE_LRU=y
|
||||
CONFIG_HAVE_MLOCK=y
|
||||
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
|
||||
CONFIG_HIGHPTE=y
|
||||
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
|
||||
CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
|
||||
|
@ -312,6 +332,7 @@ CONFIG_MTRR=y
|
|||
CONFIG_X86_PAT=y
|
||||
CONFIG_EFI=y
|
||||
CONFIG_SECCOMP=y
|
||||
# CONFIG_CC_STACKPROTECTOR is not set
|
||||
# CONFIG_HZ_100 is not set
|
||||
# CONFIG_HZ_250 is not set
|
||||
# CONFIG_HZ_300 is not set
|
||||
|
@ -322,8 +343,9 @@ CONFIG_KEXEC=y
|
|||
CONFIG_CRASH_DUMP=y
|
||||
# CONFIG_KEXEC_JUMP is not set
|
||||
CONFIG_PHYSICAL_START=0x1000000
|
||||
# CONFIG_RELOCATABLE is not set
|
||||
CONFIG_PHYSICAL_ALIGN=0x200000
|
||||
CONFIG_RELOCATABLE=y
|
||||
CONFIG_X86_NEED_RELOCS=y
|
||||
CONFIG_PHYSICAL_ALIGN=0x1000000
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
# CONFIG_COMPAT_VDSO is not set
|
||||
# CONFIG_CMDLINE_BOOL is not set
|
||||
|
@ -363,7 +385,6 @@ CONFIG_ACPI_THERMAL=y
|
|||
CONFIG_ACPI_BLACKLIST_YEAR=0
|
||||
# CONFIG_ACPI_DEBUG is not set
|
||||
# CONFIG_ACPI_PCI_SLOT is not set
|
||||
CONFIG_ACPI_SYSTEM=y
|
||||
CONFIG_X86_PM_TIMER=y
|
||||
CONFIG_ACPI_CONTAINER=y
|
||||
# CONFIG_ACPI_SBS is not set
|
||||
|
@ -425,6 +446,7 @@ CONFIG_PCI_BIOS=y
|
|||
CONFIG_PCI_DIRECT=y
|
||||
CONFIG_PCI_MMCONFIG=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
# CONFIG_DMAR is not set
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
# CONFIG_HOTPLUG_PCI_PCIE is not set
|
||||
CONFIG_PCIEAER=y
|
||||
|
@ -435,6 +457,7 @@ CONFIG_PCI_MSI=y
|
|||
# CONFIG_PCI_DEBUG is not set
|
||||
# CONFIG_PCI_STUB is not set
|
||||
CONFIG_HT_IRQ=y
|
||||
# CONFIG_PCI_IOV is not set
|
||||
CONFIG_ISA_DMA_API=y
|
||||
# CONFIG_ISA is not set
|
||||
# CONFIG_MCA is not set
|
||||
|
@ -481,7 +504,6 @@ CONFIG_NET=y
|
|||
#
|
||||
# Networking options
|
||||
#
|
||||
CONFIG_COMPAT_NET_DEV_OPS=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_PACKET_MMAP=y
|
||||
CONFIG_UNIX=y
|
||||
|
@ -639,6 +661,7 @@ CONFIG_LLC=y
|
|||
# CONFIG_LAPB is not set
|
||||
# CONFIG_ECONET is not set
|
||||
# CONFIG_WAN_ROUTER is not set
|
||||
# CONFIG_PHONET is not set
|
||||
CONFIG_NET_SCHED=y
|
||||
|
||||
#
|
||||
|
@ -696,6 +719,7 @@ CONFIG_NET_SCH_FIFO=y
|
|||
#
|
||||
# CONFIG_NET_PKTGEN is not set
|
||||
# CONFIG_NET_TCPPROBE is not set
|
||||
# CONFIG_NET_DROP_MONITOR is not set
|
||||
CONFIG_HAMRADIO=y
|
||||
|
||||
#
|
||||
|
@ -706,12 +730,10 @@ CONFIG_HAMRADIO=y
|
|||
# CONFIG_IRDA is not set
|
||||
# CONFIG_BT is not set
|
||||
# CONFIG_AF_RXRPC is not set
|
||||
# CONFIG_PHONET is not set
|
||||
CONFIG_FIB_RULES=y
|
||||
CONFIG_WIRELESS=y
|
||||
CONFIG_CFG80211=y
|
||||
# CONFIG_CFG80211_REG_DEBUG is not set
|
||||
CONFIG_NL80211=y
|
||||
CONFIG_WIRELESS_OLD_REGULATORY=y
|
||||
CONFIG_WIRELESS_EXT=y
|
||||
CONFIG_WIRELESS_EXT_SYSFS=y
|
||||
|
@ -789,6 +811,7 @@ CONFIG_MISC_DEVICES=y
|
|||
# CONFIG_ICS932S401 is not set
|
||||
# CONFIG_ENCLOSURE_SERVICES is not set
|
||||
# CONFIG_HP_ILO is not set
|
||||
# CONFIG_ISL29003 is not set
|
||||
# CONFIG_C2PORT is not set
|
||||
|
||||
#
|
||||
|
@ -842,6 +865,7 @@ CONFIG_SCSI_SPI_ATTRS=y
|
|||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
|
||||
# CONFIG_SCSI_DH is not set
|
||||
# CONFIG_SCSI_OSD_INITIATOR is not set
|
||||
CONFIG_ATA=y
|
||||
# CONFIG_ATA_NONSTANDARD is not set
|
||||
CONFIG_ATA_ACPI=y
|
||||
|
@ -940,6 +964,7 @@ CONFIG_DM_ZERO=y
|
|||
CONFIG_MACINTOSH_DRIVERS=y
|
||||
CONFIG_MAC_EMUMOUSEBTN=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_COMPAT_NET_DEV_OPS=y
|
||||
# CONFIG_IFB is not set
|
||||
# CONFIG_DUMMY is not set
|
||||
# CONFIG_BONDING is not set
|
||||
|
@ -977,6 +1002,8 @@ CONFIG_MII=y
|
|||
CONFIG_NET_VENDOR_3COM=y
|
||||
# CONFIG_VORTEX is not set
|
||||
# CONFIG_TYPHOON is not set
|
||||
# CONFIG_ETHOC is not set
|
||||
# CONFIG_DNET is not set
|
||||
CONFIG_NET_TULIP=y
|
||||
# CONFIG_DE2104X is not set
|
||||
# CONFIG_TULIP is not set
|
||||
|
@ -1026,6 +1053,7 @@ CONFIG_E1000=y
|
|||
CONFIG_E1000E=y
|
||||
# CONFIG_IP1000 is not set
|
||||
# CONFIG_IGB is not set
|
||||
# CONFIG_IGBVF is not set
|
||||
# CONFIG_NS83820 is not set
|
||||
# CONFIG_HAMACHI is not set
|
||||
# CONFIG_YELLOWFIN is not set
|
||||
|
@ -1040,6 +1068,7 @@ CONFIG_BNX2=y
|
|||
# CONFIG_QLA3XXX is not set
|
||||
# CONFIG_ATL1 is not set
|
||||
# CONFIG_ATL1E is not set
|
||||
# CONFIG_ATL1C is not set
|
||||
# CONFIG_JME is not set
|
||||
CONFIG_NETDEV_10000=y
|
||||
# CONFIG_CHELSIO_T1 is not set
|
||||
|
@ -1049,6 +1078,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
|
|||
# CONFIG_IXGBE is not set
|
||||
# CONFIG_IXGB is not set
|
||||
# CONFIG_S2IO is not set
|
||||
# CONFIG_VXGE is not set
|
||||
# CONFIG_MYRI10GE is not set
|
||||
# CONFIG_NETXEN_NIC is not set
|
||||
# CONFIG_NIU is not set
|
||||
|
@ -1058,6 +1088,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
|
|||
# CONFIG_BNX2X is not set
|
||||
# CONFIG_QLGE is not set
|
||||
# CONFIG_SFC is not set
|
||||
# CONFIG_BE2NET is not set
|
||||
CONFIG_TR=y
|
||||
# CONFIG_IBMOL is not set
|
||||
# CONFIG_IBMLS is not set
|
||||
|
@ -1073,8 +1104,8 @@ CONFIG_WLAN_80211=y
|
|||
# CONFIG_LIBERTAS is not set
|
||||
# CONFIG_LIBERTAS_THINFIRM is not set
|
||||
# CONFIG_AIRO is not set
|
||||
# CONFIG_HERMES is not set
|
||||
# CONFIG_ATMEL is not set
|
||||
# CONFIG_AT76C50X_USB is not set
|
||||
# CONFIG_AIRO_CS is not set
|
||||
# CONFIG_PCMCIA_WL3501 is not set
|
||||
# CONFIG_PRISM54 is not set
|
||||
|
@ -1084,21 +1115,21 @@ CONFIG_WLAN_80211=y
|
|||
# CONFIG_RTL8187 is not set
|
||||
# CONFIG_ADM8211 is not set
|
||||
# CONFIG_MAC80211_HWSIM is not set
|
||||
# CONFIG_MWL8K is not set
|
||||
# CONFIG_P54_COMMON is not set
|
||||
CONFIG_ATH5K=y
|
||||
# CONFIG_ATH5K_DEBUG is not set
|
||||
# CONFIG_ATH9K is not set
|
||||
# CONFIG_AR9170_USB is not set
|
||||
# CONFIG_IPW2100 is not set
|
||||
# CONFIG_IPW2200 is not set
|
||||
# CONFIG_IWLCORE is not set
|
||||
# CONFIG_IWLWIFI_LEDS is not set
|
||||
# CONFIG_IWLAGN is not set
|
||||
# CONFIG_IWL3945 is not set
|
||||
# CONFIG_IWLWIFI is not set
|
||||
# CONFIG_HOSTAP is not set
|
||||
# CONFIG_B43 is not set
|
||||
# CONFIG_B43LEGACY is not set
|
||||
# CONFIG_ZD1211RW is not set
|
||||
# CONFIG_RT2X00 is not set
|
||||
# CONFIG_HERMES is not set
|
||||
|
||||
#
|
||||
# Enable WiMAX (Networking options) to see the WiMAX drivers
|
||||
|
@ -1209,6 +1240,8 @@ CONFIG_INPUT_TABLET=y
|
|||
# CONFIG_TABLET_USB_KBTAB is not set
|
||||
# CONFIG_TABLET_USB_WACOM is not set
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
|
||||
# CONFIG_TOUCHSCREEN_AD7879 is not set
|
||||
# CONFIG_TOUCHSCREEN_FUJITSU is not set
|
||||
# CONFIG_TOUCHSCREEN_GUNZE is not set
|
||||
# CONFIG_TOUCHSCREEN_ELO is not set
|
||||
|
@ -1303,6 +1336,7 @@ CONFIG_UNIX98_PTYS=y
|
|||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_IPMI_HANDLER is not set
|
||||
CONFIG_HW_RANDOM=y
|
||||
# CONFIG_HW_RANDOM_TIMERIOMEM is not set
|
||||
CONFIG_HW_RANDOM_INTEL=y
|
||||
CONFIG_HW_RANDOM_AMD=y
|
||||
CONFIG_HW_RANDOM_GEODE=y
|
||||
|
@ -1390,7 +1424,6 @@ CONFIG_I2C_I801=y
|
|||
# CONFIG_SENSORS_PCF8574 is not set
|
||||
# CONFIG_PCF8575 is not set
|
||||
# CONFIG_SENSORS_PCA9539 is not set
|
||||
# CONFIG_SENSORS_PCF8591 is not set
|
||||
# CONFIG_SENSORS_MAX6875 is not set
|
||||
# CONFIG_SENSORS_TSL2550 is not set
|
||||
# CONFIG_I2C_DEBUG_CORE is not set
|
||||
|
@ -1424,6 +1457,7 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_ADT7475 is not set
|
||||
# CONFIG_SENSORS_K8TEMP is not set
|
||||
# CONFIG_SENSORS_ASB100 is not set
|
||||
# CONFIG_SENSORS_ATK0110 is not set
|
||||
# CONFIG_SENSORS_ATXP1 is not set
|
||||
# CONFIG_SENSORS_DS1621 is not set
|
||||
# CONFIG_SENSORS_I5K_AMB is not set
|
||||
|
@ -1433,6 +1467,7 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_FSCHER is not set
|
||||
# CONFIG_SENSORS_FSCPOS is not set
|
||||
# CONFIG_SENSORS_FSCHMD is not set
|
||||
# CONFIG_SENSORS_G760A is not set
|
||||
# CONFIG_SENSORS_GL518SM is not set
|
||||
# CONFIG_SENSORS_GL520SM is not set
|
||||
# CONFIG_SENSORS_CORETEMP is not set
|
||||
|
@ -1448,11 +1483,14 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_LM90 is not set
|
||||
# CONFIG_SENSORS_LM92 is not set
|
||||
# CONFIG_SENSORS_LM93 is not set
|
||||
# CONFIG_SENSORS_LTC4215 is not set
|
||||
# CONFIG_SENSORS_LTC4245 is not set
|
||||
# CONFIG_SENSORS_LM95241 is not set
|
||||
# CONFIG_SENSORS_MAX1619 is not set
|
||||
# CONFIG_SENSORS_MAX6650 is not set
|
||||
# CONFIG_SENSORS_PC87360 is not set
|
||||
# CONFIG_SENSORS_PC87427 is not set
|
||||
# CONFIG_SENSORS_PCF8591 is not set
|
||||
# CONFIG_SENSORS_SIS5595 is not set
|
||||
# CONFIG_SENSORS_DME1737 is not set
|
||||
# CONFIG_SENSORS_SMSC47M1 is not set
|
||||
|
@ -1643,7 +1681,6 @@ CONFIG_FB_EFI=y
|
|||
# CONFIG_FB_3DFX is not set
|
||||
# CONFIG_FB_VOODOO1 is not set
|
||||
# CONFIG_FB_VT8623 is not set
|
||||
# CONFIG_FB_CYBLA is not set
|
||||
# CONFIG_FB_TRIDENT is not set
|
||||
# CONFIG_FB_ARK is not set
|
||||
# CONFIG_FB_PM3 is not set
|
||||
|
@ -1652,6 +1689,7 @@ CONFIG_FB_EFI=y
|
|||
# CONFIG_FB_VIRTUAL is not set
|
||||
# CONFIG_FB_METRONOME is not set
|
||||
# CONFIG_FB_MB862XX is not set
|
||||
# CONFIG_FB_BROADSHEET is not set
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
# CONFIG_LCD_CLASS_DEVICE is not set
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
|
@ -1738,6 +1776,8 @@ CONFIG_SND_PCI=y
|
|||
# CONFIG_SND_INDIGO is not set
|
||||
# CONFIG_SND_INDIGOIO is not set
|
||||
# CONFIG_SND_INDIGODJ is not set
|
||||
# CONFIG_SND_INDIGOIOX is not set
|
||||
# CONFIG_SND_INDIGODJX is not set
|
||||
# CONFIG_SND_EMU10K1 is not set
|
||||
# CONFIG_SND_EMU10K1X is not set
|
||||
# CONFIG_SND_ENS1370 is not set
|
||||
|
@ -1811,15 +1851,17 @@ CONFIG_USB_HIDDEV=y
|
|||
#
|
||||
# Special HID drivers
|
||||
#
|
||||
CONFIG_HID_COMPAT=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
# CONFIG_DRAGONRISE_FF is not set
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
# CONFIG_LOGIRUMBLEPAD2_FF is not set
|
||||
|
@ -1885,11 +1927,11 @@ CONFIG_USB_PRINTER=y
|
|||
# CONFIG_USB_TMC is not set
|
||||
|
||||
#
|
||||
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
|
||||
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
|
||||
#
|
||||
|
||||
#
|
||||
# see USB_STORAGE Help for more information
|
||||
# also be needed; see USB_STORAGE Help for more info
|
||||
#
|
||||
CONFIG_USB_STORAGE=y
|
||||
# CONFIG_USB_STORAGE_DEBUG is not set
|
||||
|
@ -1931,7 +1973,6 @@ CONFIG_USB_LIBUSUAL=y
|
|||
# CONFIG_USB_LED is not set
|
||||
# CONFIG_USB_CYPRESS_CY7C63 is not set
|
||||
# CONFIG_USB_CYTHERM is not set
|
||||
# CONFIG_USB_PHIDGET is not set
|
||||
# CONFIG_USB_IDMOUSE is not set
|
||||
# CONFIG_USB_FTDI_ELAN is not set
|
||||
# CONFIG_USB_APPLEDISPLAY is not set
|
||||
|
@ -1947,6 +1988,7 @@ CONFIG_USB_LIBUSUAL=y
|
|||
#
|
||||
# OTG and related infrastructure
|
||||
#
|
||||
# CONFIG_NOP_USB_XCEIV is not set
|
||||
# CONFIG_UWB is not set
|
||||
# CONFIG_MMC is not set
|
||||
# CONFIG_MEMSTICK is not set
|
||||
|
@ -1958,8 +2000,10 @@ CONFIG_LEDS_CLASS=y
|
|||
#
|
||||
# CONFIG_LEDS_ALIX2 is not set
|
||||
# CONFIG_LEDS_PCA9532 is not set
|
||||
# CONFIG_LEDS_LP5521 is not set
|
||||
# CONFIG_LEDS_CLEVO_MAIL is not set
|
||||
# CONFIG_LEDS_PCA955X is not set
|
||||
# CONFIG_LEDS_BD2802 is not set
|
||||
|
||||
#
|
||||
# LED Triggers
|
||||
|
@ -1969,6 +2013,10 @@ CONFIG_LEDS_TRIGGERS=y
|
|||
# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
|
||||
# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
|
||||
# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
|
||||
|
||||
#
|
||||
# iptables trigger is under Netfilter config (LED target)
|
||||
#
|
||||
# CONFIG_ACCESSIBILITY is not set
|
||||
# CONFIG_INFINIBAND is not set
|
||||
CONFIG_EDAC=y
|
||||
|
@ -2037,6 +2085,7 @@ CONFIG_DMADEVICES=y
|
|||
# DMA Devices
|
||||
#
|
||||
# CONFIG_INTEL_IOATDMA is not set
|
||||
# CONFIG_AUXDISPLAY is not set
|
||||
# CONFIG_UIO is not set
|
||||
# CONFIG_STAGING is not set
|
||||
CONFIG_X86_PLATFORM_DEVICES=y
|
||||
|
@ -2071,6 +2120,7 @@ CONFIG_DMIID=y
|
|||
#
|
||||
# CONFIG_EXT2_FS is not set
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
CONFIG_EXT3_FS_XATTR=y
|
||||
CONFIG_EXT3_FS_POSIX_ACL=y
|
||||
CONFIG_EXT3_FS_SECURITY=y
|
||||
|
@ -2100,6 +2150,11 @@ CONFIG_AUTOFS4_FS=y
|
|||
# CONFIG_FUSE_FS is not set
|
||||
CONFIG_GENERIC_ACL=y
|
||||
|
||||
#
|
||||
# Caches
|
||||
#
|
||||
# CONFIG_FSCACHE is not set
|
||||
|
||||
#
|
||||
# CD-ROM/DVD Filesystems
|
||||
#
|
||||
|
@ -2151,6 +2206,7 @@ CONFIG_MISC_FILESYSTEMS=y
|
|||
# CONFIG_ROMFS_FS is not set
|
||||
# CONFIG_SYSV_FS is not set
|
||||
# CONFIG_UFS_FS is not set
|
||||
# CONFIG_NILFS2_FS is not set
|
||||
CONFIG_NETWORK_FILESYSTEMS=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_NFS_V3=y
|
||||
|
@ -2164,7 +2220,6 @@ CONFIG_NFS_ACL_SUPPORT=y
|
|||
CONFIG_NFS_COMMON=y
|
||||
CONFIG_SUNRPC=y
|
||||
CONFIG_SUNRPC_GSS=y
|
||||
# CONFIG_SUNRPC_REGISTER_V4 is not set
|
||||
CONFIG_RPCSEC_GSS_KRB5=y
|
||||
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
||||
# CONFIG_SMB_FS is not set
|
||||
|
@ -2251,6 +2306,7 @@ CONFIG_DEBUG_FS=y
|
|||
CONFIG_DEBUG_KERNEL=y
|
||||
# CONFIG_DEBUG_SHIRQ is not set
|
||||
# CONFIG_DETECT_SOFTLOCKUP is not set
|
||||
# CONFIG_DETECT_HUNG_TASK is not set
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
|
@ -2266,6 +2322,7 @@ CONFIG_TIMER_STATS=y
|
|||
# CONFIG_LOCK_STAT is not set
|
||||
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
|
||||
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
|
||||
CONFIG_STACKTRACE=y
|
||||
# CONFIG_DEBUG_KOBJECT is not set
|
||||
# CONFIG_DEBUG_HIGHMEM is not set
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
|
@ -2289,13 +2346,19 @@ CONFIG_FRAME_POINTER=y
|
|||
# CONFIG_FAULT_INJECTION is not set
|
||||
# CONFIG_LATENCYTOP is not set
|
||||
CONFIG_SYSCTL_SYSCALL_CHECK=y
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
CONFIG_USER_STACKTRACE_SUPPORT=y
|
||||
CONFIG_NOP_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_HW_BRANCH_TRACER=y
|
||||
CONFIG_HAVE_FTRACE_SYSCALLS=y
|
||||
CONFIG_RING_BUFFER=y
|
||||
CONFIG_TRACING=y
|
||||
CONFIG_TRACING_SUPPORT=y
|
||||
|
||||
#
|
||||
# Tracers
|
||||
|
@ -2305,13 +2368,21 @@ CONFIG_HAVE_HW_BRANCH_TRACER=y
|
|||
# CONFIG_SYSPROF_TRACER is not set
|
||||
# CONFIG_SCHED_TRACER is not set
|
||||
# CONFIG_CONTEXT_SWITCH_TRACER is not set
|
||||
# CONFIG_EVENT_TRACER is not set
|
||||
# CONFIG_FTRACE_SYSCALLS is not set
|
||||
# CONFIG_BOOT_TRACER is not set
|
||||
# CONFIG_TRACE_BRANCH_PROFILING is not set
|
||||
# CONFIG_POWER_TRACER is not set
|
||||
# CONFIG_STACK_TRACER is not set
|
||||
# CONFIG_HW_BRANCH_TRACER is not set
|
||||
# CONFIG_KMEMTRACE is not set
|
||||
# CONFIG_WORKQUEUE_TRACER is not set
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
# CONFIG_FTRACE_STARTUP_TEST is not set
|
||||
# CONFIG_MMIOTRACE is not set
|
||||
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
|
||||
# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
|
||||
# CONFIG_DYNAMIC_DEBUG is not set
|
||||
# CONFIG_DMA_API_DEBUG is not set
|
||||
# CONFIG_SAMPLES is not set
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
# CONFIG_KGDB is not set
|
||||
|
@ -2321,7 +2392,6 @@ CONFIG_EARLY_PRINTK=y
|
|||
CONFIG_EARLY_PRINTK_DBGP=y
|
||||
CONFIG_DEBUG_STACKOVERFLOW=y
|
||||
CONFIG_DEBUG_STACK_USAGE=y
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||
# CONFIG_X86_PTDUMP is not set
|
||||
CONFIG_DEBUG_RODATA=y
|
||||
|
@ -2329,7 +2399,7 @@ CONFIG_DEBUG_RODATA=y
|
|||
CONFIG_DEBUG_NX_TEST=m
|
||||
# CONFIG_4KSTACKS is not set
|
||||
CONFIG_DOUBLEFAULT=y
|
||||
# CONFIG_MMIOTRACE is not set
|
||||
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
|
||||
CONFIG_IO_DELAY_TYPE_0X80=0
|
||||
CONFIG_IO_DELAY_TYPE_0XED=1
|
||||
CONFIG_IO_DELAY_TYPE_UDELAY=2
|
||||
|
@ -2365,6 +2435,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y
|
|||
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
|
||||
# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
|
||||
# CONFIG_SECURITY_SMACK is not set
|
||||
# CONFIG_SECURITY_TOMOYO is not set
|
||||
# CONFIG_IMA is not set
|
||||
CONFIG_CRYPTO=y
|
||||
|
||||
#
|
||||
|
@ -2380,10 +2452,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y
|
|||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_PCOMP=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
# CONFIG_CRYPTO_GF128MUL is not set
|
||||
# CONFIG_CRYPTO_NULL is not set
|
||||
CONFIG_CRYPTO_WORKQUEUE=y
|
||||
# CONFIG_CRYPTO_CRYPTD is not set
|
||||
CONFIG_CRYPTO_AUTHENC=y
|
||||
# CONFIG_CRYPTO_TEST is not set
|
||||
|
@ -2456,6 +2530,7 @@ CONFIG_CRYPTO_DES=y
|
|||
# Compression
|
||||
#
|
||||
# CONFIG_CRYPTO_DEFLATE is not set
|
||||
# CONFIG_CRYPTO_ZLIB is not set
|
||||
# CONFIG_CRYPTO_LZO is not set
|
||||
|
||||
#
|
||||
|
@ -2467,11 +2542,13 @@ CONFIG_CRYPTO_HW=y
|
|||
# CONFIG_CRYPTO_DEV_GEODE is not set
|
||||
# CONFIG_CRYPTO_DEV_HIFN_795X is not set
|
||||
CONFIG_HAVE_KVM=y
|
||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
# CONFIG_KVM is not set
|
||||
# CONFIG_LGUEST is not set
|
||||
# CONFIG_VIRTIO_PCI is not set
|
||||
# CONFIG_VIRTIO_BALLOON is not set
|
||||
CONFIG_BINARY_PRINTF=y
|
||||
|
||||
#
|
||||
# Library routines
|
||||
|
@ -2489,7 +2566,10 @@ CONFIG_CRC32=y
|
|||
# CONFIG_LIBCRC32C is not set
|
||||
CONFIG_AUDIT_GENERIC=y
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
CONFIG_PLIST=y
|
||||
CONFIG_DECOMPRESS_GZIP=y
|
||||
CONFIG_DECOMPRESS_BZIP2=y
|
||||
CONFIG_DECOMPRESS_LZMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_NLATTR=y
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.29-rc4
|
||||
# Tue Feb 24 15:44:16 2009
|
||||
# Linux kernel version: 2.6.30-rc2
|
||||
# Mon May 11 16:22:00 2009
|
||||
#
|
||||
CONFIG_64BIT=y
|
||||
# CONFIG_X86_32 is not set
|
||||
CONFIG_X86_64=y
|
||||
CONFIG_X86=y
|
||||
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
|
||||
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
|
||||
CONFIG_GENERIC_TIME=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
|
@ -34,6 +35,7 @@ CONFIG_ARCH_HAS_CPU_RELAX=y
|
|||
CONFIG_ARCH_HAS_DEFAULT_IDLE=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
|
||||
CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y
|
||||
CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
|
@ -41,14 +43,14 @@ CONFIG_ZONE_DMA32=y
|
|||
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
||||
CONFIG_AUDIT_ARCH=y
|
||||
CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
|
||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||
CONFIG_GENERIC_HARDIRQS=y
|
||||
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
|
||||
CONFIG_GENERIC_IRQ_PROBE=y
|
||||
CONFIG_GENERIC_PENDING_IRQ=y
|
||||
CONFIG_X86_SMP=y
|
||||
CONFIG_USE_GENERIC_SMP_HELPERS=y
|
||||
CONFIG_X86_64_SMP=y
|
||||
CONFIG_X86_HT=y
|
||||
CONFIG_X86_BIOS_REBOOT=y
|
||||
CONFIG_X86_TRAMPOLINE=y
|
||||
# CONFIG_KTIME_SCALAR is not set
|
||||
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
|
||||
|
@ -61,10 +63,17 @@ CONFIG_LOCK_KERNEL=y
|
|||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||
CONFIG_LOCALVERSION=""
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_HAVE_KERNEL_GZIP=y
|
||||
CONFIG_HAVE_KERNEL_BZIP2=y
|
||||
CONFIG_HAVE_KERNEL_LZMA=y
|
||||
CONFIG_KERNEL_GZIP=y
|
||||
# CONFIG_KERNEL_BZIP2 is not set
|
||||
# CONFIG_KERNEL_LZMA is not set
|
||||
CONFIG_SWAP=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_SYSVIPC_SYSCTL=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_POSIX_MQUEUE_SYSCTL=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
|
||||
CONFIG_TASKSTATS=y
|
||||
|
@ -114,23 +123,26 @@ CONFIG_PID_NS=y
|
|||
CONFIG_NET_NS=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_RD_GZIP=y
|
||||
CONFIG_RD_BZIP2=y
|
||||
CONFIG_RD_LZMA=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_ANON_INODES=y
|
||||
# CONFIG_EMBEDDED is not set
|
||||
CONFIG_UID16=y
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_KALLSYMS=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_KALLSYMS_EXTRA_PASS=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_HOTPLUG=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_BUG=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_PCSPKR_PLATFORM=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_BASE_FULL=y
|
||||
CONFIG_FUTEX=y
|
||||
CONFIG_ANON_INODES=y
|
||||
CONFIG_EPOLL=y
|
||||
CONFIG_SIGNALFD=y
|
||||
CONFIG_TIMERFD=y
|
||||
|
@ -140,6 +152,7 @@ CONFIG_AIO=y
|
|||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
CONFIG_PCI_QUIRKS=y
|
||||
CONFIG_SLUB_DEBUG=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
# CONFIG_SLAB is not set
|
||||
CONFIG_SLUB=y
|
||||
# CONFIG_SLOB is not set
|
||||
|
@ -155,6 +168,8 @@ CONFIG_HAVE_IOREMAP_PROT=y
|
|||
CONFIG_HAVE_KPROBES=y
|
||||
CONFIG_HAVE_KRETPROBES=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
# CONFIG_SLOW_WORK is not set
|
||||
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
|
||||
CONFIG_SLABINFO=y
|
||||
CONFIG_RT_MUTEXES=y
|
||||
|
@ -167,7 +182,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y
|
|||
# CONFIG_MODULE_SRCVERSION_ALL is not set
|
||||
CONFIG_STOP_MACHINE=y
|
||||
CONFIG_BLOCK=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_BLK_DEV_BSG=y
|
||||
# CONFIG_BLK_DEV_INTEGRITY is not set
|
||||
CONFIG_BLOCK_COMPAT=y
|
||||
|
@ -195,12 +209,10 @@ CONFIG_HIGH_RES_TIMERS=y
|
|||
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
# CONFIG_NUMA_MIGRATE_IRQ_DESC is not set
|
||||
CONFIG_X86_FIND_SMP_CONFIG=y
|
||||
CONFIG_X86_MPPARSE=y
|
||||
# CONFIG_X86_ELAN is not set
|
||||
# CONFIG_X86_GENERICARCH is not set
|
||||
CONFIG_X86_EXTENDED_PLATFORM=y
|
||||
# CONFIG_X86_VSMP is not set
|
||||
# CONFIG_X86_UV is not set
|
||||
CONFIG_SCHED_OMIT_FRAME_POINTER=y
|
||||
# CONFIG_PARAVIRT_GUEST is not set
|
||||
# CONFIG_MEMTEST is not set
|
||||
|
@ -230,10 +242,10 @@ CONFIG_SCHED_OMIT_FRAME_POINTER=y
|
|||
# CONFIG_MCORE2 is not set
|
||||
CONFIG_GENERIC_CPU=y
|
||||
CONFIG_X86_CPU=y
|
||||
CONFIG_X86_L1_CACHE_BYTES=128
|
||||
CONFIG_X86_INTERNODE_CACHE_BYTES=128
|
||||
CONFIG_X86_L1_CACHE_BYTES=64
|
||||
CONFIG_X86_INTERNODE_CACHE_BYTES=64
|
||||
CONFIG_X86_CMPXCHG=y
|
||||
CONFIG_X86_L1_CACHE_SHIFT=7
|
||||
CONFIG_X86_L1_CACHE_SHIFT=6
|
||||
CONFIG_X86_WP_WORKS_OK=y
|
||||
CONFIG_X86_TSC=y
|
||||
CONFIG_X86_CMPXCHG64=y
|
||||
|
@ -242,7 +254,7 @@ CONFIG_X86_MINIMUM_CPU_FAMILY=64
|
|||
CONFIG_X86_DEBUGCTLMSR=y
|
||||
CONFIG_CPU_SUP_INTEL=y
|
||||
CONFIG_CPU_SUP_AMD=y
|
||||
CONFIG_CPU_SUP_CENTAUR_64=y
|
||||
CONFIG_CPU_SUP_CENTAUR=y
|
||||
CONFIG_X86_DS=y
|
||||
CONFIG_X86_PTRACE_BTS=y
|
||||
CONFIG_HPET_TIMER=y
|
||||
|
@ -269,6 +281,7 @@ CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
|
|||
CONFIG_X86_MCE=y
|
||||
CONFIG_X86_MCE_INTEL=y
|
||||
CONFIG_X86_MCE_AMD=y
|
||||
CONFIG_X86_MCE_THRESHOLD=y
|
||||
# CONFIG_I8K is not set
|
||||
CONFIG_MICROCODE=y
|
||||
CONFIG_MICROCODE_INTEL=y
|
||||
|
@ -276,6 +289,7 @@ CONFIG_MICROCODE_AMD=y
|
|||
CONFIG_MICROCODE_OLD_INTERFACE=y
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
# CONFIG_X86_CPU_DEBUG is not set
|
||||
CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_DIRECT_GBPAGES=y
|
||||
CONFIG_NUMA=y
|
||||
|
@ -309,6 +323,8 @@ CONFIG_ZONE_DMA_FLAG=1
|
|||
CONFIG_BOUNCE=y
|
||||
CONFIG_VIRT_TO_BUS=y
|
||||
CONFIG_UNEVICTABLE_LRU=y
|
||||
CONFIG_HAVE_MLOCK=y
|
||||
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
|
||||
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
|
||||
CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y
|
||||
CONFIG_X86_RESERVE_LOW_64K=y
|
||||
|
@ -317,6 +333,7 @@ CONFIG_MTRR=y
|
|||
CONFIG_X86_PAT=y
|
||||
CONFIG_EFI=y
|
||||
CONFIG_SECCOMP=y
|
||||
# CONFIG_CC_STACKPROTECTOR is not set
|
||||
# CONFIG_HZ_100 is not set
|
||||
# CONFIG_HZ_250 is not set
|
||||
# CONFIG_HZ_300 is not set
|
||||
|
@ -325,9 +342,10 @@ CONFIG_HZ=1000
|
|||
CONFIG_SCHED_HRTICK=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_CRASH_DUMP=y
|
||||
# CONFIG_KEXEC_JUMP is not set
|
||||
CONFIG_PHYSICAL_START=0x1000000
|
||||
# CONFIG_RELOCATABLE is not set
|
||||
CONFIG_PHYSICAL_ALIGN=0x200000
|
||||
CONFIG_RELOCATABLE=y
|
||||
CONFIG_PHYSICAL_ALIGN=0x1000000
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
# CONFIG_COMPAT_VDSO is not set
|
||||
# CONFIG_CMDLINE_BOOL is not set
|
||||
|
@ -370,7 +388,6 @@ CONFIG_ACPI_NUMA=y
|
|||
CONFIG_ACPI_BLACKLIST_YEAR=0
|
||||
# CONFIG_ACPI_DEBUG is not set
|
||||
# CONFIG_ACPI_PCI_SLOT is not set
|
||||
CONFIG_ACPI_SYSTEM=y
|
||||
CONFIG_X86_PM_TIMER=y
|
||||
CONFIG_ACPI_CONTAINER=y
|
||||
# CONFIG_ACPI_SBS is not set
|
||||
|
@ -436,6 +453,7 @@ CONFIG_PCI_MSI=y
|
|||
# CONFIG_PCI_DEBUG is not set
|
||||
# CONFIG_PCI_STUB is not set
|
||||
CONFIG_HT_IRQ=y
|
||||
# CONFIG_PCI_IOV is not set
|
||||
CONFIG_ISA_DMA_API=y
|
||||
CONFIG_K8_NB=y
|
||||
CONFIG_PCCARD=y
|
||||
|
@ -481,7 +499,6 @@ CONFIG_NET=y
|
|||
#
|
||||
# Networking options
|
||||
#
|
||||
CONFIG_COMPAT_NET_DEV_OPS=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_PACKET_MMAP=y
|
||||
CONFIG_UNIX=y
|
||||
|
@ -639,6 +656,7 @@ CONFIG_LLC=y
|
|||
# CONFIG_LAPB is not set
|
||||
# CONFIG_ECONET is not set
|
||||
# CONFIG_WAN_ROUTER is not set
|
||||
# CONFIG_PHONET is not set
|
||||
CONFIG_NET_SCHED=y
|
||||
|
||||
#
|
||||
|
@ -696,6 +714,7 @@ CONFIG_NET_SCH_FIFO=y
|
|||
#
|
||||
# CONFIG_NET_PKTGEN is not set
|
||||
# CONFIG_NET_TCPPROBE is not set
|
||||
# CONFIG_NET_DROP_MONITOR is not set
|
||||
CONFIG_HAMRADIO=y
|
||||
|
||||
#
|
||||
|
@ -706,12 +725,10 @@ CONFIG_HAMRADIO=y
|
|||
# CONFIG_IRDA is not set
|
||||
# CONFIG_BT is not set
|
||||
# CONFIG_AF_RXRPC is not set
|
||||
# CONFIG_PHONET is not set
|
||||
CONFIG_FIB_RULES=y
|
||||
CONFIG_WIRELESS=y
|
||||
CONFIG_CFG80211=y
|
||||
# CONFIG_CFG80211_REG_DEBUG is not set
|
||||
CONFIG_NL80211=y
|
||||
CONFIG_WIRELESS_OLD_REGULATORY=y
|
||||
CONFIG_WIRELESS_EXT=y
|
||||
CONFIG_WIRELESS_EXT_SYSFS=y
|
||||
|
@ -788,9 +805,8 @@ CONFIG_MISC_DEVICES=y
|
|||
# CONFIG_TIFM_CORE is not set
|
||||
# CONFIG_ICS932S401 is not set
|
||||
# CONFIG_ENCLOSURE_SERVICES is not set
|
||||
# CONFIG_SGI_XP is not set
|
||||
# CONFIG_HP_ILO is not set
|
||||
# CONFIG_SGI_GRU is not set
|
||||
# CONFIG_ISL29003 is not set
|
||||
# CONFIG_C2PORT is not set
|
||||
|
||||
#
|
||||
|
@ -844,6 +860,7 @@ CONFIG_SCSI_SPI_ATTRS=y
|
|||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
|
||||
# CONFIG_SCSI_DH is not set
|
||||
# CONFIG_SCSI_OSD_INITIATOR is not set
|
||||
CONFIG_ATA=y
|
||||
# CONFIG_ATA_NONSTANDARD is not set
|
||||
CONFIG_ATA_ACPI=y
|
||||
|
@ -940,6 +957,7 @@ CONFIG_DM_ZERO=y
|
|||
CONFIG_MACINTOSH_DRIVERS=y
|
||||
CONFIG_MAC_EMUMOUSEBTN=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_COMPAT_NET_DEV_OPS=y
|
||||
# CONFIG_IFB is not set
|
||||
# CONFIG_DUMMY is not set
|
||||
# CONFIG_BONDING is not set
|
||||
|
@ -977,6 +995,8 @@ CONFIG_MII=y
|
|||
CONFIG_NET_VENDOR_3COM=y
|
||||
# CONFIG_VORTEX is not set
|
||||
# CONFIG_TYPHOON is not set
|
||||
# CONFIG_ETHOC is not set
|
||||
# CONFIG_DNET is not set
|
||||
CONFIG_NET_TULIP=y
|
||||
# CONFIG_DE2104X is not set
|
||||
# CONFIG_TULIP is not set
|
||||
|
@ -1026,6 +1046,7 @@ CONFIG_E1000=y
|
|||
# CONFIG_E1000E is not set
|
||||
# CONFIG_IP1000 is not set
|
||||
# CONFIG_IGB is not set
|
||||
# CONFIG_IGBVF is not set
|
||||
# CONFIG_NS83820 is not set
|
||||
# CONFIG_HAMACHI is not set
|
||||
# CONFIG_YELLOWFIN is not set
|
||||
|
@ -1040,6 +1061,7 @@ CONFIG_TIGON3=y
|
|||
# CONFIG_QLA3XXX is not set
|
||||
# CONFIG_ATL1 is not set
|
||||
# CONFIG_ATL1E is not set
|
||||
# CONFIG_ATL1C is not set
|
||||
# CONFIG_JME is not set
|
||||
CONFIG_NETDEV_10000=y
|
||||
# CONFIG_CHELSIO_T1 is not set
|
||||
|
@ -1049,6 +1071,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
|
|||
# CONFIG_IXGBE is not set
|
||||
# CONFIG_IXGB is not set
|
||||
# CONFIG_S2IO is not set
|
||||
# CONFIG_VXGE is not set
|
||||
# CONFIG_MYRI10GE is not set
|
||||
# CONFIG_NETXEN_NIC is not set
|
||||
# CONFIG_NIU is not set
|
||||
|
@ -1058,6 +1081,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
|
|||
# CONFIG_BNX2X is not set
|
||||
# CONFIG_QLGE is not set
|
||||
# CONFIG_SFC is not set
|
||||
# CONFIG_BE2NET is not set
|
||||
CONFIG_TR=y
|
||||
# CONFIG_IBMOL is not set
|
||||
# CONFIG_3C359 is not set
|
||||
|
@ -1072,8 +1096,8 @@ CONFIG_WLAN_80211=y
|
|||
# CONFIG_LIBERTAS is not set
|
||||
# CONFIG_LIBERTAS_THINFIRM is not set
|
||||
# CONFIG_AIRO is not set
|
||||
# CONFIG_HERMES is not set
|
||||
# CONFIG_ATMEL is not set
|
||||
# CONFIG_AT76C50X_USB is not set
|
||||
# CONFIG_AIRO_CS is not set
|
||||
# CONFIG_PCMCIA_WL3501 is not set
|
||||
# CONFIG_PRISM54 is not set
|
||||
|
@ -1083,21 +1107,21 @@ CONFIG_WLAN_80211=y
|
|||
# CONFIG_RTL8187 is not set
|
||||
# CONFIG_ADM8211 is not set
|
||||
# CONFIG_MAC80211_HWSIM is not set
|
||||
# CONFIG_MWL8K is not set
|
||||
# CONFIG_P54_COMMON is not set
|
||||
CONFIG_ATH5K=y
|
||||
# CONFIG_ATH5K_DEBUG is not set
|
||||
# CONFIG_ATH9K is not set
|
||||
# CONFIG_AR9170_USB is not set
|
||||
# CONFIG_IPW2100 is not set
|
||||
# CONFIG_IPW2200 is not set
|
||||
# CONFIG_IWLCORE is not set
|
||||
# CONFIG_IWLWIFI_LEDS is not set
|
||||
# CONFIG_IWLAGN is not set
|
||||
# CONFIG_IWL3945 is not set
|
||||
# CONFIG_IWLWIFI is not set
|
||||
# CONFIG_HOSTAP is not set
|
||||
# CONFIG_B43 is not set
|
||||
# CONFIG_B43LEGACY is not set
|
||||
# CONFIG_ZD1211RW is not set
|
||||
# CONFIG_RT2X00 is not set
|
||||
# CONFIG_HERMES is not set
|
||||
|
||||
#
|
||||
# Enable WiMAX (Networking options) to see the WiMAX drivers
|
||||
|
@ -1208,6 +1232,8 @@ CONFIG_INPUT_TABLET=y
|
|||
# CONFIG_TABLET_USB_KBTAB is not set
|
||||
# CONFIG_TABLET_USB_WACOM is not set
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
|
||||
# CONFIG_TOUCHSCREEN_AD7879 is not set
|
||||
# CONFIG_TOUCHSCREEN_FUJITSU is not set
|
||||
# CONFIG_TOUCHSCREEN_GUNZE is not set
|
||||
# CONFIG_TOUCHSCREEN_ELO is not set
|
||||
|
@ -1301,6 +1327,7 @@ CONFIG_UNIX98_PTYS=y
|
|||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_IPMI_HANDLER is not set
|
||||
CONFIG_HW_RANDOM=y
|
||||
# CONFIG_HW_RANDOM_TIMERIOMEM is not set
|
||||
# CONFIG_HW_RANDOM_INTEL is not set
|
||||
# CONFIG_HW_RANDOM_AMD is not set
|
||||
CONFIG_NVRAM=y
|
||||
|
@ -1382,7 +1409,6 @@ CONFIG_I2C_I801=y
|
|||
# CONFIG_SENSORS_PCF8574 is not set
|
||||
# CONFIG_PCF8575 is not set
|
||||
# CONFIG_SENSORS_PCA9539 is not set
|
||||
# CONFIG_SENSORS_PCF8591 is not set
|
||||
# CONFIG_SENSORS_MAX6875 is not set
|
||||
# CONFIG_SENSORS_TSL2550 is not set
|
||||
# CONFIG_I2C_DEBUG_CORE is not set
|
||||
|
@ -1416,6 +1442,7 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_ADT7475 is not set
|
||||
# CONFIG_SENSORS_K8TEMP is not set
|
||||
# CONFIG_SENSORS_ASB100 is not set
|
||||
# CONFIG_SENSORS_ATK0110 is not set
|
||||
# CONFIG_SENSORS_ATXP1 is not set
|
||||
# CONFIG_SENSORS_DS1621 is not set
|
||||
# CONFIG_SENSORS_I5K_AMB is not set
|
||||
|
@ -1425,6 +1452,7 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_FSCHER is not set
|
||||
# CONFIG_SENSORS_FSCPOS is not set
|
||||
# CONFIG_SENSORS_FSCHMD is not set
|
||||
# CONFIG_SENSORS_G760A is not set
|
||||
# CONFIG_SENSORS_GL518SM is not set
|
||||
# CONFIG_SENSORS_GL520SM is not set
|
||||
# CONFIG_SENSORS_CORETEMP is not set
|
||||
|
@ -1440,11 +1468,14 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_LM90 is not set
|
||||
# CONFIG_SENSORS_LM92 is not set
|
||||
# CONFIG_SENSORS_LM93 is not set
|
||||
# CONFIG_SENSORS_LTC4215 is not set
|
||||
# CONFIG_SENSORS_LTC4245 is not set
|
||||
# CONFIG_SENSORS_LM95241 is not set
|
||||
# CONFIG_SENSORS_MAX1619 is not set
|
||||
# CONFIG_SENSORS_MAX6650 is not set
|
||||
# CONFIG_SENSORS_PC87360 is not set
|
||||
# CONFIG_SENSORS_PC87427 is not set
|
||||
# CONFIG_SENSORS_PCF8591 is not set
|
||||
# CONFIG_SENSORS_SIS5595 is not set
|
||||
# CONFIG_SENSORS_DME1737 is not set
|
||||
# CONFIG_SENSORS_SMSC47M1 is not set
|
||||
|
@ -1635,6 +1666,7 @@ CONFIG_FB_EFI=y
|
|||
# CONFIG_FB_VIRTUAL is not set
|
||||
# CONFIG_FB_METRONOME is not set
|
||||
# CONFIG_FB_MB862XX is not set
|
||||
# CONFIG_FB_BROADSHEET is not set
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
# CONFIG_LCD_CLASS_DEVICE is not set
|
||||
CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
||||
|
@ -1720,6 +1752,8 @@ CONFIG_SND_PCI=y
|
|||
# CONFIG_SND_INDIGO is not set
|
||||
# CONFIG_SND_INDIGOIO is not set
|
||||
# CONFIG_SND_INDIGODJ is not set
|
||||
# CONFIG_SND_INDIGOIOX is not set
|
||||
# CONFIG_SND_INDIGODJX is not set
|
||||
# CONFIG_SND_EMU10K1 is not set
|
||||
# CONFIG_SND_EMU10K1X is not set
|
||||
# CONFIG_SND_ENS1370 is not set
|
||||
|
@ -1792,15 +1826,17 @@ CONFIG_USB_HIDDEV=y
|
|||
#
|
||||
# Special HID drivers
|
||||
#
|
||||
CONFIG_HID_COMPAT=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
# CONFIG_DRAGONRISE_FF is not set
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
# CONFIG_LOGIRUMBLEPAD2_FF is not set
|
||||
|
@ -1866,11 +1902,11 @@ CONFIG_USB_PRINTER=y
|
|||
# CONFIG_USB_TMC is not set
|
||||
|
||||
#
|
||||
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
|
||||
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
|
||||
#
|
||||
|
||||
#
|
||||
# see USB_STORAGE Help for more information
|
||||
# also be needed; see USB_STORAGE Help for more info
|
||||
#
|
||||
CONFIG_USB_STORAGE=y
|
||||
# CONFIG_USB_STORAGE_DEBUG is not set
|
||||
|
@ -1912,7 +1948,6 @@ CONFIG_USB_LIBUSUAL=y
|
|||
# CONFIG_USB_LED is not set
|
||||
# CONFIG_USB_CYPRESS_CY7C63 is not set
|
||||
# CONFIG_USB_CYTHERM is not set
|
||||
# CONFIG_USB_PHIDGET is not set
|
||||
# CONFIG_USB_IDMOUSE is not set
|
||||
# CONFIG_USB_FTDI_ELAN is not set
|
||||
# CONFIG_USB_APPLEDISPLAY is not set
|
||||
|
@ -1928,6 +1963,7 @@ CONFIG_USB_LIBUSUAL=y
|
|||
#
|
||||
# OTG and related infrastructure
|
||||
#
|
||||
# CONFIG_NOP_USB_XCEIV is not set
|
||||
# CONFIG_UWB is not set
|
||||
# CONFIG_MMC is not set
|
||||
# CONFIG_MEMSTICK is not set
|
||||
|
@ -1939,8 +1975,10 @@ CONFIG_LEDS_CLASS=y
|
|||
#
|
||||
# CONFIG_LEDS_ALIX2 is not set
|
||||
# CONFIG_LEDS_PCA9532 is not set
|
||||
# CONFIG_LEDS_LP5521 is not set
|
||||
# CONFIG_LEDS_CLEVO_MAIL is not set
|
||||
# CONFIG_LEDS_PCA955X is not set
|
||||
# CONFIG_LEDS_BD2802 is not set
|
||||
|
||||
#
|
||||
# LED Triggers
|
||||
|
@ -1950,6 +1988,10 @@ CONFIG_LEDS_TRIGGERS=y
|
|||
# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
|
||||
# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
|
||||
# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
|
||||
|
||||
#
|
||||
# iptables trigger is under Netfilter config (LED target)
|
||||
#
|
||||
# CONFIG_ACCESSIBILITY is not set
|
||||
# CONFIG_INFINIBAND is not set
|
||||
CONFIG_EDAC=y
|
||||
|
@ -2018,6 +2060,7 @@ CONFIG_DMADEVICES=y
|
|||
# DMA Devices
|
||||
#
|
||||
# CONFIG_INTEL_IOATDMA is not set
|
||||
# CONFIG_AUXDISPLAY is not set
|
||||
# CONFIG_UIO is not set
|
||||
# CONFIG_STAGING is not set
|
||||
CONFIG_X86_PLATFORM_DEVICES=y
|
||||
|
@ -2051,6 +2094,7 @@ CONFIG_DMIID=y
|
|||
#
|
||||
# CONFIG_EXT2_FS is not set
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
CONFIG_EXT3_FS_XATTR=y
|
||||
CONFIG_EXT3_FS_POSIX_ACL=y
|
||||
CONFIG_EXT3_FS_SECURITY=y
|
||||
|
@ -2081,6 +2125,11 @@ CONFIG_AUTOFS4_FS=y
|
|||
# CONFIG_FUSE_FS is not set
|
||||
CONFIG_GENERIC_ACL=y
|
||||
|
||||
#
|
||||
# Caches
|
||||
#
|
||||
# CONFIG_FSCACHE is not set
|
||||
|
||||
#
|
||||
# CD-ROM/DVD Filesystems
|
||||
#
|
||||
|
@ -2132,6 +2181,7 @@ CONFIG_MISC_FILESYSTEMS=y
|
|||
# CONFIG_ROMFS_FS is not set
|
||||
# CONFIG_SYSV_FS is not set
|
||||
# CONFIG_UFS_FS is not set
|
||||
# CONFIG_NILFS2_FS is not set
|
||||
CONFIG_NETWORK_FILESYSTEMS=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_NFS_V3=y
|
||||
|
@ -2145,7 +2195,6 @@ CONFIG_NFS_ACL_SUPPORT=y
|
|||
CONFIG_NFS_COMMON=y
|
||||
CONFIG_SUNRPC=y
|
||||
CONFIG_SUNRPC_GSS=y
|
||||
# CONFIG_SUNRPC_REGISTER_V4 is not set
|
||||
CONFIG_RPCSEC_GSS_KRB5=y
|
||||
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
||||
# CONFIG_SMB_FS is not set
|
||||
|
@ -2232,6 +2281,7 @@ CONFIG_DEBUG_FS=y
|
|||
CONFIG_DEBUG_KERNEL=y
|
||||
# CONFIG_DEBUG_SHIRQ is not set
|
||||
# CONFIG_DETECT_SOFTLOCKUP is not set
|
||||
# CONFIG_DETECT_HUNG_TASK is not set
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
|
@ -2247,6 +2297,7 @@ CONFIG_TIMER_STATS=y
|
|||
# CONFIG_LOCK_STAT is not set
|
||||
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
|
||||
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
|
||||
CONFIG_STACKTRACE=y
|
||||
# CONFIG_DEBUG_KOBJECT is not set
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
# CONFIG_DEBUG_INFO is not set
|
||||
|
@ -2269,13 +2320,19 @@ CONFIG_FRAME_POINTER=y
|
|||
# CONFIG_FAULT_INJECTION is not set
|
||||
# CONFIG_LATENCYTOP is not set
|
||||
CONFIG_SYSCTL_SYSCALL_CHECK=y
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
CONFIG_USER_STACKTRACE_SUPPORT=y
|
||||
CONFIG_NOP_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_HW_BRANCH_TRACER=y
|
||||
CONFIG_HAVE_FTRACE_SYSCALLS=y
|
||||
CONFIG_RING_BUFFER=y
|
||||
CONFIG_TRACING=y
|
||||
CONFIG_TRACING_SUPPORT=y
|
||||
|
||||
#
|
||||
# Tracers
|
||||
|
@ -2285,13 +2342,21 @@ CONFIG_HAVE_HW_BRANCH_TRACER=y
|
|||
# CONFIG_SYSPROF_TRACER is not set
|
||||
# CONFIG_SCHED_TRACER is not set
|
||||
# CONFIG_CONTEXT_SWITCH_TRACER is not set
|
||||
# CONFIG_EVENT_TRACER is not set
|
||||
# CONFIG_FTRACE_SYSCALLS is not set
|
||||
# CONFIG_BOOT_TRACER is not set
|
||||
# CONFIG_TRACE_BRANCH_PROFILING is not set
|
||||
# CONFIG_POWER_TRACER is not set
|
||||
# CONFIG_STACK_TRACER is not set
|
||||
# CONFIG_HW_BRANCH_TRACER is not set
|
||||
# CONFIG_KMEMTRACE is not set
|
||||
# CONFIG_WORKQUEUE_TRACER is not set
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
# CONFIG_FTRACE_STARTUP_TEST is not set
|
||||
# CONFIG_MMIOTRACE is not set
|
||||
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
|
||||
# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
|
||||
# CONFIG_DYNAMIC_DEBUG is not set
|
||||
# CONFIG_DMA_API_DEBUG is not set
|
||||
# CONFIG_SAMPLES is not set
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
# CONFIG_KGDB is not set
|
||||
|
@ -2301,14 +2366,13 @@ CONFIG_EARLY_PRINTK=y
|
|||
CONFIG_EARLY_PRINTK_DBGP=y
|
||||
CONFIG_DEBUG_STACKOVERFLOW=y
|
||||
CONFIG_DEBUG_STACK_USAGE=y
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||
# CONFIG_X86_PTDUMP is not set
|
||||
CONFIG_DEBUG_RODATA=y
|
||||
# CONFIG_DEBUG_RODATA_TEST is not set
|
||||
CONFIG_DEBUG_NX_TEST=m
|
||||
# CONFIG_IOMMU_DEBUG is not set
|
||||
# CONFIG_MMIOTRACE is not set
|
||||
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
|
||||
CONFIG_IO_DELAY_TYPE_0X80=0
|
||||
CONFIG_IO_DELAY_TYPE_0XED=1
|
||||
CONFIG_IO_DELAY_TYPE_UDELAY=2
|
||||
|
@ -2344,6 +2408,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y
|
|||
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
|
||||
# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
|
||||
# CONFIG_SECURITY_SMACK is not set
|
||||
# CONFIG_SECURITY_TOMOYO is not set
|
||||
# CONFIG_IMA is not set
|
||||
CONFIG_CRYPTO=y
|
||||
|
||||
#
|
||||
|
@ -2359,10 +2425,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y
|
|||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_PCOMP=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
# CONFIG_CRYPTO_GF128MUL is not set
|
||||
# CONFIG_CRYPTO_NULL is not set
|
||||
CONFIG_CRYPTO_WORKQUEUE=y
|
||||
# CONFIG_CRYPTO_CRYPTD is not set
|
||||
CONFIG_CRYPTO_AUTHENC=y
|
||||
# CONFIG_CRYPTO_TEST is not set
|
||||
|
@ -2414,6 +2482,7 @@ CONFIG_CRYPTO_SHA1=y
|
|||
#
|
||||
CONFIG_CRYPTO_AES=y
|
||||
# CONFIG_CRYPTO_AES_X86_64 is not set
|
||||
# CONFIG_CRYPTO_AES_NI_INTEL is not set
|
||||
# CONFIG_CRYPTO_ANUBIS is not set
|
||||
CONFIG_CRYPTO_ARC4=y
|
||||
# CONFIG_CRYPTO_BLOWFISH is not set
|
||||
|
@ -2435,6 +2504,7 @@ CONFIG_CRYPTO_DES=y
|
|||
# Compression
|
||||
#
|
||||
# CONFIG_CRYPTO_DEFLATE is not set
|
||||
# CONFIG_CRYPTO_ZLIB is not set
|
||||
# CONFIG_CRYPTO_LZO is not set
|
||||
|
||||
#
|
||||
|
@ -2444,10 +2514,12 @@ CONFIG_CRYPTO_DES=y
|
|||
CONFIG_CRYPTO_HW=y
|
||||
# CONFIG_CRYPTO_DEV_HIFN_795X is not set
|
||||
CONFIG_HAVE_KVM=y
|
||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
# CONFIG_KVM is not set
|
||||
# CONFIG_VIRTIO_PCI is not set
|
||||
# CONFIG_VIRTIO_BALLOON is not set
|
||||
CONFIG_BINARY_PRINTF=y
|
||||
|
||||
#
|
||||
# Library routines
|
||||
|
@ -2464,7 +2536,10 @@ CONFIG_CRC32=y
|
|||
# CONFIG_CRC7 is not set
|
||||
# CONFIG_LIBCRC32C is not set
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
CONFIG_PLIST=y
|
||||
CONFIG_DECOMPRESS_GZIP=y
|
||||
CONFIG_DECOMPRESS_BZIP2=y
|
||||
CONFIG_DECOMPRESS_LZMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_NLATTR=y
|
||||
|
|
|
@ -825,9 +825,11 @@ ia32_sys_call_table:
|
|||
.quad compat_sys_signalfd4
|
||||
.quad sys_eventfd2
|
||||
.quad sys_epoll_create1
|
||||
.quad sys_dup3 /* 330 */
|
||||
.quad sys_dup3 /* 330 */
|
||||
.quad sys_pipe2
|
||||
.quad sys_inotify_init1
|
||||
.quad compat_sys_preadv
|
||||
.quad compat_sys_pwritev
|
||||
.quad compat_sys_rt_tgsigqueueinfo /* 335 */
|
||||
.quad sys_perf_counter_open
|
||||
ia32_syscall_end:
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
/*
|
||||
|
@ -74,6 +75,22 @@ static inline void alternatives_smp_switch(int smp) {}
|
|||
|
||||
const unsigned char *const *find_nop_table(void);
|
||||
|
||||
/* alternative assembly primitive: */
|
||||
#define ALTERNATIVE(oldinstr, newinstr, feature) \
|
||||
\
|
||||
"661:\n\t" oldinstr "\n662:\n" \
|
||||
".section .altinstructions,\"a\"\n" \
|
||||
_ASM_ALIGN "\n" \
|
||||
_ASM_PTR "661b\n" /* label */ \
|
||||
_ASM_PTR "663f\n" /* new instruction */ \
|
||||
" .byte " __stringify(feature) "\n" /* feature bit */ \
|
||||
" .byte 662b-661b\n" /* sourcelen */ \
|
||||
" .byte 664f-663f\n" /* replacementlen */ \
|
||||
".previous\n" \
|
||||
".section .altinstr_replacement, \"ax\"\n" \
|
||||
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
|
||||
".previous"
|
||||
|
||||
/*
|
||||
* Alternative instructions for different CPU types or capabilities.
|
||||
*
|
||||
|
@ -87,18 +104,7 @@ const unsigned char *const *find_nop_table(void);
|
|||
* without volatile and memory clobber.
|
||||
*/
|
||||
#define alternative(oldinstr, newinstr, feature) \
|
||||
asm volatile ("661:\n\t" oldinstr "\n662:\n" \
|
||||
".section .altinstructions,\"a\"\n" \
|
||||
_ASM_ALIGN "\n" \
|
||||
_ASM_PTR "661b\n" /* label */ \
|
||||
_ASM_PTR "663f\n" /* new instruction */ \
|
||||
" .byte %c0\n" /* feature bit */ \
|
||||
" .byte 662b-661b\n" /* sourcelen */ \
|
||||
" .byte 664f-663f\n" /* replacementlen */ \
|
||||
".previous\n" \
|
||||
".section .altinstr_replacement,\"ax\"\n" \
|
||||
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
|
||||
".previous" :: "i" (feature) : "memory")
|
||||
asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
|
||||
|
||||
/*
|
||||
* Alternative inline assembly with input.
|
||||
|
@ -109,35 +115,16 @@ const unsigned char *const *find_nop_table(void);
|
|||
* Best is to use constraints that are fixed size (like (%1) ... "r")
|
||||
* If you use variable sized constraints like "m" or "g" in the
|
||||
* replacement make sure to pad to the worst case length.
|
||||
* Leaving an unused argument 0 to keep API compatibility.
|
||||
*/
|
||||
#define alternative_input(oldinstr, newinstr, feature, input...) \
|
||||
asm volatile ("661:\n\t" oldinstr "\n662:\n" \
|
||||
".section .altinstructions,\"a\"\n" \
|
||||
_ASM_ALIGN "\n" \
|
||||
_ASM_PTR "661b\n" /* label */ \
|
||||
_ASM_PTR "663f\n" /* new instruction */ \
|
||||
" .byte %c0\n" /* feature bit */ \
|
||||
" .byte 662b-661b\n" /* sourcelen */ \
|
||||
" .byte 664f-663f\n" /* replacementlen */ \
|
||||
".previous\n" \
|
||||
".section .altinstr_replacement,\"ax\"\n" \
|
||||
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
|
||||
".previous" :: "i" (feature), ##input)
|
||||
asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
|
||||
: : "i" (0), ## input)
|
||||
|
||||
/* Like alternative_input, but with a single output argument */
|
||||
#define alternative_io(oldinstr, newinstr, feature, output, input...) \
|
||||
asm volatile ("661:\n\t" oldinstr "\n662:\n" \
|
||||
".section .altinstructions,\"a\"\n" \
|
||||
_ASM_ALIGN "\n" \
|
||||
_ASM_PTR "661b\n" /* label */ \
|
||||
_ASM_PTR "663f\n" /* new instruction */ \
|
||||
" .byte %c[feat]\n" /* feature bit */ \
|
||||
" .byte 662b-661b\n" /* sourcelen */ \
|
||||
" .byte 664f-663f\n" /* replacementlen */ \
|
||||
".previous\n" \
|
||||
".section .altinstr_replacement,\"ax\"\n" \
|
||||
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
|
||||
".previous" : output : [feat] "i" (feature), ##input)
|
||||
asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
|
||||
: output : "i" (0), ## input)
|
||||
|
||||
/*
|
||||
* use this macro(s) if you need more than one output parameter
|
||||
|
|
|
@ -27,6 +27,8 @@ extern int amd_iommu_init(void);
|
|||
extern int amd_iommu_init_dma_ops(void);
|
||||
extern void amd_iommu_detect(void);
|
||||
extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
|
||||
extern void amd_iommu_flush_all_domains(void);
|
||||
extern void amd_iommu_flush_all_devices(void);
|
||||
#else
|
||||
static inline int amd_iommu_init(void) { return -ENODEV; }
|
||||
static inline void amd_iommu_detect(void) { }
|
||||
|
|
|
@ -194,6 +194,27 @@
|
|||
#define PD_DMA_OPS_MASK (1UL << 0) /* domain used for dma_ops */
|
||||
#define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops
|
||||
domain for an IOMMU */
|
||||
extern bool amd_iommu_dump;
|
||||
#define DUMP_printk(format, arg...) \
|
||||
do { \
|
||||
if (amd_iommu_dump) \
|
||||
printk(KERN_INFO "AMD IOMMU: " format, ## arg); \
|
||||
} while(0);
|
||||
|
||||
/*
|
||||
* Make iterating over all IOMMUs easier
|
||||
*/
|
||||
#define for_each_iommu(iommu) \
|
||||
list_for_each_entry((iommu), &amd_iommu_list, list)
|
||||
#define for_each_iommu_safe(iommu, next) \
|
||||
list_for_each_entry_safe((iommu), (next), &amd_iommu_list, list)
|
||||
|
||||
#define APERTURE_RANGE_SHIFT 27 /* 128 MB */
|
||||
#define APERTURE_RANGE_SIZE (1ULL << APERTURE_RANGE_SHIFT)
|
||||
#define APERTURE_RANGE_PAGES (APERTURE_RANGE_SIZE >> PAGE_SHIFT)
|
||||
#define APERTURE_MAX_RANGES 32 /* allows 4GB of DMA address space */
|
||||
#define APERTURE_RANGE_INDEX(a) ((a) >> APERTURE_RANGE_SHIFT)
|
||||
#define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL)
|
||||
|
||||
/*
|
||||
* This structure contains generic data for IOMMU protection domains
|
||||
|
@ -209,6 +230,26 @@ struct protection_domain {
|
|||
void *priv; /* private data */
|
||||
};
|
||||
|
||||
/*
|
||||
* For dynamic growth the aperture size is split into ranges of 128MB of
|
||||
* DMA address space each. This struct represents one such range.
|
||||
*/
|
||||
struct aperture_range {
|
||||
|
||||
/* address allocation bitmap */
|
||||
unsigned long *bitmap;
|
||||
|
||||
/*
|
||||
* Array of PTE pages for the aperture. In this array we save all the
|
||||
* leaf pages of the domain page table used for the aperture. This way
|
||||
* we don't need to walk the page table to find a specific PTE. We can
|
||||
* just calculate its address in constant time.
|
||||
*/
|
||||
u64 *pte_pages[64];
|
||||
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* Data container for a dma_ops specific protection domain
|
||||
*/
|
||||
|
@ -222,18 +263,10 @@ struct dma_ops_domain {
|
|||
unsigned long aperture_size;
|
||||
|
||||
/* address we start to search for free addresses */
|
||||
unsigned long next_bit;
|
||||
unsigned long next_address;
|
||||
|
||||
/* address allocation bitmap */
|
||||
unsigned long *bitmap;
|
||||
|
||||
/*
|
||||
* Array of PTE pages for the aperture. In this array we save all the
|
||||
* leaf pages of the domain page table used for the aperture. This way
|
||||
* we don't need to walk the page table to find a specific PTE. We can
|
||||
* just calculate its address in constant time.
|
||||
*/
|
||||
u64 **pte_pages;
|
||||
/* address space relevant data */
|
||||
struct aperture_range *aperture[APERTURE_MAX_RANGES];
|
||||
|
||||
/* This will be set to true when TLB needs to be flushed */
|
||||
bool need_flush;
|
||||
|
|
|
@ -107,8 +107,7 @@ extern u32 native_safe_apic_wait_icr_idle(void);
|
|||
extern void native_apic_icr_write(u32 low, u32 id);
|
||||
extern u64 native_apic_icr_read(void);
|
||||
|
||||
#define EIM_8BIT_APIC_ID 0
|
||||
#define EIM_32BIT_APIC_ID 1
|
||||
extern int x2apic_mode;
|
||||
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
/*
|
||||
|
@ -166,10 +165,9 @@ static inline u64 native_x2apic_icr_read(void)
|
|||
return val;
|
||||
}
|
||||
|
||||
extern int x2apic, x2apic_phys;
|
||||
extern int x2apic_phys;
|
||||
extern void check_x2apic(void);
|
||||
extern void enable_x2apic(void);
|
||||
extern void enable_IR_x2apic(void);
|
||||
extern void x2apic_icr_write(u32 low, u32 id);
|
||||
static inline int x2apic_enabled(void)
|
||||
{
|
||||
|
@ -183,6 +181,8 @@ static inline int x2apic_enabled(void)
|
|||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define x2apic_supported() (cpu_has_x2apic)
|
||||
#else
|
||||
static inline void check_x2apic(void)
|
||||
{
|
||||
|
@ -190,28 +190,20 @@ static inline void check_x2apic(void)
|
|||
static inline void enable_x2apic(void)
|
||||
{
|
||||
}
|
||||
static inline void enable_IR_x2apic(void)
|
||||
{
|
||||
}
|
||||
static inline int x2apic_enabled(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define x2apic 0
|
||||
|
||||
#define x2apic_preenabled 0
|
||||
#define x2apic_supported() 0
|
||||
#endif
|
||||
|
||||
extern void enable_IR_x2apic(void);
|
||||
|
||||
extern int get_physical_broadcast(void);
|
||||
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
static inline void ack_x2APIC_irq(void)
|
||||
{
|
||||
/* Docs say use 0 for future compatibility */
|
||||
native_apic_msr_write(APIC_EOI, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void apic_disable(void);
|
||||
extern int lapic_get_maxlvt(void);
|
||||
extern void clear_local_APIC(void);
|
||||
extern void connect_bsp_APIC(void);
|
||||
|
@ -252,7 +244,7 @@ static inline void lapic_shutdown(void) { }
|
|||
#define local_apic_timer_c2_ok 1
|
||||
static inline void init_apic_mappings(void) { }
|
||||
static inline void disable_local_APIC(void) { }
|
||||
|
||||
static inline void apic_disable(void) { }
|
||||
#endif /* !CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
@ -410,7 +402,7 @@ static inline unsigned default_get_apic_id(unsigned long x)
|
|||
{
|
||||
unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
|
||||
|
||||
if (APIC_XAPIC(ver))
|
||||
if (APIC_XAPIC(ver) || boot_cpu_has(X86_FEATURE_EXTD_APICID))
|
||||
return (x >> 24) & 0xFF;
|
||||
else
|
||||
return (x >> 24) & 0x0F;
|
||||
|
@ -478,6 +470,9 @@ static inline unsigned int read_apic_id(void)
|
|||
extern void default_setup_apic_routing(void);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
extern struct apic apic_default;
|
||||
|
||||
/*
|
||||
* Set up the logical destination ID.
|
||||
*
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
# define APIC_INTEGRATED(x) (1)
|
||||
#endif
|
||||
#define APIC_XAPIC(x) ((x) >= 0x14)
|
||||
#define APIC_EXT_SPACE(x) ((x) & 0x80000000)
|
||||
#define APIC_TASKPRI 0x80
|
||||
#define APIC_TPRI_MASK 0xFFu
|
||||
#define APIC_ARBPRI 0x90
|
||||
|
@ -116,7 +117,9 @@
|
|||
#define APIC_TDR_DIV_32 0x8
|
||||
#define APIC_TDR_DIV_64 0x9
|
||||
#define APIC_TDR_DIV_128 0xA
|
||||
#define APIC_EILVT0 0x500
|
||||
#define APIC_EFEAT 0x400
|
||||
#define APIC_ECTRL 0x410
|
||||
#define APIC_EILVTn(n) (0x500 + 0x10 * n)
|
||||
#define APIC_EILVT_NR_AMD_K8 1 /* # of extended interrupts */
|
||||
#define APIC_EILVT_NR_AMD_10H 4
|
||||
#define APIC_EILVT_LVTOFF(x) (((x) >> 4) & 0xF)
|
||||
|
@ -125,9 +128,6 @@
|
|||
#define APIC_EILVT_MSG_NMI 0x4
|
||||
#define APIC_EILVT_MSG_EXT 0x7
|
||||
#define APIC_EILVT_MASKED (1 << 16)
|
||||
#define APIC_EILVT1 0x510
|
||||
#define APIC_EILVT2 0x520
|
||||
#define APIC_EILVT3 0x530
|
||||
|
||||
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
|
||||
#define APIC_BASE_MSR 0x800
|
||||
|
|
|
@ -247,5 +247,241 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
|
|||
#define smp_mb__before_atomic_inc() barrier()
|
||||
#define smp_mb__after_atomic_inc() barrier()
|
||||
|
||||
/* An 64bit atomic type */
|
||||
|
||||
typedef struct {
|
||||
unsigned long long counter;
|
||||
} atomic64_t;
|
||||
|
||||
#define ATOMIC64_INIT(val) { (val) }
|
||||
|
||||
/**
|
||||
* atomic64_read - read atomic64 variable
|
||||
* @v: pointer of type atomic64_t
|
||||
*
|
||||
* Atomically reads the value of @v.
|
||||
* Doesn't imply a read memory barrier.
|
||||
*/
|
||||
#define __atomic64_read(ptr) ((ptr)->counter)
|
||||
|
||||
static inline unsigned long long
|
||||
cmpxchg8b(unsigned long long *ptr, unsigned long long old, unsigned long long new)
|
||||
{
|
||||
asm volatile(
|
||||
|
||||
LOCK_PREFIX "cmpxchg8b (%[ptr])\n"
|
||||
|
||||
: "=A" (old)
|
||||
|
||||
: [ptr] "D" (ptr),
|
||||
"A" (old),
|
||||
"b" (ll_low(new)),
|
||||
"c" (ll_high(new))
|
||||
|
||||
: "memory");
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
static inline unsigned long long
|
||||
atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val,
|
||||
unsigned long long new_val)
|
||||
{
|
||||
return cmpxchg8b(&ptr->counter, old_val, new_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_xchg - xchg atomic64 variable
|
||||
* @ptr: pointer to type atomic64_t
|
||||
* @new_val: value to assign
|
||||
* @old_val: old value that was there
|
||||
*
|
||||
* Atomically xchgs the value of @ptr to @new_val and returns
|
||||
* the old value.
|
||||
*/
|
||||
|
||||
static inline unsigned long long
|
||||
atomic64_xchg(atomic64_t *ptr, unsigned long long new_val)
|
||||
{
|
||||
unsigned long long old_val;
|
||||
|
||||
do {
|
||||
old_val = atomic_read(ptr);
|
||||
} while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
|
||||
|
||||
return old_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_set - set atomic64 variable
|
||||
* @ptr: pointer to type atomic64_t
|
||||
* @new_val: value to assign
|
||||
*
|
||||
* Atomically sets the value of @ptr to @new_val.
|
||||
*/
|
||||
static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val)
|
||||
{
|
||||
atomic64_xchg(ptr, new_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_read - read atomic64 variable
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically reads the value of @ptr and returns it.
|
||||
*/
|
||||
static inline unsigned long long atomic64_read(atomic64_t *ptr)
|
||||
{
|
||||
unsigned long long curr_val;
|
||||
|
||||
do {
|
||||
curr_val = __atomic64_read(ptr);
|
||||
} while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val);
|
||||
|
||||
return curr_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_add_return - add and return
|
||||
* @delta: integer value to add
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically adds @delta to @ptr and returns @delta + *@ptr
|
||||
*/
|
||||
static inline unsigned long long
|
||||
atomic64_add_return(unsigned long long delta, atomic64_t *ptr)
|
||||
{
|
||||
unsigned long long old_val, new_val;
|
||||
|
||||
do {
|
||||
old_val = atomic_read(ptr);
|
||||
new_val = old_val + delta;
|
||||
|
||||
} while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val);
|
||||
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr)
|
||||
{
|
||||
return atomic64_add_return(-delta, ptr);
|
||||
}
|
||||
|
||||
static inline long atomic64_inc_return(atomic64_t *ptr)
|
||||
{
|
||||
return atomic64_add_return(1, ptr);
|
||||
}
|
||||
|
||||
static inline long atomic64_dec_return(atomic64_t *ptr)
|
||||
{
|
||||
return atomic64_sub_return(1, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_add - add integer to atomic64 variable
|
||||
* @delta: integer value to add
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically adds @delta to @ptr.
|
||||
*/
|
||||
static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr)
|
||||
{
|
||||
atomic64_add_return(delta, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_sub - subtract the atomic64 variable
|
||||
* @delta: integer value to subtract
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically subtracts @delta from @ptr.
|
||||
*/
|
||||
static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr)
|
||||
{
|
||||
atomic64_add(-delta, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_sub_and_test - subtract value from variable and test result
|
||||
* @delta: integer value to subtract
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically subtracts @delta from @ptr and returns
|
||||
* true if the result is zero, or false for all
|
||||
* other cases.
|
||||
*/
|
||||
static inline int
|
||||
atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr)
|
||||
{
|
||||
unsigned long long old_val = atomic64_sub_return(delta, ptr);
|
||||
|
||||
return old_val == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_inc - increment atomic64 variable
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically increments @ptr by 1.
|
||||
*/
|
||||
static inline void atomic64_inc(atomic64_t *ptr)
|
||||
{
|
||||
atomic64_add(1, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_dec - decrement atomic64 variable
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically decrements @ptr by 1.
|
||||
*/
|
||||
static inline void atomic64_dec(atomic64_t *ptr)
|
||||
{
|
||||
atomic64_sub(1, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_dec_and_test - decrement and test
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically decrements @ptr by 1 and
|
||||
* returns true if the result is 0, or false for all other
|
||||
* cases.
|
||||
*/
|
||||
static inline int atomic64_dec_and_test(atomic64_t *ptr)
|
||||
{
|
||||
return atomic64_sub_and_test(1, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_inc_and_test - increment and test
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically increments @ptr by 1
|
||||
* and returns true if the result is zero, or false for all
|
||||
* other cases.
|
||||
*/
|
||||
static inline int atomic64_inc_and_test(atomic64_t *ptr)
|
||||
{
|
||||
return atomic64_sub_and_test(-1, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic64_add_negative - add and test if negative
|
||||
* @delta: integer value to add
|
||||
* @ptr: pointer to type atomic64_t
|
||||
*
|
||||
* Atomically adds @delta to @ptr and returns true
|
||||
* if the result is negative, or false when
|
||||
* result is greater than or equal to zero.
|
||||
*/
|
||||
static inline int
|
||||
atomic64_add_negative(unsigned long long delta, atomic64_t *ptr)
|
||||
{
|
||||
long long old_val = atomic64_add_return(delta, ptr);
|
||||
|
||||
return old_val < 0;
|
||||
}
|
||||
|
||||
#include <asm-generic/atomic.h>
|
||||
#endif /* _ASM_X86_ATOMIC_32_H */
|
||||
|
|
|
@ -8,11 +8,26 @@
|
|||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <asm/page_types.h>
|
||||
|
||||
/* Physical address where kernel should be loaded. */
|
||||
#define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
|
||||
+ (CONFIG_PHYSICAL_ALIGN - 1)) \
|
||||
& ~(CONFIG_PHYSICAL_ALIGN - 1))
|
||||
|
||||
/* Minimum kernel alignment, as a power of two */
|
||||
#ifdef CONFIG_x86_64
|
||||
#define MIN_KERNEL_ALIGN_LG2 PMD_SHIFT
|
||||
#else
|
||||
#define MIN_KERNEL_ALIGN_LG2 (PAGE_SHIFT+1)
|
||||
#endif
|
||||
#define MIN_KERNEL_ALIGN (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2)
|
||||
|
||||
#if (CONFIG_PHYSICAL_ALIGN & (CONFIG_PHYSICAL_ALIGN-1)) || \
|
||||
(CONFIG_PHYSICAL_ALIGN < (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2))
|
||||
#error "Invalid value for CONFIG_PHYSICAL_ALIGN"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KERNEL_BZIP2
|
||||
#define BOOT_HEAP_SIZE 0x400000
|
||||
#else /* !CONFIG_KERNEL_BZIP2 */
|
||||
|
|
|
@ -50,7 +50,8 @@ struct setup_header {
|
|||
__u32 ramdisk_size;
|
||||
__u32 bootsect_kludge;
|
||||
__u16 heap_end_ptr;
|
||||
__u16 _pad1;
|
||||
__u8 ext_loader_ver;
|
||||
__u8 ext_loader_type;
|
||||
__u32 cmd_line_ptr;
|
||||
__u32 initrd_addr_max;
|
||||
__u32 kernel_alignment;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue