Linux 4.15-rc4
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJaNy81AAoJEHm+PkMAQRiGq2YH/1C1so18qErhPosdfeLIXLbA iC9XcIvkPuMfjDw4EfSWOzhKnzgqGuc8q/Vzz0ulDreNVUb52nBeRy69QgNoZBTB NkLdrUKBnlArvRhBXToQGW/s1eI/gobuHBJb7/fbpvsUtPYcDE2nUXAEsMlagn5L BMHNzE3TByaWj0SqJtZAZvaQN2MdWV8ArHBPaC+MtR2C1VJIyl0mT9CdCu2NpTES +FncKJ6/qplSBNSUJSfYmFLfEKVcQxvHMi1kp9jOGlVjPM3cOPKRpv8x69x/IPoB 3l82AikL+Ju0738oJ0Fp/IhfGUqpXz+FwUz1JmCdrcOby75RHomJuJCUBTtjXA4= =lYkx -----END PGP SIGNATURE----- Merge tag 'v4.15-rc4' into perf/core, to pick up fixes Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Коммит
1d2a7de8e9
|
@ -75,3 +75,4 @@ stable kernels.
|
||||||
| Qualcomm Tech. | Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
|
| Qualcomm Tech. | Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
|
||||||
| Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 |
|
| Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 |
|
||||||
| Qualcomm Tech. | QDF2400 ITS | E0065 | QCOM_QDF2400_ERRATUM_0065 |
|
| Qualcomm Tech. | QDF2400 ITS | E0065 | QCOM_QDF2400_ERRATUM_0065 |
|
||||||
|
| Qualcomm Tech. | Falkor v{1,2} | E1041 | QCOM_FALKOR_ERRATUM_1041 |
|
||||||
|
|
|
@ -898,6 +898,13 @@ controller implements weight and absolute bandwidth limit models for
|
||||||
normal scheduling policy and absolute bandwidth allocation model for
|
normal scheduling policy and absolute bandwidth allocation model for
|
||||||
realtime scheduling policy.
|
realtime scheduling policy.
|
||||||
|
|
||||||
|
WARNING: cgroup2 doesn't yet support control of realtime processes and
|
||||||
|
the cpu controller can only be enabled when all RT processes are in
|
||||||
|
the root cgroup. Be aware that system management software may already
|
||||||
|
have placed RT processes into nonroot cgroups during the system boot
|
||||||
|
process, and these processes may need to be moved to the root cgroup
|
||||||
|
before the cpu controller can be enabled.
|
||||||
|
|
||||||
|
|
||||||
CPU Interface Files
|
CPU Interface Files
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -156,6 +156,40 @@ handle it in two different ways:
|
||||||
root of the overlay. Finally the directory is moved to the new
|
root of the overlay. Finally the directory is moved to the new
|
||||||
location.
|
location.
|
||||||
|
|
||||||
|
There are several ways to tune the "redirect_dir" feature.
|
||||||
|
|
||||||
|
Kernel config options:
|
||||||
|
|
||||||
|
- OVERLAY_FS_REDIRECT_DIR:
|
||||||
|
If this is enabled, then redirect_dir is turned on by default.
|
||||||
|
- OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW:
|
||||||
|
If this is enabled, then redirects are always followed by default. Enabling
|
||||||
|
this results in a less secure configuration. Enable this option only when
|
||||||
|
worried about backward compatibility with kernels that have the redirect_dir
|
||||||
|
feature and follow redirects even if turned off.
|
||||||
|
|
||||||
|
Module options (can also be changed through /sys/module/overlay/parameters/*):
|
||||||
|
|
||||||
|
- "redirect_dir=BOOL":
|
||||||
|
See OVERLAY_FS_REDIRECT_DIR kernel config option above.
|
||||||
|
- "redirect_always_follow=BOOL":
|
||||||
|
See OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW kernel config option above.
|
||||||
|
- "redirect_max=NUM":
|
||||||
|
The maximum number of bytes in an absolute redirect (default is 256).
|
||||||
|
|
||||||
|
Mount options:
|
||||||
|
|
||||||
|
- "redirect_dir=on":
|
||||||
|
Redirects are enabled.
|
||||||
|
- "redirect_dir=follow":
|
||||||
|
Redirects are not created, but followed.
|
||||||
|
- "redirect_dir=off":
|
||||||
|
Redirects are not created and only followed if "redirect_always_follow"
|
||||||
|
feature is enabled in the kernel/module config.
|
||||||
|
- "redirect_dir=nofollow":
|
||||||
|
Redirects are not created and not followed (equivalent to "redirect_dir=off"
|
||||||
|
if "redirect_always_follow" feature is not enabled).
|
||||||
|
|
||||||
Non-directories
|
Non-directories
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -1,874 +0,0 @@
|
||||||
Crossrelease
|
|
||||||
============
|
|
||||||
|
|
||||||
Started by Byungchul Park <byungchul.park@lge.com>
|
|
||||||
|
|
||||||
Contents:
|
|
||||||
|
|
||||||
(*) Background
|
|
||||||
|
|
||||||
- What causes deadlock
|
|
||||||
- How lockdep works
|
|
||||||
|
|
||||||
(*) Limitation
|
|
||||||
|
|
||||||
- Limit lockdep
|
|
||||||
- Pros from the limitation
|
|
||||||
- Cons from the limitation
|
|
||||||
- Relax the limitation
|
|
||||||
|
|
||||||
(*) Crossrelease
|
|
||||||
|
|
||||||
- Introduce crossrelease
|
|
||||||
- Introduce commit
|
|
||||||
|
|
||||||
(*) Implementation
|
|
||||||
|
|
||||||
- Data structures
|
|
||||||
- How crossrelease works
|
|
||||||
|
|
||||||
(*) Optimizations
|
|
||||||
|
|
||||||
- Avoid duplication
|
|
||||||
- Lockless for hot paths
|
|
||||||
|
|
||||||
(*) APPENDIX A: What lockdep does to work aggresively
|
|
||||||
|
|
||||||
(*) APPENDIX B: How to avoid adding false dependencies
|
|
||||||
|
|
||||||
|
|
||||||
==========
|
|
||||||
Background
|
|
||||||
==========
|
|
||||||
|
|
||||||
What causes deadlock
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
A deadlock occurs when a context is waiting for an event to happen,
|
|
||||||
which is impossible because another (or the) context who can trigger the
|
|
||||||
event is also waiting for another (or the) event to happen, which is
|
|
||||||
also impossible due to the same reason.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
A context going to trigger event C is waiting for event A to happen.
|
|
||||||
A context going to trigger event A is waiting for event B to happen.
|
|
||||||
A context going to trigger event B is waiting for event C to happen.
|
|
||||||
|
|
||||||
A deadlock occurs when these three wait operations run at the same time,
|
|
||||||
because event C cannot be triggered if event A does not happen, which in
|
|
||||||
turn cannot be triggered if event B does not happen, which in turn
|
|
||||||
cannot be triggered if event C does not happen. After all, no event can
|
|
||||||
be triggered since any of them never meets its condition to wake up.
|
|
||||||
|
|
||||||
A dependency might exist between two waiters and a deadlock might happen
|
|
||||||
due to an incorrect releationship between dependencies. Thus, we must
|
|
||||||
define what a dependency is first. A dependency exists between them if:
|
|
||||||
|
|
||||||
1. There are two waiters waiting for each event at a given time.
|
|
||||||
2. The only way to wake up each waiter is to trigger its event.
|
|
||||||
3. Whether one can be woken up depends on whether the other can.
|
|
||||||
|
|
||||||
Each wait in the example creates its dependency like:
|
|
||||||
|
|
||||||
Event C depends on event A.
|
|
||||||
Event A depends on event B.
|
|
||||||
Event B depends on event C.
|
|
||||||
|
|
||||||
NOTE: Precisely speaking, a dependency is one between whether a
|
|
||||||
waiter for an event can be woken up and whether another waiter for
|
|
||||||
another event can be woken up. However from now on, we will describe
|
|
||||||
a dependency as if it's one between an event and another event for
|
|
||||||
simplicity.
|
|
||||||
|
|
||||||
And they form circular dependencies like:
|
|
||||||
|
|
||||||
-> C -> A -> B -
|
|
||||||
/ \
|
|
||||||
\ /
|
|
||||||
----------------
|
|
||||||
|
|
||||||
where 'A -> B' means that event A depends on event B.
|
|
||||||
|
|
||||||
Such circular dependencies lead to a deadlock since no waiter can meet
|
|
||||||
its condition to wake up as described.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Circular dependencies cause a deadlock.
|
|
||||||
|
|
||||||
|
|
||||||
How lockdep works
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Lockdep tries to detect a deadlock by checking dependencies created by
|
|
||||||
lock operations, acquire and release. Waiting for a lock corresponds to
|
|
||||||
waiting for an event, and releasing a lock corresponds to triggering an
|
|
||||||
event in the previous section.
|
|
||||||
|
|
||||||
In short, lockdep does:
|
|
||||||
|
|
||||||
1. Detect a new dependency.
|
|
||||||
2. Add the dependency into a global graph.
|
|
||||||
3. Check if that makes dependencies circular.
|
|
||||||
4. Report a deadlock or its possibility if so.
|
|
||||||
|
|
||||||
For example, consider a graph built by lockdep that looks like:
|
|
||||||
|
|
||||||
A -> B -
|
|
||||||
\
|
|
||||||
-> E
|
|
||||||
/
|
|
||||||
C -> D -
|
|
||||||
|
|
||||||
where A, B,..., E are different lock classes.
|
|
||||||
|
|
||||||
Lockdep will add a dependency into the graph on detection of a new
|
|
||||||
dependency. For example, it will add a dependency 'E -> C' when a new
|
|
||||||
dependency between lock E and lock C is detected. Then the graph will be:
|
|
||||||
|
|
||||||
A -> B -
|
|
||||||
\
|
|
||||||
-> E -
|
|
||||||
/ \
|
|
||||||
-> C -> D - \
|
|
||||||
/ /
|
|
||||||
\ /
|
|
||||||
------------------
|
|
||||||
|
|
||||||
where A, B,..., E are different lock classes.
|
|
||||||
|
|
||||||
This graph contains a subgraph which demonstrates circular dependencies:
|
|
||||||
|
|
||||||
-> E -
|
|
||||||
/ \
|
|
||||||
-> C -> D - \
|
|
||||||
/ /
|
|
||||||
\ /
|
|
||||||
------------------
|
|
||||||
|
|
||||||
where C, D and E are different lock classes.
|
|
||||||
|
|
||||||
This is the condition under which a deadlock might occur. Lockdep
|
|
||||||
reports it on detection after adding a new dependency. This is the way
|
|
||||||
how lockdep works.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Lockdep detects a deadlock or its possibility by checking if circular
|
|
||||||
dependencies were created after adding each new dependency.
|
|
||||||
|
|
||||||
|
|
||||||
==========
|
|
||||||
Limitation
|
|
||||||
==========
|
|
||||||
|
|
||||||
Limit lockdep
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Limiting lockdep to work on only typical locks e.g. spin locks and
|
|
||||||
mutexes, which are released within the acquire context, the
|
|
||||||
implementation becomes simple but its capacity for detection becomes
|
|
||||||
limited. Let's check pros and cons in next section.
|
|
||||||
|
|
||||||
|
|
||||||
Pros from the limitation
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Given the limitation, when acquiring a lock, locks in a held_locks
|
|
||||||
cannot be released if the context cannot acquire it so has to wait to
|
|
||||||
acquire it, which means all waiters for the locks in the held_locks are
|
|
||||||
stuck. It's an exact case to create dependencies between each lock in
|
|
||||||
the held_locks and the lock to acquire.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
CONTEXT X
|
|
||||||
---------
|
|
||||||
acquire A
|
|
||||||
acquire B /* Add a dependency 'A -> B' */
|
|
||||||
release B
|
|
||||||
release A
|
|
||||||
|
|
||||||
where A and B are different lock classes.
|
|
||||||
|
|
||||||
When acquiring lock A, the held_locks of CONTEXT X is empty thus no
|
|
||||||
dependency is added. But when acquiring lock B, lockdep detects and adds
|
|
||||||
a new dependency 'A -> B' between lock A in the held_locks and lock B.
|
|
||||||
They can be simply added whenever acquiring each lock.
|
|
||||||
|
|
||||||
And data required by lockdep exists in a local structure, held_locks
|
|
||||||
embedded in task_struct. Forcing to access the data within the context,
|
|
||||||
lockdep can avoid racy problems without explicit locks while handling
|
|
||||||
the local data.
|
|
||||||
|
|
||||||
Lastly, lockdep only needs to keep locks currently being held, to build
|
|
||||||
a dependency graph. However, relaxing the limitation, it needs to keep
|
|
||||||
even locks already released, because a decision whether they created
|
|
||||||
dependencies might be long-deferred.
|
|
||||||
|
|
||||||
To sum up, we can expect several advantages from the limitation:
|
|
||||||
|
|
||||||
1. Lockdep can easily identify a dependency when acquiring a lock.
|
|
||||||
2. Races are avoidable while accessing local locks in a held_locks.
|
|
||||||
3. Lockdep only needs to keep locks currently being held.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Given the limitation, the implementation becomes simple and efficient.
|
|
||||||
|
|
||||||
|
|
||||||
Cons from the limitation
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Given the limitation, lockdep is applicable only to typical locks. For
|
|
||||||
example, page locks for page access or completions for synchronization
|
|
||||||
cannot work with lockdep.
|
|
||||||
|
|
||||||
Can we detect deadlocks below, under the limitation?
|
|
||||||
|
|
||||||
Example 1:
|
|
||||||
|
|
||||||
CONTEXT X CONTEXT Y CONTEXT Z
|
|
||||||
--------- --------- ----------
|
|
||||||
mutex_lock A
|
|
||||||
lock_page B
|
|
||||||
lock_page B
|
|
||||||
mutex_lock A /* DEADLOCK */
|
|
||||||
unlock_page B held by X
|
|
||||||
unlock_page B
|
|
||||||
mutex_unlock A
|
|
||||||
mutex_unlock A
|
|
||||||
|
|
||||||
where A and B are different lock classes.
|
|
||||||
|
|
||||||
No, we cannot.
|
|
||||||
|
|
||||||
Example 2:
|
|
||||||
|
|
||||||
CONTEXT X CONTEXT Y
|
|
||||||
--------- ---------
|
|
||||||
mutex_lock A
|
|
||||||
mutex_lock A
|
|
||||||
wait_for_complete B /* DEADLOCK */
|
|
||||||
complete B
|
|
||||||
mutex_unlock A
|
|
||||||
mutex_unlock A
|
|
||||||
|
|
||||||
where A is a lock class and B is a completion variable.
|
|
||||||
|
|
||||||
No, we cannot.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Given the limitation, lockdep cannot detect a deadlock or its
|
|
||||||
possibility caused by page locks or completions.
|
|
||||||
|
|
||||||
|
|
||||||
Relax the limitation
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Under the limitation, things to create dependencies are limited to
|
|
||||||
typical locks. However, synchronization primitives like page locks and
|
|
||||||
completions, which are allowed to be released in any context, also
|
|
||||||
create dependencies and can cause a deadlock. So lockdep should track
|
|
||||||
these locks to do a better job. We have to relax the limitation for
|
|
||||||
these locks to work with lockdep.
|
|
||||||
|
|
||||||
Detecting dependencies is very important for lockdep to work because
|
|
||||||
adding a dependency means adding an opportunity to check whether it
|
|
||||||
causes a deadlock. The more lockdep adds dependencies, the more it
|
|
||||||
thoroughly works. Thus Lockdep has to do its best to detect and add as
|
|
||||||
many true dependencies into a graph as possible.
|
|
||||||
|
|
||||||
For example, considering only typical locks, lockdep builds a graph like:
|
|
||||||
|
|
||||||
A -> B -
|
|
||||||
\
|
|
||||||
-> E
|
|
||||||
/
|
|
||||||
C -> D -
|
|
||||||
|
|
||||||
where A, B,..., E are different lock classes.
|
|
||||||
|
|
||||||
On the other hand, under the relaxation, additional dependencies might
|
|
||||||
be created and added. Assuming additional 'FX -> C' and 'E -> GX' are
|
|
||||||
added thanks to the relaxation, the graph will be:
|
|
||||||
|
|
||||||
A -> B -
|
|
||||||
\
|
|
||||||
-> E -> GX
|
|
||||||
/
|
|
||||||
FX -> C -> D -
|
|
||||||
|
|
||||||
where A, B,..., E, FX and GX are different lock classes, and a suffix
|
|
||||||
'X' is added on non-typical locks.
|
|
||||||
|
|
||||||
The latter graph gives us more chances to check circular dependencies
|
|
||||||
than the former. However, it might suffer performance degradation since
|
|
||||||
relaxing the limitation, with which design and implementation of lockdep
|
|
||||||
can be efficient, might introduce inefficiency inevitably. So lockdep
|
|
||||||
should provide two options, strong detection and efficient detection.
|
|
||||||
|
|
||||||
Choosing efficient detection:
|
|
||||||
|
|
||||||
Lockdep works with only locks restricted to be released within the
|
|
||||||
acquire context. However, lockdep works efficiently.
|
|
||||||
|
|
||||||
Choosing strong detection:
|
|
||||||
|
|
||||||
Lockdep works with all synchronization primitives. However, lockdep
|
|
||||||
suffers performance degradation.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Relaxing the limitation, lockdep can add additional dependencies giving
|
|
||||||
additional opportunities to check circular dependencies.
|
|
||||||
|
|
||||||
|
|
||||||
============
|
|
||||||
Crossrelease
|
|
||||||
============
|
|
||||||
|
|
||||||
Introduce crossrelease
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
In order to allow lockdep to handle additional dependencies by what
|
|
||||||
might be released in any context, namely 'crosslock', we have to be able
|
|
||||||
to identify those created by crosslocks. The proposed 'crossrelease'
|
|
||||||
feature provoides a way to do that.
|
|
||||||
|
|
||||||
Crossrelease feature has to do:
|
|
||||||
|
|
||||||
1. Identify dependencies created by crosslocks.
|
|
||||||
2. Add the dependencies into a dependency graph.
|
|
||||||
|
|
||||||
That's all. Once a meaningful dependency is added into graph, then
|
|
||||||
lockdep would work with the graph as it did. The most important thing
|
|
||||||
crossrelease feature has to do is to correctly identify and add true
|
|
||||||
dependencies into the global graph.
|
|
||||||
|
|
||||||
A dependency e.g. 'A -> B' can be identified only in the A's release
|
|
||||||
context because a decision required to identify the dependency can be
|
|
||||||
made only in the release context. That is to decide whether A can be
|
|
||||||
released so that a waiter for A can be woken up. It cannot be made in
|
|
||||||
other than the A's release context.
|
|
||||||
|
|
||||||
It's no matter for typical locks because each acquire context is same as
|
|
||||||
its release context, thus lockdep can decide whether a lock can be
|
|
||||||
released in the acquire context. However for crosslocks, lockdep cannot
|
|
||||||
make the decision in the acquire context but has to wait until the
|
|
||||||
release context is identified.
|
|
||||||
|
|
||||||
Therefore, deadlocks by crosslocks cannot be detected just when it
|
|
||||||
happens, because those cannot be identified until the crosslocks are
|
|
||||||
released. However, deadlock possibilities can be detected and it's very
|
|
||||||
worth. See 'APPENDIX A' section to check why.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Using crossrelease feature, lockdep can work with what might be released
|
|
||||||
in any context, namely crosslock.
|
|
||||||
|
|
||||||
|
|
||||||
Introduce commit
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Since crossrelease defers the work adding true dependencies of
|
|
||||||
crosslocks until they are actually released, crossrelease has to queue
|
|
||||||
all acquisitions which might create dependencies with the crosslocks.
|
|
||||||
Then it identifies dependencies using the queued data in batches at a
|
|
||||||
proper time. We call it 'commit'.
|
|
||||||
|
|
||||||
There are four types of dependencies:
|
|
||||||
|
|
||||||
1. TT type: 'typical lock A -> typical lock B'
|
|
||||||
|
|
||||||
Just when acquiring B, lockdep can see it's in the A's release
|
|
||||||
context. So the dependency between A and B can be identified
|
|
||||||
immediately. Commit is unnecessary.
|
|
||||||
|
|
||||||
2. TC type: 'typical lock A -> crosslock BX'
|
|
||||||
|
|
||||||
Just when acquiring BX, lockdep can see it's in the A's release
|
|
||||||
context. So the dependency between A and BX can be identified
|
|
||||||
immediately. Commit is unnecessary, too.
|
|
||||||
|
|
||||||
3. CT type: 'crosslock AX -> typical lock B'
|
|
||||||
|
|
||||||
When acquiring B, lockdep cannot identify the dependency because
|
|
||||||
there's no way to know if it's in the AX's release context. It has
|
|
||||||
to wait until the decision can be made. Commit is necessary.
|
|
||||||
|
|
||||||
4. CC type: 'crosslock AX -> crosslock BX'
|
|
||||||
|
|
||||||
When acquiring BX, lockdep cannot identify the dependency because
|
|
||||||
there's no way to know if it's in the AX's release context. It has
|
|
||||||
to wait until the decision can be made. Commit is necessary.
|
|
||||||
But, handling CC type is not implemented yet. It's a future work.
|
|
||||||
|
|
||||||
Lockdep can work without commit for typical locks, but commit step is
|
|
||||||
necessary once crosslocks are involved. Introducing commit, lockdep
|
|
||||||
performs three steps. What lockdep does in each step is:
|
|
||||||
|
|
||||||
1. Acquisition: For typical locks, lockdep does what it originally did
|
|
||||||
and queues the lock so that CT type dependencies can be checked using
|
|
||||||
it at the commit step. For crosslocks, it saves data which will be
|
|
||||||
used at the commit step and increases a reference count for it.
|
|
||||||
|
|
||||||
2. Commit: No action is reauired for typical locks. For crosslocks,
|
|
||||||
lockdep adds CT type dependencies using the data saved at the
|
|
||||||
acquisition step.
|
|
||||||
|
|
||||||
3. Release: No changes are required for typical locks. When a crosslock
|
|
||||||
is released, it decreases a reference count for it.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Crossrelease introduces commit step to handle dependencies of crosslocks
|
|
||||||
in batches at a proper time.
|
|
||||||
|
|
||||||
|
|
||||||
==============
|
|
||||||
Implementation
|
|
||||||
==============
|
|
||||||
|
|
||||||
Data structures
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Crossrelease introduces two main data structures.
|
|
||||||
|
|
||||||
1. hist_lock
|
|
||||||
|
|
||||||
This is an array embedded in task_struct, for keeping lock history so
|
|
||||||
that dependencies can be added using them at the commit step. Since
|
|
||||||
it's local data, it can be accessed locklessly in the owner context.
|
|
||||||
The array is filled at the acquisition step and consumed at the
|
|
||||||
commit step. And it's managed in circular manner.
|
|
||||||
|
|
||||||
2. cross_lock
|
|
||||||
|
|
||||||
One per lockdep_map exists. This is for keeping data of crosslocks
|
|
||||||
and used at the commit step.
|
|
||||||
|
|
||||||
|
|
||||||
How crossrelease works
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
It's the key of how crossrelease works, to defer necessary works to an
|
|
||||||
appropriate point in time and perform in at once at the commit step.
|
|
||||||
Let's take a look with examples step by step, starting from how lockdep
|
|
||||||
works without crossrelease for typical locks.
|
|
||||||
|
|
||||||
acquire A /* Push A onto held_locks */
|
|
||||||
acquire B /* Push B onto held_locks and add 'A -> B' */
|
|
||||||
acquire C /* Push C onto held_locks and add 'B -> C' */
|
|
||||||
release C /* Pop C from held_locks */
|
|
||||||
release B /* Pop B from held_locks */
|
|
||||||
release A /* Pop A from held_locks */
|
|
||||||
|
|
||||||
where A, B and C are different lock classes.
|
|
||||||
|
|
||||||
NOTE: This document assumes that readers already understand how
|
|
||||||
lockdep works without crossrelease thus omits details. But there's
|
|
||||||
one thing to note. Lockdep pretends to pop a lock from held_locks
|
|
||||||
when releasing it. But it's subtly different from the original pop
|
|
||||||
operation because lockdep allows other than the top to be poped.
|
|
||||||
|
|
||||||
In this case, lockdep adds 'the top of held_locks -> the lock to acquire'
|
|
||||||
dependency every time acquiring a lock.
|
|
||||||
|
|
||||||
After adding 'A -> B', a dependency graph will be:
|
|
||||||
|
|
||||||
A -> B
|
|
||||||
|
|
||||||
where A and B are different lock classes.
|
|
||||||
|
|
||||||
And after adding 'B -> C', the graph will be:
|
|
||||||
|
|
||||||
A -> B -> C
|
|
||||||
|
|
||||||
where A, B and C are different lock classes.
|
|
||||||
|
|
||||||
Let's performs commit step even for typical locks to add dependencies.
|
|
||||||
Of course, commit step is not necessary for them, however, it would work
|
|
||||||
well because this is a more general way.
|
|
||||||
|
|
||||||
acquire A
|
|
||||||
/*
|
|
||||||
* Queue A into hist_locks
|
|
||||||
*
|
|
||||||
* In hist_locks: A
|
|
||||||
* In graph: Empty
|
|
||||||
*/
|
|
||||||
|
|
||||||
acquire B
|
|
||||||
/*
|
|
||||||
* Queue B into hist_locks
|
|
||||||
*
|
|
||||||
* In hist_locks: A, B
|
|
||||||
* In graph: Empty
|
|
||||||
*/
|
|
||||||
|
|
||||||
acquire C
|
|
||||||
/*
|
|
||||||
* Queue C into hist_locks
|
|
||||||
*
|
|
||||||
* In hist_locks: A, B, C
|
|
||||||
* In graph: Empty
|
|
||||||
*/
|
|
||||||
|
|
||||||
commit C
|
|
||||||
/*
|
|
||||||
* Add 'C -> ?'
|
|
||||||
* Answer the following to decide '?'
|
|
||||||
* What has been queued since acquire C: Nothing
|
|
||||||
*
|
|
||||||
* In hist_locks: A, B, C
|
|
||||||
* In graph: Empty
|
|
||||||
*/
|
|
||||||
|
|
||||||
release C
|
|
||||||
|
|
||||||
commit B
|
|
||||||
/*
|
|
||||||
* Add 'B -> ?'
|
|
||||||
* Answer the following to decide '?'
|
|
||||||
* What has been queued since acquire B: C
|
|
||||||
*
|
|
||||||
* In hist_locks: A, B, C
|
|
||||||
* In graph: 'B -> C'
|
|
||||||
*/
|
|
||||||
|
|
||||||
release B
|
|
||||||
|
|
||||||
commit A
|
|
||||||
/*
|
|
||||||
* Add 'A -> ?'
|
|
||||||
* Answer the following to decide '?'
|
|
||||||
* What has been queued since acquire A: B, C
|
|
||||||
*
|
|
||||||
* In hist_locks: A, B, C
|
|
||||||
* In graph: 'B -> C', 'A -> B', 'A -> C'
|
|
||||||
*/
|
|
||||||
|
|
||||||
release A
|
|
||||||
|
|
||||||
where A, B and C are different lock classes.
|
|
||||||
|
|
||||||
In this case, dependencies are added at the commit step as described.
|
|
||||||
|
|
||||||
After commits for A, B and C, the graph will be:
|
|
||||||
|
|
||||||
A -> B -> C
|
|
||||||
|
|
||||||
where A, B and C are different lock classes.
|
|
||||||
|
|
||||||
NOTE: A dependency 'A -> C' is optimized out.
|
|
||||||
|
|
||||||
We can see the former graph built without commit step is same as the
|
|
||||||
latter graph built using commit steps. Of course the former way leads to
|
|
||||||
earlier finish for building the graph, which means we can detect a
|
|
||||||
deadlock or its possibility sooner. So the former way would be prefered
|
|
||||||
when possible. But we cannot avoid using the latter way for crosslocks.
|
|
||||||
|
|
||||||
Let's look at how commit steps work for crosslocks. In this case, the
|
|
||||||
commit step is performed only on crosslock AX as real. And it assumes
|
|
||||||
that the AX release context is different from the AX acquire context.
|
|
||||||
|
|
||||||
BX RELEASE CONTEXT BX ACQUIRE CONTEXT
|
|
||||||
------------------ ------------------
|
|
||||||
acquire A
|
|
||||||
/*
|
|
||||||
* Push A onto held_locks
|
|
||||||
* Queue A into hist_locks
|
|
||||||
*
|
|
||||||
* In held_locks: A
|
|
||||||
* In hist_locks: A
|
|
||||||
* In graph: Empty
|
|
||||||
*/
|
|
||||||
|
|
||||||
acquire BX
|
|
||||||
/*
|
|
||||||
* Add 'the top of held_locks -> BX'
|
|
||||||
*
|
|
||||||
* In held_locks: A
|
|
||||||
* In hist_locks: A
|
|
||||||
* In graph: 'A -> BX'
|
|
||||||
*/
|
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
It must be guaranteed that the following operations are seen after
|
|
||||||
acquiring BX globally. It can be done by things like barrier.
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
acquire C
|
|
||||||
/*
|
|
||||||
* Push C onto held_locks
|
|
||||||
* Queue C into hist_locks
|
|
||||||
*
|
|
||||||
* In held_locks: C
|
|
||||||
* In hist_locks: C
|
|
||||||
* In graph: 'A -> BX'
|
|
||||||
*/
|
|
||||||
|
|
||||||
release C
|
|
||||||
/*
|
|
||||||
* Pop C from held_locks
|
|
||||||
*
|
|
||||||
* In held_locks: Empty
|
|
||||||
* In hist_locks: C
|
|
||||||
* In graph: 'A -> BX'
|
|
||||||
*/
|
|
||||||
acquire D
|
|
||||||
/*
|
|
||||||
* Push D onto held_locks
|
|
||||||
* Queue D into hist_locks
|
|
||||||
* Add 'the top of held_locks -> D'
|
|
||||||
*
|
|
||||||
* In held_locks: A, D
|
|
||||||
* In hist_locks: A, D
|
|
||||||
* In graph: 'A -> BX', 'A -> D'
|
|
||||||
*/
|
|
||||||
acquire E
|
|
||||||
/*
|
|
||||||
* Push E onto held_locks
|
|
||||||
* Queue E into hist_locks
|
|
||||||
*
|
|
||||||
* In held_locks: E
|
|
||||||
* In hist_locks: C, E
|
|
||||||
* In graph: 'A -> BX', 'A -> D'
|
|
||||||
*/
|
|
||||||
|
|
||||||
release E
|
|
||||||
/*
|
|
||||||
* Pop E from held_locks
|
|
||||||
*
|
|
||||||
* In held_locks: Empty
|
|
||||||
* In hist_locks: D, E
|
|
||||||
* In graph: 'A -> BX', 'A -> D'
|
|
||||||
*/
|
|
||||||
release D
|
|
||||||
/*
|
|
||||||
* Pop D from held_locks
|
|
||||||
*
|
|
||||||
* In held_locks: A
|
|
||||||
* In hist_locks: A, D
|
|
||||||
* In graph: 'A -> BX', 'A -> D'
|
|
||||||
*/
|
|
||||||
commit BX
|
|
||||||
/*
|
|
||||||
* Add 'BX -> ?'
|
|
||||||
* What has been queued since acquire BX: C, E
|
|
||||||
*
|
|
||||||
* In held_locks: Empty
|
|
||||||
* In hist_locks: D, E
|
|
||||||
* In graph: 'A -> BX', 'A -> D',
|
|
||||||
* 'BX -> C', 'BX -> E'
|
|
||||||
*/
|
|
||||||
|
|
||||||
release BX
|
|
||||||
/*
|
|
||||||
* In held_locks: Empty
|
|
||||||
* In hist_locks: D, E
|
|
||||||
* In graph: 'A -> BX', 'A -> D',
|
|
||||||
* 'BX -> C', 'BX -> E'
|
|
||||||
*/
|
|
||||||
release A
|
|
||||||
/*
|
|
||||||
* Pop A from held_locks
|
|
||||||
*
|
|
||||||
* In held_locks: Empty
|
|
||||||
* In hist_locks: A, D
|
|
||||||
* In graph: 'A -> BX', 'A -> D',
|
|
||||||
* 'BX -> C', 'BX -> E'
|
|
||||||
*/
|
|
||||||
|
|
||||||
where A, BX, C,..., E are different lock classes, and a suffix 'X' is
|
|
||||||
added on crosslocks.
|
|
||||||
|
|
||||||
Crossrelease considers all acquisitions after acqiuring BX are
|
|
||||||
candidates which might create dependencies with BX. True dependencies
|
|
||||||
will be determined when identifying the release context of BX. Meanwhile,
|
|
||||||
all typical locks are queued so that they can be used at the commit step.
|
|
||||||
And then two dependencies 'BX -> C' and 'BX -> E' are added at the
|
|
||||||
commit step when identifying the release context.
|
|
||||||
|
|
||||||
The final graph will be, with crossrelease:
|
|
||||||
|
|
||||||
-> C
|
|
||||||
/
|
|
||||||
-> BX -
|
|
||||||
/ \
|
|
||||||
A - -> E
|
|
||||||
\
|
|
||||||
-> D
|
|
||||||
|
|
||||||
where A, BX, C,..., E are different lock classes, and a suffix 'X' is
|
|
||||||
added on crosslocks.
|
|
||||||
|
|
||||||
However, the final graph will be, without crossrelease:
|
|
||||||
|
|
||||||
A -> D
|
|
||||||
|
|
||||||
where A and D are different lock classes.
|
|
||||||
|
|
||||||
The former graph has three more dependencies, 'A -> BX', 'BX -> C' and
|
|
||||||
'BX -> E' giving additional opportunities to check if they cause
|
|
||||||
deadlocks. This way lockdep can detect a deadlock or its possibility
|
|
||||||
caused by crosslocks.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
We checked how crossrelease works with several examples.
|
|
||||||
|
|
||||||
|
|
||||||
=============
|
|
||||||
Optimizations
|
|
||||||
=============
|
|
||||||
|
|
||||||
Avoid duplication
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Crossrelease feature uses a cache like what lockdep already uses for
|
|
||||||
dependency chains, but this time it's for caching CT type dependencies.
|
|
||||||
Once that dependency is cached, the same will never be added again.
|
|
||||||
|
|
||||||
|
|
||||||
Lockless for hot paths
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
To keep all locks for later use at the commit step, crossrelease adopts
|
|
||||||
a local array embedded in task_struct, which makes access to the data
|
|
||||||
lockless by forcing it to happen only within the owner context. It's
|
|
||||||
like how lockdep handles held_locks. Lockless implmentation is important
|
|
||||||
since typical locks are very frequently acquired and released.
|
|
||||||
|
|
||||||
|
|
||||||
=================================================
|
|
||||||
APPENDIX A: What lockdep does to work aggresively
|
|
||||||
=================================================
|
|
||||||
|
|
||||||
A deadlock actually occurs when all wait operations creating circular
|
|
||||||
dependencies run at the same time. Even though they don't, a potential
|
|
||||||
deadlock exists if the problematic dependencies exist. Thus it's
|
|
||||||
meaningful to detect not only an actual deadlock but also its potential
|
|
||||||
possibility. The latter is rather valuable. When a deadlock occurs
|
|
||||||
actually, we can identify what happens in the system by some means or
|
|
||||||
other even without lockdep. However, there's no way to detect possiblity
|
|
||||||
without lockdep unless the whole code is parsed in head. It's terrible.
|
|
||||||
Lockdep does the both, and crossrelease only focuses on the latter.
|
|
||||||
|
|
||||||
Whether or not a deadlock actually occurs depends on several factors.
|
|
||||||
For example, what order contexts are switched in is a factor. Assuming
|
|
||||||
circular dependencies exist, a deadlock would occur when contexts are
|
|
||||||
switched so that all wait operations creating the dependencies run
|
|
||||||
simultaneously. Thus to detect a deadlock possibility even in the case
|
|
||||||
that it has not occured yet, lockdep should consider all possible
|
|
||||||
combinations of dependencies, trying to:
|
|
||||||
|
|
||||||
1. Use a global dependency graph.
|
|
||||||
|
|
||||||
Lockdep combines all dependencies into one global graph and uses them,
|
|
||||||
regardless of which context generates them or what order contexts are
|
|
||||||
switched in. Aggregated dependencies are only considered so they are
|
|
||||||
prone to be circular if a problem exists.
|
|
||||||
|
|
||||||
2. Check dependencies between classes instead of instances.
|
|
||||||
|
|
||||||
What actually causes a deadlock are instances of lock. However,
|
|
||||||
lockdep checks dependencies between classes instead of instances.
|
|
||||||
This way lockdep can detect a deadlock which has not happened but
|
|
||||||
might happen in future by others but the same class.
|
|
||||||
|
|
||||||
3. Assume all acquisitions lead to waiting.
|
|
||||||
|
|
||||||
Although locks might be acquired without waiting which is essential
|
|
||||||
to create dependencies, lockdep assumes all acquisitions lead to
|
|
||||||
waiting since it might be true some time or another.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Lockdep detects not only an actual deadlock but also its possibility,
|
|
||||||
and the latter is more valuable.
|
|
||||||
|
|
||||||
|
|
||||||
==================================================
|
|
||||||
APPENDIX B: How to avoid adding false dependencies
|
|
||||||
==================================================
|
|
||||||
|
|
||||||
Remind what a dependency is. A dependency exists if:
|
|
||||||
|
|
||||||
1. There are two waiters waiting for each event at a given time.
|
|
||||||
2. The only way to wake up each waiter is to trigger its event.
|
|
||||||
3. Whether one can be woken up depends on whether the other can.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
acquire A
|
|
||||||
acquire B /* A dependency 'A -> B' exists */
|
|
||||||
release B
|
|
||||||
release A
|
|
||||||
|
|
||||||
where A and B are different lock classes.
|
|
||||||
|
|
||||||
A depedency 'A -> B' exists since:
|
|
||||||
|
|
||||||
1. A waiter for A and a waiter for B might exist when acquiring B.
|
|
||||||
2. Only way to wake up each is to release what it waits for.
|
|
||||||
3. Whether the waiter for A can be woken up depends on whether the
|
|
||||||
other can. IOW, TASK X cannot release A if it fails to acquire B.
|
|
||||||
|
|
||||||
For another example:
|
|
||||||
|
|
||||||
TASK X TASK Y
|
|
||||||
------ ------
|
|
||||||
acquire AX
|
|
||||||
acquire B /* A dependency 'AX -> B' exists */
|
|
||||||
release B
|
|
||||||
release AX held by Y
|
|
||||||
|
|
||||||
where AX and B are different lock classes, and a suffix 'X' is added
|
|
||||||
on crosslocks.
|
|
||||||
|
|
||||||
Even in this case involving crosslocks, the same rule can be applied. A
|
|
||||||
depedency 'AX -> B' exists since:
|
|
||||||
|
|
||||||
1. A waiter for AX and a waiter for B might exist when acquiring B.
|
|
||||||
2. Only way to wake up each is to release what it waits for.
|
|
||||||
3. Whether the waiter for AX can be woken up depends on whether the
|
|
||||||
other can. IOW, TASK X cannot release AX if it fails to acquire B.
|
|
||||||
|
|
||||||
Let's take a look at more complicated example:
|
|
||||||
|
|
||||||
TASK X TASK Y
|
|
||||||
------ ------
|
|
||||||
acquire B
|
|
||||||
release B
|
|
||||||
fork Y
|
|
||||||
acquire AX
|
|
||||||
acquire C /* A dependency 'AX -> C' exists */
|
|
||||||
release C
|
|
||||||
release AX held by Y
|
|
||||||
|
|
||||||
where AX, B and C are different lock classes, and a suffix 'X' is
|
|
||||||
added on crosslocks.
|
|
||||||
|
|
||||||
Does a dependency 'AX -> B' exist? Nope.
|
|
||||||
|
|
||||||
Two waiters are essential to create a dependency. However, waiters for
|
|
||||||
AX and B to create 'AX -> B' cannot exist at the same time in this
|
|
||||||
example. Thus the dependency 'AX -> B' cannot be created.
|
|
||||||
|
|
||||||
It would be ideal if the full set of true ones can be considered. But
|
|
||||||
we can ensure nothing but what actually happened. Relying on what
|
|
||||||
actually happens at runtime, we can anyway add only true ones, though
|
|
||||||
they might be a subset of true ones. It's similar to how lockdep works
|
|
||||||
for typical locks. There might be more true dependencies than what
|
|
||||||
lockdep has detected in runtime. Lockdep has no choice but to rely on
|
|
||||||
what actually happens. Crossrelease also relies on it.
|
|
||||||
|
|
||||||
CONCLUSION
|
|
||||||
|
|
||||||
Relying on what actually happens, lockdep can avoid adding false
|
|
||||||
dependencies.
|
|
|
@ -98,5 +98,25 @@ request is made for a page in an old zpool, it is uncompressed using its
|
||||||
original compressor. Once all pages are removed from an old zpool, the zpool
|
original compressor. Once all pages are removed from an old zpool, the zpool
|
||||||
and its compressor are freed.
|
and its compressor are freed.
|
||||||
|
|
||||||
|
Some of the pages in zswap are same-value filled pages (i.e. contents of the
|
||||||
|
page have same value or repetitive pattern). These pages include zero-filled
|
||||||
|
pages and they are handled differently. During store operation, a page is
|
||||||
|
checked if it is a same-value filled page before compressing it. If true, the
|
||||||
|
compressed length of the page is set to zero and the pattern or same-filled
|
||||||
|
value is stored.
|
||||||
|
|
||||||
|
Same-value filled pages identification feature is enabled by default and can be
|
||||||
|
disabled at boot time by setting the "same_filled_pages_enabled" attribute to 0,
|
||||||
|
e.g. zswap.same_filled_pages_enabled=0. It can also be enabled and disabled at
|
||||||
|
runtime using the sysfs "same_filled_pages_enabled" attribute, e.g.
|
||||||
|
|
||||||
|
echo 1 > /sys/module/zswap/parameters/same_filled_pages_enabled
|
||||||
|
|
||||||
|
When zswap same-filled page identification is disabled at runtime, it will stop
|
||||||
|
checking for the same-value filled pages during store operation. However, the
|
||||||
|
existing pages which are marked as same-value filled pages remain stored
|
||||||
|
unchanged in zswap until they are either loaded or invalidated.
|
||||||
|
|
||||||
A debugfs interface is provided for various statistic about pool size, number
|
A debugfs interface is provided for various statistic about pool size, number
|
||||||
of pages stored, and various counters for the reasons pages are rejected.
|
of pages stored, same-value filled pages and various counters for the reasons
|
||||||
|
pages are rejected.
|
||||||
|
|
|
@ -5431,7 +5431,7 @@ F: drivers/media/tuners/fc2580*
|
||||||
|
|
||||||
FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
|
FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
|
||||||
M: Johannes Thumshirn <jth@kernel.org>
|
M: Johannes Thumshirn <jth@kernel.org>
|
||||||
L: fcoe-devel@open-fcoe.org
|
L: linux-scsi@vger.kernel.org
|
||||||
W: www.Open-FCoE.org
|
W: www.Open-FCoE.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/scsi/libfc/
|
F: drivers/scsi/libfc/
|
||||||
|
@ -13117,6 +13117,7 @@ F: drivers/dma/dw/
|
||||||
|
|
||||||
SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
|
SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER
|
||||||
M: Jie Deng <jiedeng@synopsys.com>
|
M: Jie Deng <jiedeng@synopsys.com>
|
||||||
|
M: Jose Abreu <Jose.Abreu@synopsys.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/net/ethernet/synopsys/
|
F: drivers/net/ethernet/synopsys/
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
||||||
VERSION = 4
|
VERSION = 4
|
||||||
PATCHLEVEL = 15
|
PATCHLEVEL = 15
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION = -rc3
|
EXTRAVERSION = -rc4
|
||||||
NAME = Fearless Coyote
|
NAME = Fearless Coyote
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
switch0port10: port@10 {
|
switch0port10: port@10 {
|
||||||
reg = <10>;
|
reg = <10>;
|
||||||
label = "dsa";
|
label = "dsa";
|
||||||
phy-mode = "xgmii";
|
phy-mode = "xaui";
|
||||||
link = <&switch1port10>;
|
link = <&switch1port10>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -208,7 +208,7 @@
|
||||||
switch1port10: port@10 {
|
switch1port10: port@10 {
|
||||||
reg = <10>;
|
reg = <10>;
|
||||||
label = "dsa";
|
label = "dsa";
|
||||||
phy-mode = "xgmii";
|
phy-mode = "xaui";
|
||||||
link = <&switch0port10>;
|
link = <&switch0port10>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -557,7 +557,6 @@ config QCOM_QDF2400_ERRATUM_0065
|
||||||
|
|
||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
|
|
||||||
config SOCIONEXT_SYNQUACER_PREITS
|
config SOCIONEXT_SYNQUACER_PREITS
|
||||||
bool "Socionext Synquacer: Workaround for GICv3 pre-ITS"
|
bool "Socionext Synquacer: Workaround for GICv3 pre-ITS"
|
||||||
default y
|
default y
|
||||||
|
@ -576,6 +575,17 @@ config HISILICON_ERRATUM_161600802
|
||||||
a 128kB offset to be applied to the target address in this commands.
|
a 128kB offset to be applied to the target address in this commands.
|
||||||
|
|
||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config QCOM_FALKOR_ERRATUM_E1041
|
||||||
|
bool "Falkor E1041: Speculative instruction fetches might cause errant memory access"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Falkor CPU may speculatively fetch instructions from an improper
|
||||||
|
memory location when MMU translation is changed from SCTLR_ELn[M]=1
|
||||||
|
to SCTLR_ELn[M]=0. Prefix an ISB instruction to fix the problem.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -512,4 +512,14 @@ alternative_else_nop_endif
|
||||||
#endif
|
#endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Errata workaround prior to disable MMU. Insert an ISB immediately prior
|
||||||
|
* to executing the MSR that will change SCTLR_ELn[M] from a value of 1 to 0.
|
||||||
|
*/
|
||||||
|
.macro pre_disable_mmu_workaround
|
||||||
|
#ifdef CONFIG_QCOM_FALKOR_ERRATUM_E1041
|
||||||
|
isb
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
#endif /* __ASM_ASSEMBLER_H */
|
#endif /* __ASM_ASSEMBLER_H */
|
||||||
|
|
|
@ -60,6 +60,9 @@ enum ftr_type {
|
||||||
#define FTR_VISIBLE true /* Feature visible to the user space */
|
#define FTR_VISIBLE true /* Feature visible to the user space */
|
||||||
#define FTR_HIDDEN false /* Feature is hidden from the user */
|
#define FTR_HIDDEN false /* Feature is hidden from the user */
|
||||||
|
|
||||||
|
#define FTR_VISIBLE_IF_IS_ENABLED(config) \
|
||||||
|
(IS_ENABLED(config) ? FTR_VISIBLE : FTR_HIDDEN)
|
||||||
|
|
||||||
struct arm64_ftr_bits {
|
struct arm64_ftr_bits {
|
||||||
bool sign; /* Value is signed ? */
|
bool sign; /* Value is signed ? */
|
||||||
bool visible;
|
bool visible;
|
||||||
|
|
|
@ -91,6 +91,7 @@
|
||||||
#define BRCM_CPU_PART_VULCAN 0x516
|
#define BRCM_CPU_PART_VULCAN 0x516
|
||||||
|
|
||||||
#define QCOM_CPU_PART_FALKOR_V1 0x800
|
#define QCOM_CPU_PART_FALKOR_V1 0x800
|
||||||
|
#define QCOM_CPU_PART_FALKOR 0xC00
|
||||||
|
|
||||||
#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
|
#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
|
||||||
#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
|
#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
|
||||||
|
@ -99,6 +100,7 @@
|
||||||
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
||||||
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
|
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
|
||||||
#define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
|
#define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
|
||||||
|
#define MIDR_QCOM_FALKOR MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR)
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
#include <asm/fixmap.h>
|
#include <asm/fixmap.h>
|
||||||
#include <linux/mmdebug.h>
|
#include <linux/mmdebug.h>
|
||||||
|
#include <linux/mm_types.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
extern void __pte_error(const char *file, int line, unsigned long val);
|
extern void __pte_error(const char *file, int line, unsigned long val);
|
||||||
extern void __pmd_error(const char *file, int line, unsigned long val);
|
extern void __pmd_error(const char *file, int line, unsigned long val);
|
||||||
|
@ -149,12 +151,20 @@ static inline pte_t pte_mkwrite(pte_t pte)
|
||||||
|
|
||||||
static inline pte_t pte_mkclean(pte_t pte)
|
static inline pte_t pte_mkclean(pte_t pte)
|
||||||
{
|
{
|
||||||
return clear_pte_bit(pte, __pgprot(PTE_DIRTY));
|
pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY));
|
||||||
|
pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
|
||||||
|
|
||||||
|
return pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline pte_t pte_mkdirty(pte_t pte)
|
static inline pte_t pte_mkdirty(pte_t pte)
|
||||||
{
|
{
|
||||||
return set_pte_bit(pte, __pgprot(PTE_DIRTY));
|
pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
|
||||||
|
|
||||||
|
if (pte_write(pte))
|
||||||
|
pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
|
||||||
|
|
||||||
|
return pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline pte_t pte_mkold(pte_t pte)
|
static inline pte_t pte_mkold(pte_t pte)
|
||||||
|
@ -207,9 +217,6 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mm_struct;
|
|
||||||
struct vm_area_struct;
|
|
||||||
|
|
||||||
extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
|
extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -238,7 +245,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
|
||||||
* hardware updates of the pte (ptep_set_access_flags safely changes
|
* hardware updates of the pte (ptep_set_access_flags safely changes
|
||||||
* valid ptes without going through an invalid entry).
|
* valid ptes without going through an invalid entry).
|
||||||
*/
|
*/
|
||||||
if (pte_valid(*ptep) && pte_valid(pte)) {
|
if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(*ptep) && pte_valid(pte) &&
|
||||||
|
(mm == current->active_mm || atomic_read(&mm->mm_users) > 1)) {
|
||||||
VM_WARN_ONCE(!pte_young(pte),
|
VM_WARN_ONCE(!pte_young(pte),
|
||||||
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
|
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
|
||||||
__func__, pte_val(*ptep), pte_val(pte));
|
__func__, pte_val(*ptep), pte_val(pte));
|
||||||
|
@ -641,28 +649,23 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
|
||||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ptep_set_wrprotect - mark read-only while preserving the hardware update of
|
* ptep_set_wrprotect - mark read-only while trasferring potential hardware
|
||||||
* the Access Flag.
|
* dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
|
||||||
*/
|
*/
|
||||||
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
||||||
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
|
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
|
||||||
{
|
{
|
||||||
pte_t old_pte, pte;
|
pte_t old_pte, pte;
|
||||||
|
|
||||||
/*
|
|
||||||
* ptep_set_wrprotect() is only called on CoW mappings which are
|
|
||||||
* private (!VM_SHARED) with the pte either read-only (!PTE_WRITE &&
|
|
||||||
* PTE_RDONLY) or writable and software-dirty (PTE_WRITE &&
|
|
||||||
* !PTE_RDONLY && PTE_DIRTY); see is_cow_mapping() and
|
|
||||||
* protection_map[]. There is no race with the hardware update of the
|
|
||||||
* dirty state: clearing of PTE_RDONLY when PTE_WRITE (a.k.a. PTE_DBM)
|
|
||||||
* is set.
|
|
||||||
*/
|
|
||||||
VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(*ptep),
|
|
||||||
"%s: potential race with hardware DBM", __func__);
|
|
||||||
pte = READ_ONCE(*ptep);
|
pte = READ_ONCE(*ptep);
|
||||||
do {
|
do {
|
||||||
old_pte = pte;
|
old_pte = pte;
|
||||||
|
/*
|
||||||
|
* If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
|
||||||
|
* clear), set the PTE_DIRTY bit.
|
||||||
|
*/
|
||||||
|
if (pte_hw_dirty(pte))
|
||||||
|
pte = pte_mkdirty(pte);
|
||||||
pte = pte_wrprotect(pte);
|
pte = pte_wrprotect(pte);
|
||||||
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
|
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
|
||||||
pte_val(old_pte), pte_val(pte));
|
pte_val(old_pte), pte_val(pte));
|
||||||
|
|
|
@ -37,6 +37,7 @@ ENTRY(__cpu_soft_restart)
|
||||||
mrs x12, sctlr_el1
|
mrs x12, sctlr_el1
|
||||||
ldr x13, =SCTLR_ELx_FLAGS
|
ldr x13, =SCTLR_ELx_FLAGS
|
||||||
bic x12, x12, x13
|
bic x12, x12, x13
|
||||||
|
pre_disable_mmu_workaround
|
||||||
msr sctlr_el1, x12
|
msr sctlr_el1, x12
|
||||||
isb
|
isb
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,8 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
||||||
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
|
ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
|
||||||
|
FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
|
||||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_GIC_SHIFT, 4, 0),
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_GIC_SHIFT, 4, 0),
|
||||||
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
|
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
|
||||||
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
|
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
|
||||||
|
|
|
@ -96,6 +96,7 @@ ENTRY(entry)
|
||||||
mrs x0, sctlr_el2
|
mrs x0, sctlr_el2
|
||||||
bic x0, x0, #1 << 0 // clear SCTLR.M
|
bic x0, x0, #1 << 0 // clear SCTLR.M
|
||||||
bic x0, x0, #1 << 2 // clear SCTLR.C
|
bic x0, x0, #1 << 2 // clear SCTLR.C
|
||||||
|
pre_disable_mmu_workaround
|
||||||
msr sctlr_el2, x0
|
msr sctlr_el2, x0
|
||||||
isb
|
isb
|
||||||
b 2f
|
b 2f
|
||||||
|
@ -103,6 +104,7 @@ ENTRY(entry)
|
||||||
mrs x0, sctlr_el1
|
mrs x0, sctlr_el1
|
||||||
bic x0, x0, #1 << 0 // clear SCTLR.M
|
bic x0, x0, #1 << 0 // clear SCTLR.M
|
||||||
bic x0, x0, #1 << 2 // clear SCTLR.C
|
bic x0, x0, #1 << 2 // clear SCTLR.C
|
||||||
|
pre_disable_mmu_workaround
|
||||||
msr sctlr_el1, x0
|
msr sctlr_el1, x0
|
||||||
isb
|
isb
|
||||||
2:
|
2:
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ void fpsimd_update_current_state(struct fpsimd_state *state)
|
||||||
|
|
||||||
local_bh_disable();
|
local_bh_disable();
|
||||||
|
|
||||||
current->thread.fpsimd_state = *state;
|
current->thread.fpsimd_state.user_fpsimd = state->user_fpsimd;
|
||||||
if (system_supports_sve() && test_thread_flag(TIF_SVE))
|
if (system_supports_sve() && test_thread_flag(TIF_SVE))
|
||||||
fpsimd_to_sve(current);
|
fpsimd_to_sve(current);
|
||||||
|
|
||||||
|
|
|
@ -750,6 +750,7 @@ __primary_switch:
|
||||||
* to take into account by discarding the current kernel mapping and
|
* to take into account by discarding the current kernel mapping and
|
||||||
* creating a new one.
|
* creating a new one.
|
||||||
*/
|
*/
|
||||||
|
pre_disable_mmu_workaround
|
||||||
msr sctlr_el1, x20 // disable the MMU
|
msr sctlr_el1, x20 // disable the MMU
|
||||||
isb
|
isb
|
||||||
bl __create_page_tables // recreate kernel mapping
|
bl __create_page_tables // recreate kernel mapping
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
#include <asm/compat.h>
|
#include <asm/compat.h>
|
||||||
#include <asm/current.h>
|
#include <asm/current.h>
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
#include <asm/traps.h>
|
#include <asm/traps.h>
|
||||||
#include <asm/cputype.h>
|
#include <asm/cputype.h>
|
||||||
#include <asm/system_misc.h>
|
#include <asm/system_misc.h>
|
||||||
#include <asm/uaccess.h>
|
|
||||||
|
|
||||||
/* Breakpoint currently in use for each BRP. */
|
/* Breakpoint currently in use for each BRP. */
|
||||||
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
|
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
|
||||||
|
|
|
@ -45,6 +45,7 @@ ENTRY(arm64_relocate_new_kernel)
|
||||||
mrs x0, sctlr_el2
|
mrs x0, sctlr_el2
|
||||||
ldr x1, =SCTLR_ELx_FLAGS
|
ldr x1, =SCTLR_ELx_FLAGS
|
||||||
bic x0, x0, x1
|
bic x0, x0, x1
|
||||||
|
pre_disable_mmu_workaround
|
||||||
msr sctlr_el2, x0
|
msr sctlr_el2, x0
|
||||||
isb
|
isb
|
||||||
1:
|
1:
|
||||||
|
|
|
@ -151,6 +151,7 @@ reset:
|
||||||
mrs x5, sctlr_el2
|
mrs x5, sctlr_el2
|
||||||
ldr x6, =SCTLR_ELx_FLAGS
|
ldr x6, =SCTLR_ELx_FLAGS
|
||||||
bic x5, x5, x6 // Clear SCTL_M and etc
|
bic x5, x5, x6 // Clear SCTL_M and etc
|
||||||
|
pre_disable_mmu_workaround
|
||||||
msr sctlr_el2, x5
|
msr sctlr_el2, x5
|
||||||
isb
|
isb
|
||||||
|
|
||||||
|
|
|
@ -389,7 +389,7 @@ void ptdump_check_wx(void)
|
||||||
.check_wx = true,
|
.check_wx = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
walk_pgd(&st, &init_mm, 0);
|
walk_pgd(&st, &init_mm, VA_START);
|
||||||
note_page(&st, 0, 0, 0);
|
note_page(&st, 0, 0, 0);
|
||||||
if (st.wx_pages || st.uxn_pages)
|
if (st.wx_pages || st.uxn_pages)
|
||||||
pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
|
pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
|
||||||
|
|
|
@ -574,7 +574,6 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct siginfo info;
|
struct siginfo info;
|
||||||
const struct fault_info *inf;
|
const struct fault_info *inf;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
inf = esr_to_fault_info(esr);
|
inf = esr_to_fault_info(esr);
|
||||||
pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n",
|
pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n",
|
||||||
|
@ -589,7 +588,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||||
if (interrupts_enabled(regs))
|
if (interrupts_enabled(regs))
|
||||||
nmi_enter();
|
nmi_enter();
|
||||||
|
|
||||||
ret = ghes_notify_sea();
|
ghes_notify_sea();
|
||||||
|
|
||||||
if (interrupts_enabled(regs))
|
if (interrupts_enabled(regs))
|
||||||
nmi_exit();
|
nmi_exit();
|
||||||
|
@ -604,7 +603,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||||
info.si_addr = (void __user *)addr;
|
info.si_addr = (void __user *)addr;
|
||||||
arm64_notify_die("", regs, &info, esr);
|
arm64_notify_die("", regs, &info, esr);
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct fault_info fault_info[] = {
|
static const struct fault_info fault_info[] = {
|
||||||
|
|
|
@ -476,6 +476,8 @@ void __init arm64_memblock_init(void)
|
||||||
|
|
||||||
reserve_elfcorehdr();
|
reserve_elfcorehdr();
|
||||||
|
|
||||||
|
high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
|
||||||
|
|
||||||
dma_contiguous_reserve(arm64_dma_phys_limit);
|
dma_contiguous_reserve(arm64_dma_phys_limit);
|
||||||
|
|
||||||
memblock_allow_resize();
|
memblock_allow_resize();
|
||||||
|
@ -502,7 +504,6 @@ void __init bootmem_init(void)
|
||||||
sparse_init();
|
sparse_init();
|
||||||
zone_sizes_init(min, max);
|
zone_sizes_init(min, max);
|
||||||
|
|
||||||
high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
|
|
||||||
memblock_dump_all();
|
memblock_dump_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,25 @@
|
||||||
#define smp_rmb() RISCV_FENCE(r,r)
|
#define smp_rmb() RISCV_FENCE(r,r)
|
||||||
#define smp_wmb() RISCV_FENCE(w,w)
|
#define smp_wmb() RISCV_FENCE(w,w)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a very specific barrier: it's currently only used in two places in
|
||||||
|
* the kernel, both in the scheduler. See include/linux/spinlock.h for the two
|
||||||
|
* orderings it guarantees, but the "critical section is RCsc" guarantee
|
||||||
|
* mandates a barrier on RISC-V. The sequence looks like:
|
||||||
|
*
|
||||||
|
* lr.aq lock
|
||||||
|
* sc lock <= LOCKED
|
||||||
|
* smp_mb__after_spinlock()
|
||||||
|
* // critical section
|
||||||
|
* lr lock
|
||||||
|
* sc.rl lock <= UNLOCKED
|
||||||
|
*
|
||||||
|
* The AQ/RL pair provides a RCpc critical section, but there's not really any
|
||||||
|
* way we can take advantage of that here because the ordering is only enforced
|
||||||
|
* on that one lock. Thus, we're just doing a full fence.
|
||||||
|
*/
|
||||||
|
#define smp_mb__after_spinlock() RISCV_FENCE(rw,rw)
|
||||||
|
|
||||||
#include <asm-generic/barrier.h>
|
#include <asm-generic/barrier.h>
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
|
@ -38,10 +38,6 @@
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
|
|
||||||
#ifdef CONFIG_HVC_RISCV_SBI
|
|
||||||
#include <asm/hvc_riscv_sbi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_DUMMY_CONSOLE
|
#ifdef CONFIG_DUMMY_CONSOLE
|
||||||
struct screen_info screen_info = {
|
struct screen_info screen_info = {
|
||||||
.orig_video_lines = 30,
|
.orig_video_lines = 30,
|
||||||
|
@ -212,13 +208,6 @@ static void __init setup_bootmem(void)
|
||||||
|
|
||||||
void __init setup_arch(char **cmdline_p)
|
void __init setup_arch(char **cmdline_p)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_HVC_RISCV_SBI)
|
|
||||||
if (likely(early_console == NULL)) {
|
|
||||||
early_console = &riscv_sbi_early_console_dev;
|
|
||||||
register_console(early_console);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_CMDLINE_BOOL
|
#ifdef CONFIG_CMDLINE_BOOL
|
||||||
#ifdef CONFIG_CMDLINE_OVERRIDE
|
#ifdef CONFIG_CMDLINE_OVERRIDE
|
||||||
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
|
|
@ -70,7 +70,7 @@ SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end,
|
||||||
bool local = (flags & SYS_RISCV_FLUSH_ICACHE_LOCAL) != 0;
|
bool local = (flags & SYS_RISCV_FLUSH_ICACHE_LOCAL) != 0;
|
||||||
|
|
||||||
/* Check the reserved flags. */
|
/* Check the reserved flags. */
|
||||||
if (unlikely(flags & !SYS_RISCV_FLUSH_ICACHE_ALL))
|
if (unlikely(flags & ~SYS_RISCV_FLUSH_ICACHE_ALL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
flush_icache_mm(mm, local);
|
flush_icache_mm(mm, local);
|
||||||
|
|
|
@ -1264,12 +1264,6 @@ static inline pud_t pud_mkwrite(pud_t pud)
|
||||||
return pud;
|
return pud;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define pud_write pud_write
|
|
||||||
static inline int pud_write(pud_t pud)
|
|
||||||
{
|
|
||||||
return (pud_val(pud) & _REGION3_ENTRY_WRITE) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline pud_t pud_mkclean(pud_t pud)
|
static inline pud_t pud_mkclean(pud_t pud)
|
||||||
{
|
{
|
||||||
if (pud_large(pud)) {
|
if (pud_large(pud)) {
|
||||||
|
|
|
@ -263,6 +263,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplis
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groups_sort(group_info);
|
||||||
retval = set_current_groups(group_info);
|
retval = set_current_groups(group_info);
|
||||||
put_group_info(group_info);
|
put_group_info(group_info);
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
||||||
if (!(pmd_val(pmd) & _PAGE_VALID))
|
if (!(pmd_val(pmd) & _PAGE_VALID))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!pmd_access_permitted(pmd, write))
|
if (write && !pmd_write(pmd))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
refs = 0;
|
refs = 0;
|
||||||
|
@ -114,7 +114,7 @@ static int gup_huge_pud(pud_t *pudp, pud_t pud, unsigned long addr,
|
||||||
if (!(pud_val(pud) & _PAGE_VALID))
|
if (!(pud_val(pud) & _PAGE_VALID))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!pud_access_permitted(pud, write))
|
if (write && !pud_write(pud))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
refs = 0;
|
refs = 0;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
generic-y += barrier.h
|
generic-y += barrier.h
|
||||||
|
generic-y += bpf_perf_event.h
|
||||||
generic-y += bug.h
|
generic-y += bug.h
|
||||||
generic-y += clkdev.h
|
generic-y += clkdev.h
|
||||||
generic-y += current.h
|
generic-y += current.h
|
||||||
|
|
|
@ -400,6 +400,7 @@ config UNWINDER_FRAME_POINTER
|
||||||
config UNWINDER_GUESS
|
config UNWINDER_GUESS
|
||||||
bool "Guess unwinder"
|
bool "Guess unwinder"
|
||||||
depends on EXPERT
|
depends on EXPERT
|
||||||
|
depends on !STACKDEPOT
|
||||||
---help---
|
---help---
|
||||||
This option enables the "guess" unwinder for unwinding kernel stack
|
This option enables the "guess" unwinder for unwinding kernel stack
|
||||||
traces. It scans the stack and reports every kernel text address it
|
traces. It scans the stack and reports every kernel text address it
|
||||||
|
|
|
@ -80,6 +80,7 @@ vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o
|
||||||
ifdef CONFIG_X86_64
|
ifdef CONFIG_X86_64
|
||||||
vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/pagetable.o
|
vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/pagetable.o
|
||||||
vmlinux-objs-y += $(obj)/mem_encrypt.o
|
vmlinux-objs-y += $(obj)/mem_encrypt.o
|
||||||
|
vmlinux-objs-y += $(obj)/pgtable_64.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
|
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
|
||||||
|
|
|
@ -305,10 +305,18 @@ ENTRY(startup_64)
|
||||||
leaq boot_stack_end(%rbx), %rsp
|
leaq boot_stack_end(%rbx), %rsp
|
||||||
|
|
||||||
#ifdef CONFIG_X86_5LEVEL
|
#ifdef CONFIG_X86_5LEVEL
|
||||||
/* Check if 5-level paging has already enabled */
|
/*
|
||||||
movq %cr4, %rax
|
* Check if we need to enable 5-level paging.
|
||||||
testl $X86_CR4_LA57, %eax
|
* RSI holds real mode data and need to be preserved across
|
||||||
jnz lvl5
|
* a function call.
|
||||||
|
*/
|
||||||
|
pushq %rsi
|
||||||
|
call l5_paging_required
|
||||||
|
popq %rsi
|
||||||
|
|
||||||
|
/* If l5_paging_required() returned zero, we're done here. */
|
||||||
|
cmpq $0, %rax
|
||||||
|
je lvl5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point we are in long mode with 4-level paging enabled,
|
* At this point we are in long mode with 4-level paging enabled,
|
||||||
|
|
|
@ -169,6 +169,16 @@ void __puthex(unsigned long value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool l5_supported(void)
|
||||||
|
{
|
||||||
|
/* Check if leaf 7 is supported. */
|
||||||
|
if (native_cpuid_eax(0) < 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check if la57 is supported. */
|
||||||
|
return native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31));
|
||||||
|
}
|
||||||
|
|
||||||
#if CONFIG_X86_NEED_RELOCS
|
#if CONFIG_X86_NEED_RELOCS
|
||||||
static void handle_relocations(void *output, unsigned long output_len,
|
static void handle_relocations(void *output, unsigned long output_len,
|
||||||
unsigned long virt_addr)
|
unsigned long virt_addr)
|
||||||
|
@ -362,6 +372,12 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
|
||||||
console_init();
|
console_init();
|
||||||
debug_putstr("early console in extract_kernel\n");
|
debug_putstr("early console in extract_kernel\n");
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_X86_5LEVEL) && !l5_supported()) {
|
||||||
|
error("This linux kernel as configured requires 5-level paging\n"
|
||||||
|
"This CPU does not support the required 'cr4.la57' feature\n"
|
||||||
|
"Unable to boot - please use a kernel appropriate for your CPU\n");
|
||||||
|
}
|
||||||
|
|
||||||
free_mem_ptr = heap; /* Heap */
|
free_mem_ptr = heap; /* Heap */
|
||||||
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
|
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <asm/processor.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __force_order is used by special_insns.h asm code to force instruction
|
||||||
|
* serialization.
|
||||||
|
*
|
||||||
|
* It is not referenced from the code, but GCC < 5 with -fPIE would fail
|
||||||
|
* due to an undefined symbol. Define it to make these ancient GCCs work.
|
||||||
|
*/
|
||||||
|
unsigned long __force_order;
|
||||||
|
|
||||||
|
int l5_paging_required(void)
|
||||||
|
{
|
||||||
|
/* Check if leaf 7 is supported. */
|
||||||
|
|
||||||
|
if (native_cpuid_eax(0) < 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check if la57 is supported. */
|
||||||
|
if (!(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check if 5-level paging has already been enabled. */
|
||||||
|
if (native_read_cr4() & X86_CR4_LA57)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -44,9 +44,9 @@ FDINITRD=$6
|
||||||
|
|
||||||
# Make sure the files actually exist
|
# Make sure the files actually exist
|
||||||
verify "$FBZIMAGE"
|
verify "$FBZIMAGE"
|
||||||
verify "$MTOOLSRC"
|
|
||||||
|
|
||||||
genbzdisk() {
|
genbzdisk() {
|
||||||
|
verify "$MTOOLSRC"
|
||||||
mformat a:
|
mformat a:
|
||||||
syslinux $FIMAGE
|
syslinux $FIMAGE
|
||||||
echo "$KCMDLINE" | mcopy - a:syslinux.cfg
|
echo "$KCMDLINE" | mcopy - a:syslinux.cfg
|
||||||
|
@ -57,6 +57,7 @@ genbzdisk() {
|
||||||
}
|
}
|
||||||
|
|
||||||
genfdimage144() {
|
genfdimage144() {
|
||||||
|
verify "$MTOOLSRC"
|
||||||
dd if=/dev/zero of=$FIMAGE bs=1024 count=1440 2> /dev/null
|
dd if=/dev/zero of=$FIMAGE bs=1024 count=1440 2> /dev/null
|
||||||
mformat v:
|
mformat v:
|
||||||
syslinux $FIMAGE
|
syslinux $FIMAGE
|
||||||
|
@ -68,6 +69,7 @@ genfdimage144() {
|
||||||
}
|
}
|
||||||
|
|
||||||
genfdimage288() {
|
genfdimage288() {
|
||||||
|
verify "$MTOOLSRC"
|
||||||
dd if=/dev/zero of=$FIMAGE bs=1024 count=2880 2> /dev/null
|
dd if=/dev/zero of=$FIMAGE bs=1024 count=2880 2> /dev/null
|
||||||
mformat w:
|
mformat w:
|
||||||
syslinux $FIMAGE
|
syslinux $FIMAGE
|
||||||
|
|
|
@ -59,13 +59,6 @@ static int encrypt(struct blkcipher_desc *desc,
|
||||||
|
|
||||||
salsa20_ivsetup(ctx, walk.iv);
|
salsa20_ivsetup(ctx, walk.iv);
|
||||||
|
|
||||||
if (likely(walk.nbytes == nbytes))
|
|
||||||
{
|
|
||||||
salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
|
|
||||||
walk.dst.virt.addr, nbytes);
|
|
||||||
return blkcipher_walk_done(desc, &walk, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (walk.nbytes >= 64) {
|
while (walk.nbytes >= 64) {
|
||||||
salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
|
salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
|
||||||
walk.dst.virt.addr,
|
walk.dst.virt.addr,
|
||||||
|
|
|
@ -12,7 +12,13 @@
|
||||||
|
|
||||||
/* image of the saved processor state */
|
/* image of the saved processor state */
|
||||||
struct saved_context {
|
struct saved_context {
|
||||||
u16 es, fs, gs, ss;
|
/*
|
||||||
|
* On x86_32, all segment registers, with the possible exception of
|
||||||
|
* gs, are saved at kernel entry in pt_regs.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_X86_32_LAZY_GS
|
||||||
|
u16 gs;
|
||||||
|
#endif
|
||||||
unsigned long cr0, cr2, cr3, cr4;
|
unsigned long cr0, cr2, cr3, cr4;
|
||||||
u64 misc_enable;
|
u64 misc_enable;
|
||||||
bool misc_enable_saved;
|
bool misc_enable_saved;
|
||||||
|
|
|
@ -20,8 +20,20 @@
|
||||||
*/
|
*/
|
||||||
struct saved_context {
|
struct saved_context {
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
u16 ds, es, fs, gs, ss;
|
|
||||||
unsigned long gs_base, gs_kernel_base, fs_base;
|
/*
|
||||||
|
* User CS and SS are saved in current_pt_regs(). The rest of the
|
||||||
|
* segment selectors need to be saved and restored here.
|
||||||
|
*/
|
||||||
|
u16 ds, es, fs, gs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Usermode FSBASE and GSBASE may not match the fs and gs selectors,
|
||||||
|
* so we save them separately. We save the kernelmode GSBASE to
|
||||||
|
* restore percpu access after resume.
|
||||||
|
*/
|
||||||
|
unsigned long kernelmode_gs_base, usermode_gs_base, fs_base;
|
||||||
|
|
||||||
unsigned long cr0, cr2, cr3, cr4, cr8;
|
unsigned long cr0, cr2, cr3, cr4, cr8;
|
||||||
u64 misc_enable;
|
u64 misc_enable;
|
||||||
bool misc_enable_saved;
|
bool misc_enable_saved;
|
||||||
|
@ -30,8 +42,7 @@ struct saved_context {
|
||||||
u16 gdt_pad; /* Unused */
|
u16 gdt_pad; /* Unused */
|
||||||
struct desc_ptr gdt_desc;
|
struct desc_ptr gdt_desc;
|
||||||
u16 idt_pad;
|
u16 idt_pad;
|
||||||
u16 idt_limit;
|
struct desc_ptr idt;
|
||||||
unsigned long idt_base;
|
|
||||||
u16 ldt;
|
u16 ldt;
|
||||||
u16 tss;
|
u16 tss;
|
||||||
unsigned long tr;
|
unsigned long tr;
|
||||||
|
|
|
@ -106,7 +106,7 @@ EXPORT_SYMBOL(__max_logical_packages);
|
||||||
static unsigned int logical_packages __read_mostly;
|
static unsigned int logical_packages __read_mostly;
|
||||||
|
|
||||||
/* Maximum number of SMT threads on any online core */
|
/* Maximum number of SMT threads on any online core */
|
||||||
int __max_smt_threads __read_mostly;
|
int __read_mostly __max_smt_threads = 1;
|
||||||
|
|
||||||
/* Flag to indicate if a complete sched domain rebuild is required */
|
/* Flag to indicate if a complete sched domain rebuild is required */
|
||||||
bool x86_topology_update;
|
bool x86_topology_update;
|
||||||
|
@ -1304,7 +1304,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
|
||||||
* Today neither Intel nor AMD support heterogenous systems so
|
* Today neither Intel nor AMD support heterogenous systems so
|
||||||
* extrapolate the boot cpu's data to all packages.
|
* extrapolate the boot cpu's data to all packages.
|
||||||
*/
|
*/
|
||||||
ncpus = cpu_data(0).booted_cores * smp_num_siblings;
|
ncpus = cpu_data(0).booted_cores * topology_max_smt_threads();
|
||||||
__max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
|
__max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
|
||||||
pr_info("Max logical packages: %u\n", __max_logical_packages);
|
pr_info("Max logical packages: %u\n", __max_logical_packages);
|
||||||
|
|
||||||
|
|
|
@ -607,7 +607,7 @@ fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1)
|
||||||
fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1)
|
fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1)
|
||||||
fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1)
|
fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1)
|
||||||
fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1)
|
fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1)
|
||||||
ff:
|
ff: UD0
|
||||||
EndTable
|
EndTable
|
||||||
|
|
||||||
Table: 3-byte opcode 1 (0x0f 0x38)
|
Table: 3-byte opcode 1 (0x0f 0x38)
|
||||||
|
@ -717,7 +717,7 @@ AVXcode: 2
|
||||||
7e: vpermt2d/q Vx,Hx,Wx (66),(ev)
|
7e: vpermt2d/q Vx,Hx,Wx (66),(ev)
|
||||||
7f: vpermt2ps/d Vx,Hx,Wx (66),(ev)
|
7f: vpermt2ps/d Vx,Hx,Wx (66),(ev)
|
||||||
80: INVEPT Gy,Mdq (66)
|
80: INVEPT Gy,Mdq (66)
|
||||||
81: INVPID Gy,Mdq (66)
|
81: INVVPID Gy,Mdq (66)
|
||||||
82: INVPCID Gy,Mdq (66)
|
82: INVPCID Gy,Mdq (66)
|
||||||
83: vpmultishiftqb Vx,Hx,Wx (66),(ev)
|
83: vpmultishiftqb Vx,Hx,Wx (66),(ev)
|
||||||
88: vexpandps/d Vpd,Wpd (66),(ev)
|
88: vexpandps/d Vpd,Wpd (66),(ev)
|
||||||
|
@ -970,6 +970,15 @@ GrpTable: Grp9
|
||||||
EndTable
|
EndTable
|
||||||
|
|
||||||
GrpTable: Grp10
|
GrpTable: Grp10
|
||||||
|
# all are UD1
|
||||||
|
0: UD1
|
||||||
|
1: UD1
|
||||||
|
2: UD1
|
||||||
|
3: UD1
|
||||||
|
4: UD1
|
||||||
|
5: UD1
|
||||||
|
6: UD1
|
||||||
|
7: UD1
|
||||||
EndTable
|
EndTable
|
||||||
|
|
||||||
# Grp11A and Grp11B are expressed as Grp11 in Intel SDM
|
# Grp11A and Grp11B are expressed as Grp11 in Intel SDM
|
||||||
|
|
|
@ -404,11 +404,11 @@ void iounmap(volatile void __iomem *addr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mmiotrace_iounmap(addr);
|
||||||
|
|
||||||
addr = (volatile void __iomem *)
|
addr = (volatile void __iomem *)
|
||||||
(PAGE_MASK & (unsigned long __force)addr);
|
(PAGE_MASK & (unsigned long __force)addr);
|
||||||
|
|
||||||
mmiotrace_iounmap(addr);
|
|
||||||
|
|
||||||
/* Use the vm area unlocked, assuming the caller
|
/* Use the vm area unlocked, assuming the caller
|
||||||
ensures there isn't another iounmap for the same address
|
ensures there isn't another iounmap for the same address
|
||||||
in parallel. Reuse of the virtual address is prevented by
|
in parallel. Reuse of the virtual address is prevented by
|
||||||
|
|
|
@ -435,17 +435,18 @@ int register_kmmio_probe(struct kmmio_probe *p)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned long size = 0;
|
unsigned long size = 0;
|
||||||
|
unsigned long addr = p->addr & PAGE_MASK;
|
||||||
const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
|
const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
|
||||||
unsigned int l;
|
unsigned int l;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
spin_lock_irqsave(&kmmio_lock, flags);
|
spin_lock_irqsave(&kmmio_lock, flags);
|
||||||
if (get_kmmio_probe(p->addr)) {
|
if (get_kmmio_probe(addr)) {
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pte = lookup_address(p->addr, &l);
|
pte = lookup_address(addr, &l);
|
||||||
if (!pte) {
|
if (!pte) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -454,7 +455,7 @@ int register_kmmio_probe(struct kmmio_probe *p)
|
||||||
kmmio_count++;
|
kmmio_count++;
|
||||||
list_add_rcu(&p->list, &kmmio_probes);
|
list_add_rcu(&p->list, &kmmio_probes);
|
||||||
while (size < size_lim) {
|
while (size < size_lim) {
|
||||||
if (add_kmmio_fault_page(p->addr + size))
|
if (add_kmmio_fault_page(addr + size))
|
||||||
pr_err("Unable to set page fault.\n");
|
pr_err("Unable to set page fault.\n");
|
||||||
size += page_level_size(l);
|
size += page_level_size(l);
|
||||||
}
|
}
|
||||||
|
@ -528,19 +529,20 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long size = 0;
|
unsigned long size = 0;
|
||||||
|
unsigned long addr = p->addr & PAGE_MASK;
|
||||||
const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
|
const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
|
||||||
struct kmmio_fault_page *release_list = NULL;
|
struct kmmio_fault_page *release_list = NULL;
|
||||||
struct kmmio_delayed_release *drelease;
|
struct kmmio_delayed_release *drelease;
|
||||||
unsigned int l;
|
unsigned int l;
|
||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
|
|
||||||
pte = lookup_address(p->addr, &l);
|
pte = lookup_address(addr, &l);
|
||||||
if (!pte)
|
if (!pte)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock_irqsave(&kmmio_lock, flags);
|
spin_lock_irqsave(&kmmio_lock, flags);
|
||||||
while (size < size_lim) {
|
while (size < size_lim) {
|
||||||
release_kmmio_fault_page(p->addr + size, &release_list);
|
release_kmmio_fault_page(addr + size, &release_list);
|
||||||
size += page_level_size(l);
|
size += page_level_size(l);
|
||||||
}
|
}
|
||||||
list_del_rcu(&p->list);
|
list_del_rcu(&p->list);
|
||||||
|
|
|
@ -665,6 +665,16 @@ static void pci_amd_enable_64bit_bar(struct pci_dev *dev)
|
||||||
unsigned i;
|
unsigned i;
|
||||||
u32 base, limit, high;
|
u32 base, limit, high;
|
||||||
struct resource *res, *conflict;
|
struct resource *res, *conflict;
|
||||||
|
struct pci_dev *other;
|
||||||
|
|
||||||
|
/* Check that we are the only device of that type */
|
||||||
|
other = pci_get_device(dev->vendor, dev->device, NULL);
|
||||||
|
if (other != dev ||
|
||||||
|
(other = pci_get_device(dev->vendor, dev->device, other))) {
|
||||||
|
/* This is a multi-socket system, don't touch it for now */
|
||||||
|
pci_dev_put(other);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
pci_read_config_dword(dev, AMD_141b_MMIO_BASE(i), &base);
|
pci_read_config_dword(dev, AMD_141b_MMIO_BASE(i), &base);
|
||||||
|
@ -696,8 +706,13 @@ static void pci_amd_enable_64bit_bar(struct pci_dev *dev)
|
||||||
res->end = 0xfd00000000ull - 1;
|
res->end = 0xfd00000000ull - 1;
|
||||||
|
|
||||||
/* Just grab the free area behind system memory for this */
|
/* Just grab the free area behind system memory for this */
|
||||||
while ((conflict = request_resource_conflict(&iomem_resource, res)))
|
while ((conflict = request_resource_conflict(&iomem_resource, res))) {
|
||||||
|
if (conflict->end >= res->end) {
|
||||||
|
kfree(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
res->start = conflict->end + 1;
|
res->start = conflict->end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
dev_info(&dev->dev, "adding root bus resource %pR\n", res);
|
dev_info(&dev->dev, "adding root bus resource %pR\n", res);
|
||||||
|
|
||||||
|
@ -714,10 +729,10 @@ static void pci_amd_enable_64bit_bar(struct pci_dev *dev)
|
||||||
|
|
||||||
pci_bus_add_resource(dev->bus, res, 0);
|
pci_bus_add_resource(dev->bus, res, 0);
|
||||||
}
|
}
|
||||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1401, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1401, pci_amd_enable_64bit_bar);
|
||||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x141b, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x141b, pci_amd_enable_64bit_bar);
|
||||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1571, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1571, pci_amd_enable_64bit_bar);
|
||||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
|
||||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -82,12 +82,8 @@ static void __save_processor_state(struct saved_context *ctxt)
|
||||||
/*
|
/*
|
||||||
* descriptor tables
|
* descriptor tables
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
store_idt(&ctxt->idt);
|
store_idt(&ctxt->idt);
|
||||||
#else
|
|
||||||
/* CONFIG_X86_64 */
|
|
||||||
store_idt((struct desc_ptr *)&ctxt->idt_limit);
|
|
||||||
#endif
|
|
||||||
/*
|
/*
|
||||||
* We save it here, but restore it only in the hibernate case.
|
* We save it here, but restore it only in the hibernate case.
|
||||||
* For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit
|
* For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit
|
||||||
|
@ -103,22 +99,18 @@ static void __save_processor_state(struct saved_context *ctxt)
|
||||||
/*
|
/*
|
||||||
* segment registers
|
* segment registers
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32_LAZY_GS
|
||||||
savesegment(es, ctxt->es);
|
|
||||||
savesegment(fs, ctxt->fs);
|
|
||||||
savesegment(gs, ctxt->gs);
|
savesegment(gs, ctxt->gs);
|
||||||
savesegment(ss, ctxt->ss);
|
#endif
|
||||||
#else
|
#ifdef CONFIG_X86_64
|
||||||
/* CONFIG_X86_64 */
|
savesegment(gs, ctxt->gs);
|
||||||
asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds));
|
savesegment(fs, ctxt->fs);
|
||||||
asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
|
savesegment(ds, ctxt->ds);
|
||||||
asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
|
savesegment(es, ctxt->es);
|
||||||
asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
|
|
||||||
asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
|
|
||||||
|
|
||||||
rdmsrl(MSR_FS_BASE, ctxt->fs_base);
|
rdmsrl(MSR_FS_BASE, ctxt->fs_base);
|
||||||
rdmsrl(MSR_GS_BASE, ctxt->gs_base);
|
rdmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
|
||||||
rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
|
rdmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base);
|
||||||
mtrr_save_fixed_ranges(NULL);
|
mtrr_save_fixed_ranges(NULL);
|
||||||
|
|
||||||
rdmsrl(MSR_EFER, ctxt->efer);
|
rdmsrl(MSR_EFER, ctxt->efer);
|
||||||
|
@ -178,6 +170,9 @@ static void fix_processor_context(void)
|
||||||
write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
|
write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
|
||||||
|
|
||||||
syscall_init(); /* This sets MSR_*STAR and related */
|
syscall_init(); /* This sets MSR_*STAR and related */
|
||||||
|
#else
|
||||||
|
if (boot_cpu_has(X86_FEATURE_SEP))
|
||||||
|
enable_sep_cpu();
|
||||||
#endif
|
#endif
|
||||||
load_TR_desc(); /* This does ltr */
|
load_TR_desc(); /* This does ltr */
|
||||||
load_mm_ldt(current->active_mm); /* This does lldt */
|
load_mm_ldt(current->active_mm); /* This does lldt */
|
||||||
|
@ -193,6 +188,9 @@ static void fix_processor_context(void)
|
||||||
* __restore_processor_state - restore the contents of CPU registers saved
|
* __restore_processor_state - restore the contents of CPU registers saved
|
||||||
* by __save_processor_state()
|
* by __save_processor_state()
|
||||||
* @ctxt - structure to load the registers contents from
|
* @ctxt - structure to load the registers contents from
|
||||||
|
*
|
||||||
|
* The asm code that gets us here will have restored a usable GDT, although
|
||||||
|
* it will be pointing to the wrong alias.
|
||||||
*/
|
*/
|
||||||
static void notrace __restore_processor_state(struct saved_context *ctxt)
|
static void notrace __restore_processor_state(struct saved_context *ctxt)
|
||||||
{
|
{
|
||||||
|
@ -215,57 +213,50 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
||||||
write_cr2(ctxt->cr2);
|
write_cr2(ctxt->cr2);
|
||||||
write_cr0(ctxt->cr0);
|
write_cr0(ctxt->cr0);
|
||||||
|
|
||||||
/*
|
/* Restore the IDT. */
|
||||||
* now restore the descriptor tables to their proper values
|
|
||||||
* ltr is done i fix_processor_context().
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
load_idt(&ctxt->idt);
|
load_idt(&ctxt->idt);
|
||||||
#else
|
|
||||||
/* CONFIG_X86_64 */
|
|
||||||
load_idt((const struct desc_ptr *)&ctxt->idt_limit);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
/*
|
/*
|
||||||
* We need GSBASE restored before percpu access can work.
|
* Just in case the asm code got us here with the SS, DS, or ES
|
||||||
* percpu access can happen in exception handlers or in complicated
|
* out of sync with the GDT, update them.
|
||||||
* helpers like load_gs_index().
|
|
||||||
*/
|
*/
|
||||||
wrmsrl(MSR_GS_BASE, ctxt->gs_base);
|
loadsegment(ss, __KERNEL_DS);
|
||||||
|
loadsegment(ds, __USER_DS);
|
||||||
|
loadsegment(es, __USER_DS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore percpu access. Percpu access can happen in exception
|
||||||
|
* handlers or in complicated helpers like load_gs_index().
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
wrmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
|
||||||
|
#else
|
||||||
|
loadsegment(fs, __KERNEL_PERCPU);
|
||||||
|
loadsegment(gs, __KERNEL_STACK_CANARY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Restore the TSS, RO GDT, LDT, and usermode-relevant MSRs. */
|
||||||
fix_processor_context();
|
fix_processor_context();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore segment registers. This happens after restoring the GDT
|
* Now that we have descriptor tables fully restored and working
|
||||||
* and LDT, which happen in fix_processor_context().
|
* exception handling, restore the usermode segments.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_64
|
||||||
|
loadsegment(ds, ctxt->es);
|
||||||
loadsegment(es, ctxt->es);
|
loadsegment(es, ctxt->es);
|
||||||
loadsegment(fs, ctxt->fs);
|
loadsegment(fs, ctxt->fs);
|
||||||
loadsegment(gs, ctxt->gs);
|
|
||||||
loadsegment(ss, ctxt->ss);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sysenter MSRs
|
|
||||||
*/
|
|
||||||
if (boot_cpu_has(X86_FEATURE_SEP))
|
|
||||||
enable_sep_cpu();
|
|
||||||
#else
|
|
||||||
/* CONFIG_X86_64 */
|
|
||||||
asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
|
|
||||||
asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
|
|
||||||
asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
|
|
||||||
load_gs_index(ctxt->gs);
|
load_gs_index(ctxt->gs);
|
||||||
asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore FSBASE and user GSBASE after reloading the respective
|
* Restore FSBASE and GSBASE after restoring the selectors, since
|
||||||
* segment selectors.
|
* restoring the selectors clobbers the bases. Keep in mind
|
||||||
|
* that MSR_KERNEL_GS_BASE is horribly misnamed.
|
||||||
*/
|
*/
|
||||||
wrmsrl(MSR_FS_BASE, ctxt->fs_base);
|
wrmsrl(MSR_FS_BASE, ctxt->fs_base);
|
||||||
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
|
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base);
|
||||||
|
#elif defined(CONFIG_X86_32_LAZY_GS)
|
||||||
|
loadsegment(gs, ctxt->gs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
do_fpu_end();
|
do_fpu_end();
|
||||||
|
|
|
@ -57,7 +57,7 @@ static u32 xen_apic_read(u32 reg)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (reg == APIC_LVR)
|
if (reg == APIC_LVR)
|
||||||
return 0x10;
|
return 0x14;
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
if (reg == APIC_LDR)
|
if (reg == APIC_LDR)
|
||||||
return SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
|
return SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
|
||||||
|
|
|
@ -672,15 +672,16 @@ void af_alg_free_areq_sgls(struct af_alg_async_req *areq)
|
||||||
}
|
}
|
||||||
|
|
||||||
tsgl = areq->tsgl;
|
tsgl = areq->tsgl;
|
||||||
|
if (tsgl) {
|
||||||
for_each_sg(tsgl, sg, areq->tsgl_entries, i) {
|
for_each_sg(tsgl, sg, areq->tsgl_entries, i) {
|
||||||
if (!sg_page(sg))
|
if (!sg_page(sg))
|
||||||
continue;
|
continue;
|
||||||
put_page(sg_page(sg));
|
put_page(sg_page(sg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (areq->tsgl && areq->tsgl_entries)
|
|
||||||
sock_kfree_s(sk, tsgl, areq->tsgl_entries * sizeof(*tsgl));
|
sock_kfree_s(sk, tsgl, areq->tsgl_entries * sizeof(*tsgl));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(af_alg_free_areq_sgls);
|
EXPORT_SYMBOL_GPL(af_alg_free_areq_sgls);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -503,6 +503,7 @@ static void aead_release(void *private)
|
||||||
struct aead_tfm *tfm = private;
|
struct aead_tfm *tfm = private;
|
||||||
|
|
||||||
crypto_free_aead(tfm->aead);
|
crypto_free_aead(tfm->aead);
|
||||||
|
crypto_put_default_null_skcipher2();
|
||||||
kfree(tfm);
|
kfree(tfm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +536,6 @@ static void aead_sock_destruct(struct sock *sk)
|
||||||
unsigned int ivlen = crypto_aead_ivsize(tfm);
|
unsigned int ivlen = crypto_aead_ivsize(tfm);
|
||||||
|
|
||||||
af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
|
af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
|
||||||
crypto_put_default_null_skcipher2();
|
|
||||||
sock_kzfree_s(sk, ctx->iv, ivlen);
|
sock_kzfree_s(sk, ctx->iv, ivlen);
|
||||||
sock_kfree_s(sk, ctx, ctx->len);
|
sock_kfree_s(sk, ctx, ctx->len);
|
||||||
af_alg_release_parent(sk);
|
af_alg_release_parent(sk);
|
||||||
|
|
|
@ -195,11 +195,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
|
||||||
salg = shash_attr_alg(tb[1], 0, 0);
|
salg = shash_attr_alg(tb[1], 0, 0);
|
||||||
if (IS_ERR(salg))
|
if (IS_ERR(salg))
|
||||||
return PTR_ERR(salg);
|
return PTR_ERR(salg);
|
||||||
|
alg = &salg->base;
|
||||||
|
|
||||||
|
/* The underlying hash algorithm must be unkeyed */
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
if (crypto_shash_alg_has_setkey(salg))
|
||||||
|
goto out_put_alg;
|
||||||
|
|
||||||
ds = salg->digestsize;
|
ds = salg->digestsize;
|
||||||
ss = salg->statesize;
|
ss = salg->statesize;
|
||||||
alg = &salg->base;
|
|
||||||
if (ds > alg->cra_blocksize ||
|
if (ds > alg->cra_blocksize ||
|
||||||
ss < alg->cra_blocksize)
|
ss < alg->cra_blocksize)
|
||||||
goto out_put_alg;
|
goto out_put_alg;
|
||||||
|
|
|
@ -30,7 +30,7 @@ int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (fips_enabled) {
|
if (fips_enabled) {
|
||||||
while (!*ptr && n_sz) {
|
while (n_sz && !*ptr) {
|
||||||
ptr++;
|
ptr++;
|
||||||
n_sz--;
|
n_sz--;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,13 +188,6 @@ static int encrypt(struct blkcipher_desc *desc,
|
||||||
|
|
||||||
salsa20_ivsetup(ctx, walk.iv);
|
salsa20_ivsetup(ctx, walk.iv);
|
||||||
|
|
||||||
if (likely(walk.nbytes == nbytes))
|
|
||||||
{
|
|
||||||
salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
|
|
||||||
walk.src.virt.addr, nbytes);
|
|
||||||
return blkcipher_walk_done(desc, &walk, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (walk.nbytes >= 64) {
|
while (walk.nbytes >= 64) {
|
||||||
salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
|
salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
|
||||||
walk.src.virt.addr,
|
walk.src.virt.addr,
|
||||||
|
|
|
@ -25,11 +25,12 @@
|
||||||
|
|
||||||
static const struct crypto_type crypto_shash_type;
|
static const struct crypto_type crypto_shash_type;
|
||||||
|
|
||||||
static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
|
int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
|
||||||
unsigned int keylen)
|
unsigned int keylen)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(shash_no_setkey);
|
||||||
|
|
||||||
static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
|
static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
|
||||||
unsigned int keylen)
|
unsigned int keylen)
|
||||||
|
|
|
@ -1138,7 +1138,7 @@ int acpi_subsys_thaw_noirq(struct device *dev)
|
||||||
* skip all of the subsequent "thaw" callbacks for the device.
|
* skip all of the subsequent "thaw" callbacks for the device.
|
||||||
*/
|
*/
|
||||||
if (dev_pm_smart_suspend_and_suspended(dev)) {
|
if (dev_pm_smart_suspend_and_suspended(dev)) {
|
||||||
dev->power.direct_complete = true;
|
dev_pm_skip_next_resume_phases(dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* MeidaTek AHCI SATA driver
|
* MediaTek AHCI SATA driver
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017 MediaTek Inc.
|
* Copyright (c) 2017 MediaTek Inc.
|
||||||
* Author: Ryder Lee <ryder.lee@mediatek.com>
|
* Author: Ryder Lee <ryder.lee@mediatek.com>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
#define DRV_NAME "ahci"
|
#define DRV_NAME "ahci-mtk"
|
||||||
|
|
||||||
#define SYS_CFG 0x14
|
#define SYS_CFG 0x14
|
||||||
#define SYS_CFG_SATA_MSK GENMASK(31, 30)
|
#define SYS_CFG_SATA_MSK GENMASK(31, 30)
|
||||||
|
@ -192,5 +192,5 @@ static struct platform_driver mtk_ahci_driver = {
|
||||||
};
|
};
|
||||||
module_platform_driver(mtk_ahci_driver);
|
module_platform_driver(mtk_ahci_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("MeidaTek SATA AHCI Driver");
|
MODULE_DESCRIPTION("MediaTek SATA AHCI Driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
|
|
||||||
/* port register default value */
|
/* port register default value */
|
||||||
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
|
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
|
||||||
|
#define AHCI_PORT_PHY2_CFG 0x28184d1f
|
||||||
|
#define AHCI_PORT_PHY3_CFG 0x0e081509
|
||||||
#define AHCI_PORT_TRANS_CFG 0x08000029
|
#define AHCI_PORT_TRANS_CFG 0x08000029
|
||||||
#define AHCI_PORT_AXICC_CFG 0x3fffffff
|
#define AHCI_PORT_AXICC_CFG 0x3fffffff
|
||||||
|
|
||||||
|
@ -183,6 +185,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
|
||||||
writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
|
writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
|
||||||
qpriv->ecc_addr);
|
qpriv->ecc_addr);
|
||||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||||
|
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
|
||||||
|
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
|
||||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||||
if (qpriv->is_dmacoherent)
|
if (qpriv->is_dmacoherent)
|
||||||
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
||||||
|
@ -190,6 +194,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
|
||||||
|
|
||||||
case AHCI_LS2080A:
|
case AHCI_LS2080A:
|
||||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||||
|
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
|
||||||
|
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
|
||||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||||
if (qpriv->is_dmacoherent)
|
if (qpriv->is_dmacoherent)
|
||||||
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
||||||
|
@ -201,6 +207,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
|
||||||
writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
|
writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
|
||||||
qpriv->ecc_addr);
|
qpriv->ecc_addr);
|
||||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||||
|
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
|
||||||
|
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
|
||||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||||
if (qpriv->is_dmacoherent)
|
if (qpriv->is_dmacoherent)
|
||||||
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
||||||
|
@ -212,6 +220,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
|
||||||
writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A,
|
writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A,
|
||||||
qpriv->ecc_addr);
|
qpriv->ecc_addr);
|
||||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||||
|
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
|
||||||
|
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
|
||||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||||
if (qpriv->is_dmacoherent)
|
if (qpriv->is_dmacoherent)
|
||||||
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
||||||
|
@ -219,6 +229,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
|
||||||
|
|
||||||
case AHCI_LS2088A:
|
case AHCI_LS2088A:
|
||||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||||
|
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
|
||||||
|
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
|
||||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||||
if (qpriv->is_dmacoherent)
|
if (qpriv->is_dmacoherent)
|
||||||
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
|
||||||
|
|
|
@ -3082,13 +3082,19 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
|
||||||
bit = fls(mask) - 1;
|
bit = fls(mask) - 1;
|
||||||
mask &= ~(1 << bit);
|
mask &= ~(1 << bit);
|
||||||
|
|
||||||
/* Mask off all speeds higher than or equal to the current
|
/*
|
||||||
* one. Force 1.5Gbps if current SPD is not available.
|
* Mask off all speeds higher than or equal to the current one. At
|
||||||
|
* this point, if current SPD is not available and we previously
|
||||||
|
* recorded the link speed from SStatus, the driver has already
|
||||||
|
* masked off the highest bit so mask should already be 1 or 0.
|
||||||
|
* Otherwise, we should not force 1.5Gbps on a link where we have
|
||||||
|
* not previously recorded speed from SStatus. Just return in this
|
||||||
|
* case.
|
||||||
*/
|
*/
|
||||||
if (spd > 1)
|
if (spd > 1)
|
||||||
mask &= (1 << (spd - 1)) - 1;
|
mask &= (1 << (spd - 1)) - 1;
|
||||||
else
|
else
|
||||||
mask &= 1;
|
return -EINVAL;
|
||||||
|
|
||||||
/* were we already at the bottom? */
|
/* were we already at the bottom? */
|
||||||
if (!mask)
|
if (!mask)
|
||||||
|
|
|
@ -82,7 +82,7 @@ static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed
|
||||||
* is issued to the device. However, if the controller clock is 133MHz,
|
* is issued to the device. However, if the controller clock is 133MHz,
|
||||||
* the following tables must be used.
|
* the following tables must be used.
|
||||||
*/
|
*/
|
||||||
static struct pdc2027x_pio_timing {
|
static const struct pdc2027x_pio_timing {
|
||||||
u8 value0, value1, value2;
|
u8 value0, value1, value2;
|
||||||
} pdc2027x_pio_timing_tbl[] = {
|
} pdc2027x_pio_timing_tbl[] = {
|
||||||
{ 0xfb, 0x2b, 0xac }, /* PIO mode 0 */
|
{ 0xfb, 0x2b, 0xac }, /* PIO mode 0 */
|
||||||
|
@ -92,7 +92,7 @@ static struct pdc2027x_pio_timing {
|
||||||
{ 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
|
{ 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pdc2027x_mdma_timing {
|
static const struct pdc2027x_mdma_timing {
|
||||||
u8 value0, value1;
|
u8 value0, value1;
|
||||||
} pdc2027x_mdma_timing_tbl[] = {
|
} pdc2027x_mdma_timing_tbl[] = {
|
||||||
{ 0xdf, 0x5f }, /* MDMA mode 0 */
|
{ 0xdf, 0x5f }, /* MDMA mode 0 */
|
||||||
|
@ -100,7 +100,7 @@ static struct pdc2027x_mdma_timing {
|
||||||
{ 0x69, 0x25 }, /* MDMA mode 2 */
|
{ 0x69, 0x25 }, /* MDMA mode 2 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pdc2027x_udma_timing {
|
static const struct pdc2027x_udma_timing {
|
||||||
u8 value0, value1, value2;
|
u8 value0, value1, value2;
|
||||||
} pdc2027x_udma_timing_tbl[] = {
|
} pdc2027x_udma_timing_tbl[] = {
|
||||||
{ 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
|
{ 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
|
||||||
|
@ -649,7 +649,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
|
||||||
* @host: target ATA host
|
* @host: target ATA host
|
||||||
* @board_idx: board identifier
|
* @board_idx: board identifier
|
||||||
*/
|
*/
|
||||||
static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
|
static void pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
|
||||||
{
|
{
|
||||||
long pll_clock;
|
long pll_clock;
|
||||||
|
|
||||||
|
@ -665,8 +665,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
|
||||||
|
|
||||||
/* Adjust PLL control register */
|
/* Adjust PLL control register */
|
||||||
pdc_adjust_pll(host, pll_clock, board_idx);
|
pdc_adjust_pll(host, pll_clock, board_idx);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -753,8 +751,7 @@ static int pdc2027x_init_one(struct pci_dev *pdev,
|
||||||
//pci_enable_intx(pdev);
|
//pci_enable_intx(pdev);
|
||||||
|
|
||||||
/* initialize adapter */
|
/* initialize adapter */
|
||||||
if (pdc_hardware_init(host, board_idx) != 0)
|
pdc_hardware_init(host, board_idx);
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
pci_set_master(pdev);
|
pci_set_master(pdev);
|
||||||
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
|
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
|
||||||
|
@ -778,8 +775,7 @@ static int pdc2027x_reinit_one(struct pci_dev *pdev)
|
||||||
else
|
else
|
||||||
board_idx = PDC_UDMA_133;
|
board_idx = PDC_UDMA_133;
|
||||||
|
|
||||||
if (pdc_hardware_init(host, board_idx))
|
pdc_hardware_init(host, board_idx);
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
ata_host_resume(host);
|
ata_host_resume(host);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -525,6 +525,21 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
|
||||||
|
|
||||||
/*------------------------- Resume routines -------------------------*/
|
/*------------------------- Resume routines -------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_pm_skip_next_resume_phases - Skip next system resume phases for device.
|
||||||
|
* @dev: Target device.
|
||||||
|
*
|
||||||
|
* Make the core skip the "early resume" and "resume" phases for @dev.
|
||||||
|
*
|
||||||
|
* This function can be called by middle-layer code during the "noirq" phase of
|
||||||
|
* system resume if necessary, but not by device drivers.
|
||||||
|
*/
|
||||||
|
void dev_pm_skip_next_resume_phases(struct device *dev)
|
||||||
|
{
|
||||||
|
dev->power.is_late_suspended = false;
|
||||||
|
dev->power.is_suspended = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_resume_noirq - Execute a "noirq resume" callback for given device.
|
* device_resume_noirq - Execute a "noirq resume" callback for given device.
|
||||||
* @dev: Device to handle.
|
* @dev: Device to handle.
|
||||||
|
|
|
@ -199,6 +199,9 @@ struct smi_info {
|
||||||
/* The timer for this si. */
|
/* The timer for this si. */
|
||||||
struct timer_list si_timer;
|
struct timer_list si_timer;
|
||||||
|
|
||||||
|
/* This flag is set, if the timer can be set */
|
||||||
|
bool timer_can_start;
|
||||||
|
|
||||||
/* This flag is set, if the timer is running (timer_pending() isn't enough) */
|
/* This flag is set, if the timer is running (timer_pending() isn't enough) */
|
||||||
bool timer_running;
|
bool timer_running;
|
||||||
|
|
||||||
|
@ -355,6 +358,8 @@ out:
|
||||||
|
|
||||||
static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
|
static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
|
||||||
{
|
{
|
||||||
|
if (!smi_info->timer_can_start)
|
||||||
|
return;
|
||||||
smi_info->last_timeout_jiffies = jiffies;
|
smi_info->last_timeout_jiffies = jiffies;
|
||||||
mod_timer(&smi_info->si_timer, new_val);
|
mod_timer(&smi_info->si_timer, new_val);
|
||||||
smi_info->timer_running = true;
|
smi_info->timer_running = true;
|
||||||
|
@ -374,21 +379,18 @@ static void start_new_msg(struct smi_info *smi_info, unsigned char *msg,
|
||||||
smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
|
smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_check_enables(struct smi_info *smi_info, bool start_timer)
|
static void start_check_enables(struct smi_info *smi_info)
|
||||||
{
|
{
|
||||||
unsigned char msg[2];
|
unsigned char msg[2];
|
||||||
|
|
||||||
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
|
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
|
||||||
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
|
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
|
||||||
|
|
||||||
if (start_timer)
|
|
||||||
start_new_msg(smi_info, msg, 2);
|
start_new_msg(smi_info, msg, 2);
|
||||||
else
|
|
||||||
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
|
|
||||||
smi_info->si_state = SI_CHECKING_ENABLES;
|
smi_info->si_state = SI_CHECKING_ENABLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
|
static void start_clear_flags(struct smi_info *smi_info)
|
||||||
{
|
{
|
||||||
unsigned char msg[3];
|
unsigned char msg[3];
|
||||||
|
|
||||||
|
@ -397,10 +399,7 @@ static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
|
||||||
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
|
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
|
||||||
msg[2] = WDT_PRE_TIMEOUT_INT;
|
msg[2] = WDT_PRE_TIMEOUT_INT;
|
||||||
|
|
||||||
if (start_timer)
|
|
||||||
start_new_msg(smi_info, msg, 3);
|
start_new_msg(smi_info, msg, 3);
|
||||||
else
|
|
||||||
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
|
|
||||||
smi_info->si_state = SI_CLEARING_FLAGS;
|
smi_info->si_state = SI_CLEARING_FLAGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,11 +434,11 @@ static void start_getting_events(struct smi_info *smi_info)
|
||||||
* Note that we cannot just use disable_irq(), since the interrupt may
|
* Note that we cannot just use disable_irq(), since the interrupt may
|
||||||
* be shared.
|
* be shared.
|
||||||
*/
|
*/
|
||||||
static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer)
|
static inline bool disable_si_irq(struct smi_info *smi_info)
|
||||||
{
|
{
|
||||||
if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
|
if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
|
||||||
smi_info->interrupt_disabled = true;
|
smi_info->interrupt_disabled = true;
|
||||||
start_check_enables(smi_info, start_timer);
|
start_check_enables(smi_info);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -449,7 +448,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info)
|
||||||
{
|
{
|
||||||
if ((smi_info->io.irq) && (smi_info->interrupt_disabled)) {
|
if ((smi_info->io.irq) && (smi_info->interrupt_disabled)) {
|
||||||
smi_info->interrupt_disabled = false;
|
smi_info->interrupt_disabled = false;
|
||||||
start_check_enables(smi_info, true);
|
start_check_enables(smi_info);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -467,7 +466,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
|
||||||
|
|
||||||
msg = ipmi_alloc_smi_msg();
|
msg = ipmi_alloc_smi_msg();
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
if (!disable_si_irq(smi_info, true))
|
if (!disable_si_irq(smi_info))
|
||||||
smi_info->si_state = SI_NORMAL;
|
smi_info->si_state = SI_NORMAL;
|
||||||
} else if (enable_si_irq(smi_info)) {
|
} else if (enable_si_irq(smi_info)) {
|
||||||
ipmi_free_smi_msg(msg);
|
ipmi_free_smi_msg(msg);
|
||||||
|
@ -483,7 +482,7 @@ retry:
|
||||||
/* Watchdog pre-timeout */
|
/* Watchdog pre-timeout */
|
||||||
smi_inc_stat(smi_info, watchdog_pretimeouts);
|
smi_inc_stat(smi_info, watchdog_pretimeouts);
|
||||||
|
|
||||||
start_clear_flags(smi_info, true);
|
start_clear_flags(smi_info);
|
||||||
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
|
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
|
||||||
if (smi_info->intf)
|
if (smi_info->intf)
|
||||||
ipmi_smi_watchdog_pretimeout(smi_info->intf);
|
ipmi_smi_watchdog_pretimeout(smi_info->intf);
|
||||||
|
@ -866,7 +865,7 @@ restart:
|
||||||
* disable and messages disabled.
|
* disable and messages disabled.
|
||||||
*/
|
*/
|
||||||
if (smi_info->supports_event_msg_buff || smi_info->io.irq) {
|
if (smi_info->supports_event_msg_buff || smi_info->io.irq) {
|
||||||
start_check_enables(smi_info, true);
|
start_check_enables(smi_info);
|
||||||
} else {
|
} else {
|
||||||
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
|
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
|
||||||
if (!smi_info->curr_msg)
|
if (!smi_info->curr_msg)
|
||||||
|
@ -1167,6 +1166,7 @@ static int smi_start_processing(void *send_info,
|
||||||
|
|
||||||
/* Set up the timer that drives the interface. */
|
/* Set up the timer that drives the interface. */
|
||||||
timer_setup(&new_smi->si_timer, smi_timeout, 0);
|
timer_setup(&new_smi->si_timer, smi_timeout, 0);
|
||||||
|
new_smi->timer_can_start = true;
|
||||||
smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
|
smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
|
||||||
|
|
||||||
/* Try to claim any interrupts. */
|
/* Try to claim any interrupts. */
|
||||||
|
@ -1936,10 +1936,12 @@ static void check_for_broken_irqs(struct smi_info *smi_info)
|
||||||
check_set_rcv_irq(smi_info);
|
check_set_rcv_irq(smi_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
|
static inline void stop_timer_and_thread(struct smi_info *smi_info)
|
||||||
{
|
{
|
||||||
if (smi_info->thread != NULL)
|
if (smi_info->thread != NULL)
|
||||||
kthread_stop(smi_info->thread);
|
kthread_stop(smi_info->thread);
|
||||||
|
|
||||||
|
smi_info->timer_can_start = false;
|
||||||
if (smi_info->timer_running)
|
if (smi_info->timer_running)
|
||||||
del_timer_sync(&smi_info->si_timer);
|
del_timer_sync(&smi_info->si_timer);
|
||||||
}
|
}
|
||||||
|
@ -2152,7 +2154,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||||
* Start clearing the flags before we enable interrupts or the
|
* Start clearing the flags before we enable interrupts or the
|
||||||
* timer to avoid racing with the timer.
|
* timer to avoid racing with the timer.
|
||||||
*/
|
*/
|
||||||
start_clear_flags(new_smi, false);
|
start_clear_flags(new_smi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IRQ is defined to be set when non-zero. req_events will
|
* IRQ is defined to be set when non-zero. req_events will
|
||||||
|
@ -2238,7 +2240,7 @@ out_err_remove_attrs:
|
||||||
dev_set_drvdata(new_smi->io.dev, NULL);
|
dev_set_drvdata(new_smi->io.dev, NULL);
|
||||||
|
|
||||||
out_err_stop_timer:
|
out_err_stop_timer:
|
||||||
wait_for_timer_and_thread(new_smi);
|
stop_timer_and_thread(new_smi);
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
new_smi->interrupt_disabled = true;
|
new_smi->interrupt_disabled = true;
|
||||||
|
@ -2388,7 +2390,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
|
||||||
*/
|
*/
|
||||||
if (to_clean->io.irq_cleanup)
|
if (to_clean->io.irq_cleanup)
|
||||||
to_clean->io.irq_cleanup(&to_clean->io);
|
to_clean->io.irq_cleanup(&to_clean->io);
|
||||||
wait_for_timer_and_thread(to_clean);
|
stop_timer_and_thread(to_clean);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timeouts are stopped, now make sure the interrupts are off
|
* Timeouts are stopped, now make sure the interrupts are off
|
||||||
|
@ -2400,7 +2402,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
|
||||||
schedule_timeout_uninterruptible(1);
|
schedule_timeout_uninterruptible(1);
|
||||||
}
|
}
|
||||||
if (to_clean->handlers)
|
if (to_clean->handlers)
|
||||||
disable_si_irq(to_clean, false);
|
disable_si_irq(to_clean);
|
||||||
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
|
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
|
||||||
poll(to_clean);
|
poll(to_clean);
|
||||||
schedule_timeout_uninterruptible(1);
|
schedule_timeout_uninterruptible(1);
|
||||||
|
|
|
@ -10,6 +10,8 @@ static int __init ipmi_parisc_probe(struct parisc_device *dev)
|
||||||
{
|
{
|
||||||
struct si_sm_io io;
|
struct si_sm_io io;
|
||||||
|
|
||||||
|
memset(&io, 0, sizeof(io));
|
||||||
|
|
||||||
io.si_type = SI_KCS;
|
io.si_type = SI_KCS;
|
||||||
io.addr_source = SI_DEVICETREE;
|
io.addr_source = SI_DEVICETREE;
|
||||||
io.addr_type = IPMI_MEM_ADDR_SPACE;
|
io.addr_type = IPMI_MEM_ADDR_SPACE;
|
||||||
|
|
|
@ -103,10 +103,13 @@ static int ipmi_pci_probe(struct pci_dev *pdev,
|
||||||
io.addr_source_cleanup = ipmi_pci_cleanup;
|
io.addr_source_cleanup = ipmi_pci_cleanup;
|
||||||
io.addr_source_data = pdev;
|
io.addr_source_data = pdev;
|
||||||
|
|
||||||
if (pci_resource_flags(pdev, 0) & IORESOURCE_IO)
|
if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
|
||||||
io.addr_type = IPMI_IO_ADDR_SPACE;
|
io.addr_type = IPMI_IO_ADDR_SPACE;
|
||||||
else
|
io.io_setup = ipmi_si_port_setup;
|
||||||
|
} else {
|
||||||
io.addr_type = IPMI_MEM_ADDR_SPACE;
|
io.addr_type = IPMI_MEM_ADDR_SPACE;
|
||||||
|
io.io_setup = ipmi_si_mem_setup;
|
||||||
|
}
|
||||||
io.addr_data = pci_resource_start(pdev, 0);
|
io.addr_data = pci_resource_start(pdev, 0);
|
||||||
|
|
||||||
io.regspacing = ipmi_pci_probe_regspacing(&io);
|
io.regspacing = ipmi_pci_probe_regspacing(&io);
|
||||||
|
|
|
@ -708,7 +708,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
|
||||||
unsigned long flags)
|
unsigned long flags)
|
||||||
{
|
{
|
||||||
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
struct at_dma_chan *atchan = to_at_dma_chan(chan);
|
||||||
struct data_chunk *first = xt->sgl;
|
struct data_chunk *first;
|
||||||
struct at_desc *desc = NULL;
|
struct at_desc *desc = NULL;
|
||||||
size_t xfer_count;
|
size_t xfer_count;
|
||||||
unsigned int dwidth;
|
unsigned int dwidth;
|
||||||
|
@ -720,6 +720,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
|
||||||
if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
|
if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
first = xt->sgl;
|
||||||
|
|
||||||
dev_info(chan2dev(chan),
|
dev_info(chan2dev(chan),
|
||||||
"%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
|
"%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
|
||||||
__func__, &xt->src_start, &xt->dst_start, xt->numf,
|
__func__, &xt->src_start, &xt->dst_start, xt->numf,
|
||||||
|
|
|
@ -555,7 +555,7 @@ static int jz4740_dma_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = dma_async_device_register(dd);
|
ret = dma_async_device_register(dd);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_clk;
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
|
ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
|
||||||
|
@ -568,6 +568,8 @@ static int jz4740_dma_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
err_unregister:
|
err_unregister:
|
||||||
dma_async_device_unregister(dd);
|
dma_async_device_unregister(dd);
|
||||||
|
err_clk:
|
||||||
|
clk_disable_unprepare(dmadev->clk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,12 @@ MODULE_PARM_DESC(run, "Run the test (default: false)");
|
||||||
#define PATTERN_COUNT_MASK 0x1f
|
#define PATTERN_COUNT_MASK 0x1f
|
||||||
#define PATTERN_MEMSET_IDX 0x01
|
#define PATTERN_MEMSET_IDX 0x01
|
||||||
|
|
||||||
|
/* poor man's completion - we want to use wait_event_freezable() on it */
|
||||||
|
struct dmatest_done {
|
||||||
|
bool done;
|
||||||
|
wait_queue_head_t *wait;
|
||||||
|
};
|
||||||
|
|
||||||
struct dmatest_thread {
|
struct dmatest_thread {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct dmatest_info *info;
|
struct dmatest_info *info;
|
||||||
|
@ -165,6 +171,8 @@ struct dmatest_thread {
|
||||||
u8 **dsts;
|
u8 **dsts;
|
||||||
u8 **udsts;
|
u8 **udsts;
|
||||||
enum dma_transaction_type type;
|
enum dma_transaction_type type;
|
||||||
|
wait_queue_head_t done_wait;
|
||||||
|
struct dmatest_done test_done;
|
||||||
bool done;
|
bool done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -342,18 +350,25 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
|
||||||
return error_count;
|
return error_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* poor man's completion - we want to use wait_event_freezable() on it */
|
|
||||||
struct dmatest_done {
|
|
||||||
bool done;
|
|
||||||
wait_queue_head_t *wait;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void dmatest_callback(void *arg)
|
static void dmatest_callback(void *arg)
|
||||||
{
|
{
|
||||||
struct dmatest_done *done = arg;
|
struct dmatest_done *done = arg;
|
||||||
|
struct dmatest_thread *thread =
|
||||||
|
container_of(arg, struct dmatest_thread, done_wait);
|
||||||
|
if (!thread->done) {
|
||||||
done->done = true;
|
done->done = true;
|
||||||
wake_up_all(done->wait);
|
wake_up_all(done->wait);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If thread->done, it means that this callback occurred
|
||||||
|
* after the parent thread has cleaned up. This can
|
||||||
|
* happen in the case that driver doesn't implement
|
||||||
|
* the terminate_all() functionality and a dma operation
|
||||||
|
* did not occur within the timeout period
|
||||||
|
*/
|
||||||
|
WARN(1, "dmatest: Kernel memory may be corrupted!!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int min_odd(unsigned int x, unsigned int y)
|
static unsigned int min_odd(unsigned int x, unsigned int y)
|
||||||
|
@ -424,9 +439,8 @@ static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len)
|
||||||
*/
|
*/
|
||||||
static int dmatest_func(void *data)
|
static int dmatest_func(void *data)
|
||||||
{
|
{
|
||||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);
|
|
||||||
struct dmatest_thread *thread = data;
|
struct dmatest_thread *thread = data;
|
||||||
struct dmatest_done done = { .wait = &done_wait };
|
struct dmatest_done *done = &thread->test_done;
|
||||||
struct dmatest_info *info;
|
struct dmatest_info *info;
|
||||||
struct dmatest_params *params;
|
struct dmatest_params *params;
|
||||||
struct dma_chan *chan;
|
struct dma_chan *chan;
|
||||||
|
@ -673,9 +687,9 @@ static int dmatest_func(void *data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
done.done = false;
|
done->done = false;
|
||||||
tx->callback = dmatest_callback;
|
tx->callback = dmatest_callback;
|
||||||
tx->callback_param = &done;
|
tx->callback_param = done;
|
||||||
cookie = tx->tx_submit(tx);
|
cookie = tx->tx_submit(tx);
|
||||||
|
|
||||||
if (dma_submit_error(cookie)) {
|
if (dma_submit_error(cookie)) {
|
||||||
|
@ -688,21 +702,12 @@ static int dmatest_func(void *data)
|
||||||
}
|
}
|
||||||
dma_async_issue_pending(chan);
|
dma_async_issue_pending(chan);
|
||||||
|
|
||||||
wait_event_freezable_timeout(done_wait, done.done,
|
wait_event_freezable_timeout(thread->done_wait, done->done,
|
||||||
msecs_to_jiffies(params->timeout));
|
msecs_to_jiffies(params->timeout));
|
||||||
|
|
||||||
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
|
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
|
||||||
|
|
||||||
if (!done.done) {
|
if (!done->done) {
|
||||||
/*
|
|
||||||
* We're leaving the timed out dma operation with
|
|
||||||
* dangling pointer to done_wait. To make this
|
|
||||||
* correct, we'll need to allocate wait_done for
|
|
||||||
* each test iteration and perform "who's gonna
|
|
||||||
* free it this time?" dancing. For now, just
|
|
||||||
* leave it dangling.
|
|
||||||
*/
|
|
||||||
WARN(1, "dmatest: Kernel stack may be corrupted!!\n");
|
|
||||||
dmaengine_unmap_put(um);
|
dmaengine_unmap_put(um);
|
||||||
result("test timed out", total_tests, src_off, dst_off,
|
result("test timed out", total_tests, src_off, dst_off,
|
||||||
len, 0);
|
len, 0);
|
||||||
|
@ -789,7 +794,7 @@ err_thread_type:
|
||||||
dmatest_KBs(runtime, total_len), ret);
|
dmatest_KBs(runtime, total_len), ret);
|
||||||
|
|
||||||
/* terminate all transfers on specified channels */
|
/* terminate all transfers on specified channels */
|
||||||
if (ret)
|
if (ret || failed_tests)
|
||||||
dmaengine_terminate_all(chan);
|
dmaengine_terminate_all(chan);
|
||||||
|
|
||||||
thread->done = true;
|
thread->done = true;
|
||||||
|
@ -849,6 +854,8 @@ static int dmatest_add_threads(struct dmatest_info *info,
|
||||||
thread->info = info;
|
thread->info = info;
|
||||||
thread->chan = dtc->chan;
|
thread->chan = dtc->chan;
|
||||||
thread->type = type;
|
thread->type = type;
|
||||||
|
thread->test_done.wait = &thread->done_wait;
|
||||||
|
init_waitqueue_head(&thread->done_wait);
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
|
thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
|
||||||
dma_chan_name(chan), op, i);
|
dma_chan_name(chan), op, i);
|
||||||
|
|
|
@ -863,11 +863,11 @@ static void fsl_edma_irq_exit(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma)
|
static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < DMAMUX_NR; i++)
|
for (i = 0; i < nr_clocks; i++)
|
||||||
clk_disable_unprepare(fsl_edma->muxclk[i]);
|
clk_disable_unprepare(fsl_edma->muxclk[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
|
||||||
fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
|
fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(fsl_edma->muxbase[i]))
|
if (IS_ERR(fsl_edma->muxbase[i])) {
|
||||||
|
/* on error: disable all previously enabled clks */
|
||||||
|
fsl_disable_clocks(fsl_edma, i);
|
||||||
return PTR_ERR(fsl_edma->muxbase[i]);
|
return PTR_ERR(fsl_edma->muxbase[i]);
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(clkname, "dmamux%d", i);
|
sprintf(clkname, "dmamux%d", i);
|
||||||
fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
|
fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
|
||||||
if (IS_ERR(fsl_edma->muxclk[i])) {
|
if (IS_ERR(fsl_edma->muxclk[i])) {
|
||||||
dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
|
dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
|
||||||
|
/* on error: disable all previously enabled clks */
|
||||||
|
fsl_disable_clocks(fsl_edma, i);
|
||||||
return PTR_ERR(fsl_edma->muxclk[i]);
|
return PTR_ERR(fsl_edma->muxclk[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(fsl_edma->muxclk[i]);
|
ret = clk_prepare_enable(fsl_edma->muxclk[i]);
|
||||||
if (ret) {
|
if (ret)
|
||||||
/* disable only clks which were enabled on error */
|
/* on error: disable all previously enabled clks */
|
||||||
for (; i >= 0; i--)
|
fsl_disable_clocks(fsl_edma, i);
|
||||||
clk_disable_unprepare(fsl_edma->muxclk[i]);
|
|
||||||
|
|
||||||
dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Can't register Freescale eDMA engine. (%d)\n", ret);
|
"Can't register Freescale eDMA engine. (%d)\n", ret);
|
||||||
fsl_disable_clocks(fsl_edma);
|
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Can't register Freescale eDMA of_dma. (%d)\n", ret);
|
"Can't register Freescale eDMA of_dma. (%d)\n", ret);
|
||||||
dma_async_device_unregister(&fsl_edma->dma_dev);
|
dma_async_device_unregister(&fsl_edma->dma_dev);
|
||||||
fsl_disable_clocks(fsl_edma);
|
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev)
|
||||||
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
|
fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
|
||||||
of_dma_controller_free(np);
|
of_dma_controller_free(np);
|
||||||
dma_async_device_unregister(&fsl_edma->dma_dev);
|
dma_async_device_unregister(&fsl_edma->dma_dev);
|
||||||
fsl_disable_clocks(fsl_edma);
|
fsl_disable_clocks(fsl_edma, DMAMUX_NR);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,7 +390,7 @@ static int ioat_dma_self_test(struct ioatdma_device *ioat_dma)
|
||||||
if (memcmp(src, dest, IOAT_TEST_SIZE)) {
|
if (memcmp(src, dest, IOAT_TEST_SIZE)) {
|
||||||
dev_err(dev, "Self-test copy failed compare, disabling\n");
|
dev_err(dev, "Self-test copy failed compare, disabling\n");
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto free_resources;
|
goto unmap_dma;
|
||||||
}
|
}
|
||||||
|
|
||||||
unmap_dma:
|
unmap_dma:
|
||||||
|
|
|
@ -152,15 +152,24 @@ static void drm_connector_free(struct kref *kref)
|
||||||
connector->funcs->destroy(connector);
|
connector->funcs->destroy(connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_free_work_fn(struct work_struct *work)
|
void drm_connector_free_work_fn(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct drm_connector *connector =
|
struct drm_connector *connector, *n;
|
||||||
container_of(work, struct drm_connector, free_work);
|
struct drm_device *dev =
|
||||||
struct drm_device *dev = connector->dev;
|
container_of(work, struct drm_device, mode_config.connector_free_work);
|
||||||
|
struct drm_mode_config *config = &dev->mode_config;
|
||||||
|
unsigned long flags;
|
||||||
|
struct llist_node *freed;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&config->connector_list_lock, flags);
|
||||||
|
freed = llist_del_all(&config->connector_free_list);
|
||||||
|
spin_unlock_irqrestore(&config->connector_list_lock, flags);
|
||||||
|
|
||||||
|
llist_for_each_entry_safe(connector, n, freed, free_node) {
|
||||||
drm_mode_object_unregister(dev, &connector->base);
|
drm_mode_object_unregister(dev, &connector->base);
|
||||||
connector->funcs->destroy(connector);
|
connector->funcs->destroy(connector);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_connector_init - Init a preallocated connector
|
* drm_connector_init - Init a preallocated connector
|
||||||
|
@ -191,8 +200,6 @@ int drm_connector_init(struct drm_device *dev,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
INIT_WORK(&connector->free_work, drm_connector_free_work_fn);
|
|
||||||
|
|
||||||
connector->base.properties = &connector->properties;
|
connector->base.properties = &connector->properties;
|
||||||
connector->dev = dev;
|
connector->dev = dev;
|
||||||
connector->funcs = funcs;
|
connector->funcs = funcs;
|
||||||
|
@ -547,10 +554,17 @@ EXPORT_SYMBOL(drm_connector_list_iter_begin);
|
||||||
* actually release the connector when dropping our final reference.
|
* actually release the connector when dropping our final reference.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
drm_connector_put_safe(struct drm_connector *conn)
|
__drm_connector_put_safe(struct drm_connector *conn)
|
||||||
{
|
{
|
||||||
if (refcount_dec_and_test(&conn->base.refcount.refcount))
|
struct drm_mode_config *config = &conn->dev->mode_config;
|
||||||
schedule_work(&conn->free_work);
|
|
||||||
|
lockdep_assert_held(&config->connector_list_lock);
|
||||||
|
|
||||||
|
if (!refcount_dec_and_test(&conn->base.refcount.refcount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
llist_add(&conn->free_node, &config->connector_free_list);
|
||||||
|
schedule_work(&config->connector_free_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -582,10 +596,10 @@ drm_connector_list_iter_next(struct drm_connector_list_iter *iter)
|
||||||
|
|
||||||
/* loop until it's not a zombie connector */
|
/* loop until it's not a zombie connector */
|
||||||
} while (!kref_get_unless_zero(&iter->conn->base.refcount));
|
} while (!kref_get_unless_zero(&iter->conn->base.refcount));
|
||||||
spin_unlock_irqrestore(&config->connector_list_lock, flags);
|
|
||||||
|
|
||||||
if (old_conn)
|
if (old_conn)
|
||||||
drm_connector_put_safe(old_conn);
|
__drm_connector_put_safe(old_conn);
|
||||||
|
spin_unlock_irqrestore(&config->connector_list_lock, flags);
|
||||||
|
|
||||||
return iter->conn;
|
return iter->conn;
|
||||||
}
|
}
|
||||||
|
@ -602,9 +616,15 @@ EXPORT_SYMBOL(drm_connector_list_iter_next);
|
||||||
*/
|
*/
|
||||||
void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
|
void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
|
||||||
{
|
{
|
||||||
|
struct drm_mode_config *config = &iter->dev->mode_config;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
iter->dev = NULL;
|
iter->dev = NULL;
|
||||||
if (iter->conn)
|
if (iter->conn) {
|
||||||
drm_connector_put_safe(iter->conn);
|
spin_lock_irqsave(&config->connector_list_lock, flags);
|
||||||
|
__drm_connector_put_safe(iter->conn);
|
||||||
|
spin_unlock_irqrestore(&config->connector_list_lock, flags);
|
||||||
|
}
|
||||||
lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);
|
lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_connector_list_iter_end);
|
EXPORT_SYMBOL(drm_connector_list_iter_end);
|
||||||
|
@ -1231,6 +1251,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
||||||
if (edid)
|
if (edid)
|
||||||
size = EDID_LENGTH * (1 + edid->extensions);
|
size = EDID_LENGTH * (1 + edid->extensions);
|
||||||
|
|
||||||
|
/* Set the display info, using edid if available, otherwise
|
||||||
|
* reseting the values to defaults. This duplicates the work
|
||||||
|
* done in drm_add_edid_modes, but that function is not
|
||||||
|
* consistently called before this one in all drivers and the
|
||||||
|
* computation is cheap enough that it seems better to
|
||||||
|
* duplicate it rather than attempt to ensure some arbitrary
|
||||||
|
* ordering of calls.
|
||||||
|
*/
|
||||||
|
if (edid)
|
||||||
|
drm_add_display_info(connector, edid);
|
||||||
|
else
|
||||||
|
drm_reset_display_info(connector);
|
||||||
|
|
||||||
drm_object_property_set_value(&connector->base,
|
drm_object_property_set_value(&connector->base,
|
||||||
dev->mode_config.non_desktop_property,
|
dev->mode_config.non_desktop_property,
|
||||||
connector->display_info.non_desktop);
|
connector->display_info.non_desktop);
|
||||||
|
|
|
@ -142,6 +142,7 @@ int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
|
||||||
uint64_t value);
|
uint64_t value);
|
||||||
int drm_connector_create_standard_properties(struct drm_device *dev);
|
int drm_connector_create_standard_properties(struct drm_device *dev);
|
||||||
const char *drm_get_connector_force_name(enum drm_connector_force force);
|
const char *drm_get_connector_force_name(enum drm_connector_force force);
|
||||||
|
void drm_connector_free_work_fn(struct work_struct *work);
|
||||||
|
|
||||||
/* IOCTL */
|
/* IOCTL */
|
||||||
int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
|
int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
|
||||||
|
|
|
@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
|
||||||
*
|
*
|
||||||
* Returns true if @vendor is in @edid, false otherwise
|
* Returns true if @vendor is in @edid, false otherwise
|
||||||
*/
|
*/
|
||||||
static bool edid_vendor(struct edid *edid, const char *vendor)
|
static bool edid_vendor(const struct edid *edid, const char *vendor)
|
||||||
{
|
{
|
||||||
char edid_vendor[3];
|
char edid_vendor[3];
|
||||||
|
|
||||||
|
@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
|
||||||
*
|
*
|
||||||
* This tells subsequent routines what fixes they need to apply.
|
* This tells subsequent routines what fixes they need to apply.
|
||||||
*/
|
*/
|
||||||
static u32 edid_get_quirks(struct edid *edid)
|
static u32 edid_get_quirks(const struct edid *edid)
|
||||||
{
|
{
|
||||||
const struct edid_quirk *quirk;
|
const struct edid_quirk *quirk;
|
||||||
int i;
|
int i;
|
||||||
|
@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||||
/*
|
/*
|
||||||
* Search EDID for CEA extension block.
|
* Search EDID for CEA extension block.
|
||||||
*/
|
*/
|
||||||
static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
|
static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
|
||||||
{
|
{
|
||||||
u8 *edid_ext = NULL;
|
u8 *edid_ext = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
|
||||||
return edid_ext;
|
return edid_ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 *drm_find_cea_extension(struct edid *edid)
|
static u8 *drm_find_cea_extension(const struct edid *edid)
|
||||||
{
|
{
|
||||||
return drm_find_edid_extension(edid, CEA_EXT);
|
return drm_find_edid_extension(edid, CEA_EXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 *drm_find_displayid_extension(struct edid *edid)
|
static u8 *drm_find_displayid_extension(const struct edid *edid)
|
||||||
{
|
{
|
||||||
return drm_find_edid_extension(edid, DISPLAYID_EXT);
|
return drm_find_edid_extension(edid, DISPLAYID_EXT);
|
||||||
}
|
}
|
||||||
|
@ -4363,7 +4363,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_parse_cea_ext(struct drm_connector *connector,
|
static void drm_parse_cea_ext(struct drm_connector *connector,
|
||||||
struct edid *edid)
|
const struct edid *edid)
|
||||||
{
|
{
|
||||||
struct drm_display_info *info = &connector->display_info;
|
struct drm_display_info *info = &connector->display_info;
|
||||||
const u8 *edid_ext;
|
const u8 *edid_ext;
|
||||||
|
@ -4397,11 +4397,33 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_add_display_info(struct drm_connector *connector,
|
/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
|
||||||
struct edid *edid, u32 quirks)
|
* all of the values which would have been set from EDID
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drm_reset_display_info(struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
struct drm_display_info *info = &connector->display_info;
|
struct drm_display_info *info = &connector->display_info;
|
||||||
|
|
||||||
|
info->width_mm = 0;
|
||||||
|
info->height_mm = 0;
|
||||||
|
|
||||||
|
info->bpc = 0;
|
||||||
|
info->color_formats = 0;
|
||||||
|
info->cea_rev = 0;
|
||||||
|
info->max_tmds_clock = 0;
|
||||||
|
info->dvi_dual = false;
|
||||||
|
|
||||||
|
info->non_desktop = 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(drm_reset_display_info);
|
||||||
|
|
||||||
|
u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
|
||||||
|
{
|
||||||
|
struct drm_display_info *info = &connector->display_info;
|
||||||
|
|
||||||
|
u32 quirks = edid_get_quirks(edid);
|
||||||
|
|
||||||
info->width_mm = edid->width_cm * 10;
|
info->width_mm = edid->width_cm * 10;
|
||||||
info->height_mm = edid->height_cm * 10;
|
info->height_mm = edid->height_cm * 10;
|
||||||
|
|
||||||
|
@ -4414,11 +4436,13 @@ static void drm_add_display_info(struct drm_connector *connector,
|
||||||
|
|
||||||
info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
|
info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
|
||||||
|
|
||||||
|
DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
|
||||||
|
|
||||||
if (edid->revision < 3)
|
if (edid->revision < 3)
|
||||||
return;
|
return quirks;
|
||||||
|
|
||||||
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
|
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
|
||||||
return;
|
return quirks;
|
||||||
|
|
||||||
drm_parse_cea_ext(connector, edid);
|
drm_parse_cea_ext(connector, edid);
|
||||||
|
|
||||||
|
@ -4438,7 +4462,7 @@ static void drm_add_display_info(struct drm_connector *connector,
|
||||||
|
|
||||||
/* Only defined for 1.4 with digital displays */
|
/* Only defined for 1.4 with digital displays */
|
||||||
if (edid->revision < 4)
|
if (edid->revision < 4)
|
||||||
return;
|
return quirks;
|
||||||
|
|
||||||
switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
|
switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
|
||||||
case DRM_EDID_DIGITAL_DEPTH_6:
|
case DRM_EDID_DIGITAL_DEPTH_6:
|
||||||
|
@ -4473,7 +4497,9 @@ static void drm_add_display_info(struct drm_connector *connector,
|
||||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
||||||
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
|
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
|
||||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
|
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
|
||||||
|
return quirks;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(drm_add_display_info);
|
||||||
|
|
||||||
static int validate_displayid(u8 *displayid, int length, int idx)
|
static int validate_displayid(u8 *displayid, int length, int idx)
|
||||||
{
|
{
|
||||||
|
@ -4627,14 +4653,12 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
quirks = edid_get_quirks(edid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
|
* CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
|
||||||
* To avoid multiple parsing of same block, lets parse that map
|
* To avoid multiple parsing of same block, lets parse that map
|
||||||
* from sink info, before parsing CEA modes.
|
* from sink info, before parsing CEA modes.
|
||||||
*/
|
*/
|
||||||
drm_add_display_info(connector, edid, quirks);
|
quirks = drm_add_display_info(connector, edid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EDID spec says modes should be preferred in this order:
|
* EDID spec says modes should be preferred in this order:
|
||||||
|
|
|
@ -254,10 +254,10 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
|
||||||
return lessee;
|
return lessee;
|
||||||
|
|
||||||
out_lessee:
|
out_lessee:
|
||||||
drm_master_put(&lessee);
|
|
||||||
|
|
||||||
mutex_unlock(&dev->mode_config.idr_mutex);
|
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||||
|
|
||||||
|
drm_master_put(&lessee);
|
||||||
|
|
||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -575,21 +575,23 @@ EXPORT_SYMBOL(drm_mm_remove_node);
|
||||||
*/
|
*/
|
||||||
void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
|
void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
|
||||||
{
|
{
|
||||||
|
struct drm_mm *mm = old->mm;
|
||||||
|
|
||||||
DRM_MM_BUG_ON(!old->allocated);
|
DRM_MM_BUG_ON(!old->allocated);
|
||||||
|
|
||||||
*new = *old;
|
*new = *old;
|
||||||
|
|
||||||
list_replace(&old->node_list, &new->node_list);
|
list_replace(&old->node_list, &new->node_list);
|
||||||
rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree.rb_root);
|
rb_replace_node_cached(&old->rb, &new->rb, &mm->interval_tree);
|
||||||
|
|
||||||
if (drm_mm_hole_follows(old)) {
|
if (drm_mm_hole_follows(old)) {
|
||||||
list_replace(&old->hole_stack, &new->hole_stack);
|
list_replace(&old->hole_stack, &new->hole_stack);
|
||||||
rb_replace_node(&old->rb_hole_size,
|
rb_replace_node(&old->rb_hole_size,
|
||||||
&new->rb_hole_size,
|
&new->rb_hole_size,
|
||||||
&old->mm->holes_size);
|
&mm->holes_size);
|
||||||
rb_replace_node(&old->rb_hole_addr,
|
rb_replace_node(&old->rb_hole_addr,
|
||||||
&new->rb_hole_addr,
|
&new->rb_hole_addr,
|
||||||
&old->mm->holes_addr);
|
&mm->holes_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
old->allocated = false;
|
old->allocated = false;
|
||||||
|
|
|
@ -382,6 +382,9 @@ void drm_mode_config_init(struct drm_device *dev)
|
||||||
ida_init(&dev->mode_config.connector_ida);
|
ida_init(&dev->mode_config.connector_ida);
|
||||||
spin_lock_init(&dev->mode_config.connector_list_lock);
|
spin_lock_init(&dev->mode_config.connector_list_lock);
|
||||||
|
|
||||||
|
init_llist_head(&dev->mode_config.connector_free_list);
|
||||||
|
INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);
|
||||||
|
|
||||||
drm_mode_create_standard_properties(dev);
|
drm_mode_create_standard_properties(dev);
|
||||||
|
|
||||||
/* Just to be sure */
|
/* Just to be sure */
|
||||||
|
@ -432,7 +435,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
drm_connector_list_iter_end(&conn_iter);
|
drm_connector_list_iter_end(&conn_iter);
|
||||||
/* connector_iter drops references in a work item. */
|
/* connector_iter drops references in a work item. */
|
||||||
flush_scheduled_work();
|
flush_work(&dev->mode_config.connector_free_work);
|
||||||
if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
|
if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_for_each_connector_iter(connector, &conn_iter)
|
drm_for_each_connector_iter(connector, &conn_iter)
|
||||||
|
|
|
@ -888,8 +888,10 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
|
||||||
/* If we got force-completed because of GPU reset rather than
|
/* If we got force-completed because of GPU reset rather than
|
||||||
* through our IRQ handler, signal the fence now.
|
* through our IRQ handler, signal the fence now.
|
||||||
*/
|
*/
|
||||||
if (exec->fence)
|
if (exec->fence) {
|
||||||
dma_fence_signal(exec->fence);
|
dma_fence_signal(exec->fence);
|
||||||
|
dma_fence_put(exec->fence);
|
||||||
|
}
|
||||||
|
|
||||||
if (exec->bo) {
|
if (exec->bo) {
|
||||||
for (i = 0; i < exec->bo_count; i++) {
|
for (i = 0; i < exec->bo_count; i++) {
|
||||||
|
|
|
@ -139,6 +139,7 @@ vc4_irq_finish_render_job(struct drm_device *dev)
|
||||||
list_move_tail(&exec->head, &vc4->job_done_list);
|
list_move_tail(&exec->head, &vc4->job_done_list);
|
||||||
if (exec->fence) {
|
if (exec->fence) {
|
||||||
dma_fence_signal_locked(exec->fence);
|
dma_fence_signal_locked(exec->fence);
|
||||||
|
dma_fence_put(exec->fence);
|
||||||
exec->fence = NULL;
|
exec->fence = NULL;
|
||||||
}
|
}
|
||||||
vc4_submit_next_render_job(dev);
|
vc4_submit_next_render_job(dev);
|
||||||
|
|
|
@ -42,9 +42,11 @@ static struct stm_ftrace {
|
||||||
* @len: length of the data packet
|
* @len: length of the data packet
|
||||||
*/
|
*/
|
||||||
static void notrace
|
static void notrace
|
||||||
stm_ftrace_write(const void *buf, unsigned int len)
|
stm_ftrace_write(struct trace_export *export, const void *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
stm_source_write(&stm_ftrace.data, STM_FTRACE_CHAN, buf, len);
|
struct stm_ftrace *stm = container_of(export, struct stm_ftrace, ftrace);
|
||||||
|
|
||||||
|
stm_source_write(&stm->data, STM_FTRACE_CHAN, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm_ftrace_link(struct stm_source_data *data)
|
static int stm_ftrace_link(struct stm_source_data *data)
|
||||||
|
|
|
@ -379,7 +379,7 @@ static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_device_id cht_wc_i2c_adap_id_table[] = {
|
static const struct platform_device_id cht_wc_i2c_adap_id_table[] = {
|
||||||
{ .name = "cht_wcove_ext_chgr" },
|
{ .name = "cht_wcove_ext_chgr" },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
|
@ -983,7 +983,7 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
|
||||||
|
|
||||||
if (adapdata->smba) {
|
if (adapdata->smba) {
|
||||||
i2c_del_adapter(adap);
|
i2c_del_adapter(adap);
|
||||||
if (adapdata->port == (0 << 1)) {
|
if (adapdata->port == (0 << piix4_port_shift_sb800)) {
|
||||||
release_region(adapdata->smba, SMBIOSIZE);
|
release_region(adapdata->smba, SMBIOSIZE);
|
||||||
if (adapdata->sb800_main)
|
if (adapdata->sb800_main)
|
||||||
release_region(SB800_PIIX4_SMB_IDX, 2);
|
release_region(SB800_PIIX4_SMB_IDX, 2);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* i2c-stm32.h
|
* i2c-stm32.h
|
||||||
*
|
*
|
||||||
* Copyright (C) M'boumba Cedric Madianga 2017
|
* Copyright (C) M'boumba Cedric Madianga 2017
|
||||||
|
* Copyright (C) STMicroelectronics 2017
|
||||||
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
|
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
|
||||||
*
|
*
|
||||||
* License terms: GNU General Public License (GPL), version 2
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _I2C_STM32_H
|
#ifndef _I2C_STM32_H
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Driver for STMicroelectronics STM32 I2C controller
|
* Driver for STMicroelectronics STM32 I2C controller
|
||||||
*
|
*
|
||||||
|
@ -6,11 +7,11 @@
|
||||||
* http://www.st.com/resource/en/reference_manual/DM00031020.pdf
|
* http://www.st.com/resource/en/reference_manual/DM00031020.pdf
|
||||||
*
|
*
|
||||||
* Copyright (C) M'boumba Cedric Madianga 2016
|
* Copyright (C) M'boumba Cedric Madianga 2016
|
||||||
|
* Copyright (C) STMicroelectronics 2017
|
||||||
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
|
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
|
||||||
*
|
*
|
||||||
* This driver is based on i2c-st.c
|
* This driver is based on i2c-st.c
|
||||||
*
|
*
|
||||||
* License terms: GNU General Public License (GPL), version 2
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Driver for STMicroelectronics STM32F7 I2C controller
|
* Driver for STMicroelectronics STM32F7 I2C controller
|
||||||
*
|
*
|
||||||
|
@ -7,11 +8,11 @@
|
||||||
* http://www.st.com/resource/en/reference_manual/dm00124865.pdf
|
* http://www.st.com/resource/en/reference_manual/dm00124865.pdf
|
||||||
*
|
*
|
||||||
* Copyright (C) M'boumba Cedric Madianga 2017
|
* Copyright (C) M'boumba Cedric Madianga 2017
|
||||||
|
* Copyright (C) STMicroelectronics 2017
|
||||||
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
|
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
|
||||||
*
|
*
|
||||||
* This driver is based on i2c-stm32f4.c
|
* This driver is based on i2c-stm32f4.c
|
||||||
*
|
*
|
||||||
* License terms: GNU General Public License (GPL), version 2
|
|
||||||
*/
|
*/
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -4458,7 +4458,7 @@ out:
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rdma_nl_cbs cma_cb_table[] = {
|
static const struct rdma_nl_cbs cma_cb_table[RDMA_NL_RDMA_CM_NUM_OPS] = {
|
||||||
[RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats},
|
[RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1146,7 +1146,7 @@ struct net_device *ib_get_net_dev_by_params(struct ib_device *dev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ib_get_net_dev_by_params);
|
EXPORT_SYMBOL(ib_get_net_dev_by_params);
|
||||||
|
|
||||||
static const struct rdma_nl_cbs ibnl_ls_cb_table[] = {
|
static const struct rdma_nl_cbs ibnl_ls_cb_table[RDMA_NL_LS_NUM_OPS] = {
|
||||||
[RDMA_NL_LS_OP_RESOLVE] = {
|
[RDMA_NL_LS_OP_RESOLVE] = {
|
||||||
.doit = ib_nl_handle_resolve_resp,
|
.doit = ib_nl_handle_resolve_resp,
|
||||||
.flags = RDMA_NL_ADMIN_PERM,
|
.flags = RDMA_NL_ADMIN_PERM,
|
||||||
|
|
|
@ -80,7 +80,7 @@ const char *__attribute_const__ iwcm_reject_msg(int reason)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwcm_reject_msg);
|
EXPORT_SYMBOL(iwcm_reject_msg);
|
||||||
|
|
||||||
static struct rdma_nl_cbs iwcm_nl_cb_table[] = {
|
static struct rdma_nl_cbs iwcm_nl_cb_table[RDMA_NL_IWPM_NUM_OPS] = {
|
||||||
[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
|
[RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
|
||||||
[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
|
[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
|
||||||
[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
|
[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
|
||||||
|
|
|
@ -303,7 +303,7 @@ out: cb->args[0] = idx;
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rdma_nl_cbs nldev_cb_table[] = {
|
static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
|
||||||
[RDMA_NLDEV_CMD_GET] = {
|
[RDMA_NLDEV_CMD_GET] = {
|
||||||
.doit = nldev_get_doit,
|
.doit = nldev_get_doit,
|
||||||
.dump = nldev_get_dumpit,
|
.dump = nldev_get_dumpit,
|
||||||
|
|
|
@ -739,8 +739,11 @@ int ib_mad_enforce_security(struct ib_mad_agent_private *map, u16 pkey_index)
|
||||||
if (!rdma_protocol_ib(map->agent.device, map->agent.port_num))
|
if (!rdma_protocol_ib(map->agent.device, map->agent.port_num))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (map->agent.qp->qp_type == IB_QPT_SMI && !map->agent.smp_allowed)
|
if (map->agent.qp->qp_type == IB_QPT_SMI) {
|
||||||
|
if (!map->agent.smp_allowed)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return ib_security_pkey_access(map->agent.device,
|
return ib_security_pkey_access(map->agent.device,
|
||||||
map->agent.port_num,
|
map->agent.port_num,
|
||||||
|
|
|
@ -1971,6 +1971,12 @@ static int modify_qp(struct ib_uverbs_file *file,
|
||||||
goto release_qp;
|
goto release_qp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((cmd->base.attr_mask & IB_QP_ALT_PATH) &&
|
||||||
|
!rdma_is_port_valid(qp->device, cmd->base.alt_port_num)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto release_qp;
|
||||||
|
}
|
||||||
|
|
||||||
attr->qp_state = cmd->base.qp_state;
|
attr->qp_state = cmd->base.qp_state;
|
||||||
attr->cur_qp_state = cmd->base.cur_qp_state;
|
attr->cur_qp_state = cmd->base.cur_qp_state;
|
||||||
attr->path_mtu = cmd->base.path_mtu;
|
attr->path_mtu = cmd->base.path_mtu;
|
||||||
|
|
|
@ -395,6 +395,11 @@ next_cqe:
|
||||||
|
|
||||||
static int cqe_completes_wr(struct t4_cqe *cqe, struct t4_wq *wq)
|
static int cqe_completes_wr(struct t4_cqe *cqe, struct t4_wq *wq)
|
||||||
{
|
{
|
||||||
|
if (CQE_OPCODE(cqe) == C4IW_DRAIN_OPCODE) {
|
||||||
|
WARN_ONCE(1, "Unexpected DRAIN CQE qp id %u!\n", wq->sq.qid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (CQE_OPCODE(cqe) == FW_RI_TERMINATE)
|
if (CQE_OPCODE(cqe) == FW_RI_TERMINATE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -868,7 +868,12 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
|
||||||
|
|
||||||
qhp = to_c4iw_qp(ibqp);
|
qhp = to_c4iw_qp(ibqp);
|
||||||
spin_lock_irqsave(&qhp->lock, flag);
|
spin_lock_irqsave(&qhp->lock, flag);
|
||||||
if (t4_wq_in_error(&qhp->wq)) {
|
|
||||||
|
/*
|
||||||
|
* If the qp has been flushed, then just insert a special
|
||||||
|
* drain cqe.
|
||||||
|
*/
|
||||||
|
if (qhp->wq.flushed) {
|
||||||
spin_unlock_irqrestore(&qhp->lock, flag);
|
spin_unlock_irqrestore(&qhp->lock, flag);
|
||||||
complete_sq_drain_wr(qhp, wr);
|
complete_sq_drain_wr(qhp, wr);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1011,7 +1016,12 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
|
||||||
|
|
||||||
qhp = to_c4iw_qp(ibqp);
|
qhp = to_c4iw_qp(ibqp);
|
||||||
spin_lock_irqsave(&qhp->lock, flag);
|
spin_lock_irqsave(&qhp->lock, flag);
|
||||||
if (t4_wq_in_error(&qhp->wq)) {
|
|
||||||
|
/*
|
||||||
|
* If the qp has been flushed, then just insert a special
|
||||||
|
* drain cqe.
|
||||||
|
*/
|
||||||
|
if (qhp->wq.flushed) {
|
||||||
spin_unlock_irqrestore(&qhp->lock, flag);
|
spin_unlock_irqrestore(&qhp->lock, flag);
|
||||||
complete_rq_drain_wr(qhp, wr);
|
complete_rq_drain_wr(qhp, wr);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1285,21 +1295,21 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
|
||||||
spin_unlock_irqrestore(&rchp->lock, flag);
|
spin_unlock_irqrestore(&rchp->lock, flag);
|
||||||
|
|
||||||
if (schp == rchp) {
|
if (schp == rchp) {
|
||||||
if (t4_clear_cq_armed(&rchp->cq) &&
|
if ((rq_flushed || sq_flushed) &&
|
||||||
(rq_flushed || sq_flushed)) {
|
t4_clear_cq_armed(&rchp->cq)) {
|
||||||
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
|
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
|
||||||
(*rchp->ibcq.comp_handler)(&rchp->ibcq,
|
(*rchp->ibcq.comp_handler)(&rchp->ibcq,
|
||||||
rchp->ibcq.cq_context);
|
rchp->ibcq.cq_context);
|
||||||
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
|
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (t4_clear_cq_armed(&rchp->cq) && rq_flushed) {
|
if (rq_flushed && t4_clear_cq_armed(&rchp->cq)) {
|
||||||
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
|
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
|
||||||
(*rchp->ibcq.comp_handler)(&rchp->ibcq,
|
(*rchp->ibcq.comp_handler)(&rchp->ibcq,
|
||||||
rchp->ibcq.cq_context);
|
rchp->ibcq.cq_context);
|
||||||
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
|
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
|
||||||
}
|
}
|
||||||
if (t4_clear_cq_armed(&schp->cq) && sq_flushed) {
|
if (sq_flushed && t4_clear_cq_armed(&schp->cq)) {
|
||||||
spin_lock_irqsave(&schp->comp_handler_lock, flag);
|
spin_lock_irqsave(&schp->comp_handler_lock, flag);
|
||||||
(*schp->ibcq.comp_handler)(&schp->ibcq,
|
(*schp->ibcq.comp_handler)(&schp->ibcq,
|
||||||
schp->ibcq.cq_context);
|
schp->ibcq.cq_context);
|
||||||
|
|
|
@ -666,6 +666,19 @@ static int set_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_rss *rss_ctx,
|
||||||
return (-EOPNOTSUPP);
|
return (-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ucmd->rx_hash_fields_mask & ~(MLX4_IB_RX_HASH_SRC_IPV4 |
|
||||||
|
MLX4_IB_RX_HASH_DST_IPV4 |
|
||||||
|
MLX4_IB_RX_HASH_SRC_IPV6 |
|
||||||
|
MLX4_IB_RX_HASH_DST_IPV6 |
|
||||||
|
MLX4_IB_RX_HASH_SRC_PORT_TCP |
|
||||||
|
MLX4_IB_RX_HASH_DST_PORT_TCP |
|
||||||
|
MLX4_IB_RX_HASH_SRC_PORT_UDP |
|
||||||
|
MLX4_IB_RX_HASH_DST_PORT_UDP)) {
|
||||||
|
pr_debug("RX Hash fields_mask has unsupported mask (0x%llx)\n",
|
||||||
|
ucmd->rx_hash_fields_mask);
|
||||||
|
return (-EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV4) &&
|
if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV4) &&
|
||||||
(ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV4)) {
|
(ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV4)) {
|
||||||
rss_ctx->flags = MLX4_RSS_IPV4;
|
rss_ctx->flags = MLX4_RSS_IPV4;
|
||||||
|
@ -691,11 +704,11 @@ static int set_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_rss *rss_ctx,
|
||||||
return (-EOPNOTSUPP);
|
return (-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rss_ctx->flags & MLX4_RSS_IPV4) {
|
if (rss_ctx->flags & MLX4_RSS_IPV4)
|
||||||
rss_ctx->flags |= MLX4_RSS_UDP_IPV4;
|
rss_ctx->flags |= MLX4_RSS_UDP_IPV4;
|
||||||
} else if (rss_ctx->flags & MLX4_RSS_IPV6) {
|
if (rss_ctx->flags & MLX4_RSS_IPV6)
|
||||||
rss_ctx->flags |= MLX4_RSS_UDP_IPV6;
|
rss_ctx->flags |= MLX4_RSS_UDP_IPV6;
|
||||||
} else {
|
if (!(rss_ctx->flags & (MLX4_RSS_IPV6 | MLX4_RSS_IPV4))) {
|
||||||
pr_debug("RX Hash fields_mask is not supported - UDP must be set with IPv4 or IPv6\n");
|
pr_debug("RX Hash fields_mask is not supported - UDP must be set with IPv4 or IPv6\n");
|
||||||
return (-EOPNOTSUPP);
|
return (-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
@ -707,15 +720,14 @@ static int set_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_rss *rss_ctx,
|
||||||
|
|
||||||
if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) &&
|
if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) &&
|
||||||
(ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) {
|
(ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) {
|
||||||
if (rss_ctx->flags & MLX4_RSS_IPV4) {
|
if (rss_ctx->flags & MLX4_RSS_IPV4)
|
||||||
rss_ctx->flags |= MLX4_RSS_TCP_IPV4;
|
rss_ctx->flags |= MLX4_RSS_TCP_IPV4;
|
||||||
} else if (rss_ctx->flags & MLX4_RSS_IPV6) {
|
if (rss_ctx->flags & MLX4_RSS_IPV6)
|
||||||
rss_ctx->flags |= MLX4_RSS_TCP_IPV6;
|
rss_ctx->flags |= MLX4_RSS_TCP_IPV6;
|
||||||
} else {
|
if (!(rss_ctx->flags & (MLX4_RSS_IPV6 | MLX4_RSS_IPV4))) {
|
||||||
pr_debug("RX Hash fields_mask is not supported - TCP must be set with IPv4 or IPv6\n");
|
pr_debug("RX Hash fields_mask is not supported - TCP must be set with IPv4 or IPv6\n");
|
||||||
return (-EOPNOTSUPP);
|
return (-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) ||
|
} else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) ||
|
||||||
(ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) {
|
(ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) {
|
||||||
pr_debug("RX Hash fields_mask is not supported - both TCP SRC and DST must be set\n");
|
pr_debug("RX Hash fields_mask is not supported - both TCP SRC and DST must be set\n");
|
||||||
|
|
|
@ -1145,6 +1145,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
|
||||||
noio_flag = memalloc_noio_save();
|
noio_flag = memalloc_noio_save();
|
||||||
p->tx_ring = vzalloc(ipoib_sendq_size * sizeof(*p->tx_ring));
|
p->tx_ring = vzalloc(ipoib_sendq_size * sizeof(*p->tx_ring));
|
||||||
if (!p->tx_ring) {
|
if (!p->tx_ring) {
|
||||||
|
memalloc_noio_restore(noio_flag);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_tx;
|
goto err_tx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1611,7 +1611,8 @@ static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
|
||||||
int l;
|
int l;
|
||||||
struct dm_buffer *b, *tmp;
|
struct dm_buffer *b, *tmp;
|
||||||
unsigned long freed = 0;
|
unsigned long freed = 0;
|
||||||
unsigned long count = nr_to_scan;
|
unsigned long count = c->n_buffers[LIST_CLEAN] +
|
||||||
|
c->n_buffers[LIST_DIRTY];
|
||||||
unsigned long retain_target = get_retain_buffers(c);
|
unsigned long retain_target = get_retain_buffers(c);
|
||||||
|
|
||||||
for (l = 0; l < LIST_SIZE; l++) {
|
for (l = 0; l < LIST_SIZE; l++) {
|
||||||
|
@ -1647,8 +1648,11 @@ static unsigned long
|
||||||
dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
||||||
{
|
{
|
||||||
struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker);
|
struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker);
|
||||||
|
unsigned long count = READ_ONCE(c->n_buffers[LIST_CLEAN]) +
|
||||||
|
READ_ONCE(c->n_buffers[LIST_DIRTY]);
|
||||||
|
unsigned long retain_target = get_retain_buffers(c);
|
||||||
|
|
||||||
return READ_ONCE(c->n_buffers[LIST_CLEAN]) + READ_ONCE(c->n_buffers[LIST_DIRTY]);
|
return (count < retain_target) ? 0 : (count - retain_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -3472,18 +3472,18 @@ static int __init dm_cache_init(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_register_target(&cache_target);
|
|
||||||
if (r) {
|
|
||||||
DMERR("cache target registration failed: %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
migration_cache = KMEM_CACHE(dm_cache_migration, 0);
|
migration_cache = KMEM_CACHE(dm_cache_migration, 0);
|
||||||
if (!migration_cache) {
|
if (!migration_cache) {
|
||||||
dm_unregister_target(&cache_target);
|
dm_unregister_target(&cache_target);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = dm_register_target(&cache_target);
|
||||||
|
if (r) {
|
||||||
|
DMERR("cache target registration failed: %d", r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -457,6 +457,38 @@ do { \
|
||||||
dm_noflush_suspending((m)->ti)); \
|
dm_noflush_suspending((m)->ti)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether bios must be queued in the device-mapper core rather
|
||||||
|
* than here in the target.
|
||||||
|
*
|
||||||
|
* If MPATHF_QUEUE_IF_NO_PATH and MPATHF_SAVED_QUEUE_IF_NO_PATH hold
|
||||||
|
* the same value then we are not between multipath_presuspend()
|
||||||
|
* and multipath_resume() calls and we have no need to check
|
||||||
|
* for the DMF_NOFLUSH_SUSPENDING flag.
|
||||||
|
*/
|
||||||
|
static bool __must_push_back(struct multipath *m, unsigned long flags)
|
||||||
|
{
|
||||||
|
return ((test_bit(MPATHF_QUEUE_IF_NO_PATH, &flags) !=
|
||||||
|
test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &flags)) &&
|
||||||
|
dm_noflush_suspending(m->ti));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following functions use READ_ONCE to get atomic access to
|
||||||
|
* all m->flags to avoid taking spinlock
|
||||||
|
*/
|
||||||
|
static bool must_push_back_rq(struct multipath *m)
|
||||||
|
{
|
||||||
|
unsigned long flags = READ_ONCE(m->flags);
|
||||||
|
return test_bit(MPATHF_QUEUE_IF_NO_PATH, &flags) || __must_push_back(m, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool must_push_back_bio(struct multipath *m)
|
||||||
|
{
|
||||||
|
unsigned long flags = READ_ONCE(m->flags);
|
||||||
|
return __must_push_back(m, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map cloned requests (request-based multipath)
|
* Map cloned requests (request-based multipath)
|
||||||
*/
|
*/
|
||||||
|
@ -478,7 +510,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
|
||||||
pgpath = choose_pgpath(m, nr_bytes);
|
pgpath = choose_pgpath(m, nr_bytes);
|
||||||
|
|
||||||
if (!pgpath) {
|
if (!pgpath) {
|
||||||
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
|
if (must_push_back_rq(m))
|
||||||
return DM_MAPIO_DELAY_REQUEUE;
|
return DM_MAPIO_DELAY_REQUEUE;
|
||||||
dm_report_EIO(m); /* Failed */
|
dm_report_EIO(m); /* Failed */
|
||||||
return DM_MAPIO_KILL;
|
return DM_MAPIO_KILL;
|
||||||
|
@ -553,7 +585,7 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, struct dm_m
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pgpath) {
|
if (!pgpath) {
|
||||||
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
|
if (must_push_back_bio(m))
|
||||||
return DM_MAPIO_REQUEUE;
|
return DM_MAPIO_REQUEUE;
|
||||||
dm_report_EIO(m);
|
dm_report_EIO(m);
|
||||||
return DM_MAPIO_KILL;
|
return DM_MAPIO_KILL;
|
||||||
|
@ -651,8 +683,7 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
|
||||||
assign_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags,
|
assign_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags,
|
||||||
(save_old_value && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) ||
|
(save_old_value && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) ||
|
||||||
(!save_old_value && queue_if_no_path));
|
(!save_old_value && queue_if_no_path));
|
||||||
assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags,
|
assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags, queue_if_no_path);
|
||||||
queue_if_no_path || dm_noflush_suspending(m->ti));
|
|
||||||
spin_unlock_irqrestore(&m->lock, flags);
|
spin_unlock_irqrestore(&m->lock, flags);
|
||||||
|
|
||||||
if (!queue_if_no_path) {
|
if (!queue_if_no_path) {
|
||||||
|
@ -1486,7 +1517,7 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
|
||||||
fail_path(pgpath);
|
fail_path(pgpath);
|
||||||
|
|
||||||
if (atomic_read(&m->nr_valid_paths) == 0 &&
|
if (atomic_read(&m->nr_valid_paths) == 0 &&
|
||||||
!test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
!must_push_back_rq(m)) {
|
||||||
if (error == BLK_STS_IOERR)
|
if (error == BLK_STS_IOERR)
|
||||||
dm_report_EIO(m);
|
dm_report_EIO(m);
|
||||||
/* complete with the original error */
|
/* complete with the original error */
|
||||||
|
@ -1521,8 +1552,12 @@ static int multipath_end_io_bio(struct dm_target *ti, struct bio *clone,
|
||||||
|
|
||||||
if (atomic_read(&m->nr_valid_paths) == 0 &&
|
if (atomic_read(&m->nr_valid_paths) == 0 &&
|
||||||
!test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
!test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
||||||
|
if (must_push_back_bio(m)) {
|
||||||
|
r = DM_ENDIO_REQUEUE;
|
||||||
|
} else {
|
||||||
dm_report_EIO(m);
|
dm_report_EIO(m);
|
||||||
*error = BLK_STS_IOERR;
|
*error = BLK_STS_IOERR;
|
||||||
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1957,13 +1992,6 @@ static int __init dm_multipath_init(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_register_target(&multipath_target);
|
|
||||||
if (r < 0) {
|
|
||||||
DMERR("request-based register failed %d", r);
|
|
||||||
r = -EINVAL;
|
|
||||||
goto bad_register_target;
|
|
||||||
}
|
|
||||||
|
|
||||||
kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);
|
kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);
|
||||||
if (!kmultipathd) {
|
if (!kmultipathd) {
|
||||||
DMERR("failed to create workqueue kmpathd");
|
DMERR("failed to create workqueue kmpathd");
|
||||||
|
@ -1985,13 +2013,20 @@ static int __init dm_multipath_init(void)
|
||||||
goto bad_alloc_kmpath_handlerd;
|
goto bad_alloc_kmpath_handlerd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = dm_register_target(&multipath_target);
|
||||||
|
if (r < 0) {
|
||||||
|
DMERR("request-based register failed %d", r);
|
||||||
|
r = -EINVAL;
|
||||||
|
goto bad_register_target;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
bad_register_target:
|
||||||
|
destroy_workqueue(kmpath_handlerd);
|
||||||
bad_alloc_kmpath_handlerd:
|
bad_alloc_kmpath_handlerd:
|
||||||
destroy_workqueue(kmultipathd);
|
destroy_workqueue(kmultipathd);
|
||||||
bad_alloc_kmultipathd:
|
bad_alloc_kmultipathd:
|
||||||
dm_unregister_target(&multipath_target);
|
|
||||||
bad_register_target:
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2411,24 +2411,6 @@ static int __init dm_snapshot_init(void)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dm_register_target(&snapshot_target);
|
|
||||||
if (r < 0) {
|
|
||||||
DMERR("snapshot target register failed %d", r);
|
|
||||||
goto bad_register_snapshot_target;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = dm_register_target(&origin_target);
|
|
||||||
if (r < 0) {
|
|
||||||
DMERR("Origin target register failed %d", r);
|
|
||||||
goto bad_register_origin_target;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = dm_register_target(&merge_target);
|
|
||||||
if (r < 0) {
|
|
||||||
DMERR("Merge target register failed %d", r);
|
|
||||||
goto bad_register_merge_target;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = init_origin_hash();
|
r = init_origin_hash();
|
||||||
if (r) {
|
if (r) {
|
||||||
DMERR("init_origin_hash failed.");
|
DMERR("init_origin_hash failed.");
|
||||||
|
@ -2449,19 +2431,37 @@ static int __init dm_snapshot_init(void)
|
||||||
goto bad_pending_cache;
|
goto bad_pending_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = dm_register_target(&snapshot_target);
|
||||||
|
if (r < 0) {
|
||||||
|
DMERR("snapshot target register failed %d", r);
|
||||||
|
goto bad_register_snapshot_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = dm_register_target(&origin_target);
|
||||||
|
if (r < 0) {
|
||||||
|
DMERR("Origin target register failed %d", r);
|
||||||
|
goto bad_register_origin_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = dm_register_target(&merge_target);
|
||||||
|
if (r < 0) {
|
||||||
|
DMERR("Merge target register failed %d", r);
|
||||||
|
goto bad_register_merge_target;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad_pending_cache:
|
|
||||||
kmem_cache_destroy(exception_cache);
|
|
||||||
bad_exception_cache:
|
|
||||||
exit_origin_hash();
|
|
||||||
bad_origin_hash:
|
|
||||||
dm_unregister_target(&merge_target);
|
|
||||||
bad_register_merge_target:
|
bad_register_merge_target:
|
||||||
dm_unregister_target(&origin_target);
|
dm_unregister_target(&origin_target);
|
||||||
bad_register_origin_target:
|
bad_register_origin_target:
|
||||||
dm_unregister_target(&snapshot_target);
|
dm_unregister_target(&snapshot_target);
|
||||||
bad_register_snapshot_target:
|
bad_register_snapshot_target:
|
||||||
|
kmem_cache_destroy(pending_cache);
|
||||||
|
bad_pending_cache:
|
||||||
|
kmem_cache_destroy(exception_cache);
|
||||||
|
bad_exception_cache:
|
||||||
|
exit_origin_hash();
|
||||||
|
bad_origin_hash:
|
||||||
dm_exception_store_exit();
|
dm_exception_store_exit();
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -453,14 +453,15 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
|
||||||
|
|
||||||
refcount_set(&dd->count, 1);
|
refcount_set(&dd->count, 1);
|
||||||
list_add(&dd->list, &t->devices);
|
list_add(&dd->list, &t->devices);
|
||||||
|
goto out;
|
||||||
|
|
||||||
} else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) {
|
} else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) {
|
||||||
r = upgrade_mode(dd, mode, t->md);
|
r = upgrade_mode(dd, mode, t->md);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
refcount_inc(&dd->count);
|
|
||||||
}
|
}
|
||||||
|
refcount_inc(&dd->count);
|
||||||
|
out:
|
||||||
*result = dd->dm_dev;
|
*result = dd->dm_dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4355,30 +4355,28 @@ static struct target_type thin_target = {
|
||||||
|
|
||||||
static int __init dm_thin_init(void)
|
static int __init dm_thin_init(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r = -ENOMEM;
|
||||||
|
|
||||||
pool_table_init();
|
pool_table_init();
|
||||||
|
|
||||||
|
_new_mapping_cache = KMEM_CACHE(dm_thin_new_mapping, 0);
|
||||||
|
if (!_new_mapping_cache)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = dm_register_target(&thin_target);
|
r = dm_register_target(&thin_target);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
goto bad_new_mapping_cache;
|
||||||
|
|
||||||
r = dm_register_target(&pool_target);
|
r = dm_register_target(&pool_target);
|
||||||
if (r)
|
if (r)
|
||||||
goto bad_pool_target;
|
goto bad_thin_target;
|
||||||
|
|
||||||
r = -ENOMEM;
|
|
||||||
|
|
||||||
_new_mapping_cache = KMEM_CACHE(dm_thin_new_mapping, 0);
|
|
||||||
if (!_new_mapping_cache)
|
|
||||||
goto bad_new_mapping_cache;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad_new_mapping_cache:
|
bad_thin_target:
|
||||||
dm_unregister_target(&pool_target);
|
|
||||||
bad_pool_target:
|
|
||||||
dm_unregister_target(&thin_target);
|
dm_unregister_target(&thin_target);
|
||||||
|
bad_new_mapping_cache:
|
||||||
|
kmem_cache_destroy(_new_mapping_cache);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -562,7 +562,7 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
|
||||||
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
|
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
|
||||||
{
|
{
|
||||||
struct at24_data *at24 = priv;
|
struct at24_data *at24 = priv;
|
||||||
struct i2c_client *client;
|
struct device *dev = &at24->client[0]->dev;
|
||||||
char *buf = val;
|
char *buf = val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -572,11 +572,9 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
|
||||||
if (off + count > at24->chip.byte_len)
|
if (off + count > at24->chip.byte_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
client = at24_translate_offset(at24, &off);
|
ret = pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(&client->dev);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pm_runtime_put_noidle(&client->dev);
|
pm_runtime_put_noidle(dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,7 +590,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
|
||||||
status = at24->read_func(at24, buf, off, count);
|
status = at24->read_func(at24, buf, off, count);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
pm_runtime_put(&client->dev);
|
pm_runtime_put(dev);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
buf += status;
|
buf += status;
|
||||||
|
@ -602,7 +600,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
|
||||||
|
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
|
|
||||||
pm_runtime_put(&client->dev);
|
pm_runtime_put(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -610,7 +608,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
|
||||||
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
||||||
{
|
{
|
||||||
struct at24_data *at24 = priv;
|
struct at24_data *at24 = priv;
|
||||||
struct i2c_client *client;
|
struct device *dev = &at24->client[0]->dev;
|
||||||
char *buf = val;
|
char *buf = val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -620,11 +618,9 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
||||||
if (off + count > at24->chip.byte_len)
|
if (off + count > at24->chip.byte_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
client = at24_translate_offset(at24, &off);
|
ret = pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(&client->dev);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pm_runtime_put_noidle(&client->dev);
|
pm_runtime_put_noidle(dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,7 +636,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
||||||
status = at24->write_func(at24, buf, off, count);
|
status = at24->write_func(at24, buf, off, count);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
pm_runtime_put(&client->dev);
|
pm_runtime_put(dev);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
buf += status;
|
buf += status;
|
||||||
|
@ -650,7 +646,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
||||||
|
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
|
|
||||||
pm_runtime_put(&client->dev);
|
pm_runtime_put(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -880,7 +876,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
at24->nvmem_config.reg_read = at24_read;
|
at24->nvmem_config.reg_read = at24_read;
|
||||||
at24->nvmem_config.reg_write = at24_write;
|
at24->nvmem_config.reg_write = at24_write;
|
||||||
at24->nvmem_config.priv = at24;
|
at24->nvmem_config.priv = at24;
|
||||||
at24->nvmem_config.stride = 4;
|
at24->nvmem_config.stride = 1;
|
||||||
at24->nvmem_config.word_size = 1;
|
at24->nvmem_config.word_size = 1;
|
||||||
at24->nvmem_config.size = chip.byte_len;
|
at24->nvmem_config.size = chip.byte_len;
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/pti.h>
|
#include <linux/intel-pti.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
|
|
@ -75,9 +75,11 @@ struct mmc_fixup {
|
||||||
#define EXT_CSD_REV_ANY (-1u)
|
#define EXT_CSD_REV_ANY (-1u)
|
||||||
|
|
||||||
#define CID_MANFID_SANDISK 0x2
|
#define CID_MANFID_SANDISK 0x2
|
||||||
|
#define CID_MANFID_ATP 0x9
|
||||||
#define CID_MANFID_TOSHIBA 0x11
|
#define CID_MANFID_TOSHIBA 0x11
|
||||||
#define CID_MANFID_MICRON 0x13
|
#define CID_MANFID_MICRON 0x13
|
||||||
#define CID_MANFID_SAMSUNG 0x15
|
#define CID_MANFID_SAMSUNG 0x15
|
||||||
|
#define CID_MANFID_APACER 0x27
|
||||||
#define CID_MANFID_KINGSTON 0x70
|
#define CID_MANFID_KINGSTON 0x70
|
||||||
#define CID_MANFID_HYNIX 0x90
|
#define CID_MANFID_HYNIX 0x90
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче