code:
==============================
RT-mutex implementation design
==============================

Copyright (c) 2006 Steven Rostedt

Licensed under the GNU Free Documentation License, Version 1.2

This document tries to describe the design of the rtmutex.c implementation.
It doesn't describe the reasons why rtmutex.c exists. For that please see
Documentation/locking/rt-mutex.rst.  Although this document does explain problems
that happen without this code, but that is in the concept to understand
what the code actually is doing.

The goal of this document is to help others understand the priority
inheritance (PI) algorithm that is used, as well as reasons for the
decisions that were made to implement PI in the manner that was done.

Unbounded Priority Inversion
----------------------------

Priority inversion is when a lower priority process executes while a higher
priority process wants to run.  This happens for several reasons, and
most of the time it can't be helped.  Anytime a high priority process wants
to use a resource that a lower priority process has (a mutex for example),
the high priority process must wait until the lower priority process is done
with the resource.  This is a priority inversion.  What we want to prevent
is something called unbounded priority inversion.  That is when the high
priority process is prevented from running by a lower priority process for
an undetermined amount of time.

The classic example of unbounded priority inversion is where you have three
processes, let's call them processes A, B, and C, where A is the highest
priority process, C is the lowest, and B is in between. A tries to grab a lock
that C owns and must wait and lets C run to release the lock. But in the
meantime, B executes, and since B is of a higher priority than C, it preempts C,
but by doing so, it is in fact preempting A which is a higher priority process.
Now there's no way of knowing how long A will be sleeping waiting for C
to release the lock, because for all we know, B is a CPU hog and will
never give C a chance to release the lock.  This is called unbounded priority
inversion.

Here's a little ASCII art to show the problem::

     grab lock L1 (owned by C)
       |
  A ---+
          C preempted by B
            |
  C    +----+

  B         +-------->
                  B now keeps A from running.

Priority Inheritance (PI)
-------------------------

There are several ways to solve this issue, but other ways are out of scope
for this document.  Here we only discuss PI.

PI is where a process inherits the priority of another process if the other
process blocks on a lock owned by the current process.  To make this easier
to understand, let's use the previous example, with processes A, B, and C again.

This time, when A blocks on the lock owned by C, C would inherit the priority
of A.  So now if B becomes runnable, it would not preempt C, since C now has
the high priority of A.  As soon as C releases the lock, it loses its
inherited priority, and A then can continue with the resource that C had.

Terminology
-----------

Here I explain some terminology that is used in this document to help describe
the design that is used to implement PI.

PI chain
         - The PI chain is an ordered series of locks and processes that cause
           processes to inherit priorities from a previous process that is
           blocked on one of its locks.  This is described in more detail
           later in this document.

mutex
         - In this document, to differentiate from locks that implement
           PI and spin locks that are used in the PI code, from now on
           the PI locks will be called a mutex.

lock
         - In this document from now on, I will use the term lock when
           referring to spin locks that are used to protect parts of the PI
           algorithm.  These locks disable preemption for UP (when
           CONFIG_PREEMPT is enabled) and on SMP prevents multiple CPUs from
           entering critical sections simultaneously.

spin lock
         - Same as lock above.

waiter
         - A waiter is a struct that is stored on the stack of a blocked
           process.  Since the scope of the waiter is within the code for
           a process being blocked on the mutex, it is fine to allocate
           the waiter on the process's stack (local variable).  This
           structure holds a pointer to the task, as well as the mutex that
           the task is blocked on.  It also has rbtree node structures to
           place the task in the waiters rbtree of a mutex as well as the
           pi_waiters rbtree of a mutex owner task (described below).

           waiter is sometimes used in reference to the task that is waiting
           on a mutex. This is the same as waiter->task.

waiters
         - A list of processes that are blocked on a mutex.

top waiter
         - The highest priority process waiting on a specific mutex.

top pi waiter
              - The highest priority process waiting on one of the mutexes
                that a specific process owns.

Note:
       task and process are used interchangeably in this document, mostly to
       differentiate between two processes that are being described together.

PI chain
--------

The PI chain is a list of processes and mutexes that may cause priority
inheritance to take place.  Multiple chains may converge, but a chain
would never diverge, since a process can't be blocked on more than one
mutex at a time.

Example::

   Process:  A, B, C, D, E
   Mutexes:  L1, L2, L3, L4

   A owns: L1
           B blocked on L1
           B owns L2
                  C blocked on L2
                  C owns L3
                         D blocked on L3
                         D owns L4
                                E blocked on L4

The chain would be::

   E->L4->D->L3->C->L2->B->L1->A

To show where two chains merge, we could add another process F and
another mutex L5 where B owns L5 and F is blocked on mutex L5.

The chain for F would be::

   F->L5->B->L1->A

Since a process may own more than one mutex, but never be blocked on more than
one, the chains merge.

Here we show both chains::

   E->L4->D->L3->C->L2-+
                       |
                       +->B->L1->A
                       |
                 F->L5-+

For PI to work, the processes at the right end of these chains (or we may
also call it the Top of the chain) must be equal to or higher in priority
than the processes to the left or below in the chain.

Also since a mutex may have more than one process blocked on it, we can
have multiple chains merge at mutexes.  If we add another process G that is
blocked on mutex L2::

  G->L2->B->L1->A

And once again, to show how this can grow I will show the merging chains
again::

   E->L4->D->L3->C-+
                   +->L2-+
                   |     |
                 G-+     +->B->L1->A
                         |
                   F->L5-+

If process G has the highest priority in the chain, then all the tasks up
the chain (A and B in this example), must have their priorities increased
to that of G.

Mutex Waiters Tree
------------------

Every mutex keeps track of all the waiters that are blocked on itself. The
mutex has a rbtree to store these waiters by priority.  This tree is protected
by a spin lock that is located in the struct of the mutex. This lock is called
wait_lock.

Task PI Tree
------------

To keep track of the PI chains, each process has its own PI rbtree.  This is
a tree of all top waiters of the mutexes that are owned by the process.
Note that this tree only holds the top waiters and not all waiters that are
blocked on mutexes owned by the process.

The top of the task's PI tree is always the highest priority task that
is waiting on a mutex that is owned by the task.  So if the task has
inherited a priority, it will always be the priority of the task that is
at the top of this tree.

This tree is stored in the task structure of a process as a rbtree called
pi_waiters.  It is protected by a spin lock also in the task structure,
called pi_lock.  This lock may also be taken in interrupt context, so when
locking the pi_lock, interrupts must be disabled.

Depth of the PI Chain
---------------------

The maximum depth of the PI chain is not dynamic, and could actually be
defined.  But is very complex to figure it out, since it depends on all
the nesting of mutexes.  Let's look at the example where we have 3 mutexes,
L1, L2, and L3, and four separate functions func1, func2, func3 and func4.
The following shows a locking order of L1->L2->L3, but may not actually
be directly nested that way::

  void func1(void)
  {
	mutex_lock(L1);

	/* do anything */

	mutex_unlock(L1);
  }

  void func2(void)
  {
	mutex_lock(L1);
	mutex_lock(L2);

	/* do something */

	mutex_unlock(L2);
	mutex_unlock(L1);
  }

  void func3(void)
  {
	mutex_lock(L2);
	mutex_lock(L3);

	/* do something else */

	mutex_unlock(L3);
	mutex_unlock(L2);
  }

  void func4(void)
  {
	mutex_lock(L3);

	/* do something again */

	mutex_unlock(L3);
  }

Now we add 4 processes that run each of these functions separately.
Processes A, B, C, and D which run functions func1, func2, func3 and func4
respectively, and such that D runs first and A last.  With D being preempted
in func4 in the "do something again" area, we have a locking that follows::

  D owns L3
         C blocked on L3
         C owns L2
                B blocked on L2
                B owns L1
                       A blocked on L1

  And thus we have the chain A->L1->B->L2->C->L3->D.

This gives us a PI depth of 4 (four processes), but looking at any of the
functions individually, it seems as though they only have at most a locking
depth of two.  So, although the locking depth is defined at compile time,
it still is very difficult to find the possibilities of that depth.

Now since mutexes can be defined by user-land applications, we don't want a DOS
type of application that nests large amounts of mutexes to create a large
PI chain, and have the code holding spin locks while looking at a large
amount of data.  So to prevent this, the implementation not only implements
a maximum lock depth, but also only holds at most two different locks at a
time, as it walks the PI chain.  More about this below.

Mutex owner and flags
---------------------

The mutex structure contains a pointer to the owner of the mutex.  If the
mutex is not owned, this owner is set to NULL.  Since all architectures
have the task structure on at least a two byte alignment (and if this is
not true, the rtmutex.c code will be broken!), this allows for the least
significant bit to be used as a flag.  Bit 0 is used as the "Has Waiters"
flag. It's set whenever there are waiters on a mutex.

See Documentation/locking/rt-mutex.rst for further details.

cmpxchg Tricks
--------------

Some architectures implement an atomic cmpxchg (Compare and Exchange).  This
is used (when applicable) to keep the fast path of grabbing and releasing
mutexes short.

cmpxchg is basically the following function performed atomically::

  unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
  {
	unsigned long T = *A;
	if (*A == *B) {
		*A = *C;
	}
	return T;
  }
  #define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)

This is really nice to have, since it allows you to only update a variable
if the variable is what you expect it to be.  You know if it succeeded if
the return value (the old value of A) is equal to B.

The macro rt_mutex_cmpxchg is used to try to lock and unlock mutexes. If
the architecture does not support CMPXCHG, then this macro is simply set
to fail every time.  But if CMPXCHG is supported, then this will
help out extremely to keep the fast path short.

The use of rt_mutex_cmpxchg with the flags in the owner field help optimize
the system for architectures that support it.  This will also be explained
later in this document.

Priority adjustments
--------------------

The implementation of the PI code in rtmutex.c has several places that a
process must adjust its priority.  With the help of the pi_waiters of a
process this is rather easy to know what needs to be adjusted.

The functions implementing the task adjustments are rt_mutex_adjust_prio
and rt_mutex_setprio. rt_mutex_setprio is only used in rt_mutex_adjust_prio.

rt_mutex_adjust_prio examines the priority of the task, and the highest
priority process that is waiting any of mutexes owned by the task. Since
the pi_waiters of a task holds an order by priority of all the top waiters
of all the mutexes that the task owns, we simply need to compare the top
pi waiter to its own normal/deadline priority and take the higher one.
Then rt_mutex_setprio is called to adjust the priority of the task to the
new priority. Note that rt_mutex_setprio is defined in kernel/sched/core.c
to implement the actual change in priority.

Note:
	For the "prio" field in task_struct, the lower the number, the
	higher the priority. A "prio" of 5 is of higher priority than a
	"prio" of 10.

It is interesting to note that rt_mutex_adjust_prio can either increase
or decrease the priority of the task.  In the case that a higher priority
process has just blocked on a mutex owned by the task, rt_mutex_adjust_prio
would increase/boost the task's priority.  But if a higher priority task
were for some reason to leave the mutex (timeout or signal), this same function
would decrease/unboost the priority of the task.  That is because the pi_waiters
always contains the highest priority task that is waiting on a mutex owned
by the task, so we only need to compare the priority of that top pi waiter
to the normal priority of the given task.

High level overview of the PI chain walk
----------------------------------------

The PI chain walk is implemented by the function rt_mutex_adjust_prio_chain.

The implementation has gone through several iterations, and has ended up
with what we believe is the best.  It walks the PI chain by only grabbing
at most two locks at a time, and is very efficient.

The rt_mutex_adjust_prio_chain can be used either to boost or lower process
priorities.

rt_mutex_adjust_prio_chain is called with a task to be checked for PI
(de)boosting (the owner of a mutex that a process is blocking on), a flag to
check for deadlocking, the mutex that the task owns, a pointer to a waiter
that is the process's waiter struct that is blocked on the mutex (although this
parameter may be NULL for deboosting), a pointer to the mutex on which the task
is blocked, and a top_task as the top waiter of the mutex.

For this explanation, I will not mention deadlock detection. This explanation
will try to stay at a high level.

When this function is called, there are no locks held.  That also means
that the state of the owner and lock can change when entered into this function.

Before this function is called, the task has already had rt_mutex_adjust_prio
performed on it.  This means that the task is set to the priority that it
should be at, but the rbtree nodes of the task's waiter have not been updated
with the new priorities, and this task may not be in the proper locations
in the pi_waiters and waiters trees that the task is blocked on. This function
solves all that.

The main operation of this function is summarized by Thomas Gleixner in
rtmutex.c. See the 'Chain walk basics and protection scope' comment for further
details.

Taking of a mutex (The walk through)
------------------------------------

OK, now let's take a look at the detailed walk through of what happens when
taking a mutex.

The first thing that is tried is the fast taking of the mutex.  This is
done when we have CMPXCHG enabled (otherwise the fast taking automatically
fails).  Only when the owner field of the mutex is NULL can the lock be
taken with the CMPXCHG and nothing else needs to be done.

If there is contention on the lock, we go about the slow path
(rt_mutex_slowlock).

The slow path function is where the task's waiter structure is created on
the stack.  This is because the waiter structure is only needed for the
scope of this function.  The waiter structure holds the nodes to store
the task on the waiters tree of the mutex, and if need be, the pi_waiters
tree of the owner.

The wait_lock of the mutex is taken since the slow path of unlocking the
mutex also takes this lock.

We then call try_to_take_rt_mutex.  This is where the architecture that
does not implement CMPXCHG would always grab the lock (if there's no
contention).

try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
slow path.  The first thing that is done here is an atomic setting of
the "Has Waiters" flag of the mutex's owner field. By setting this flag
now, the current owner of the mutex being contended for can't release the mutex
without going into the slow unlock path, and it would then need to grab the
wait_lock, which this code currently holds. So setting the "Has Waiters" flag
forces the current owner to synchronize with this code.

The lock is taken if the following are true:

   1) The lock has no owner
   2) The current task is the highest priority against all other
      waiters of the lock

If the task succeeds to acquire the lock, then the task is set as the
owner of the lock, and if the lock still has waiters, the top_waiter
(highest priority task waiting on the lock) is added to this task's
pi_waiters tree.

If the lock is not taken by try_to_take_rt_mutex(), then the
task_blocks_on_rt_mutex() function is called. This will add the task to
the lock's waiter tree and propagate the pi chain of the lock as well
as the lock's owner's pi_waiters tree. This is described in the next
section.

Task blocks on mutex
--------------------

The accounting of a mutex and process is done with the waiter structure of
the process.  The "task" field is set to the process, and the "lock" field
to the mutex.  The rbtree node of waiter are initialized to the processes
current priority.

Since the wait_lock was taken at the entry of the slow lock, we can safely
add the waiter to the task waiter tree.  If the current process is the
highest priority process currently waiting on this mutex, then we remove the
previous top waiter process (if it exists) from the pi_waiters of the owner,
and add the current process to that tree.  Since the pi_waiter of the owner
has changed, we call rt_mutex_adjust_prio on the owner to see if the owner
should adjust its priority accordingly.

If the owner is also blocked on a lock, and had its pi_waiters changed
(or deadlock checking is on), we unlock the wait_lock of the mutex and go ahead
and run rt_mutex_adjust_prio_chain on the owner, as described earlier.

Now all locks are released, and if the current process is still blocked on a
mutex (waiter "task" field is not NULL), then we go to sleep (call schedule).

Waking up in the loop
---------------------

The task can then wake up for a couple of reasons:
  1) The previous lock owner released the lock, and the task now is top_waiter
  2) we received a signal or timeout

In both cases, the task will try again to acquire the lock. If it
does, then it will take itself off the waiters tree and set itself back
to the TASK_RUNNING state.

In first case, if the lock was acquired by another task before this task
could get the lock, then it will go back to sleep and wait to be woken again.

The second case is only applicable for tasks that are grabbing a mutex
that can wake up before getting the lock, either due to a signal or
a timeout (i.e. rt_mutex_timed_futex_lock()). When woken, it will try to
take the lock again, if it succeeds, then the task will return with the
lock held, otherwise it will return with -EINTR if the task was woken
by a signal, or -ETIMEDOUT if it timed out.

Unlocking the Mutex
-------------------

The unlocking of a mutex also has a fast path for those architectures with
CMPXCHG.  Since the taking of a mutex on contention always sets the
"Has Waiters" flag of the mutex's owner, we use this to know if we need to
take the slow path when unlocking the mutex.  If the mutex doesn't have any
waiters, the owner field of the mutex would equal the current process and
the mutex can be unlocked by just replacing the owner field with NULL.

If the owner field has the "Has Waiters" bit set (or CMPXCHG is not available),
the slow unlock path is taken.

The first thing done in the slow unlock path is to take the wait_lock of the
mutex.  This synchronizes the locking and unlocking of the mutex.

A check is made to see if the mutex has waiters or not.  On architectures that
do not have CMPXCHG, this is the location that the owner of the mutex will
determine if a waiter needs to be awoken or not.  On architectures that
do have CMPXCHG, that check is done in the fast path, but it is still needed
in the slow path too.  If a waiter of a mutex woke up because of a signal
or timeout between the time the owner failed the fast path CMPXCHG check and
the grabbing of the wait_lock, the mutex may not have any waiters, thus the
owner still needs to make this check. If there are no waiters then the mutex
owner field is set to NULL, the wait_lock is released and nothing more is
needed.

If there are waiters, then we need to wake one up.

On the wake up code, the pi_lock of the current owner is taken.  The top
waiter of the lock is found and removed from the waiters tree of the mutex
as well as the pi_waiters tree of the current owner. The "Has Waiters" bit is
marked to prevent lower priority tasks from stealing the lock.

Finally we unlock the pi_lock of the pending owner and wake it up.

Contact
-------

For updates on this document, please email Steven Rostedt <rostedt@goodmis.org>

Credits
-------

Author:  Steven Rostedt <rostedt@goodmis.org>

Updated: Alex Shi <alex.shi@linaro.org>	- 7/6/2017

Original Reviewers:
		     Ingo Molnar, Thomas Gleixner, Thomas Duetsch, and
		     Randy Dunlap

Update (7/6/2017) Reviewers: Steven Rostedt and Sebastian Siewior

Updates
-------

This document was originally written for 2.6.17-rc3-mm1
was updated on 4.12


code:
==================================
RT-mutex subsystem with PI support
==================================

RT-mutexes with priority inheritance are used to support PI-futexes,
which enable pthread_mutex_t priority inheritance attributes
(PTHREAD_PRIO_INHERIT). [See Documentation/locking/pi-futex.rst for more details
about PI-futexes.]

This technology was developed in the -rt tree and streamlined for
pthread_mutex support.

Basic principles:
-----------------

RT-mutexes extend the semantics of simple mutexes by the priority
inheritance protocol.

A low priority owner of a rt-mutex inherits the priority of a higher
priority waiter until the rt-mutex is released. If the temporarily
boosted owner blocks on a rt-mutex itself it propagates the priority
boosting to the owner of the other rt_mutex it gets blocked on. The
priority boosting is immediately removed once the rt_mutex has been
unlocked.

This approach allows us to shorten the block of high-prio tasks on
mutexes which protect shared resources. Priority inheritance is not a
magic bullet for poorly designed applications, but it allows
well-designed applications to use userspace locks in critical parts of
an high priority thread, without losing determinism.

The enqueueing of the waiters into the rtmutex waiter tree is done in
priority order. For same priorities FIFO order is chosen. For each
rtmutex, only the top priority waiter is enqueued into the owner's
priority waiters tree. This tree too queues in priority order. Whenever
the top priority waiter of a task changes (for example it timed out or
got a signal), the priority of the owner task is readjusted. The
priority enqueueing is handled by "pi_waiters".

RT-mutexes are optimized for fastpath operations and have no internal
locking overhead when locking an uncontended mutex or unlocking a mutex
without waiters. The optimized fastpath operations require cmpxchg
support. [If that is not available then the rt-mutex internal spinlock
is used]

The state of the rt-mutex is tracked via the owner field of the rt-mutex
structure:

lock->owner holds the task_struct pointer of the owner. Bit 0 is used to
keep track of the "lock has waiters" state:

 ============ ======= ================================================
 owner        bit0    Notes
 ============ ======= ================================================
 NULL         0       lock is free (fast acquire possible)
 NULL         1       lock is free and has waiters and the top waiter
		      is going to take the lock [1]_
 taskpointer  0       lock is held (fast release possible)
 taskpointer  1       lock is held and has waiters [2]_
 ============ ======= ================================================

The fast atomic compare exchange based acquire and release is only
possible when bit 0 of lock->owner is 0.

.. [1] It also can be a transitional state when grabbing the lock
       with ->wait_lock is held. To prevent any fast path cmpxchg to the lock,
       we need to set the bit0 before looking at the lock, and the owner may
       be NULL in this small time, hence this can be a transitional state.

.. [2] There is a small time when bit 0 is set but there are no
       waiters. This can happen when grabbing the lock in the slow path.
       To prevent a cmpxchg of the owner releasing the lock, we need to
       set this bit before looking at the lock.

BTW, there is still technically a "Pending Owner", it's just not called
that anymore. The pending owner happens to be the top_waiter of a lock
that has no owner and has been woken up to grab the lock.

repo_name: angery/linux


code:
======================================
Sequence counters and sequential locks
======================================

Introduction
============

Sequence counters are a reader-writer consistency mechanism with
lockless readers (read-only retry loops), and no writer starvation. They
are used for data that's rarely written to (e.g. system time), where the
reader wants a consistent set of information and is willing to retry if
that information changes.

A data set is consistent when the sequence count at the beginning of the
read side critical section is even and the same sequence count value is
read again at the end of the critical section. The data in the set must
be copied out inside the read side critical section. If the sequence
count has changed between the start and the end of the critical section,
the reader must retry.

Writers increment the sequence count at the start and the end of their
critical section. After starting the critical section the sequence count
is odd and indicates to the readers that an update is in progress. At
the end of the write side critical section the sequence count becomes
even again which lets readers make progress.

A sequence counter write side critical section must never be preempted
or interrupted by read side sections. Otherwise the reader will spin for
the entire scheduler tick due to the odd sequence count value and the
interrupted writer. If that reader belongs to a real-time scheduling
class, it can spin forever and the kernel will livelock.

This mechanism cannot be used if the protected data contains pointers,
as the writer can invalidate a pointer that the reader is following.

.. _seqcount_t:

Sequence counters (``seqcount_t``)
==================================

This is the raw counting mechanism, which does not protect against
multiple writers.  Write side critical sections must thus be serialized
by an external lock.

If the write serialization primitive is not implicitly disabling
preemption, preemption must be explicitly disabled before entering the
write side section. If the read section can be invoked from hardirq or
softirq contexts, interrupts or bottom halves must also be respectively
disabled before entering the write section.

If it's desired to automatically handle the sequence counter
requirements of writer serialization and non-preemptibility, use
:ref:`seqlock_t` instead.

Initialization::

	/* dynamic */
	seqcount_t foo_seqcount;
	seqcount_init(&foo_seqcount);

	/* static */
	static seqcount_t foo_seqcount = SEQCNT_ZERO(foo_seqcount);

	/* C99 struct init */
	struct {
		.seq   = SEQCNT_ZERO(foo.seq),
	} foo;

Write path::

	/* Serialized context with disabled preemption */

	write_seqcount_begin(&foo_seqcount);

	/* ... [[write-side critical section]] ... */

	write_seqcount_end(&foo_seqcount);

Read path::

	do {
		seq = read_seqcount_begin(&foo_seqcount);

		/* ... [[read-side critical section]] ... */

	} while (read_seqcount_retry(&foo_seqcount, seq));

.. _seqcount_locktype_t:

Sequence counters with associated locks (``seqcount_LOCKNAME_t``)
-----------------------------------------------------------------

As discussed at :ref:`seqcount_t`, sequence count write side critical
sections must be serialized and non-preemptible. This variant of
sequence counters associate the lock used for writer serialization at
initialization time, which enables lockdep to validate that the write
side critical sections are properly serialized.

This lock association is a NOOP if lockdep is disabled and has neither
storage nor runtime overhead. If lockdep is enabled, the lock pointer is
stored in struct seqcount and lockdep's "lock is held" assertions are
injected at the beginning of the write side critical section to validate
that it is properly protected.

For lock types which do not implicitly disable preemption, preemption
protection is enforced in the write side function.

The following sequence counters with associated locks are defined:

  - ``seqcount_spinlock_t``
  - ``seqcount_raw_spinlock_t``
  - ``seqcount_rwlock_t``
  - ``seqcount_mutex_t``
  - ``seqcount_ww_mutex_t``

The sequence counter read and write APIs can take either a plain
seqcount_t or any of the seqcount_LOCKNAME_t variants above.

Initialization (replace "LOCKNAME" with one of the supported locks)::

	/* dynamic */
	seqcount_LOCKNAME_t foo_seqcount;
	seqcount_LOCKNAME_init(&foo_seqcount, &lock);

	/* static */
	static seqcount_LOCKNAME_t foo_seqcount =
		SEQCNT_LOCKNAME_ZERO(foo_seqcount, &lock);

	/* C99 struct init */
	struct {
		.seq   = SEQCNT_LOCKNAME_ZERO(foo.seq, &lock),
	} foo;

Write path: same as in :ref:`seqcount_t`, while running from a context
with the associated write serialization lock acquired.

Read path: same as in :ref:`seqcount_t`.

.. _seqcount_latch_t:

Latch sequence counters (``seqcount_latch_t``)
----------------------------------------------

Latch sequence counters are a multiversion concurrency control mechanism
where the embedded seqcount_t counter even/odd value is used to switch
between two copies of protected data. This allows the sequence counter
read path to safely interrupt its own write side critical section.

Use seqcount_latch_t when the write side sections cannot be protected
from interruption by readers. This is typically the case when the read
side can be invoked from NMI handlers.

Check `raw_write_seqcount_latch()` for more information.

.. _seqlock_t:

Sequential locks (``seqlock_t``)
================================

This contains the :ref:`seqcount_t` mechanism earlier discussed, plus an
embedded spinlock for writer serialization and non-preemptibility.

If the read side section can be invoked from hardirq or softirq context,
use the write side function variants which disable interrupts or bottom
halves respectively.

Initialization::

	/* dynamic */
	seqlock_t foo_seqlock;
	seqlock_init(&foo_seqlock);

	/* static */
	static DEFINE_SEQLOCK(foo_seqlock);

	/* C99 struct init */
	struct {
		.seql   = __SEQLOCK_UNLOCKED(foo.seql)
	} foo;

Write path::

	write_seqlock(&foo_seqlock);

	/* ... [[write-side critical section]] ... */

	write_sequnlock(&foo_seqlock);

Read path, three categories:

1. Normal Sequence readers which never block a writer but they must
   retry if a writer is in progress by detecting change in the sequence
   number.  Writers do not wait for a sequence reader::

	do {
		seq = read_seqbegin(&foo_seqlock);

		/* ... [[read-side critical section]] ... */

	} while (read_seqretry(&foo_seqlock, seq));

2. Locking readers which will wait if a writer or another locking reader
   is in progress. A locking reader in progress will also block a writer
   from entering its critical section. This read lock is
   exclusive. Unlike rwlock_t, only one locking reader can acquire it::

	read_seqlock_excl(&foo_seqlock);

	/* ... [[read-side critical section]] ... */

	read_sequnlock_excl(&foo_seqlock);

3. Conditional lockless reader (as in 1), or locking reader (as in 2),
   according to a passed marker. This is used to avoid lockless readers
   starvation (too much retry loops) in case of a sharp spike in write
   activity. First, a lockless read is tried (even marker passed). If
   that trial fails (odd sequence counter is returned, which is used as
   the next iteration marker), the lockless read is transformed to a
   full locking read and no retry loop is necessary::

	/* marker; even initialization */
	int seq = 0;
	do {
		read_seqbegin_or_lock(&foo_seqlock, &seq);

		/* ... [[read-side critical section]] ... */

	} while (need_seqretry(&foo_seqlock, seq));
	done_seqretry(&foo_seqlock, seq);

API documentation
=================

.. kernel-doc:: include/linux/seqlock.h


code:
===============
Locking lessons
===============

Lesson 1: Spin locks
====================

The most basic primitive for locking is spinlock::

  static DEFINE_SPINLOCK(xxx_lock);

	unsigned long flags;

	spin_lock_irqsave(&xxx_lock, flags);
	... critical section here ..
	spin_unlock_irqrestore(&xxx_lock, flags);

The above is always safe. It will disable interrupts _locally_, but the
spinlock itself will guarantee the global lock, so it will guarantee that
there is only one thread-of-control within the region(s) protected by that
lock. This works well even under UP also, so the code does _not_ need to
worry about UP vs SMP issues: the spinlocks work correctly under both.

   NOTE! Implications of spin_locks for memory are further described in:

     Documentation/memory-barriers.txt

       (5) ACQUIRE operations.

       (6) RELEASE operations.

The above is usually pretty simple (you usually need and want only one
spinlock for most things - using more than one spinlock can make things a
lot more complex and even slower and is usually worth it only for
sequences that you **know** need to be split up: avoid it at all cost if you
aren't sure).

This is really the only really hard part about spinlocks: once you start
using spinlocks they tend to expand to areas you might not have noticed
before, because you have to make sure the spinlocks correctly protect the
shared data structures **everywhere** they are used. The spinlocks are most
easily added to places that are completely independent of other code (for
example, internal driver data structures that nobody else ever touches).

   NOTE! The spin-lock is safe only when you **also** use the lock itself
   to do locking across CPU's, which implies that EVERYTHING that
   touches a shared variable has to agree about the spinlock they want
   to use.

----

Lesson 2: reader-writer spinlocks.
==================================

If your data accesses have a very natural pattern where you usually tend
to mostly read from the shared variables, the reader-writer locks
(rw_lock) versions of the spinlocks are sometimes useful. They allow multiple
readers to be in the same critical region at once, but if somebody wants
to change the variables it has to get an exclusive write lock.

   NOTE! reader-writer locks require more atomic memory operations than
   simple spinlocks.  Unless the reader critical section is long, you
   are better off just using spinlocks.

The routines look the same as above::

   rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);

	unsigned long flags;

	read_lock_irqsave(&xxx_lock, flags);
	.. critical section that only reads the info ...
	read_unlock_irqrestore(&xxx_lock, flags);

	write_lock_irqsave(&xxx_lock, flags);
	.. read and write exclusive access to the info ...
	write_unlock_irqrestore(&xxx_lock, flags);

The above kind of lock may be useful for complex data structures like
linked lists, especially searching for entries without changing the list
itself.  The read lock allows many concurrent readers.  Anything that
**changes** the list will have to get the write lock.

   NOTE! RCU is better for list traversal, but requires careful
   attention to design detail (see Documentation/RCU/listRCU.rst).

Also, you cannot "upgrade" a read-lock to a write-lock, so if you at _any_
time need to do any changes (even if you don't do it every time), you have
to get the write-lock at the very beginning.

   NOTE! We are working hard to remove reader-writer spinlocks in most
   cases, so please don't add a new one without consensus.  (Instead, see
   Documentation/RCU/rcu.rst for complete information.)

----

Lesson 3: spinlocks revisited.
==============================

The single spin-lock primitives above are by no means the only ones. They
are the most safe ones, and the ones that work under all circumstances,
but partly **because** they are safe they are also fairly slow. They are slower
than they'd need to be, because they do have to disable interrupts
(which is just a single instruction on a x86, but it's an expensive one -
and on other architectures it can be worse).

If you have a case where you have to protect a data structure across
several CPU's and you want to use spinlocks you can potentially use
cheaper versions of the spinlocks. IFF you know that the spinlocks are
never used in interrupt handlers, you can use the non-irq versions::

	spin_lock(&lock);
	...
	spin_unlock(&lock);

(and the equivalent read-write versions too, of course). The spinlock will
guarantee the same kind of exclusive access, and it will be much faster.
This is useful if you know that the data in question is only ever
manipulated from a "process context", ie no interrupts involved.

The reasons you mustn't use these versions if you have interrupts that
play with the spinlock is that you can get deadlocks::

	spin_lock(&lock);
	...
		<- interrupt comes in:
			spin_lock(&lock);

where an interrupt tries to lock an already locked variable. This is ok if
the other interrupt happens on another CPU, but it is _not_ ok if the
interrupt happens on the same CPU that already holds the lock, because the
lock will obviously never be released (because the interrupt is waiting
for the lock, and the lock-holder is interrupted by the interrupt and will
not continue until the interrupt has been processed).

(This is also the reason why the irq-versions of the spinlocks only need
to disable the _local_ interrupts - it's ok to use spinlocks in interrupts
on other CPU's, because an interrupt on another CPU doesn't interrupt the
CPU that holds the lock, so the lock-holder can continue and eventually
releases the lock).

		Linus

----

Reference information:
======================

For dynamic initialization, use spin_lock_init() or rwlock_init() as
appropriate::

   spinlock_t xxx_lock;
   rwlock_t xxx_rw_lock;

   static int __init xxx_init(void)
   {
	spin_lock_init(&xxx_lock);
	rwlock_init(&xxx_rw_lock);
	...
   }

   module_init(xxx_init);

For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
__SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.


code:
======================================
Wound/Wait Deadlock-Proof Mutex Design
======================================

Please read mutex-design.rst first, as it applies to wait/wound mutexes too.

Motivation for WW-Mutexes
-------------------------

GPU's do operations that commonly involve many buffers.  Those buffers
can be shared across contexts/processes, exist in different memory
domains (for example VRAM vs system memory), and so on.  And with
PRIME / dmabuf, they can even be shared across devices.  So there are
a handful of situations where the driver needs to wait for buffers to
become ready.  If you think about this in terms of waiting on a buffer
mutex for it to become available, this presents a problem because
there is no way to guarantee that buffers appear in a execbuf/batch in
the same order in all contexts.  That is directly under control of
userspace, and a result of the sequence of GL calls that an application
makes.	Which results in the potential for deadlock.  The problem gets
more complex when you consider that the kernel may need to migrate the
buffer(s) into VRAM before the GPU operates on the buffer(s), which
may in turn require evicting some other buffers (and you don't want to
evict other buffers which are already queued up to the GPU), but for a
simplified understanding of the problem you can ignore this.

The algorithm that the TTM graphics subsystem came up with for dealing with
this problem is quite simple.  For each group of buffers (execbuf) that need
to be locked, the caller would be assigned a unique reservation id/ticket,
from a global counter.  In case of deadlock while locking all the buffers
associated with a execbuf, the one with the lowest reservation ticket (i.e.
the oldest task) wins, and the one with the higher reservation id (i.e. the
younger task) unlocks all of the buffers that it has already locked, and then
tries again.

In the RDBMS literature, a reservation ticket is associated with a transaction.
and the deadlock handling approach is called Wait-Die. The name is based on
the actions of a locking thread when it encounters an already locked mutex.
If the transaction holding the lock is younger, the locking transaction waits.
If the transaction holding the lock is older, the locking transaction backs off
and dies. Hence Wait-Die.
There is also another algorithm called Wound-Wait:
If the transaction holding the lock is younger, the locking transaction
wounds the transaction holding the lock, requesting it to die.
If the transaction holding the lock is older, it waits for the other
transaction. Hence Wound-Wait.
The two algorithms are both fair in that a transaction will eventually succeed.
However, the Wound-Wait algorithm is typically stated to generate fewer backoffs
compared to Wait-Die, but is, on the other hand, associated with more work than
Wait-Die when recovering from a backoff. Wound-Wait is also a preemptive
algorithm in that transactions are wounded by other transactions, and that
requires a reliable way to pick up the wounded condition and preempt the
running transaction. Note that this is not the same as process preemption. A
Wound-Wait transaction is considered preempted when it dies (returning
-EDEADLK) following a wound.

Concepts
--------

Compared to normal mutexes two additional concepts/objects show up in the lock
interface for w/w mutexes:

Acquire context: To ensure eventual forward progress it is important that a task
trying to acquire locks doesn't grab a new reservation id, but keeps the one it
acquired when starting the lock acquisition. This ticket is stored in the
acquire context. Furthermore the acquire context keeps track of debugging state
to catch w/w mutex interface abuse. An acquire context is representing a
transaction.

W/w class: In contrast to normal mutexes the lock class needs to be explicit for
w/w mutexes, since it is required to initialize the acquire context. The lock
class also specifies what algorithm to use, Wound-Wait or Wait-Die.

Furthermore there are three different class of w/w lock acquire functions:

* Normal lock acquisition with a context, using ww_mutex_lock.

* Slowpath lock acquisition on the contending lock, used by the task that just
  killed its transaction after having dropped all already acquired locks.
  These functions have the _slow postfix.

  From a simple semantics point-of-view the _slow functions are not strictly
  required, since simply calling the normal ww_mutex_lock functions on the
  contending lock (after having dropped all other already acquired locks) will
  work correctly. After all if no other ww mutex has been acquired yet there's
  no deadlock potential and hence the ww_mutex_lock call will block and not
  prematurely return -EDEADLK. The advantage of the _slow functions is in
  interface safety:

  - ww_mutex_lock has a __must_check int return type, whereas ww_mutex_lock_slow
    has a void return type. Note that since ww mutex code needs loops/retries
    anyway the __must_check doesn't result in spurious warnings, even though the
    very first lock operation can never fail.
  - When full debugging is enabled ww_mutex_lock_slow checks that all acquired
    ww mutex have been released (preventing deadlocks) and makes sure that we
    block on the contending lock (preventing spinning through the -EDEADLK
    slowpath until the contended lock can be acquired).

* Functions to only acquire a single w/w mutex, which results in the exact same
  semantics as a normal mutex. This is done by calling ww_mutex_lock with a NULL
  context.

  Again this is not strictly required. But often you only want to acquire a
  single lock in which case it's pointless to set up an acquire context (and so
  better to avoid grabbing a deadlock avoidance ticket).

Of course, all the usual variants for handling wake-ups due to signals are also
provided.

Usage
-----

The algorithm (Wait-Die vs Wound-Wait) is chosen by using either
DEFINE_WW_CLASS() (Wound-Wait) or DEFINE_WD_CLASS() (Wait-Die)
As a rough rule of thumb, use Wound-Wait iff you
expect the number of simultaneous competing transactions to be typically small,
and you want to reduce the number of rollbacks.

Three different ways to acquire locks within the same w/w class. Common
definitions for methods #1 and #2::

  static DEFINE_WW_CLASS(ww_class);

  struct obj {
	struct ww_mutex lock;
	/* obj data */
  };

  struct obj_entry {
	struct list_head head;
	struct obj *obj;
  };

Method 1, using a list in execbuf->buffers that's not allowed to be reordered.
This is useful if a list of required objects is already tracked somewhere.
Furthermore the lock helper can use propagate the -EALREADY return code back to
the caller as a signal that an object is twice on the list. This is useful if
the list is constructed from userspace input and the ABI requires userspace to
not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl)::

  int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
  {
	struct obj *res_obj = NULL;
	struct obj_entry *contended_entry = NULL;
	struct obj_entry *entry;

	ww_acquire_init(ctx, &ww_class);

  retry:
	list_for_each_entry (entry, list, head) {
		if (entry->obj == res_obj) {
			res_obj = NULL;
			continue;
		}
		ret = ww_mutex_lock(&entry->obj->lock, ctx);
		if (ret < 0) {
			contended_entry = entry;
			goto err;
		}
	}

	ww_acquire_done(ctx);
	return 0;

  err:
	list_for_each_entry_continue_reverse (entry, list, head)
		ww_mutex_unlock(&entry->obj->lock);

	if (res_obj)
		ww_mutex_unlock(&res_obj->lock);

	if (ret == -EDEADLK) {
		/* we lost out in a seqno race, lock and retry.. */
		ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
		res_obj = contended_entry->obj;
		goto retry;
	}
	ww_acquire_fini(ctx);

	return ret;
  }

Method 2, using a list in execbuf->buffers that can be reordered. Same semantics
of duplicate entry detection using -EALREADY as method 1 above. But the
list-reordering allows for a bit more idiomatic code::

  int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
  {
	struct obj_entry *entry, *entry2;

	ww_acquire_init(ctx, &ww_class);

	list_for_each_entry (entry, list, head) {
		ret = ww_mutex_lock(&entry->obj->lock, ctx);
		if (ret < 0) {
			entry2 = entry;

			list_for_each_entry_continue_reverse (entry2, list, head)
				ww_mutex_unlock(&entry2->obj->lock);

			if (ret != -EDEADLK) {
				ww_acquire_fini(ctx);
				return ret;
			}

			/* we lost out in a seqno race, lock and retry.. */
			ww_mutex_lock_slow(&entry->obj->lock, ctx);

			/*
			 * Move buf to head of the list, this will point
			 * buf->next to the first unlocked entry,
			 * restarting the for loop.
			 */
			list_del(&entry->head);
			list_add(&entry->head, list);
		}
	}

	ww_acquire_done(ctx);
	return 0;
  }

Unlocking works the same way for both methods #1 and #2::

  void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
  {
	struct obj_entry *entry;

	list_for_each_entry (entry, list, head)
		ww_mutex_unlock(&entry->obj->lock);

	ww_acquire_fini(ctx);
  }

Method 3 is useful if the list of objects is constructed ad-hoc and not upfront,
e.g. when adjusting edges in a graph where each node has its own ww_mutex lock,
and edges can only be changed when holding the locks of all involved nodes. w/w
mutexes are a natural fit for such a case for two reasons:

- They can handle lock-acquisition in any order which allows us to start walking
  a graph from a starting point and then iteratively discovering new edges and
  locking down the nodes those edges connect to.
- Due to the -EALREADY return code signalling that a given objects is already
  held there's no need for additional book-keeping to break cycles in the graph
  or keep track off which looks are already held (when using more than one node
  as a starting point).

Note that this approach differs in two important ways from the above methods:

- Since the list of objects is dynamically constructed (and might very well be
  different when retrying due to hitting the -EDEADLK die condition) there's
  no need to keep any object on a persistent list when it's not locked. We can
  therefore move the list_head into the object itself.
- On the other hand the dynamic object list construction also means that the -EALREADY return
  code can't be propagated.

Note also that methods #1 and #2 and method #3 can be combined, e.g. to first lock a
list of starting nodes (passed in from userspace) using one of the above
methods. And then lock any additional objects affected by the operations using
method #3 below. The backoff/retry procedure will be a bit more involved, since
when the dynamic locking step hits -EDEADLK we also need to unlock all the
objects acquired with the fixed list. But the w/w mutex debug checks will catch
any interface misuse for these cases.

Also, method 3 can't fail the lock acquisition step since it doesn't return
-EALREADY. Of course this would be different when using the _interruptible
variants, but that's outside of the scope of these examples here::

  struct obj {
	struct ww_mutex ww_mutex;
	struct list_head locked_list;
  };

  static DEFINE_WW_CLASS(ww_class);

  void __unlock_objs(struct list_head *list)
  {
	struct obj *entry, *temp;

	list_for_each_entry_safe (entry, temp, list, locked_list) {
		/* need to do that before unlocking, since only the current lock holder is
		allowed to use object */
		list_del(&entry->locked_list);
		ww_mutex_unlock(entry->ww_mutex)
	}
  }

  void lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
  {
	struct obj *obj;

	ww_acquire_init(ctx, &ww_class);

  retry:
	/* re-init loop start state */
	loop {
		/* magic code which walks over a graph and decides which objects
		 * to lock */

		ret = ww_mutex_lock(obj->ww_mutex, ctx);
		if (ret == -EALREADY) {
			/* we have that one already, get to the next object */
			continue;
		}
		if (ret == -EDEADLK) {
			__unlock_objs(list);

			ww_mutex_lock_slow(obj, ctx);
			list_add(&entry->locked_list, list);
			goto retry;
		}

		/* locked a new object, add it to the list */
		list_add_tail(&entry->locked_list, list);
	}

	ww_acquire_done(ctx);
	return 0;
  }

  void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
  {
	__unlock_objs(list);
	ww_acquire_fini(ctx);
  }

Method 4: Only lock one single objects. In that case deadlock detection and
prevention is obviously overkill, since with grabbing just one lock you can't
produce a deadlock within just one class. To simplify this case the w/w mutex
api can be used with a NULL context.

Implementation Details
----------------------

Design:
^^^^^^^

  ww_mutex currently encapsulates a struct mutex, this means no extra overhead for
  normal mutex locks, which are far more common. As such there is only a small
  increase in code size if wait/wound mutexes are not used.

  We maintain the following invariants for the wait list:

  (1) Waiters with an acquire context are sorted by stamp order; waiters
      without an acquire context are interspersed in FIFO order.
  (2) For Wait-Die, among waiters with contexts, only the first one can have
      other locks acquired already (ctx->acquired > 0). Note that this waiter
      may come after other waiters without contexts in the list.

  The Wound-Wait preemption is implemented with a lazy-preemption scheme:
  The wounded status of the transaction is checked only when there is
  contention for a new lock and hence a true chance of deadlock. In that
  situation, if the transaction is wounded, it backs off, clears the
  wounded status and retries. A great benefit of implementing preemption in
  this way is that the wounded transaction can identify a contending lock to
  wait for before restarting the transaction. Just blindly restarting the
  transaction would likely make the transaction end up in a situation where
  it would have to back off again.

  In general, not much contention is expected. The locks are typically used to
  serialize access to resources for devices, and optimization focus should
  therefore be directed towards the uncontended cases.

Lockdep:
^^^^^^^^

  Special care has been taken to warn for as many cases of api abuse
  as possible. Some common api abuses will be caught with
  CONFIG_DEBUG_MUTEXES, but CONFIG_PROVE_LOCKING is recommended.

  Some of the errors which will be warned about:
   - Forgetting to call ww_acquire_fini or ww_acquire_init.
   - Attempting to lock more mutexes after ww_acquire_done.
   - Attempting to lock the wrong mutex after -EDEADLK and
     unlocking all mutexes.
   - Attempting to lock the right mutex after -EDEADLK,
     before unlocking all mutexes.

   - Calling ww_mutex_lock_slow before -EDEADLK was returned.

   - Unlocking mutexes with the wrong unlock function.
   - Calling one of the ww_acquire_* twice on the same context.
   - Using a different ww_class for the mutex than for the ww_acquire_ctx.
   - Normal lockdep errors that can result in deadlocks.

  Some of the lockdep errors that can result in deadlocks:
   - Calling ww_acquire_init to initialize a second ww_acquire_ctx before
     having called ww_acquire_fini on the first.
   - 'normal' deadlocks that can occur.

FIXME:
  Update this section once we have the TASK_DEADLOCK task state flag magic
  implemented.


code:
.. SPDX-License-Identifier: GPL-2.0

=======================
Booting Linux/LoongArch
=======================

:Author: Yanteng Si <siyanteng@loongson.cn>
:Date:   18 Nov 2022

Information passed from BootLoader to kernel
============================================

LoongArch supports ACPI and FDT. The information that needs to be passed
to the kernel includes the memmap, the initrd, the command line, optionally
the ACPI/FDT tables, and so on.

The kernel is passed the following arguments on `kernel_entry` :

      - a0 = efi_boot: `efi_boot` is a flag indicating whether
        this boot environment is fully UEFI-compliant.

      - a1 = cmdline: `cmdline` is a pointer to the kernel command line.

      - a2 = systemtable: `systemtable` points to the EFI system table.
        All pointers involved at this stage are in physical addresses.

Header of Linux/LoongArch kernel images
=======================================

Linux/LoongArch kernel images are EFI images. Being PE files, they have
a 64-byte header structured like::

	u32	MZ_MAGIC                /* "MZ", MS-DOS header */
	u32	res0 = 0                /* Reserved */
	u64	kernel_entry            /* Kernel entry point */
	u64	_end - _text            /* Kernel image effective size */
	u64	load_offset             /* Kernel image load offset from start of RAM */
	u64	res1 = 0                /* Reserved */
	u64	res2 = 0                /* Reserved */
	u64	res3 = 0                /* Reserved */
	u32	LINUX_PE_MAGIC          /* Magic number */
	u32	pe_header - _head       /* Offset to the PE header */


code:
.. SPDX-License-Identifier: GPL-2.0

.. kernel-feat:: $srctree/Documentation/features loongarch


code:
.. SPDX-License-Identifier: GPL-2.0

======================
LoongArch Architecture
======================

.. toctree::
   :maxdepth: 2
   :numbered:

   introduction
   booting
   irq-chip-model

   features

.. only::  subproject and html

   Indices
   =======

   * :ref:`genindex`


code:
.. SPDX-License-Identifier: GPL-2.0

=========================
Introduction to LoongArch
=========================

LoongArch is a new RISC ISA, which is a bit like MIPS or RISC-V. There are
currently 3 variants: a reduced 32-bit version (LA32R), a standard 32-bit
version (LA32S) and a 64-bit version (LA64). There are 4 privilege levels
(PLVs) defined in LoongArch: PLV0~PLV3, from high to low. Kernel runs at PLV0
while applications run at PLV3. This document introduces the registers, basic
instruction set, virtual memory and some other topics of LoongArch.

Registers
=========

LoongArch registers include general purpose registers (GPRs), floating point
registers (FPRs), vector registers (VRs) and control status registers (CSRs)
used in privileged mode (PLV0).

GPRs
----

LoongArch has 32 GPRs ( ``$r0`` ~ ``$r31`` ); each one is 32-bit wide in LA32
and 64-bit wide in LA64. ``$r0`` is hard-wired to zero, and the other registers
are not architecturally special. (Except ``$r1``, which is hard-wired as the
link register of the BL instruction.)

The kernel uses a variant of the LoongArch register convention, as described in
the LoongArch ELF psABI spec, in :ref:`References <loongarch-references>`:

================= =============== =================== ============
Name              Alias           Usage               Preserved
                                                      across calls
================= =============== =================== ============
``$r0``           ``$zero``       Constant zero       Unused
``$r1``           ``$ra``         Return address      No
``$r2``           ``$tp``         TLS/Thread pointer  Unused
``$r3``           ``$sp``         Stack pointer       Yes
``$r4``-``$r11``  ``$a0``-``$a7`` Argument registers  No
``$r4``-``$r5``   ``$v0``-``$v1`` Return value        No
``$r12``-``$r20`` ``$t0``-``$t8`` Temp registers      No
``$r21``          ``$u0``         Percpu base address Unused
``$r22``          ``$fp``         Frame pointer       Yes
``$r23``-``$r31`` ``$s0``-``$s8`` Static registers    Yes
================= =============== =================== ============

.. Note::
    The register ``$r21`` is reserved in the ELF psABI, but used by the Linux
    kernel for storing the percpu base address. It normally has no ABI name,
    but is called ``$u0`` in the kernel. You may also see ``$v0`` or ``$v1``
    in some old code,however they are deprecated aliases of ``$a0`` and ``$a1``
    respectively.

FPRs
----

LoongArch has 32 FPRs ( ``$f0`` ~ ``$f31`` ) when FPU is present. Each one is
64-bit wide on the LA64 cores.

The floating-point register convention is the same as described in the
LoongArch ELF psABI spec:

================= ================== =================== ============
Name              Alias              Usage               Preserved
                                                         across calls
================= ================== =================== ============
``$f0``-``$f7``   ``$fa0``-``$fa7``  Argument registers  No
``$f0``-``$f1``   ``$fv0``-``$fv1``  Return value        No
``$f8``-``$f23``  ``$ft0``-``$ft15`` Temp registers      No
``$f24``-``$f31`` ``$fs0``-``$fs7``  Static registers    Yes
================= ================== =================== ============

.. Note::
    You may see ``$fv0`` or ``$fv1`` in some old code, however they are
    deprecated aliases of ``$fa0`` and ``$fa1`` respectively.

VRs
----

There are currently 2 vector extensions to LoongArch:

- LSX (Loongson SIMD eXtension) with 128-bit vectors,
- LASX (Loongson Advanced SIMD eXtension) with 256-bit vectors.

LSX brings ``$v0`` ~ ``$v31`` while LASX brings ``$x0`` ~ ``$x31`` as the vector
registers.

The VRs overlap with FPRs: for example, on a core implementing LSX and LASX,
the lower 128 bits of ``$x0`` is shared with ``$v0``, and the lower 64 bits of
``$v0`` is shared with ``$f0``; same with all other VRs.

CSRs
----

CSRs can only be accessed from privileged mode (PLV0):

================= ===================================== ==============
Address           Full Name                             Abbrev Name
================= ===================================== ==============
0x0               Current Mode Information              CRMD
0x1               Pre-exception Mode Information        PRMD
0x2               Extension Unit Enable                 EUEN
0x3               Miscellaneous Control                 MISC
0x4               Exception Configuration               ECFG
0x5               Exception Status                      ESTAT
0x6               Exception Return Address              ERA
0x7               Bad (Faulting) Virtual Address        BADV
0x8               Bad (Faulting) Instruction Word       BADI
0xC               Exception Entrypoint Address          EENTRY
0x10              TLB Index                             TLBIDX
0x11              TLB Entry High-order Bits             TLBEHI
0x12              TLB Entry Low-order Bits 0            TLBELO0
0x13              TLB Entry Low-order Bits 1            TLBELO1
0x18              Address Space Identifier              ASID
0x19              Page Global Directory Address for     PGDL
                  Lower-half Address Space
0x1A              Page Global Directory Address for     PGDH
                  Higher-half Address Space
0x1B              Page Global Directory Address         PGD
0x1C              Page Walk Control for Lower-          PWCL
                  half Address Space
0x1D              Page Walk Control for Higher-         PWCH
                  half Address Space
0x1E              STLB Page Size                        STLBPS
0x1F              Reduced Virtual Address Configuration RVACFG
0x20              CPU Identifier                        CPUID
0x21              Privileged Resource Configuration 1   PRCFG1
0x22              Privileged Resource Configuration 2   PRCFG2
0x23              Privileged Resource Configuration 3   PRCFG3
0x30+n (0≤n≤15)   Saved Data register                   SAVEn
0x40              Timer Identifier                      TID
0x41              Timer Configuration                   TCFG
0x42              Timer Value                           TVAL
0x43              Compensation of Timer Count           CNTC
0x44              Timer Interrupt Clearing              TICLR
0x60              LLBit Control                         LLBCTL
0x80              Implementation-specific Control 1     IMPCTL1
0x81              Implementation-specific Control 2     IMPCTL2
0x88              TLB Refill Exception Entrypoint       TLBRENTRY
                  Address
0x89              TLB Refill Exception BAD (Faulting)   TLBRBADV
                  Virtual Address
0x8A              TLB Refill Exception Return Address   TLBRERA
0x8B              TLB Refill Exception Saved Data       TLBRSAVE
                  Register
0x8C              TLB Refill Exception Entry Low-order  TLBRELO0
                  Bits 0
0x8D              TLB Refill Exception Entry Low-order  TLBRELO1
                  Bits 1
0x8E              TLB Refill Exception Entry High-order TLBEHI
                  Bits
0x8F              TLB Refill Exception Pre-exception    TLBRPRMD
                  Mode Information
0x90              Machine Error Control                 MERRCTL
0x91              Machine Error Information 1           MERRINFO1
0x92              Machine Error Information 2           MERRINFO2
0x93              Machine Error Exception Entrypoint    MERRENTRY
                  Address
0x94              Machine Error Exception Return        MERRERA
                  Address
0x95              Machine Error Exception Saved Data    MERRSAVE
                  Register
0x98              Cache TAGs                            CTAG
0x180+n (0≤n≤3)   Direct Mapping Configuration Window n DMWn
0x200+2n (0≤n≤31) Performance Monitor Configuration n   PMCFGn
0x201+2n (0≤n≤31) Performance Monitor Overall Counter n PMCNTn
0x300             Memory Load/Store WatchPoint          MWPC
                  Overall Control
0x301             Memory Load/Store WatchPoint          MWPS
                  Overall Status
0x310+8n (0≤n≤7)  Memory Load/Store WatchPoint n        MWPnCFG1
                  Configuration 1
0x311+8n (0≤n≤7)  Memory Load/Store WatchPoint n        MWPnCFG2
                  Configuration 2
0x312+8n (0≤n≤7)  Memory Load/Store WatchPoint n        MWPnCFG3
                  Configuration 3
0x313+8n (0≤n≤7)  Memory Load/Store WatchPoint n        MWPnCFG4
                  Configuration 4
0x380             Instruction Fetch WatchPoint          FWPC
                  Overall Control
0x381             Instruction Fetch WatchPoint          FWPS
                  Overall Status
0x390+8n (0≤n≤7)  Instruction Fetch WatchPoint n        FWPnCFG1
                  Configuration 1
0x391+8n (0≤n≤7)  Instruction Fetch WatchPoint n        FWPnCFG2
                  Configuration 2
0x392+8n (0≤n≤7)  Instruction Fetch WatchPoint n        FWPnCFG3
                  Configuration 3
0x393+8n (0≤n≤7)  Instruction Fetch WatchPoint n        FWPnCFG4
                  Configuration 4
0x500             Debug Register                        DBG
0x501             Debug Exception Return Address        DERA
0x502             Debug Exception Saved Data Register   DSAVE
================= ===================================== ==============

ERA, TLBRERA, MERRERA and DERA are sometimes also known as EPC, TLBREPC, MERREPC
and DEPC respectively.

Basic Instruction Set
=====================

Instruction formats
-------------------

LoongArch instructions are 32 bits wide, belonging to 9 basic instruction
formats (and variants of them):

=========== ==========================
Format name Composition
=========== ==========================
2R          Opcode + Rj + Rd
3R          Opcode + Rk + Rj + Rd
4R          Opcode + Ra + Rk + Rj + Rd
2RI8        Opcode + I8 + Rj + Rd
2RI12       Opcode + I12 + Rj + Rd
2RI14       Opcode + I14 + Rj + Rd
2RI16       Opcode + I16 + Rj + Rd
1RI21       Opcode + I21L + Rj + I21H
I26         Opcode + I26L + I26H
=========== ==========================

Rd is the destination register operand, while Rj, Rk and Ra ("a" stands for
"additional") are the source register operands. I8/I12/I14/I16/I21/I26 are
immediate operands of respective width. The longer I21 and I26 are stored
in separate higher and lower parts in the instruction word, denoted by the "L"
and "H" suffixes.

List of Instructions
--------------------

For brevity, only instruction names (mnemonics) are listed here; please see the
:ref:`References <loongarch-references>` for details.

1. Arithmetic Instructions::

    ADD.W SUB.W ADDI.W ADD.D SUB.D ADDI.D
    SLT SLTU SLTI SLTUI
    AND OR NOR XOR ANDN ORN ANDI ORI XORI
    MUL.W MULH.W MULH.WU DIV.W DIV.WU MOD.W MOD.WU
    MUL.D MULH.D MULH.DU DIV.D DIV.DU MOD.D MOD.DU
    PCADDI PCADDU12I PCADDU18I
    LU12I.W LU32I.D LU52I.D ADDU16I.D

2. Bit-shift Instructions::

    SLL.W SRL.W SRA.W ROTR.W SLLI.W SRLI.W SRAI.W ROTRI.W
    SLL.D SRL.D SRA.D ROTR.D SLLI.D SRLI.D SRAI.D ROTRI.D

3. Bit-manipulation Instructions::

    EXT.W.B EXT.W.H CLO.W CLO.D SLZ.W CLZ.D CTO.W CTO.D CTZ.W CTZ.D
    BYTEPICK.W BYTEPICK.D BSTRINS.W BSTRINS.D BSTRPICK.W BSTRPICK.D
    REVB.2H REVB.4H REVB.2W REVB.D REVH.2W REVH.D BITREV.4B BITREV.8B BITREV.W BITREV.D
    MASKEQZ MASKNEZ

4. Branch Instructions::

    BEQ BNE BLT BGE BLTU BGEU BEQZ BNEZ B BL JIRL

5. Load/Store Instructions::

    LD.B LD.BU LD.H LD.HU LD.W LD.WU LD.D ST.B ST.H ST.W ST.D
    LDX.B LDX.BU LDX.H LDX.HU LDX.W LDX.WU LDX.D STX.B STX.H STX.W STX.D
    LDPTR.W LDPTR.D STPTR.W STPTR.D
    PRELD PRELDX

6. Atomic Operation Instructions::

    LL.W SC.W LL.D SC.D
    AMSWAP.W AMSWAP.D AMADD.W AMADD.D AMAND.W AMAND.D AMOR.W AMOR.D AMXOR.W AMXOR.D
    AMMAX.W AMMAX.D AMMIN.W AMMIN.D

7. Barrier Instructions::

    IBAR DBAR

8. Special Instructions::

    SYSCALL BREAK CPUCFG NOP IDLE ERTN(ERET) DBCL(DBGCALL) RDTIMEL.W RDTIMEH.W RDTIME.D
    ASRTLE.D ASRTGT.D

9. Privileged Instructions::

    CSRRD CSRWR CSRXCHG
    IOCSRRD.B IOCSRRD.H IOCSRRD.W IOCSRRD.D IOCSRWR.B IOCSRWR.H IOCSRWR.W IOCSRWR.D
    CACOP TLBP(TLBSRCH) TLBRD TLBWR TLBFILL TLBCLR TLBFLUSH INVTLB LDDIR LDPTE

Virtual Memory
==============

LoongArch supports direct-mapped virtual memory and page-mapped virtual memory.

Direct-mapped virtual memory is configured by CSR.DMWn (n=0~3), it has a simple
relationship between virtual address (VA) and physical address (PA)::

 VA = PA + FixedOffset

Page-mapped virtual memory has arbitrary relationship between VA and PA, which
is recorded in TLB and page tables. LoongArch's TLB includes a fully-associative
MTLB (Multiple Page Size TLB) and set-associative STLB (Single Page Size TLB).

By default, the whole virtual address space of LA32 is configured like this:

============ =========================== =============================
Name         Address Range               Attributes
============ =========================== =============================
``UVRANGE``  ``0x00000000 - 0x7FFFFFFF`` Page-mapped, Cached, PLV0~3
``KPRANGE0`` ``0x80000000 - 0x9FFFFFFF`` Direct-mapped, Uncached, PLV0
``KPRANGE1`` ``0xA0000000 - 0xBFFFFFFF`` Direct-mapped, Cached, PLV0
``KVRANGE``  ``0xC0000000 - 0xFFFFFFFF`` Page-mapped, Cached, PLV0
============ =========================== =============================

User mode (PLV3) can only access UVRANGE. For direct-mapped KPRANGE0 and
KPRANGE1, PA is equal to VA with bit30~31 cleared. For example, the uncached
direct-mapped VA of 0x00001000 is 0x80001000, and the cached direct-mapped
VA of 0x00001000 is 0xA0001000.

By default, the whole virtual address space of LA64 is configured like this:

============ ====================== ======================================
Name         Address Range          Attributes
============ ====================== ======================================
``XUVRANGE`` ``0x0000000000000000 - Page-mapped, Cached, PLV0~3
             0x3FFFFFFFFFFFFFFF``
``XSPRANGE`` ``0x4000000000000000 - Direct-mapped, Cached / Uncached, PLV0
             0x7FFFFFFFFFFFFFFF``
``XKPRANGE`` ``0x8000000000000000 - Direct-mapped, Cached / Uncached, PLV0
             0xBFFFFFFFFFFFFFFF``
``XKVRANGE`` ``0xC000000000000000 - Page-mapped, Cached, PLV0
             0xFFFFFFFFFFFFFFFF``
============ ====================== ======================================

User mode (PLV3) can only access XUVRANGE. For direct-mapped XSPRANGE and
XKPRANGE, PA is equal to VA with bits 60~63 cleared, and the cache attribute
is configured by bits 60~61 in VA: 0 is for strongly-ordered uncached, 1 is
for coherent cached, and 2 is for weakly-ordered uncached.

Currently we only use XKPRANGE for direct mapping and XSPRANGE is reserved.

To put this in action: the strongly-ordered uncached direct-mapped VA (in
XKPRANGE) of 0x00000000_00001000 is 0x80000000_00001000, the coherent cached
direct-mapped VA (in XKPRANGE) of 0x00000000_00001000 is 0x90000000_00001000,
and the weakly-ordered uncached direct-mapped VA (in XKPRANGE) of 0x00000000
_00001000 is 0xA0000000_00001000.

Relationship of Loongson and LoongArch
======================================

LoongArch is a RISC ISA which is different from any other existing ones, while
Loongson is a family of processors. Loongson includes 3 series: Loongson-1 is
the 32-bit processor series, Loongson-2 is the low-end 64-bit processor series,
and Loongson-3 is the high-end 64-bit processor series. Old Loongson is based on
MIPS, while New Loongson is based on LoongArch. Take Loongson-3 as an example:
Loongson-3A1000/3B1500/3A2000/3A3000/3A4000 are MIPS-compatible, while Loongson-
3A5000 (and future revisions) are all based on LoongArch.

.. _loongarch-references:

References
==========

Official web site of Loongson Technology Corp. Ltd.:

  http://www.loongson.cn/

Developer web site of Loongson and LoongArch (Software and Documentation):

  http://www.loongnix.cn/

  https://github.com/loongson/

  https://loongson.github.io/LoongArch-Documentation/

Documentation of LoongArch ISA:

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-CN.pdf (in Chinese)

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-Vol1-v1.02-EN.pdf (in English)

Documentation of LoongArch ELF psABI:

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-CN.pdf (in Chinese)

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/LoongArch-ELF-ABI-v2.00-EN.pdf (in English)

Linux kernel repository of Loongson and LoongArch:

  https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git


code:
.. SPDX-License-Identifier: GPL-2.0

=======================================
IRQ chip model (hierarchy) of LoongArch
=======================================

Currently, LoongArch based processors (e.g. Loongson-3A5000) can only work together
with LS7A chipsets. The irq chips in LoongArch computers include CPUINTC (CPU Core
Interrupt Controller), LIOINTC (Legacy I/O Interrupt Controller), EIOINTC (Extended
I/O Interrupt Controller), HTVECINTC (Hyper-Transport Vector Interrupt Controller),
PCH-PIC (Main Interrupt Controller in LS7A chipset), PCH-LPC (LPC Interrupt Controller
in LS7A chipset) and PCH-MSI (MSI Interrupt Controller).

CPUINTC is a per-core controller (in CPU), LIOINTC/EIOINTC/HTVECINTC are per-package
controllers (in CPU), while PCH-PIC/PCH-LPC/PCH-MSI are controllers out of CPU (i.e.,
in chipsets). These controllers (in other words, irqchips) are linked in a hierarchy,
and there are two models of hierarchy (legacy model and extended model).

Legacy IRQ model
================

In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt go
to CPUINTC directly, CPU UARTS interrupts go to LIOINTC, while all other devices
interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and gathered by HTVECINTC, and then go
to LIOINTC, and then CPUINTC::

     +-----+     +---------+     +-------+
     | IPI | --> | CPUINTC | <-- | Timer |
     +-----+     +---------+     +-------+
                      ^
                      |
                 +---------+     +-------+
                 | LIOINTC | <-- | UARTs |
                 +---------+     +-------+
                      ^
                      |
                +-----------+
                | HTVECINTC |
                +-----------+
                 ^         ^
                 |         |
           +---------+ +---------+
           | PCH-PIC | | PCH-MSI |
           +---------+ +---------+
             ^     ^           ^
             |     |           |
     +---------+ +---------+ +---------+
     | PCH-LPC | | Devices | | Devices |
     +---------+ +---------+ +---------+
          ^
          |
     +---------+
     | Devices |
     +---------+

Extended IRQ model
==================

In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt go
to CPUINTC directly, CPU UARTS interrupts go to LIOINTC, while all other devices
interrupts go to PCH-PIC/PCH-LPC/PCH-MSI and gathered by EIOINTC, and then go to
to CPUINTC directly::

          +-----+     +---------+     +-------+
          | IPI | --> | CPUINTC | <-- | Timer |
          +-----+     +---------+     +-------+
                       ^       ^
                       |       |
                +---------+ +---------+     +-------+
                | EIOINTC | | LIOINTC | <-- | UARTs |
                +---------+ +---------+     +-------+
                 ^       ^
                 |       |
          +---------+ +---------+
          | PCH-PIC | | PCH-MSI |
          +---------+ +---------+
            ^     ^           ^
            |     |           |
    +---------+ +---------+ +---------+
    | PCH-LPC | | Devices | | Devices |
    +---------+ +---------+ +---------+
         ^
         |
    +---------+
    | Devices |
    +---------+

ACPI-related definitions
========================

CPUINTC::

  ACPI_MADT_TYPE_CORE_PIC;
  struct acpi_madt_core_pic;
  enum acpi_madt_core_pic_version;

LIOINTC::

  ACPI_MADT_TYPE_LIO_PIC;
  struct acpi_madt_lio_pic;
  enum acpi_madt_lio_pic_version;

EIOINTC::

  ACPI_MADT_TYPE_EIO_PIC;
  struct acpi_madt_eio_pic;
  enum acpi_madt_eio_pic_version;

HTVECINTC::

  ACPI_MADT_TYPE_HT_PIC;
  struct acpi_madt_ht_pic;
  enum acpi_madt_ht_pic_version;

PCH-PIC::

  ACPI_MADT_TYPE_BIO_PIC;
  struct acpi_madt_bio_pic;
  enum acpi_madt_bio_pic_version;

PCH-MSI::

  ACPI_MADT_TYPE_MSI_PIC;
  struct acpi_madt_msi_pic;
  enum acpi_madt_msi_pic_version;

PCH-LPC::

  ACPI_MADT_TYPE_LPC_PIC;
  struct acpi_madt_lpc_pic;
  enum acpi_madt_lpc_pic_version;

References
==========

Documentation of Loongson-3A5000:

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-3A5000-usermanual-1.02-CN.pdf (in Chinese)

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-3A5000-usermanual-1.02-EN.pdf (in English)

Documentation of Loongson's LS7A chipset:

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-7A1000-usermanual-2.00-CN.pdf (in Chinese)

  https://github.com/loongson/LoongArch-Documentation/releases/latest/download/Loongson-7A1000-usermanual-2.00-EN.pdf (in English)

.. Note::
    - CPUINTC is CSR.ECFG/CSR.ESTAT and its interrupt controller described
      in Section 7.4 of "LoongArch Reference Manual, Vol 1";
    - LIOINTC is "Legacy I/OInterrupts" described in Section 11.1 of
      "Loongson 3A5000 Processor Reference Manual";
    - EIOINTC is "Extended I/O Interrupts" described in Section 11.2 of
      "Loongson 3A5000 Processor Reference Manual";
    - HTVECINTC is "HyperTransport Interrupts" described in Section 14.3 of
      "Loongson 3A5000 Processor Reference Manual";
    - PCH-PIC/PCH-MSI is "Interrupt Controller" described in Section 5 of
      "Loongson 7A1000 Bridge User Manual";
    - PCH-LPC is "LPC Interrupts" described in Section 24.3 of
      "Loongson 7A1000 Bridge User Manual".


code:
=====================================
Amiga Buddha and Catweasel IDE Driver
=====================================

The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by
Geert Uytterhoeven based on the following specifications:

------------------------------------------------------------------------

Register map of the Buddha IDE controller and the
Buddha-part of the Catweasel Zorro-II version

The Autoconfiguration has been implemented just as Commodore
described  in  their  manuals, no tricks have been used (for
example leaving some address lines out of the equations...).
If you want to configure the board yourself (for example let
a  Linux  kernel  configure the card), look at the Commodore
Docs.  Reading the nibbles should give this information::

  Vendor number: 4626 ($1212)
  product number: 0 (42 for Catweasel Z-II)
  Serial number: 0
  Rom-vector: $1000

The  card  should be a Z-II board, size 64K, not for freemem
list, Rom-Vektor is valid, no second Autoconfig-board on the
same card, no space preference, supports "Shutup_forever".

Setting  the  base address should be done in two steps, just
as  the Amiga Kickstart does:  The lower nibble of the 8-Bit
address is written to $4a, then the whole Byte is written to
$48, while it doesn't matter how often you're writing to $4a
as  long as $48 is not touched.  After $48 has been written,
the  whole card disappears from $e8 and is mapped to the new
address just written.  Make sure $4a is written before $48,
otherwise your chance is only 1:16 to find the board :-).

The local memory-map is even active when mapped to $e8:

==============  ===========================================
$0-$7e		Autokonfig-space, see Z-II docs.

$80-$7fd	reserved

$7fe		Speed-select Register: Read & Write
		(description see further down)

$800-$8ff	IDE-Select 0 (Port 0, Register set 0)

$900-$9ff	IDE-Select 1 (Port 0, Register set 1)

$a00-$aff	IDE-Select 2 (Port 1, Register set 0)

$b00-$bff	IDE-Select 3 (Port 1, Register set 1)

$c00-$cff	IDE-Select 4 (Port 2, Register set 0,
                Catweasel only!)

$d00-$dff	IDE-Select 5 (Port 3, Register set 1,
		Catweasel only!)

$e00-$eff	local expansion port, on Catweasel Z-II the
		Catweasel registers are also mapped here.
		Never touch, use multidisk.device!

$f00		read only, Byte-access: Bit 7 shows the
		level of the IRQ-line of IDE port 0.

$f01-$f3f	mirror of $f00

$f40		read only, Byte-access: Bit 7 shows the
		level of the IRQ-line of IDE port 1.

$f41-$f7f	mirror of $f40

$f80		read only, Byte-access: Bit 7 shows the
		level of the IRQ-line of IDE port 2.
		(Catweasel only!)

$f81-$fbf	mirror of $f80

$fc0		write-only: Writing any value to this
		register enables IRQs to be passed from the
		IDE ports to the Zorro bus. This mechanism
		has been implemented to be compatible with
		harddisks that are either defective or have
		a buggy firmware and pull the IRQ line up
		while starting up. If interrupts would
		always be passed to the bus, the computer
		might not start up. Once enabled, this flag
		can not be disabled again. The level of the
		flag can not be determined by software
		(what for? Write to me if it's necessary!).

$fc1-$fff	mirror of $fc0

$1000-$ffff	Buddha-Rom with offset $1000 in the rom
		chip. The addresses $0 to $fff of the rom
		chip cannot be read. Rom is Byte-wide and
		mapped to even addresses.
==============  ===========================================

The  IDE ports issue an INT2.  You can read the level of the
IRQ-lines  of  the  IDE-ports by reading from the three (two
for  Buddha-only)  registers  $f00, $f40 and $f80.  This way
more  than one I/O request can be handled and you can easily
determine  what  driver  has  to serve the INT2.  Buddha and
Catweasel  expansion  boards  can issue an INT6.  A separate
memory  map  is available for the I/O module and the sysop's
I/O module.

The IDE ports are fed by the address lines A2 to A4, just as
the  Amiga  1200  and  Amiga  4000  IDE ports are.  This way
existing  drivers  can be easily ported to Buddha.  A move.l
polls  two  words  out of the same address of IDE port since
every  word  is  mirrored  once.  movem is not possible, but
it's  not  necessary  either,  because  you can only speedup
68000  systems  with  this  technique.   A 68020 system with
fastmem is faster with move.l.

If you're using the mirrored registers of the IDE-ports with
A6=1,  the Buddha doesn't care about the speed that you have
selected  in  the  speed  register (see further down).  With
A6=1  (for example $840 for port 0, register set 0), a 780ns
access  is being made.  These registers should be used for a
command   access   to  the  harddisk/CD-Rom,  since  command
accesses  are Byte-wide and have to be made slower according
to the ATA-X3T9 manual.

Now  for the speed-register:  The register is byte-wide, and
only  the  upper  three  bits are used (Bits 7 to 5).  Bit 4
must  always  be set to 1 to be compatible with later Buddha
versions  (if  I'll  ever  update this one).  I presume that
I'll  never use the lower four bits, but they have to be set
to 1 by definition.

The  values in this table have to be shifted 5 bits to the
left and or'd with $1f (this sets the lower 5 bits).

All  the timings have in common:  Select and IOR/IOW rise at
the  same  time.   IOR  and  IOW have a propagation delay of
about  30ns  to  the clocks on the Zorro bus, that's why the
values  are no multiple of 71.  One clock-cycle is 71ns long
(exactly 70,5 at 14,18 Mhz on PAL systems).

value 0 (Default after reset)
  497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles)
  (same timing as the Amiga 1200 does on it's IDE port without
  accelerator card)

value 1
  639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles)

value 2
  781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles)

value 3
  355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)

value 4
  355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles)

value 5
  355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles)

value 6
  1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles)

value 7
  355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)

When accessing IDE registers with A6=1 (for example $84x),
the timing will always be mode 0 8-bit compatible, no matter
what you have selected in the speed register:

781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive.

All  the  timings with a very short select-signal (the 355ns
fast  accesses)  depend  on the accelerator card used in the
system:  Sometimes two more clock cycles are inserted by the
bus  interface,  making  the  whole access 497ns long.  This
doesn't  affect  the  reliability  of the controller nor the
performance  of  the  card,  since  this doesn't happen very
often.

All  the  timings  are  calculated  and  only  confirmed  by
measurements  that allowed me to count the clock cycles.  If
the  system  is clocked by an oscillator other than 28,37516
Mhz  (for  example  the  NTSC-frequency  28,63636 Mhz), each
clock  cycle is shortened to a bit less than 70ns (not worth
mentioning).   You  could think of a small performance boost
by  overclocking  the  system,  but  you would either need a
multisync  monitor,  or  a  graphics card, and your internal
diskdrive would go crazy, that's why you shouldn't tune your
Amiga this way.

Giving  you  the  possibility  to  write  software  that  is
compatible  with both the Buddha and the Catweasel Z-II, The
Buddha  acts  just  like  a  Catweasel  Z-II  with no device
connected  to  the  third  IDE-port.   The IRQ-register $f80
always  shows a "no IRQ here" on the Buddha, and accesses to
the  third  IDE  port  are  going into data's Nirwana on the
Buddha.

Jens Schönfeld february 19th, 1997

updated may 27th, 1997

eMail: sysop@nostlgic.tng.oche.de


code:
.. SPDX-License-Identifier: GPL-2.0

.. kernel-feat:: $srctree/Documentation/features m68k


code:
.. SPDX-License-Identifier: GPL-2.0

=================
m68k Architecture
=================

.. toctree::
   :maxdepth: 2

   kernel-options
   buddha-driver

   features

.. only::  subproject and html

   Indices
   =======

   * :ref:`genindex`