mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 12:52:29 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf 7.2-rc5
Cross-merge BPF and other fixes after downstream PR. Conflicts: net/core/filter.c Changes [2] in bpf-next conflict with a recent fix [1] from the 'net' tree. Resolved by using [1] as a base and applying same flags handling logic as in [2] in the bpf_redirect_peer() helper. [1] https://lore.kernel.org/all/20260706185609.330006-2-daniel@iogearbox.net/ [2] https://lore.kernel.org/all/20260618182035.43811-2-jordan@jrife.io/ Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
This commit is contained in:
13
.mailmap
13
.mailmap
@@ -66,6 +66,11 @@ Alex Hung <alexhung@gmail.com> <alex.hung@canonical.com>
|
||||
Alex Shi <alexs@kernel.org> <alex.shi@intel.com>
|
||||
Alex Shi <alexs@kernel.org> <alex.shi@linaro.org>
|
||||
Alex Shi <alexs@kernel.org> <alex.shi@linux.alibaba.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <maxtram95@gmail.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@mellanox.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@nvidia.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <maxim@isovalent.com>
|
||||
Alice Mikityanska <alice.kernel@fastmail.im> <alice@isovalent.com>
|
||||
Aloka Dixit <quic_alokad@quicinc.com> <alokad@codeaurora.org>
|
||||
Al Viro <viro@ftp.linux.org.uk>
|
||||
Al Viro <viro@zenIV.linux.org.uk>
|
||||
@@ -540,6 +545,7 @@ Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
|
||||
Maciej W. Rozycki <macro@orcam.me.uk> <macro@linux-mips.org>
|
||||
Maharaja Kennadyrajan <quic_mkenna@quicinc.com> <mkenna@codeaurora.org>
|
||||
Maheshwar Ajja <quic_majja@quicinc.com> <majja@codeaurora.org>
|
||||
Maíra Canal <mairacanal@riseup.net> <maira.canal@usp.br>
|
||||
Malathi Gottam <quic_mgottam@quicinc.com> <mgottam@codeaurora.org>
|
||||
Manikanta Pubbisetty <quic_mpubbise@quicinc.com> <mpubbise@codeaurora.org>
|
||||
Manivannan Sadhasivam <mani@kernel.org> <manivannanece23@gmail.com>
|
||||
@@ -585,8 +591,6 @@ Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@osg.samsung.com>
|
||||
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@redhat.com>
|
||||
Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com>
|
||||
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com>
|
||||
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@mellanox.com>
|
||||
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@nvidia.com>
|
||||
Maxime Ripard <mripard@kernel.org> <maxime@cerno.tech>
|
||||
Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com>
|
||||
Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com>
|
||||
@@ -595,8 +599,8 @@ Mayuresh Janorkar <mayur@ti.com>
|
||||
Md Sadre Alam <quic_mdalam@quicinc.com> <mdalam@codeaurora.org>
|
||||
Miaoqing Pan <quic_miaoqing@quicinc.com> <miaoqing@codeaurora.org>
|
||||
Michael Buesch <m@bues.ch>
|
||||
Michal Grzeschik <mgr@kernel.org> <m.grzeschik@pengutronix.de>
|
||||
Michal Grzeschik <mgr@kernel.org> <mgr@pengutronix.de>
|
||||
Michael Grzeschik <mgr@kernel.org> <m.grzeschik@pengutronix.de>
|
||||
Michael Grzeschik <mgr@kernel.org> <mgr@pengutronix.de>
|
||||
Michael Riesch <michael.riesch@collabora.com> <michael.riesch@wolfvision.net>
|
||||
Michal Simek <michal.simek@amd.com> <michal.simek@xilinx.com>
|
||||
Michel Dänzer <michel@tungstengraphics.com>
|
||||
@@ -817,6 +821,7 @@ Simon Wunderlich <sw@simonwunderlich.de> <simon.wunderlich@s2003.tu-chemnitz.de>
|
||||
Simon Wunderlich <sw@simonwunderlich.de> <simon.wunderlich@saxnet.de>
|
||||
Simon Wunderlich <sw@simonwunderlich.de> <simon@open-mesh.com>
|
||||
Simon Wunderlich <sw@simonwunderlich.de> <siwu@hrz.tu-chemnitz.de>
|
||||
SJ Park <sj@kernel.org>
|
||||
Sricharan Ramabadhran <quic_srichara@quicinc.com> <sricharan@codeaurora.org>
|
||||
Srinivas Kandagatla <srini@kernel.org> <srinivas.kandagatla@st.com>
|
||||
Srinivas Kandagatla <srini@kernel.org> <srinivas.kandagatla@linaro.org>
|
||||
|
||||
7
CREDITS
7
CREDITS
@@ -3626,6 +3626,13 @@ S: 69 rue Dunois
|
||||
S: 75013 Paris
|
||||
S: France
|
||||
|
||||
N: Wolfram Sang
|
||||
E: wsa@kernel.org
|
||||
W: sang-engineering.com
|
||||
P: rsa4096/140DE4CC14A029B6 3991 B1EA B9E2 6751 A4F7 645D 140D E4CC 14A0 29B6
|
||||
D: I2C Maintainer 2012 - 2026
|
||||
S: Berlin, Germany
|
||||
|
||||
N: Aleksa Sarai
|
||||
E: cyphar@cyphar.com
|
||||
W: https://www.cyphar.com/
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
what: /sys/kernel/mm/damon/
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Interface for Data Access MONitoring (DAMON). Contains files
|
||||
for controlling DAMON. For more details on DAMON itself,
|
||||
please refer to Documentation/admin-guide/mm/damon/index.rst.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Interface for privileged users of DAMON. Contains files for
|
||||
controlling DAMON that aimed to be used by privileged users.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/nr_kdamonds
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for controlling each DAMON worker thread (kdamond)
|
||||
named '0' to 'N-1' under the kdamonds/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/state
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing 'on' or 'off' to this file makes the kdamond starts or
|
||||
stops, respectively. Reading the file returns the keywords
|
||||
based on the current status. Writing 'commit' to this file
|
||||
@@ -40,33 +40,33 @@ Description: Writing 'on' or 'off' to this file makes the kdamond starts or
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/pid
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the pid of the kdamond if it is
|
||||
running.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/refresh_ms
|
||||
Date: Jul 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the time interval for
|
||||
automatic DAMON status file contents update. Writing '0'
|
||||
disables the update. Reading this file returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/nr_contexts
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for controlling each DAMON context named '0' to
|
||||
'N-1' under the contexts/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/avail_operations
|
||||
Date: Apr 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the available monitoring operations
|
||||
sets on the currently running kernel.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/operations
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a keyword for a monitoring operations set ('vaddr' for
|
||||
virtual address spaces monitoring, 'fvaddr' for fixed virtual
|
||||
address ranges monitoring, and 'paddr' for the physical address
|
||||
@@ -79,42 +79,42 @@ Description: Writing a keyword for a monitoring operations set ('vaddr' for
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/addr_unit
|
||||
Date: Aug 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing an integer to this file sets the 'address unit'
|
||||
parameter of the given operations set of the context. Reading
|
||||
the file returns the last-written 'address unit' value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/pause
|
||||
Date: Mar 2026
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a boolean keyword to this file sets the 'pause' request
|
||||
parameter for the context. Reading the file returns the
|
||||
last-written 'pause' value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/sample_us
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the sampling interval of the
|
||||
DAMON context in microseconds as the value. Reading this file
|
||||
returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/aggr_us
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the aggregation interval of
|
||||
the DAMON context in microseconds as the value. Reading this
|
||||
file returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/update_us
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the update interval of the
|
||||
DAMON context in microseconds as the value. Reading this file
|
||||
returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/intrvals_goal/access_bp
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the monitoring intervals
|
||||
auto-tuning target DAMON-observed access events ratio within
|
||||
the given time interval (aggrs in same directory), in bp
|
||||
@@ -122,7 +122,7 @@ Description: Writing a value to this file sets the monitoring intervals
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/intrvals_goal/aggrs
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the time interval to achieve
|
||||
the monitoring intervals auto-tuning target DAMON-observed
|
||||
access events ratio (access_bp in same directory) within.
|
||||
@@ -130,14 +130,14 @@ Description: Writing a value to this file sets the time interval to achieve
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/intrvals_goal/min_sample_us
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the minimum value of
|
||||
auto-tuned sampling interval in microseconds. Reading this
|
||||
file returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/intervals/intrvals_goal/max_sample_us
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the maximum value of
|
||||
auto-tuned sampling interval in microseconds. Reading this
|
||||
file returns the value.
|
||||
@@ -145,42 +145,42 @@ Description: Writing a value to this file sets the maximum value of
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/nr_regions/min
|
||||
|
||||
WDate: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the minimum number of
|
||||
monitoring regions of the DAMON context as the value. Reading
|
||||
this file returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/monitoring_attrs/nr_regions/max
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the maximum number of
|
||||
monitoring regions of the DAMON context as the value. Reading
|
||||
this file returns the value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/targets/nr_targets
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for controlling each DAMON target of the context
|
||||
named '0' to 'N-1' under the contexts/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/targets/<T>/pid_target
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the pid of
|
||||
the target process if the context is for virtual address spaces
|
||||
monitoring, respectively.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/targets/<T>/obsolete_target
|
||||
Date: Oct 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
obsoleteness of the matching parameters commit destination
|
||||
target.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/targets/<T>/regions/nr_regions
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for setting each DAMON target memory region of the
|
||||
context named '0' to 'N-1' under the regions/ directory. In
|
||||
@@ -190,181 +190,181 @@ Description: Writing a number 'N' to this file creates the number of
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/targets/<T>/regions/<R>/start
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the start
|
||||
address of the monitoring region.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/targets/<T>/regions/<R>/end
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the end
|
||||
address of the monitoring region.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/nr_schemes
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for controlling each DAMON-based operation scheme
|
||||
of the context named '0' to 'N-1' under the schemes/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/action
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the action
|
||||
of the scheme.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/target_nid
|
||||
Date: Jun 2024
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Action's target NUMA node id. Supported by only relevant
|
||||
actions.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/apply_interval_us
|
||||
Date: Sep 2023
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a value to this file sets the action apply interval of
|
||||
the scheme in microseconds. Reading this file returns the
|
||||
value.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/access_pattern/sz/min
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the minimum
|
||||
size of the scheme's target regions in bytes.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/access_pattern/sz/max
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the maximum
|
||||
size of the scheme's target regions in bytes.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/access_pattern/nr_accesses/min
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the manimum
|
||||
'nr_accesses' of the scheme's target regions.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/access_pattern/nr_accesses/max
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the maximum
|
||||
'nr_accesses' of the scheme's target regions.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/access_pattern/age/min
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the minimum
|
||||
'age' of the scheme's target regions.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/access_pattern/age/max
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the maximum
|
||||
'age' of the scheme's target regions.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/ms
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the time
|
||||
quota of the scheme in milliseconds.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/bytes
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the size
|
||||
quota of the scheme in bytes.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/effective_bytes
|
||||
Date: Feb 2024
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading from this file gets the effective size quota of the
|
||||
scheme in bytes, which adjusted for the time quota and goals.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/reset_interval_ms
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the quotas
|
||||
charge reset interval of the scheme in milliseconds.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/nr_goals
|
||||
Date: Nov 2023
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for setting automatic tuning of the scheme's
|
||||
aggressiveness named '0' to 'N-1' under the goals/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/target_metric
|
||||
Date: Feb 2024
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the quota
|
||||
auto-tuning goal metric.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/target_value
|
||||
Date: Nov 2023
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the target
|
||||
value of the goal metric.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/current_value
|
||||
Date: Nov 2023
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the current
|
||||
value of the goal metric.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/nid
|
||||
Date: Apr 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the nid
|
||||
parameter of the goal.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goals/<G>/path
|
||||
Date: Oct 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the path
|
||||
parameter of the goal.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/goal_tuner
|
||||
Date: Mar 2026
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
goal-based effective quota auto-tuning algorithm to use.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/fail_charge_num
|
||||
Date: Mar 2026
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
action-failed memory quota charging ratio numerator.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/fail_charge_denom
|
||||
Date: Mar 2026
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
action-failed memory quota charging ratio denominator.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/weights/sz_permil
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
under-quota limit regions prioritization weight for 'size' in
|
||||
permil.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/weights/nr_accesses_permil
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
under-quota limit regions prioritization weight for
|
||||
'nr_accesses' in permil.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/quotas/weights/age_permil
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the
|
||||
under-quota limit regions prioritization weight for 'age' in
|
||||
permil.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/watermarks/metric
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the metric
|
||||
of the watermarks for the scheme. The writable/readable
|
||||
keywords for this file are 'none' for disabling the watermarks
|
||||
@@ -373,44 +373,44 @@ Description: Writing to and reading from this file sets and gets the metric
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/watermarks/interval_us
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the metric
|
||||
check interval of the watermarks for the scheme in
|
||||
microseconds.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/watermarks/high
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the high
|
||||
watermark of the scheme in permil.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/watermarks/mid
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the mid
|
||||
watermark of the scheme in permil.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/watermarks/low
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the low
|
||||
watermark of the scheme in permil.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Directory for DAMON core layer-handled DAMOS filters.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/nr_filters
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for setting filters of the scheme named '0' to
|
||||
'N-1' under the core_filters/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/type
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the type of
|
||||
the memory of the interest. 'anon' for anonymous pages,
|
||||
'memcg' for specific memory cgroup, 'young' for young pages,
|
||||
@@ -419,62 +419,62 @@ Description: Writing to and reading from this file sets and gets the type of
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/memcg_path
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: If 'memcg' is written to the 'type' file, writing to and
|
||||
reading from this file sets and gets the path to the memory
|
||||
cgroup of the interest.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/addr_start
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: If 'addr' is written to the 'type' file, writing to or reading
|
||||
from this file sets or gets the start address of the address
|
||||
range for the filter.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/addr_end
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: If 'addr' is written to the 'type' file, writing to or reading
|
||||
from this file sets or gets the end address of the address
|
||||
range for the filter.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/min
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: If 'hugepage_size' is written to the 'type' file, writing to
|
||||
or reading from this file sets or gets the minimum size of the
|
||||
hugepage for the filter.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/max
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: If 'hugepage_size' is written to the 'type' file, writing to
|
||||
or reading from this file sets or gets the maximum size of the
|
||||
hugepage for the filter.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/damon_target_idx
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: If 'target' is written to the 'type' file, writing to or
|
||||
reading from this file sets or gets the index of the DAMON
|
||||
monitoring target of the interest.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/matching
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing 'Y' or 'N' to this file sets whether the filter is for
|
||||
the memory of the 'type', or all except the 'type'.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters/<F>/allow
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing 'Y' or 'N' to this file sets whether to allow or reject
|
||||
applying the scheme's action to the memory that satisfies the
|
||||
'type' and the 'matching' of the directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/ops_filters
|
||||
Date: Feb 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Directory for DAMON operations set layer-handled DAMOS filters.
|
||||
Files under this directory works same to those of
|
||||
/sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/core_filters
|
||||
@@ -482,7 +482,7 @@ Description: Directory for DAMON operations set layer-handled DAMOS filters.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/filters
|
||||
Date: Dec 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Directory for DAMOS filters. Files under this directory works
|
||||
same to those of
|
||||
/sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/{core,ops}_filters
|
||||
@@ -491,14 +491,14 @@ Description: Directory for DAMOS filters. Files under this directory works
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/dests/nr_dests
|
||||
Date: Jul 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number 'N' to this file creates the number of
|
||||
directories for setting action destinations of the scheme named
|
||||
'0' to 'N-1' under the dests/ directory.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/dests/<D>/id
|
||||
Date: Jul 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the id of
|
||||
the DAMOS action destination. For DAMOS_MIGRATE_{HOT,COLD}
|
||||
actions, the destination node's node id can be written and
|
||||
@@ -506,98 +506,98 @@ Description: Writing to and reading from this file sets and gets the id of
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/dests/<D>/weight
|
||||
Date: Jul 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing to and reading from this file sets and gets the weight
|
||||
of the DAMOS action destination to select as the destination of
|
||||
each action among the destinations.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/nr_tried
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the number of regions that the action
|
||||
of the scheme has tried to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/sz_tried
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the total size of regions that the
|
||||
action of the scheme has tried to be applied in bytes.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/nr_applied
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the number of regions that the action
|
||||
of the scheme has successfully applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/sz_applied
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the total size of regions that the
|
||||
action of the scheme has successfully applied in bytes.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/sz_ops_filter_passed
|
||||
Date: Dec 2024
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the total size of memory that passed
|
||||
DAMON operations layer-handled filters of the scheme in bytes.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/qt_exceeds
|
||||
Date: Mar 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the number of the exceed events of
|
||||
the scheme's quotas.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/nr_snapshots
|
||||
Date: Dec 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the total number of DAMON snapshots
|
||||
that the scheme has tried to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/max_nr_snapshots
|
||||
Date: Dec 2025
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Writing a number to this file sets the upper limit of
|
||||
nr_snapshots that deactivates the scheme when the limit is
|
||||
reached or exceeded.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/tried_regions/total_bytes
|
||||
Date: Jul 2023
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the total amount of memory that
|
||||
corresponding DAMON-based Operation Scheme's action has tried
|
||||
to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/tried_regions/<R>/start
|
||||
Date: Oct 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the start address of a memory region
|
||||
that corresponding DAMON-based Operation Scheme's action has
|
||||
tried to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/tried_regions/<R>/end
|
||||
Date: Oct 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the end address of a memory region
|
||||
that corresponding DAMON-based Operation Scheme's action has
|
||||
tried to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/tried_regions/<R>/nr_accesses
|
||||
Date: Oct 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the 'nr_accesses' of a memory region
|
||||
that corresponding DAMON-based Operation Scheme's action has
|
||||
tried to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/tried_regions/<R>/age
|
||||
Date: Oct 2022
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the 'age' of a memory region that
|
||||
corresponding DAMON-based Operation Scheme's action has tried
|
||||
to be applied.
|
||||
|
||||
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/tried_regions/<R>/sz_filter_passed
|
||||
Date: Dec 2024
|
||||
Contact: SeongJae Park <sj@kernel.org>
|
||||
Contact: SJ Park <sj@kernel.org>
|
||||
Description: Reading this file returns the size of the memory in the region
|
||||
that passed DAMON operations layer-handled filters of the
|
||||
scheme in bytes.
|
||||
|
||||
@@ -1585,31 +1585,31 @@ attribute-sets:
|
||||
type: u32
|
||||
-
|
||||
name: mode
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: guard
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: protect
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: fast-leave
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: learning
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: unicast-flood
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: proxyarp
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: learning-sync
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: proxyarp-wifi
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: root-id
|
||||
type: binary
|
||||
@@ -1656,34 +1656,34 @@ attribute-sets:
|
||||
type: pad
|
||||
-
|
||||
name: mcast-flood
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: mcast-to-ucast
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: vlan-tunnel
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: bcast-flood
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: group-fwd-mask
|
||||
type: u16
|
||||
-
|
||||
name: neigh-suppress
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: isolated
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: backup-port
|
||||
type: u32
|
||||
-
|
||||
name: mrp-ring-open
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: mrp-in-open
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: mcast-eht-hosts-limit
|
||||
type: u32
|
||||
@@ -1692,10 +1692,10 @@ attribute-sets:
|
||||
type: u32
|
||||
-
|
||||
name: locked
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: mab
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: mcast-n-groups
|
||||
type: u32
|
||||
@@ -1704,7 +1704,7 @@ attribute-sets:
|
||||
type: u32
|
||||
-
|
||||
name: neigh-vlan-suppress
|
||||
type: flag
|
||||
type: u8
|
||||
-
|
||||
name: backup-nhid
|
||||
type: u32
|
||||
|
||||
@@ -59,7 +59,7 @@ advantechwdt:
|
||||
|
||||
alim1535_wdt:
|
||||
timeout:
|
||||
Watchdog timeout in seconds. (0 < timeout < 18000, default=60
|
||||
Watchdog timeout in seconds. (0 < timeout < 18000, default=60)
|
||||
nowayout:
|
||||
Watchdog cannot be stopped once started
|
||||
(default=kernel config parameter)
|
||||
@@ -68,7 +68,7 @@ alim1535_wdt:
|
||||
|
||||
alim7101_wdt:
|
||||
timeout:
|
||||
Watchdog timeout in seconds. (1<=timeout<=3600, default=30
|
||||
Watchdog timeout in seconds. (1<=timeout<=3600, default=30)
|
||||
use_gpio:
|
||||
Use the gpio watchdog (required by old cobalt boards).
|
||||
default=0/off/no
|
||||
|
||||
14
MAINTAINERS
14
MAINTAINERS
@@ -6482,7 +6482,7 @@ L: linux-cifs@vger.kernel.org
|
||||
L: samba-technical@lists.samba.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
W: https://wiki.samba.org/index.php/LinuxCIFS
|
||||
T: git https://git.samba.org/sfrench/cifs-2.6.git
|
||||
T: git https://git.samba.org/sfrench/cifs-2.6.git for-next
|
||||
F: Documentation/admin-guide/cifs/
|
||||
F: fs/smb/client/
|
||||
F: fs/smb/common/
|
||||
@@ -7129,7 +7129,7 @@ W: https://docs.dasharo.com/
|
||||
F: drivers/platform/x86/dasharo-acpi.c
|
||||
|
||||
DAMON
|
||||
M: SeongJae Park <sj@kernel.org>
|
||||
M: SJ Park <sj@kernel.org>
|
||||
L: damon@lists.linux.dev
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
@@ -14146,7 +14146,7 @@ R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
R: Tom Talpey <tom@talpey.com>
|
||||
L: linux-cifs@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git https://git.samba.org/ksmbd.git
|
||||
T: git https://git.samba.org/ksmbd.git ksmbd-for-next
|
||||
F: Documentation/filesystems/smb/ksmbd.rst
|
||||
F: fs/smb/common/
|
||||
F: fs/smb/server/
|
||||
@@ -17261,6 +17261,7 @@ R: Ryan Roberts <ryan.roberts@arm.com>
|
||||
R: Dev Jain <dev.jain@arm.com>
|
||||
R: Barry Song <baohua@kernel.org>
|
||||
R: Lance Yang <lance.yang@linux.dev>
|
||||
R: Usama Arif <usama.arif@linux.dev>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
W: http://www.linux-mm.org
|
||||
@@ -19112,6 +19113,7 @@ F: drivers/nfc/
|
||||
F: include/net/nfc/
|
||||
F: include/uapi/linux/nfc.h
|
||||
F: net/nfc/
|
||||
F: tools/testing/selftests/nci/
|
||||
|
||||
NFC VIRTUAL NCI DEVICE DRIVER
|
||||
M: Bongsu Jeon <bongsu.jeon@samsung.com>
|
||||
@@ -25976,8 +25978,9 @@ F: Documentation/devicetree/bindings/phy/st,stm32mp25-combophy.yaml
|
||||
F: drivers/phy/st/phy-stm32-combophy.c
|
||||
|
||||
STMMAC ETHERNET DRIVER
|
||||
M: Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Orphan
|
||||
S: Maintained
|
||||
F: Documentation/networking/device_drivers/ethernet/stmicro/
|
||||
F: drivers/net/ethernet/stmicro/stmmac/
|
||||
|
||||
@@ -27933,7 +27936,6 @@ F: drivers/usb/isp1760/*
|
||||
|
||||
USB LAN78XX ETHERNET DRIVER
|
||||
M: Thangaraj Samynathan <Thangaraj.S@microchip.com>
|
||||
M: Rengarajan Sundararajan <Rengarajan.S@microchip.com>
|
||||
M: UNGLinuxDriver@microchip.com
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -29402,7 +29404,7 @@ F: net/xdp/
|
||||
F: tools/testing/selftests/bpf/*xsk*
|
||||
|
||||
XEN BLOCK SUBSYSTEM
|
||||
M: Roger Pau Monné <roger.pau@citrix.com>
|
||||
M: Roger Pau Monné <roger@xenproject.org>
|
||||
L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: drivers/block/xen*
|
||||
|
||||
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@
|
||||
VERSION = 7
|
||||
PATCHLEVEL = 2
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc3
|
||||
EXTRAVERSION = -rc4
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -67,7 +67,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_DESIGNWARE_CORE=y
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_DRM=m
|
||||
CONFIG_DRM_I2C_ADV7511=m
|
||||
|
||||
@@ -67,7 +67,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_DESIGNWARE_CORE=y
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_FB=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
|
||||
@@ -67,7 +67,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_DESIGNWARE_CORE=y
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_DRM=m
|
||||
CONFIG_DRM_I2C_ADV7511=m
|
||||
|
||||
@@ -61,7 +61,6 @@ CONFIG_SERIAL_8250_DW=y
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_COMPAT is not set
|
||||
CONFIG_I2C_DESIGNWARE_CORE=y
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/mach_desc.h>
|
||||
#include <asm/setup.h>
|
||||
@@ -43,9 +44,10 @@ static int __init arc_get_cpu_map(const char *name, struct cpumask *cpumask)
|
||||
{
|
||||
unsigned long dt_root = of_get_flat_dt_root();
|
||||
const char *buf;
|
||||
int len;
|
||||
|
||||
buf = of_get_flat_dt_prop(dt_root, name, NULL);
|
||||
if (!buf)
|
||||
buf = of_get_flat_dt_prop(dt_root, name, &len);
|
||||
if (!buf || !memchr(buf, '\0', len))
|
||||
return -EINVAL;
|
||||
|
||||
if (cpulist_parse(buf, cpumask))
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
* Annoyingly, the negative levels for Address size faults aren't laid out
|
||||
* contiguously (or in the desired order)
|
||||
*/
|
||||
#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x25 : 0x2C)
|
||||
#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x29 : 0x2C)
|
||||
#define ESR_ELx_FSC_ADDRSZ_L(n) ((n) < 0 ? ESR_ELx_FSC_ADDRSZ_nL(n) : \
|
||||
(ESR_ELx_FSC_ADDRSZ + (n)))
|
||||
|
||||
|
||||
@@ -78,8 +78,12 @@ enum fixed_addresses {
|
||||
/*
|
||||
* Temporary boot-time mappings, used by early_ioremap(),
|
||||
* before ioremap() is functional.
|
||||
*
|
||||
* Reserve one extra page so a 256K mapping may start at any
|
||||
* offset within a page. early_ioremap() maps the page-aligned
|
||||
* physical range, so the initial offset can consume an extra page.
|
||||
*/
|
||||
#define NR_FIX_BTMAPS (SZ_256K / PAGE_SIZE)
|
||||
#define NR_FIX_BTMAPS ((SZ_256K / PAGE_SIZE) + 1)
|
||||
#define FIX_BTMAPS_SLOTS 7
|
||||
#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
struct prev_kprobe {
|
||||
struct kprobe *kp;
|
||||
unsigned int status;
|
||||
|
||||
/*
|
||||
* The original DAIF state of the outer kprobe, saved here before
|
||||
* a nested kprobe overwrites kcb->saved_irqflag during reentry.
|
||||
*/
|
||||
unsigned long saved_irqflag;
|
||||
};
|
||||
|
||||
/* per-cpu kprobe control block */
|
||||
|
||||
@@ -174,12 +174,27 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
kcb->prev_kprobe.kp = kprobe_running();
|
||||
kcb->prev_kprobe.status = kcb->kprobe_status;
|
||||
|
||||
/*
|
||||
* Save the outer kprobe's original DAIF flags before the nested
|
||||
* kprobe calls kprobes_save_local_irqflag() and overwrites
|
||||
* kcb->saved_irqflag. Without this, the outer kprobe will restore
|
||||
* the wrong DAIF state and leave interrupts permanently masked.
|
||||
*/
|
||||
kcb->prev_kprobe.saved_irqflag = kcb->saved_irqflag;
|
||||
}
|
||||
|
||||
static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
|
||||
kcb->kprobe_status = kcb->prev_kprobe.status;
|
||||
|
||||
/*
|
||||
* Restore the outer kprobe's saved_irqflag so that when its
|
||||
* single-step completes, kprobes_restore_local_irqflag() uses
|
||||
* the correct original DAIF value.
|
||||
*/
|
||||
kcb->saved_irqflag = kcb->prev_kprobe.saved_irqflag;
|
||||
}
|
||||
|
||||
static void __kprobes set_current_kprobe(struct kprobe *p)
|
||||
@@ -240,10 +255,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p,
|
||||
switch (kcb->kprobe_status) {
|
||||
case KPROBE_HIT_SSDONE:
|
||||
case KPROBE_HIT_ACTIVE:
|
||||
case KPROBE_HIT_SS:
|
||||
/*
|
||||
* A probe can be hit while another kprobe is preparing or
|
||||
* executing its XOL single-step instruction. This is still a
|
||||
* recoverable one-level reentry, so handle it in the same way as
|
||||
* reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
|
||||
*/
|
||||
kprobes_inc_nmissed_count(p);
|
||||
setup_singlestep(p, regs, kcb, 1);
|
||||
break;
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_REENTER:
|
||||
pr_warn("Failed to recover from reentered kprobes.\n");
|
||||
dump_kprobe(p);
|
||||
@@ -282,9 +303,31 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
|
||||
struct kprobe *cur = kprobe_running();
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
|
||||
/*
|
||||
* Simulated kprobes execute in the debug trap context and have no
|
||||
* XOL slot. Any page fault taken while a simulated kprobe is in
|
||||
* progress cannot have been caused by kprobe single-stepping and
|
||||
* must be left alone for the normal page fault handler, including
|
||||
* fixup_exception.
|
||||
*/
|
||||
if (cur && !cur->ainsn.xol_insn)
|
||||
return 0;
|
||||
|
||||
switch (kcb->kprobe_status) {
|
||||
case KPROBE_HIT_SS:
|
||||
case KPROBE_REENTER:
|
||||
/*
|
||||
* A page fault taken while in KPROBE_HIT_SS or
|
||||
* KPROBE_REENTER state is only attributable to kprobe
|
||||
* single-stepping if the faulting PC points to the
|
||||
* current kprobe's XOL instruction. If the fault occurred
|
||||
* elsewhere (e.g. in perf or tracing code invoked from the
|
||||
* debug exception path), leave it for the normal page fault
|
||||
* handler to process.
|
||||
*/
|
||||
if (instruction_pointer(regs) != (unsigned long)cur->ainsn.xol_insn)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We are here because the instruction being single
|
||||
* stepped caused a page fault. We reset the current
|
||||
|
||||
@@ -76,6 +76,8 @@ static void data_abort_decode(unsigned long esr)
|
||||
pr_alert(" SF = %lu, AR = %lu\n",
|
||||
(esr & ESR_ELx_SF) >> ESR_ELx_SF_SHIFT,
|
||||
(esr & ESR_ELx_AR) >> ESR_ELx_AR_SHIFT);
|
||||
pr_alert(" Xs = %llu\n",
|
||||
(iss2 & ESR_ELx_Xs_MASK) >> ESR_ELx_Xs_SHIFT);
|
||||
} else {
|
||||
pr_alert(" ISV = 0, ISS = 0x%08lx, ISS2 = 0x%08lx\n",
|
||||
esr & ESR_ELx_ISS_MASK, iss2);
|
||||
@@ -87,11 +89,10 @@ static void data_abort_decode(unsigned long esr)
|
||||
(iss2 & ESR_ELx_TnD) >> ESR_ELx_TnD_SHIFT,
|
||||
(iss2 & ESR_ELx_TagAccess) >> ESR_ELx_TagAccess_SHIFT);
|
||||
|
||||
pr_alert(" GCS = %ld, Overlay = %lu, DirtyBit = %lu, Xs = %llu\n",
|
||||
pr_alert(" GCS = %ld, Overlay = %lu, DirtyBit = %lu\n",
|
||||
(iss2 & ESR_ELx_GCS) >> ESR_ELx_GCS_SHIFT,
|
||||
(iss2 & ESR_ELx_Overlay) >> ESR_ELx_Overlay_SHIFT,
|
||||
(iss2 & ESR_ELx_DirtyBit) >> ESR_ELx_DirtyBit_SHIFT,
|
||||
(iss2 & ESR_ELx_Xs_MASK) >> ESR_ELx_Xs_SHIFT);
|
||||
(iss2 & ESR_ELx_DirtyBit) >> ESR_ELx_DirtyBit_SHIFT);
|
||||
}
|
||||
|
||||
static void mem_abort_decode(unsigned long esr)
|
||||
|
||||
@@ -87,7 +87,7 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,
|
||||
p4dp = p4d_offset(pgdp, addr);
|
||||
pudp = pud_offset(p4dp, addr);
|
||||
pmdp = pmd_offset(pudp, addr);
|
||||
if ((pte_t *)pmdp == ptep) {
|
||||
if ((pte_t *)PTR_ALIGN_DOWN(pmdp, sizeof(*pmdp) * CONT_PMDS) == ptep) {
|
||||
*pgsize = PMD_SIZE;
|
||||
return CONT_PMDS;
|
||||
}
|
||||
|
||||
@@ -2194,7 +2194,7 @@ static int prevent_memory_remove_notifier(struct notifier_block *nb,
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_unmap_without_split(pfn, arg->nr_pages))
|
||||
if (!can_unmap_without_split(arg->start_pfn, arg->nr_pages))
|
||||
return NOTIFY_BAD;
|
||||
|
||||
return NOTIFY_OK;
|
||||
|
||||
@@ -55,10 +55,12 @@ static inline void clear_page(void *page)
|
||||
#define clear_user_page(addr, vaddr, page) \
|
||||
do { clear_page(addr); \
|
||||
flush_dcache_page(page); \
|
||||
(void)(vaddr); \
|
||||
} while (0)
|
||||
#define copy_user_page(to, from, vaddr, page) \
|
||||
do { copy_page(to, from); \
|
||||
flush_dcache_page(page); \
|
||||
(void)(vaddr); \
|
||||
} while (0)
|
||||
|
||||
extern unsigned long m68k_memoffset;
|
||||
|
||||
@@ -157,7 +157,7 @@ config RISCV
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
select HAVE_DMA_CONTIGUOUS if MMU
|
||||
select HAVE_DYNAMIC_FTRACE if MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE)
|
||||
select FUNCTION_ALIGNMENT_4B if HAVE_DYNAMIC_FTRACE && RISCV_ISA_C
|
||||
select FUNCTION_ALIGNMENT_4B if DYNAMIC_FTRACE && RISCV_ISA_C
|
||||
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS if HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
|
||||
select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if (DYNAMIC_FTRACE_WITH_ARGS && !CFI)
|
||||
select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE
|
||||
|
||||
@@ -40,7 +40,7 @@ do { \
|
||||
flush_icache_mm(vma->vm_mm, 0); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_MMU)
|
||||
/* This is accessed in assembly code. cpumask_var_t would be too complex. */
|
||||
extern DECLARE_BITMAP(new_valid_map_cpus, NR_CPUS);
|
||||
extern char _end[];
|
||||
@@ -56,7 +56,8 @@ static inline void mark_new_valid_map(void)
|
||||
#define flush_cache_vmap flush_cache_vmap
|
||||
static inline void flush_cache_vmap(unsigned long start, unsigned long end)
|
||||
{
|
||||
if (is_vmalloc_or_module_addr((void *)start))
|
||||
if (is_vmalloc_or_module_addr((void *)start) ||
|
||||
(start >= VMEMMAP_START && end <= VMEMMAP_END))
|
||||
mark_new_valid_map();
|
||||
}
|
||||
#define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end)
|
||||
|
||||
@@ -102,12 +102,14 @@ __io_reads_ins(reads, u32, l, __io_br(), __io_ar(addr))
|
||||
#define readsw(addr, buffer, count) __readsw(addr, buffer, count)
|
||||
#define readsl(addr, buffer, count) __readsl(addr, buffer, count)
|
||||
|
||||
#ifdef CONFIG_HAS_IOPORT
|
||||
__io_reads_ins(ins, u8, b, __io_pbr(), __io_par(addr))
|
||||
__io_reads_ins(ins, u16, w, __io_pbr(), __io_par(addr))
|
||||
__io_reads_ins(ins, u32, l, __io_pbr(), __io_par(addr))
|
||||
#define insb(addr, buffer, count) __insb(PCI_IOBASE + (addr), buffer, count)
|
||||
#define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count)
|
||||
#define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count)
|
||||
#endif
|
||||
|
||||
__io_writes_outs(writes, u8, b, __io_bw(), __io_aw())
|
||||
__io_writes_outs(writes, u16, w, __io_bw(), __io_aw())
|
||||
@@ -116,26 +118,32 @@ __io_writes_outs(writes, u32, l, __io_bw(), __io_aw())
|
||||
#define writesw(addr, buffer, count) __writesw(addr, buffer, count)
|
||||
#define writesl(addr, buffer, count) __writesl(addr, buffer, count)
|
||||
|
||||
#ifdef CONFIG_HAS_IOPORT
|
||||
__io_writes_outs(outs, u8, b, __io_pbw(), __io_paw())
|
||||
__io_writes_outs(outs, u16, w, __io_pbw(), __io_paw())
|
||||
__io_writes_outs(outs, u32, l, __io_pbw(), __io_paw())
|
||||
#define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count)
|
||||
#define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count)
|
||||
#define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
__io_reads_ins(reads, u64, q, __io_br(), __io_ar(addr))
|
||||
#define readsq(addr, buffer, count) __readsq(addr, buffer, count)
|
||||
|
||||
#ifdef CONFIG_HAS_IOPORT
|
||||
__io_reads_ins(ins, u64, q, __io_pbr(), __io_par(addr))
|
||||
#define insq(addr, buffer, count) __insq(PCI_IOBASE + (addr), buffer, count)
|
||||
#endif
|
||||
|
||||
__io_writes_outs(writes, u64, q, __io_bw(), __io_aw())
|
||||
#define writesq(addr, buffer, count) __writesq(addr, buffer, count)
|
||||
|
||||
#ifdef CONFIG_HAS_IOPORT
|
||||
__io_writes_outs(outs, u64, q, __io_pbr(), __io_paw())
|
||||
#define outsq(addr, buffer, count) __outsq(PCI_IOBASE + (addr), buffer, count)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
|
||||
|
||||
@@ -209,13 +209,13 @@ struct kvm_vcpu_arch {
|
||||
/*
|
||||
* VCPU interrupts
|
||||
*
|
||||
* We have a lockless approach for tracking pending VCPU interrupts
|
||||
* implemented using atomic bitops. The irqs_pending bitmap represent
|
||||
* pending interrupts whereas irqs_pending_mask represent bits changed
|
||||
* in irqs_pending. Our approach is modeled around multiple producer
|
||||
* and single consumer problem where the consumer is the VCPU itself.
|
||||
* The irqs_pending bitmap represents pending interrupts whereas
|
||||
* irqs_pending_mask represents bits changed in irqs_pending. Updates
|
||||
* to these bitmaps are serialized so vcpu interrupt sync/flush cannot
|
||||
* drop a newly injected interrupt while syncing guest-visible HVIP.
|
||||
*/
|
||||
#define KVM_RISCV_VCPU_NR_IRQS 64
|
||||
raw_spinlock_t irqs_pending_lock;
|
||||
DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
|
||||
DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ SYM_CODE_START(handle_exception)
|
||||
.Lrestore_kernel_tpsp:
|
||||
csrr tp, CSR_SCRATCH
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_MMU)
|
||||
/*
|
||||
* The RISC-V kernel does not flush TLBs on all CPUS after each new
|
||||
* vmalloc mapping or kfence_unprotect(), which may result in
|
||||
|
||||
@@ -450,6 +450,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
|
||||
if (cpusetsize > cpumask_size())
|
||||
cpusetsize = cpumask_size();
|
||||
|
||||
cpumask_clear(&cpus);
|
||||
ret = copy_from_user(&cpus, cpus_user, cpusetsize);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
@@ -69,9 +69,9 @@ CPPFLAGS_$(vdso_lds) += -DHAS_VGETTIMEOFDAY
|
||||
endif
|
||||
|
||||
# Disable -pg to prevent insert call site
|
||||
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS)
|
||||
CFLAGS_REMOVE_getrandom.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS)
|
||||
CFLAGS_REMOVE_hwprobe.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS)
|
||||
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_LTO)
|
||||
CFLAGS_REMOVE_getrandom.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_LTO)
|
||||
CFLAGS_REMOVE_hwprobe.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_LTO)
|
||||
|
||||
# Force dependency
|
||||
$(obj)/$(vdso_o): $(obj)/$(vdso_so)
|
||||
|
||||
@@ -7,11 +7,19 @@
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
/*
|
||||
* WARNING: Do NOT add a CFI landing pad at the start of this function.
|
||||
* Unwinders such as libgcc identify the sigreturn trampoline by matching the
|
||||
* instruction sequence. Adding a landing pad here would break unwinding from
|
||||
* signal handlers.
|
||||
*
|
||||
* This trampoline is used only for signal return and not via an indirect
|
||||
* call/jump from userspace, so adding CFI landing pad is unnecessary.
|
||||
*/
|
||||
.text
|
||||
SYM_FUNC_START(__vdso_rt_sigreturn)
|
||||
.cfi_startproc
|
||||
.cfi_signal_frame
|
||||
vdso_lpad
|
||||
li a7, __NR_rt_sigreturn
|
||||
ecall
|
||||
.cfi_endproc
|
||||
|
||||
@@ -53,12 +53,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
unsigned long mask, val;
|
||||
|
||||
lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
|
||||
|
||||
if (!kvm_riscv_aia_available())
|
||||
return;
|
||||
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
|
||||
mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
|
||||
val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
|
||||
mask = vcpu->arch.irqs_pending_mask[1];
|
||||
if (mask) {
|
||||
vcpu->arch.irqs_pending_mask[1] = 0;
|
||||
val = vcpu->arch.irqs_pending[1] & mask;
|
||||
|
||||
csr->hviph &= ~mask;
|
||||
csr->hviph |= val;
|
||||
@@ -69,6 +72,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
|
||||
lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
|
||||
|
||||
if (kvm_riscv_aia_available())
|
||||
csr->vsieh = ncsr_read(CSR_VSIEH);
|
||||
}
|
||||
@@ -77,13 +82,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
|
||||
bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
||||
{
|
||||
unsigned long seip;
|
||||
#ifdef CONFIG_32BIT
|
||||
unsigned long flags;
|
||||
bool pending;
|
||||
#endif
|
||||
|
||||
if (!kvm_riscv_aia_available())
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending[1]) &
|
||||
(vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask)))
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
pending = vcpu->arch.irqs_pending[1] &
|
||||
(vcpu->arch.aia_context.guest_csr.vsieh &
|
||||
upper_32_bits(mask));
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
if (pending)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -207,6 +221,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
|
||||
#ifdef CONFIG_32BIT
|
||||
unsigned long flags;
|
||||
#endif
|
||||
|
||||
if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
|
||||
return -ENOENT;
|
||||
@@ -219,8 +236,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
|
||||
((unsigned long *)csr)[reg_num] = val;
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
|
||||
WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
|
||||
if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
vcpu->arch.irqs_pending_mask[1] = 0;
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
|
||||
flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/kvm_gstage.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
unsigned long kvm_riscv_gstage_max_pgd_levels __ro_after_init = 3;
|
||||
@@ -171,8 +173,10 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage,
|
||||
}
|
||||
|
||||
if (pte_val(*ptep) != pte_val(map->pte)) {
|
||||
bool was_invalid = !pte_val(*ptep);
|
||||
set_pte(ptep, map->pte);
|
||||
if (gstage_pte_leaf(ptep))
|
||||
if (gstage_pte_leaf(ptep) &&
|
||||
!(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)))
|
||||
gstage_tlb_flush(gstage, current_level, map->addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa,
|
||||
pgprot_t prot;
|
||||
unsigned long pfn;
|
||||
phys_addr_t addr, end;
|
||||
unsigned long pgd_levels = kvm->arch.pgd_levels;
|
||||
struct kvm_mmu_memory_cache pcache = {
|
||||
.gfp_custom = (in_atomic) ? GFP_ATOMIC | __GFP_ACCOUNT : 0,
|
||||
.gfp_zero = __GFP_ZERO,
|
||||
@@ -63,7 +64,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa,
|
||||
if (!writable)
|
||||
map.pte = pte_wrprotect(map.pte);
|
||||
|
||||
ret = kvm_mmu_topup_memory_cache(&pcache, kvm->arch.pgd_levels);
|
||||
ret = __kvm_mmu_topup_memory_cache(&pcache, pgd_levels, pgd_levels);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu *vcpu,
|
||||
|
||||
static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool loaded;
|
||||
|
||||
/**
|
||||
@@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
|
||||
|
||||
kvm_riscv_vcpu_aia_reset(vcpu);
|
||||
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
|
||||
bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
kvm_riscv_vcpu_pmu_reset(vcpu);
|
||||
|
||||
@@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
|
||||
/* Setup VCPU hfence queue */
|
||||
spin_lock_init(&vcpu->arch.hfence_lock);
|
||||
raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
|
||||
|
||||
spin_lock_init(&vcpu->arch.reset_state.lock);
|
||||
|
||||
@@ -352,10 +356,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
unsigned long mask, val;
|
||||
unsigned long flags;
|
||||
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
|
||||
mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
|
||||
val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
mask = vcpu->arch.irqs_pending_mask[0];
|
||||
if (mask) {
|
||||
vcpu->arch.irqs_pending_mask[0] = 0;
|
||||
val = vcpu->arch.irqs_pending[0] & mask;
|
||||
|
||||
csr->hvip &= ~mask;
|
||||
csr->hvip |= val;
|
||||
@@ -363,11 +371,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
|
||||
|
||||
/* Flush AIA high interrupts */
|
||||
kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long hvip;
|
||||
unsigned long flags;
|
||||
struct kvm_vcpu_arch *v = &vcpu->arch;
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
|
||||
@@ -376,34 +387,41 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
|
||||
|
||||
/* Sync-up HVIP.VSSIP bit changes does by Guest */
|
||||
hvip = ncsr_read(CSR_HVIP);
|
||||
|
||||
raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
|
||||
|
||||
if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
|
||||
if (hvip & (1UL << IRQ_VS_SOFT)) {
|
||||
if (!test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
set_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
if (!__test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
__set_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
} else {
|
||||
if (!test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
clear_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
if (!__test_and_set_bit(IRQ_VS_SOFT,
|
||||
v->irqs_pending_mask))
|
||||
__clear_bit(IRQ_VS_SOFT, v->irqs_pending);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */
|
||||
if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) {
|
||||
if (!(hvip & (1UL << IRQ_PMU_OVF)) &&
|
||||
!test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
|
||||
clear_bit(IRQ_PMU_OVF, v->irqs_pending);
|
||||
!__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
|
||||
__clear_bit(IRQ_PMU_OVF, v->irqs_pending);
|
||||
}
|
||||
|
||||
/* Sync-up AIA high interrupts */
|
||||
kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
|
||||
|
||||
/* Sync-up timer CSRs */
|
||||
kvm_riscv_vcpu_timer_sync(vcpu);
|
||||
}
|
||||
|
||||
int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* We only allow VS-mode software, timer, and external
|
||||
* interrupts when irq is one of the local interrupts
|
||||
@@ -416,9 +434,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
irq != IRQ_PMU_OVF)
|
||||
return -EINVAL;
|
||||
|
||||
set_bit(irq, vcpu->arch.irqs_pending);
|
||||
smp_mb__before_atomic();
|
||||
set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
__set_bit(irq, vcpu->arch.irqs_pending);
|
||||
__set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
kvm_vcpu_kick(vcpu);
|
||||
|
||||
@@ -427,6 +446,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
|
||||
int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* We only allow VS-mode software, timer, counter overflow and external
|
||||
* interrupts when irq is one of the local interrupts
|
||||
@@ -439,26 +460,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
|
||||
irq != IRQ_PMU_OVF)
|
||||
return -EINVAL;
|
||||
|
||||
clear_bit(irq, vcpu->arch.irqs_pending);
|
||||
smp_mb__before_atomic();
|
||||
set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
__clear_bit(irq, vcpu->arch.irqs_pending);
|
||||
__set_bit(irq, vcpu->arch.irqs_pending_mask);
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long ie;
|
||||
bool ret;
|
||||
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
|
||||
<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
|
||||
ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
|
||||
(unsigned long)mask;
|
||||
if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie)
|
||||
return true;
|
||||
ret = vcpu->arch.irqs_pending[0] & ie;
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
|
||||
/* Check AIA high interrupts */
|
||||
return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
|
||||
if (!ret)
|
||||
ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
|
||||
|
||||
@@ -38,6 +38,25 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
return kvm_riscv_vcpu_mmio_store(vcpu, run,
|
||||
fault_addr,
|
||||
trap->htinst);
|
||||
case EXC_INST_GUEST_PAGE_FAULT: {
|
||||
/*
|
||||
* No memslot backs this GPA and an instruction fetch
|
||||
* cannot be emulated as MMIO. On bare metal a fetch
|
||||
* from an unbacked physical address raises an
|
||||
* instruction access fault, so reflect that back to
|
||||
* the guest.
|
||||
*/
|
||||
struct kvm_cpu_trap inst_trap = {
|
||||
.sepc = trap->sepc,
|
||||
.scause = EXC_INST_ACCESS,
|
||||
.stval = trap->stval,
|
||||
.htval = 0,
|
||||
.htinst = 0,
|
||||
};
|
||||
|
||||
kvm_riscv_vcpu_trap_redirect(vcpu, &inst_trap);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
};
|
||||
|
||||
@@ -50,19 +50,13 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu,
|
||||
reg_val = vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOM))
|
||||
return -ENOENT;
|
||||
reg_val = riscv_cbom_block_size;
|
||||
reg_val = (kvm_riscv_isa_check_host(ZICBOM)) ? 0 : riscv_cbom_block_size;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOZ))
|
||||
return -ENOENT;
|
||||
reg_val = riscv_cboz_block_size;
|
||||
reg_val = (kvm_riscv_isa_check_host(ZICBOZ)) ? 0 : riscv_cboz_block_size;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOP))
|
||||
return -ENOENT;
|
||||
reg_val = riscv_cbop_block_size;
|
||||
reg_val = (kvm_riscv_isa_check_host(ZICBOP)) ? 0 : riscv_cbop_block_size;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(mvendorid):
|
||||
reg_val = vcpu->arch.mvendorid;
|
||||
@@ -144,21 +138,15 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOM))
|
||||
return -ENOENT;
|
||||
if (reg_val != riscv_cbom_block_size)
|
||||
if (reg_val && reg_val != riscv_cbom_block_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOZ))
|
||||
return -ENOENT;
|
||||
if (reg_val != riscv_cboz_block_size)
|
||||
if (reg_val && reg_val != riscv_cboz_block_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(zicbop_block_size):
|
||||
if (kvm_riscv_isa_check_host(ZICBOP))
|
||||
return -ENOENT;
|
||||
if (reg_val != riscv_cbop_block_size)
|
||||
if (reg_val && reg_val != riscv_cbop_block_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case KVM_REG_RISCV_CONFIG_REG(mvendorid):
|
||||
@@ -298,6 +286,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
|
||||
unsigned long flags;
|
||||
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
@@ -311,8 +300,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
|
||||
|
||||
((unsigned long *)csr)[reg_num] = reg_val;
|
||||
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
|
||||
WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
vcpu->arch.irqs_pending_mask[0] = 0;
|
||||
raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -614,20 +606,6 @@ static int copy_config_reg_indices(const struct kvm_vcpu *vcpu,
|
||||
u64 size;
|
||||
u64 reg;
|
||||
|
||||
/*
|
||||
* Avoid reporting config reg if the corresponding extension
|
||||
* was not available.
|
||||
*/
|
||||
if (i == KVM_REG_RISCV_CONFIG_REG(zicbom_block_size) &&
|
||||
kvm_riscv_isa_check_host(ZICBOM))
|
||||
continue;
|
||||
else if (i == KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) &&
|
||||
kvm_riscv_isa_check_host(ZICBOZ))
|
||||
continue;
|
||||
else if (i == KVM_REG_RISCV_CONFIG_REG(zicbop_block_size) &&
|
||||
kvm_riscv_isa_check_host(ZICBOP))
|
||||
continue;
|
||||
|
||||
size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
|
||||
reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CONFIG | i;
|
||||
|
||||
|
||||
@@ -586,7 +586,7 @@ int kvm_riscv_vcpu_pmu_ctr_start(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
||||
}
|
||||
}
|
||||
/* Start the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
for_each_set_bit(i, &ctr_mask, BITS_PER_LONG) {
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
@@ -658,7 +658,7 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
||||
}
|
||||
|
||||
/* Stop the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
for_each_set_bit(i, &ctr_mask, BITS_PER_LONG) {
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
|
||||
@@ -327,9 +327,11 @@ static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature,
|
||||
if (conf->flags & SBI_FWFT_SET_FLAG_LOCK)
|
||||
return SBI_ERR_DENIED_LOCKED;
|
||||
|
||||
conf->flags = flags;
|
||||
ret = conf->feature->set(vcpu, conf, false, value);
|
||||
if (ret == SBI_SUCCESS)
|
||||
conf->flags = flags;
|
||||
|
||||
return conf->feature->set(vcpu, conf, false, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/kvm_isa.h>
|
||||
@@ -129,11 +130,20 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu,
|
||||
return -ENOENT;
|
||||
}
|
||||
} else if (reg_num <= KVM_REG_RISCV_VECTOR_REG(31)) {
|
||||
unsigned long reg_offset;
|
||||
|
||||
if (reg_size != vlenb)
|
||||
return -EINVAL;
|
||||
WARN_ON(!cntx->vector.datap);
|
||||
*reg_addr = cntx->vector.datap +
|
||||
(reg_num - KVM_REG_RISCV_VECTOR_REG(0)) * vlenb;
|
||||
/*
|
||||
* The reg_num is derived from the userspace-provided ONE_REG
|
||||
* id. Sanitize it with array_index_nospec() to prevent
|
||||
* speculative out-of-bounds access to the vector register
|
||||
* buffer (32 vector registers: v0..v31).
|
||||
*/
|
||||
reg_offset = array_index_nospec(
|
||||
reg_num - KVM_REG_RISCV_VECTOR_REG(0), 32);
|
||||
*reg_addr = cntx->vector.datap + reg_offset * vlenb;
|
||||
} else {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
|
||||
#include "../kernel/head.h"
|
||||
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_MMU)
|
||||
DECLARE_BITMAP(new_valid_map_cpus, NR_CPUS);
|
||||
#endif
|
||||
|
||||
struct kernel_mapping kernel_map __ro_after_init;
|
||||
EXPORT_SYMBOL(kernel_map);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include <asm/cpu_mf.h>
|
||||
#include <asm/hwctrset.h>
|
||||
@@ -768,6 +769,7 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
|
||||
if (!is_userspace_event(ev)) {
|
||||
if (ev >= ARRAY_SIZE(cpumf_generic_events_user))
|
||||
return -EOPNOTSUPP;
|
||||
ev = array_index_nospec(ev, ARRAY_SIZE(cpumf_generic_events_user));
|
||||
ev = cpumf_generic_events_user[ev];
|
||||
}
|
||||
} else if (!attr->exclude_kernel && attr->exclude_user) {
|
||||
@@ -778,6 +780,7 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
|
||||
if (!is_userspace_event(ev)) {
|
||||
if (ev >= ARRAY_SIZE(cpumf_generic_events_basic))
|
||||
return -EOPNOTSUPP;
|
||||
ev = array_index_nospec(ev, ARRAY_SIZE(cpumf_generic_events_basic));
|
||||
ev = cpumf_generic_events_basic[ev];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier);
|
||||
EXPORT_SYMBOL(s390_epoch_delta_notifier);
|
||||
|
||||
unsigned char ptff_function_mask[16];
|
||||
EXPORT_SYMBOL(ptff_function_mask);
|
||||
|
||||
static unsigned long lpar_offset;
|
||||
static unsigned long initial_leap_seconds;
|
||||
|
||||
@@ -23,7 +23,7 @@ static __always_inline __wsum csum_copy(void *dst, const void *src, int len, __w
|
||||
if (!cpu_has_vx()) {
|
||||
if (copy)
|
||||
memcpy(dst, src, len);
|
||||
return cksm(dst, len, sum);
|
||||
return cksm(src, len, sum);
|
||||
}
|
||||
kernel_fpu_begin(&vxstate, KERNEL_VXR_V16V23);
|
||||
fpu_vlvgf(16, (__force u32)sum, 1);
|
||||
|
||||
@@ -184,10 +184,15 @@ static unsigned long get_cmdline_acpi_rsdp(void)
|
||||
char val[MAX_ADDR_LEN] = { };
|
||||
int ret;
|
||||
|
||||
ret = cmdline_find_option("acpi_rsdp", val, MAX_ADDR_LEN);
|
||||
ret = cmdline_find_option("acpi_rsdp", val, sizeof(val));
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (ret >= sizeof(val)) {
|
||||
warn("acpi_rsdp= value too long; ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (boot_kstrtoul(val, 16, &addr))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -117,7 +117,7 @@ static unsigned int probe_baud(int port)
|
||||
static void parse_console_uart8250(void)
|
||||
{
|
||||
char optstr[64], *options;
|
||||
int baud = DEFAULT_BAUD;
|
||||
int baud;
|
||||
int port = 0;
|
||||
|
||||
/*
|
||||
@@ -136,10 +136,13 @@ static void parse_console_uart8250(void)
|
||||
else
|
||||
return;
|
||||
|
||||
if (options && (options[0] == ','))
|
||||
baud = simple_strtoull(options + 1, &options, 0);
|
||||
else
|
||||
if (options && (options[0] == ',')) {
|
||||
baud = simple_strtoull(options + 1, NULL, 0);
|
||||
if (!baud)
|
||||
baud = DEFAULT_BAUD;
|
||||
} else {
|
||||
baud = probe_baud(port);
|
||||
}
|
||||
|
||||
if (port)
|
||||
early_serial_init(port, baud);
|
||||
|
||||
@@ -46,7 +46,6 @@ obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
|
||||
obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
||||
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
|
||||
obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
|
||||
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
|
||||
obj-$(CONFIG_CPU_SUP_ZHAOXIN) += zhaoxin.o
|
||||
obj-$(CONFIG_CPU_SUP_VORTEX_32) += vortex.o
|
||||
|
||||
|
||||
@@ -2052,7 +2052,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn)
|
||||
if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
|
||||
ktimer->expired_tscdeadline = ktimer->tscdeadline;
|
||||
|
||||
if (!from_timer_fn && apic->apicv_active) {
|
||||
if (!from_timer_fn && apic->apicv_active && vcpu->wants_to_run) {
|
||||
WARN_ON(kvm_get_running_vcpu() != vcpu);
|
||||
kvm_apic_inject_pending_timer_irqs(apic);
|
||||
return;
|
||||
|
||||
@@ -2642,6 +2642,7 @@ static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,
|
||||
*/
|
||||
if (tdp_enabled && invalid_list &&
|
||||
child->role.guest_mode &&
|
||||
!child->root_count &&
|
||||
!atomic_long_read(&child->parent_ptes.val))
|
||||
return kvm_mmu_prepare_zap_page(kvm, child,
|
||||
invalid_list);
|
||||
@@ -4852,16 +4853,17 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
if (r != RET_PF_CONTINUE)
|
||||
return r;
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault))
|
||||
goto out_unlock;
|
||||
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault)) {
|
||||
r = RET_PF_RETRY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
r = direct_map(vcpu, fault);
|
||||
|
||||
out_unlock:
|
||||
@@ -7574,7 +7576,9 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen)
|
||||
static void mmu_destroy_caches(void)
|
||||
{
|
||||
kmem_cache_destroy(pte_list_desc_cache);
|
||||
pte_list_desc_cache = NULL;
|
||||
kmem_cache_destroy(mmu_page_header_cache);
|
||||
mmu_page_header_cache = NULL;
|
||||
}
|
||||
|
||||
static void kvm_wake_nx_recovery_thread(struct kvm *kvm)
|
||||
|
||||
@@ -864,15 +864,17 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
}
|
||||
#endif
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault))
|
||||
goto out_unlock;
|
||||
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault)) {
|
||||
r = RET_PF_RETRY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
r = FNAME(fetch)(vcpu, fault, &walker);
|
||||
|
||||
out_unlock:
|
||||
|
||||
@@ -336,6 +336,7 @@ static void nested_put_vmcs12_pages(struct kvm_vcpu *vcpu)
|
||||
static void free_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
struct vmcs *shadow_vmcs;
|
||||
|
||||
if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01))
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
@@ -353,9 +354,15 @@ static void free_nested(struct kvm_vcpu *vcpu)
|
||||
vmx->nested.current_vmptr = INVALID_GPA;
|
||||
if (enable_shadow_vmcs) {
|
||||
vmx_disable_shadow_vmcs(vmx);
|
||||
vmcs_clear(vmx->vmcs01.shadow_vmcs);
|
||||
free_vmcs(vmx->vmcs01.shadow_vmcs);
|
||||
|
||||
/*
|
||||
* Keep the pointer visible until after VMCLEAR, so migration
|
||||
* can clear an active shadow VMCS on the old CPU.
|
||||
*/
|
||||
shadow_vmcs = vmx->vmcs01.shadow_vmcs;
|
||||
vmcs_clear(shadow_vmcs);
|
||||
vmx->vmcs01.shadow_vmcs = NULL;
|
||||
free_vmcs(shadow_vmcs);
|
||||
}
|
||||
kfree(vmx->nested.cached_vmcs12);
|
||||
vmx->nested.cached_vmcs12 = NULL;
|
||||
|
||||
64
block/bio.c
64
block/bio.c
@@ -555,6 +555,14 @@ struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
|
||||
bio = bio_alloc_percpu_cache(bs);
|
||||
} else {
|
||||
opf &= ~REQ_ALLOC_CACHE;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a bioset without a percpu cache, or when the percpu cache was
|
||||
* empty, try a slab allocation with optimistic GFP_ flags before
|
||||
* falling back to the mempool.
|
||||
*/
|
||||
if (!bio) {
|
||||
p = kmem_cache_alloc(bs->bio_slab, gfp);
|
||||
if (p)
|
||||
bio = p + bs->front_pad;
|
||||
@@ -1191,7 +1199,7 @@ void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter)
|
||||
* for the next iteration.
|
||||
*/
|
||||
static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
|
||||
unsigned len_align_mask)
|
||||
struct bio_vec *bv, unsigned len_align_mask)
|
||||
{
|
||||
size_t nbytes = bio->bi_iter.bi_size & len_align_mask;
|
||||
|
||||
@@ -1200,23 +1208,16 @@ static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
|
||||
|
||||
iov_iter_revert(iter, nbytes);
|
||||
bio->bi_iter.bi_size -= nbytes;
|
||||
do {
|
||||
struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
|
||||
|
||||
if (nbytes < bv->bv_len) {
|
||||
bv->bv_len -= nbytes;
|
||||
break;
|
||||
}
|
||||
|
||||
while (nbytes >= bv->bv_len) {
|
||||
if (bio_flagged(bio, BIO_PAGE_PINNED))
|
||||
unpin_user_page(bv->bv_page);
|
||||
|
||||
bio->bi_vcnt--;
|
||||
if (!--bio->bi_vcnt)
|
||||
return -EFAULT;
|
||||
nbytes -= bv->bv_len;
|
||||
} while (nbytes);
|
||||
|
||||
if (!bio->bi_vcnt)
|
||||
return -EFAULT;
|
||||
bv--;
|
||||
}
|
||||
bv->bv_len -= nbytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1276,7 +1277,8 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,
|
||||
|
||||
if (is_pci_p2pdma_page(bio->bi_io_vec->bv_page))
|
||||
bio->bi_opf |= REQ_NOMERGE;
|
||||
return bio_iov_iter_align_down(bio, iter, len_align_mask);
|
||||
return bio_iov_iter_align_down(bio, iter,
|
||||
&bio->bi_io_vec[bio->bi_vcnt - 1], len_align_mask);
|
||||
}
|
||||
|
||||
static struct folio *folio_alloc_greedy(gfp_t gfp, size_t *size,
|
||||
@@ -1285,7 +1287,8 @@ static struct folio *folio_alloc_greedy(gfp_t gfp, size_t *size,
|
||||
struct folio *folio;
|
||||
|
||||
while (*size > minsize) {
|
||||
folio = folio_alloc(gfp | __GFP_NORETRY, get_order(*size));
|
||||
folio = folio_alloc(gfp | __GFP_NORETRY | __GFP_NOWARN,
|
||||
get_order(*size));
|
||||
if (folio)
|
||||
return folio;
|
||||
*size = rounddown_pow_of_two(*size - 1);
|
||||
@@ -1302,7 +1305,7 @@ static void bio_free_folios(struct bio *bio)
|
||||
bio_for_each_bvec_all(bv, bio, i) {
|
||||
struct folio *folio = bvec_folio(bv);
|
||||
|
||||
if (!is_zero_folio(folio))
|
||||
if (!is_zero_folio(folio) && !is_huge_zero_folio(folio))
|
||||
folio_put(folio);
|
||||
}
|
||||
}
|
||||
@@ -1360,7 +1363,8 @@ static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter,
|
||||
|
||||
if (!bio->bi_iter.bi_size)
|
||||
return -ENOMEM;
|
||||
return bio_iov_iter_align_down(bio, iter, minsize - 1);
|
||||
return bio_iov_iter_align_down(bio, iter,
|
||||
&bio->bi_io_vec[bio->bi_vcnt - 1], minsize - 1);
|
||||
}
|
||||
|
||||
static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
|
||||
@@ -1368,21 +1372,18 @@ static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
|
||||
{
|
||||
size_t len = min3(iov_iter_count(iter), maxlen, SZ_1M);
|
||||
struct folio *folio;
|
||||
ssize_t ret;
|
||||
|
||||
folio = folio_alloc_greedy(GFP_KERNEL, &len, minsize);
|
||||
if (!folio)
|
||||
return -ENOMEM;
|
||||
|
||||
do {
|
||||
ssize_t ret;
|
||||
|
||||
ret = iov_iter_extract_bvecs(iter, bio->bi_io_vec + 1, len,
|
||||
&bio->bi_vcnt, bio->bi_max_vecs - 1, 0);
|
||||
if (ret <= 0) {
|
||||
if (!bio->bi_vcnt) {
|
||||
folio_put(folio);
|
||||
return ret;
|
||||
}
|
||||
if (!bio->bi_vcnt)
|
||||
goto out_folio_put;
|
||||
break;
|
||||
}
|
||||
len -= ret;
|
||||
@@ -1398,7 +1399,20 @@ static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
|
||||
bvec_set_folio(&bio->bi_io_vec[0], folio, bio->bi_iter.bi_size, 0);
|
||||
if (iov_iter_extract_will_pin(iter))
|
||||
bio_set_flag(bio, BIO_PAGE_PINNED);
|
||||
return bio_iov_iter_align_down(bio, iter, minsize - 1);
|
||||
|
||||
/* The first vec stores the bounce buffer, so do not subtract 1 here. */
|
||||
ret = bio_iov_iter_align_down(bio, iter,
|
||||
&bio->bi_io_vec[bio->bi_vcnt], minsize - 1);
|
||||
if (ret)
|
||||
goto out_folio_put;
|
||||
|
||||
/* Update the bounc buffer bv_len to the aligned down size. */
|
||||
bio->bi_io_vec[0].bv_len = bio->bi_iter.bi_size;
|
||||
return 0;
|
||||
|
||||
out_folio_put:
|
||||
folio_put(folio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -434,15 +434,15 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
|
||||
blkg->pd[i]->online = true;
|
||||
}
|
||||
}
|
||||
blkg->online = true;
|
||||
}
|
||||
blkg->online = true;
|
||||
spin_unlock(&blkcg->lock);
|
||||
|
||||
if (!ret)
|
||||
return blkg;
|
||||
|
||||
/* @blkg failed fully initialized, use the usual release path */
|
||||
blkg_put(blkg);
|
||||
percpu_ref_kill(&blkg->refcnt);
|
||||
return ERR_PTR(ret);
|
||||
|
||||
err_free_blkg:
|
||||
|
||||
@@ -653,6 +653,7 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
unsigned long addr = (unsigned long) kbuf;
|
||||
bool do_copy;
|
||||
struct bio *bio;
|
||||
int ret;
|
||||
|
||||
@@ -661,7 +662,8 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
|
||||
if (!len || !kbuf)
|
||||
return -EINVAL;
|
||||
|
||||
if (!blk_rq_aligned(rq->q, addr, len) || object_is_on_stack(kbuf))
|
||||
do_copy = !blk_rq_aligned(rq->q, addr, len) || object_is_on_stack(kbuf);
|
||||
if (do_copy)
|
||||
bio = bio_copy_kern(rq, kbuf, len, gfp_mask);
|
||||
else
|
||||
bio = bio_map_kern(rq, kbuf, len, gfp_mask);
|
||||
@@ -670,8 +672,11 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
|
||||
return PTR_ERR(bio);
|
||||
|
||||
ret = blk_rq_append_bio(rq, bio);
|
||||
if (unlikely(ret))
|
||||
if (unlikely(ret)) {
|
||||
if (do_copy)
|
||||
bio_free_pages(bio);
|
||||
blk_mq_map_bio_put(bio);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_rq_map_kern);
|
||||
|
||||
13
block/blk.h
13
block/blk.h
@@ -717,6 +717,7 @@ static inline int req_ref_read(struct request *req)
|
||||
static inline u64 blk_time_get_ns(void)
|
||||
{
|
||||
struct blk_plug *plug = current->plug;
|
||||
u64 now;
|
||||
|
||||
if (!plug || !in_task())
|
||||
return ktime_get_ns();
|
||||
@@ -725,12 +726,18 @@ static inline u64 blk_time_get_ns(void)
|
||||
* 0 could very well be a valid time, but rather than flag "this is
|
||||
* a valid timestamp" separately, just accept that we'll do an extra
|
||||
* ktime_get_ns() if we just happen to get 0 as the current time.
|
||||
*
|
||||
* cur_ktime can be zeroed by pre-emption the moment PF_BLOCK_TS is set.
|
||||
*/
|
||||
if (!plug->cur_ktime) {
|
||||
plug->cur_ktime = ktime_get_ns();
|
||||
now = READ_ONCE(plug->cur_ktime);
|
||||
if (!now) {
|
||||
now = ktime_get_ns();
|
||||
WRITE_ONCE(plug->cur_ktime, now);
|
||||
/* Ensure PF_BLOCK_TS is set after cur_ktime. */
|
||||
barrier();
|
||||
current->flags |= PF_BLOCK_TS;
|
||||
}
|
||||
return plug->cur_ktime;
|
||||
return now;
|
||||
}
|
||||
|
||||
static inline ktime_t blk_time_get(void)
|
||||
|
||||
@@ -812,8 +812,13 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
||||
* reference during concurrent disk deletion:
|
||||
* update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
|
||||
* kn->active -> update_nr_hwq_lock (via this sysfs write path)
|
||||
*
|
||||
* Use the writer lock instead of the reader lock of update_nr_hwq_lock
|
||||
* to serialize the two-stage elevator switch steps in
|
||||
* elevator_change(): the core switch step under the elevator lock and
|
||||
* the elevator_change_done() step outside the elevator lock.
|
||||
*/
|
||||
if (!down_read_trylock(&set->update_nr_hwq_lock)) {
|
||||
if (!down_write_trylock(&set->update_nr_hwq_lock)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@@ -824,7 +829,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
||||
} else {
|
||||
ret = -ENOENT;
|
||||
}
|
||||
up_read(&set->update_nr_hwq_lock);
|
||||
up_write(&set->update_nr_hwq_lock);
|
||||
|
||||
out:
|
||||
if (ctx.type)
|
||||
|
||||
@@ -276,9 +276,10 @@ static int blk_error_injection_show(struct seq_file *s, void *private)
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(inj, &disk->error_injection_list, entry) {
|
||||
seq_printf(s, "%llu:%llu status=%s,chance=%u",
|
||||
inj->start, inj->end,
|
||||
blk_status_to_tag(inj->status), inj->chance);
|
||||
seq_printf(s, "%llu:%llu op=%s,status=%s,chance=%u",
|
||||
inj->start, inj->end,
|
||||
blk_op_str(inj->op),
|
||||
blk_status_to_tag(inj->status), inj->chance);
|
||||
seq_putc(s, '\n');
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -208,7 +208,14 @@ int aix_partition(struct parsed_partitions *state)
|
||||
if (n) {
|
||||
int foundlvs = 0;
|
||||
|
||||
for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) {
|
||||
/*
|
||||
* The lvd array was read as a single sector; only the
|
||||
* struct lvd entries that fit in it are valid. Bound the
|
||||
* scan so an on-disk numlvs larger than that cannot walk
|
||||
* the read buffer out of bounds.
|
||||
*/
|
||||
for (i = 0; foundlvs < numlvs && i < state->limit &&
|
||||
i < SECTOR_SIZE / (int)sizeof(struct lvd); i++) {
|
||||
lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps);
|
||||
if (lvip[i].pps_per_lv)
|
||||
foundlvs += 1;
|
||||
|
||||
@@ -43,20 +43,22 @@ struct aie2_ctx_health {
|
||||
|
||||
static inline void aie2_tdr_signal(struct amdxdna_dev *xdna)
|
||||
{
|
||||
WRITE_ONCE(xdna->dev_handle->tdr_status, AIE2_TDR_SIGNALED);
|
||||
WRITE_ONCE(xdna->dev_handle->last_signal_ts, jiffies);
|
||||
}
|
||||
|
||||
static bool aie2_tdr_detect(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
unsigned long last = READ_ONCE(ndev->last_signal_ts);
|
||||
|
||||
if (READ_ONCE(ndev->tdr_status) == AIE2_TDR_WAIT) {
|
||||
XDNA_ERR(xdna, "TDR timeout detected");
|
||||
return true;
|
||||
}
|
||||
if (!tdr_timeout_ms)
|
||||
return false;
|
||||
|
||||
WRITE_ONCE(ndev->tdr_status, AIE2_TDR_WAIT);
|
||||
return false;
|
||||
if (!time_after(jiffies, last + msecs_to_jiffies(tdr_timeout_ms)))
|
||||
return false;
|
||||
|
||||
XDNA_ERR(xdna, "TDR timeout detected");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void aie2_cmd_release(struct kref *ref)
|
||||
@@ -434,6 +436,12 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
||||
mmput(job->mm);
|
||||
fence = ERR_PTR(ret);
|
||||
} else {
|
||||
/*
|
||||
* Command is successfully posted to hardware, update the
|
||||
* tdr timestamp. The total pending commands are limited.
|
||||
* So there will not be a case that driver keeps posting
|
||||
* commands without getting any hardware respond.
|
||||
*/
|
||||
aie2_tdr_signal(hwctx->client->xdna);
|
||||
}
|
||||
trace_xdna_job(sched_job, hwctx->name, "sent to device",
|
||||
@@ -658,7 +666,9 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
const struct drm_sched_init_args args = {
|
||||
.ops = &sched_ops,
|
||||
.credit_limit = HWCTX_MAX_CMDS,
|
||||
.timeout = msecs_to_jiffies(tdr_timeout_ms),
|
||||
.timeout = tdr_timeout_ms ?
|
||||
msecs_to_jiffies(tdr_timeout_ms) :
|
||||
MAX_SCHEDULE_TIMEOUT,
|
||||
.name = "amdxdna_js",
|
||||
.dev = xdna->ddev.dev,
|
||||
};
|
||||
|
||||
@@ -420,6 +420,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
||||
goto stop_fw;
|
||||
}
|
||||
|
||||
WRITE_ONCE(ndev->last_signal_ts, jiffies);
|
||||
ndev->dev_status = AIE2_DEV_START;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -143,11 +143,6 @@ struct aie2_exec_msg_ops {
|
||||
u32 (*get_chain_msg_op)(u32 cmd_op);
|
||||
};
|
||||
|
||||
enum aie2_tdr_status {
|
||||
AIE2_TDR_WAIT,
|
||||
AIE2_TDR_SIGNALED,
|
||||
};
|
||||
|
||||
struct amdxdna_dev_hdl {
|
||||
struct aie_device aie;
|
||||
const struct amdxdna_dev_priv *priv;
|
||||
@@ -179,7 +174,7 @@ struct amdxdna_dev_hdl {
|
||||
u32 hwctx_num;
|
||||
|
||||
struct amdxdna_async_error last_async_err;
|
||||
enum aie2_tdr_status tdr_status;
|
||||
unsigned long last_signal_ts;
|
||||
};
|
||||
|
||||
struct aie2_hw_ops {
|
||||
|
||||
@@ -577,6 +577,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job)
|
||||
amdxdna_arg_bos_put(job);
|
||||
amdxdna_gem_put_obj(job->cmd_bo);
|
||||
dma_fence_put(job->fence);
|
||||
mmdrop(job->mm);
|
||||
}
|
||||
|
||||
int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
@@ -590,6 +591,10 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
int ret, idx;
|
||||
|
||||
XDNA_DBG(xdna, "Command BO hdl %d, Arg BO count %d", cmd_bo_hdl, arg_bo_cnt);
|
||||
|
||||
if (!xdna->dev_info->ops->cmd_submit)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
job = kzalloc_flex(*job, bos, arg_bo_cnt);
|
||||
if (!job)
|
||||
return -ENOMEM;
|
||||
@@ -603,6 +608,16 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
ret = -EINVAL;
|
||||
goto free_job;
|
||||
}
|
||||
} else if (!drv_cmd) {
|
||||
/*
|
||||
* Only internal driver commands (drv_cmd != NULL) may omit a
|
||||
* command BO. A user command submission with the invalid handle
|
||||
* would leave job->cmd_bo NULL and later fault when the scheduler
|
||||
* dereferences it in amdxdna_cmd_set_state().
|
||||
*/
|
||||
XDNA_DBG(xdna, "Command BO handle required for user submission");
|
||||
ret = -EINVAL;
|
||||
goto free_job;
|
||||
}
|
||||
|
||||
ret = amdxdna_arg_bos_lookup(client, job, arg_bo_hdls, arg_bo_cnt);
|
||||
@@ -628,6 +643,7 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
|
||||
job->hwctx = hwctx;
|
||||
job->mm = current->mm;
|
||||
mmgrab(job->mm);
|
||||
|
||||
job->fence = amdxdna_fence_create(hwctx);
|
||||
if (!job->fence) {
|
||||
@@ -662,6 +678,8 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
cmd_put:
|
||||
amdxdna_gem_put_obj(job->cmd_bo);
|
||||
free_job:
|
||||
if (job->mm)
|
||||
mmdrop(job->mm);
|
||||
kfree(job);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -192,9 +192,17 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
|
||||
return len;
|
||||
}
|
||||
|
||||
static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
||||
static bool feat_matrix_chained(struct ethosu_device *edev, struct feat_matrix *fm)
|
||||
{
|
||||
u32 storage = fm->precision >> 14;
|
||||
|
||||
return !ethosu_is_u65(edev) && storage == 2;
|
||||
}
|
||||
|
||||
static u64 feat_matrix_length(struct ethosu_device *edev,
|
||||
struct ethosu_validated_cmdstream_info *info,
|
||||
struct feat_matrix *fm,
|
||||
u32 x, u32 y, u32 c)
|
||||
u32 x, u32 y, u32 c, bool ofm)
|
||||
{
|
||||
u32 element_size, storage = fm->precision >> 14;
|
||||
int tile = 0;
|
||||
@@ -203,6 +211,9 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
||||
if (fm->region < 0)
|
||||
return U64_MAX;
|
||||
|
||||
if (feat_matrix_chained(edev, fm))
|
||||
return 0;
|
||||
|
||||
switch (storage) {
|
||||
case 0:
|
||||
if (x >= fm->width0 + 1) {
|
||||
@@ -223,6 +234,8 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
||||
tile = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return U64_MAX;
|
||||
}
|
||||
if (fm->base[tile] == U64_MAX)
|
||||
return U64_MAX;
|
||||
@@ -231,10 +244,11 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
||||
|
||||
switch ((fm->precision >> 6) & 0x3) { // format
|
||||
case 0: //nhwc:
|
||||
addr += x * fm->stride_x + c;
|
||||
element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
|
||||
addr += x * fm->stride_x + c * element_size;
|
||||
break;
|
||||
case 1: //nhcwb16:
|
||||
element_size = BIT((fm->precision >> 1) & 0x3);
|
||||
element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
|
||||
|
||||
addr += (c / 16) * fm->stride_c + (16 * x + (c & 0xf)) * element_size;
|
||||
break;
|
||||
@@ -250,6 +264,7 @@ static int calc_sizes(struct drm_device *ddev,
|
||||
u16 op, struct cmd_state *st,
|
||||
bool ifm, bool ifm2, bool weight, bool scale)
|
||||
{
|
||||
struct ethosu_device *edev = to_ethosu_device(ddev);
|
||||
u64 len;
|
||||
|
||||
if (ifm) {
|
||||
@@ -267,8 +282,8 @@ static int calc_sizes(struct drm_device *ddev,
|
||||
if (ifm_height < 0 || ifm_width < 0)
|
||||
return -EINVAL;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm, ifm_width,
|
||||
ifm_height, st->ifm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm, ifm_width,
|
||||
ifm_height, st->ifm.depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm.region, st->ifm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
@@ -276,8 +291,8 @@ static int calc_sizes(struct drm_device *ddev,
|
||||
}
|
||||
|
||||
if (ifm2) {
|
||||
len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
|
||||
0, st->ofm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm2, st->ifm.depth,
|
||||
0, st->ofm.depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm2.region, st->ifm2.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
@@ -308,13 +323,14 @@ static int calc_sizes(struct drm_device *ddev,
|
||||
st->scale[0].base + st->scale[0].length);
|
||||
}
|
||||
|
||||
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth, true);
|
||||
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ofm.region, st->ofm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
return -EINVAL;
|
||||
info->output_region[st->ofm.region] = true;
|
||||
if (!feat_matrix_chained(edev, &st->ofm))
|
||||
info->output_region[st->ofm.region] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -324,6 +340,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
|
||||
u16 op, struct cmd_state *st,
|
||||
bool ifm, bool ifm2)
|
||||
{
|
||||
struct ethosu_device *edev = to_ethosu_device(ddev);
|
||||
u32 height, width, depth;
|
||||
u64 len;
|
||||
|
||||
@@ -332,8 +349,8 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
|
||||
width = st->ifm.broadcast & 0x2 ? 0 : st->ofm.width;
|
||||
depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm, width,
|
||||
height, depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm, width,
|
||||
height, depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm.region, st->ifm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
@@ -345,21 +362,22 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
|
||||
width = st->ifm2.broadcast & 0x2 ? 0 : st->ofm.width;
|
||||
depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm2, width,
|
||||
height, depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm2, width,
|
||||
height, depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm2.region, st->ifm2.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth, true);
|
||||
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ofm.region, st->ofm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
return -EINVAL;
|
||||
info->output_region[st->ofm.region] = true;
|
||||
if (!feat_matrix_chained(edev, &st->ofm))
|
||||
info->output_region[st->ofm.region] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (log->size < log->header_size) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) {
|
||||
ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
|
||||
return -EINVAL;
|
||||
|
||||
@@ -927,7 +927,7 @@ static void diagnose_failure_mtl(struct ivpu_device *vdev)
|
||||
|
||||
static void diagnose_failure_lnl(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
|
||||
|
||||
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, reg)) {
|
||||
ivpu_err(vdev, "ATS_ERR_LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n",
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/libata.h>
|
||||
@@ -226,7 +225,6 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev,
|
||||
struct sata_dwc_device *hsdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
hsdev->dma = devm_kzalloc(dev, sizeof(*hsdev->dma), GFP_KERNEL);
|
||||
if (!hsdev->dma)
|
||||
@@ -236,11 +234,9 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev,
|
||||
hsdev->dma->id = pdev->id;
|
||||
|
||||
/* Get SATA DMA interrupt number */
|
||||
hsdev->dma->irq = irq_of_parse_and_map(np, 1);
|
||||
if (!hsdev->dma->irq) {
|
||||
dev_err(dev, "no SATA DMA irq\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
hsdev->dma->irq = platform_get_irq(pdev, 1);
|
||||
if (hsdev->dma->irq < 0)
|
||||
return hsdev->dma->irq;
|
||||
|
||||
/* Get physical SATA DMA register base address */
|
||||
hsdev->dma->regs = devm_platform_ioremap_resource(pdev, 1);
|
||||
@@ -398,8 +394,7 @@ static void clear_serror(struct ata_port *ap)
|
||||
|
||||
static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
|
||||
{
|
||||
sata_dwc_writel(&hsdev->sata_dwc_regs->intpr,
|
||||
sata_dwc_readl(&hsdev->sata_dwc_regs->intpr));
|
||||
sata_dwc_writel(&hsdev->sata_dwc_regs->intpr, bit);
|
||||
}
|
||||
|
||||
static u32 qcmd_tag_to_mask(u8 tag)
|
||||
@@ -612,14 +607,9 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
|
||||
status = ap->ops->sff_check_status(ap);
|
||||
dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
|
||||
|
||||
tag = 0;
|
||||
while (tag_mask) {
|
||||
while (!(tag_mask & 0x00000001)) {
|
||||
tag++;
|
||||
tag_mask <<= 1;
|
||||
}
|
||||
|
||||
tag_mask &= (~0x00000001);
|
||||
tag = __ffs(tag_mask);
|
||||
tag_mask &= ~(1U << tag);
|
||||
qc = ata_qc_from_tag(ap, tag);
|
||||
if (unlikely(!qc)) {
|
||||
dev_err(ap->dev, "failed to get qc");
|
||||
@@ -1126,7 +1116,6 @@ static const struct ata_port_info sata_dwc_port_info[] = {
|
||||
static int sata_dwc_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device *dev = &ofdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct sata_dwc_device *hsdev;
|
||||
u32 idr, versionr;
|
||||
char *ver = (char *)&versionr;
|
||||
@@ -1169,18 +1158,13 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||
/* Save dev for later use in dev_xxx() routines */
|
||||
hsdev->dev = dev;
|
||||
|
||||
/* Enable SATA Interrupts */
|
||||
sata_dwc_enable_interrupts(hsdev);
|
||||
|
||||
/* Get SATA interrupt number */
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq) {
|
||||
dev_err(dev, "no SATA DMA irq\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = platform_get_irq(ofdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
#ifdef CONFIG_SATA_DWC_OLD_DMA
|
||||
if (!of_property_present(np, "dmas")) {
|
||||
if (!of_property_present(dev->of_node, "dmas")) {
|
||||
err = sata_dwc_dma_init_old(ofdev, hsdev);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -1204,6 +1188,8 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||
if (err)
|
||||
dev_err(dev, "failed to activate host");
|
||||
|
||||
/* Enable SATA Interrupts */
|
||||
sata_dwc_enable_interrupts(hsdev);
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
|
||||
@@ -1113,6 +1113,7 @@ static void __loop_clr_fd(struct loop_device *lo)
|
||||
struct queue_limits lim;
|
||||
struct file *filp;
|
||||
gfp_t gfp = lo->old_gfp_mask;
|
||||
int err;
|
||||
|
||||
spin_lock_irq(&lo->lo_lock);
|
||||
filp = lo->lo_backing_file;
|
||||
@@ -1146,26 +1147,21 @@ static void __loop_clr_fd(struct loop_device *lo)
|
||||
|
||||
disk_force_media_change(lo->lo_disk);
|
||||
|
||||
if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
|
||||
int err;
|
||||
|
||||
/*
|
||||
* open_mutex has been held already in release path, so don't
|
||||
* acquire it if this function is called in such case.
|
||||
*
|
||||
* If the reread partition isn't from release path, lo_refcnt
|
||||
* must be at least one and it can only become zero when the
|
||||
* current holder is released.
|
||||
*/
|
||||
err = bdev_disk_changed(lo->lo_disk, false);
|
||||
if (err)
|
||||
pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
|
||||
__func__, lo->lo_number, err);
|
||||
/* Device is gone, no point in returning error */
|
||||
}
|
||||
/*
|
||||
* Remove all partitions, including partitions added manually with
|
||||
* BLKPG, which may exist even if LO_FLAGS_PARTSCAN is not set.
|
||||
*
|
||||
* open_mutex has been held already in release path, so don't acquire
|
||||
* it here.
|
||||
*/
|
||||
err = bdev_disk_changed(lo->lo_disk, false);
|
||||
if (err)
|
||||
pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
|
||||
__func__, lo->lo_number, err);
|
||||
/* Device is gone, no point in returning error */
|
||||
|
||||
/*
|
||||
* lo->lo_state is set to Lo_unbound here after above partscan has
|
||||
* lo->lo_state is set to Lo_unbound here after removing partitions has
|
||||
* finished. There cannot be anybody else entering __loop_clr_fd() as
|
||||
* Lo_rundown state protects us from all the other places trying to
|
||||
* change the 'lo' device.
|
||||
|
||||
@@ -1950,9 +1950,14 @@ static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
|
||||
bool has_current_state;
|
||||
void *p;
|
||||
|
||||
if (osd_req->r_result)
|
||||
if (osd_req->r_result < 0)
|
||||
return osd_req->r_result;
|
||||
|
||||
/*
|
||||
* Writes aren't allowed to return a data payload.
|
||||
*/
|
||||
WARN_ON_ONCE(osd_req->r_result > 0);
|
||||
|
||||
/*
|
||||
* Nothing to do for a snapshot object map.
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/wait_bit.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/swap.h>
|
||||
@@ -26,7 +27,6 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
@@ -327,7 +327,6 @@ struct ublk_device {
|
||||
|
||||
struct ublk_params params;
|
||||
|
||||
struct completion completion;
|
||||
u32 nr_queue_ready;
|
||||
bool unprivileged_daemons;
|
||||
struct mutex cancel_mutex;
|
||||
@@ -3054,12 +3053,12 @@ static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id,
|
||||
if (ublk_dev_ready(ub)) {
|
||||
/*
|
||||
* All queues ready - clear device-level canceling flag
|
||||
* and complete the recovery/initialization.
|
||||
* and wake ublk_dev_ready() waiters.
|
||||
*/
|
||||
mutex_lock(&ub->cancel_mutex);
|
||||
ub->canceling = false;
|
||||
mutex_unlock(&ub->cancel_mutex);
|
||||
complete_all(&ub->completion);
|
||||
wake_up_var(&ub->nr_queue_ready);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4273,7 +4272,6 @@ static int ublk_init_queues(struct ublk_device *ub)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
init_completion(&ub->completion);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -4417,6 +4415,26 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)
|
||||
return ub->ublksrv_tgid == ublksrv_pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until all queues have fetched their I/O commands, and return with
|
||||
* ub->mutex held and readiness guaranteed: then every queue's ->canceling
|
||||
* is cleared. Ready may regress between wakeup and mutex_lock() (F_BATCH
|
||||
* UNPREP, daemon death), so re-check it under the mutex and wait again.
|
||||
*/
|
||||
static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub)
|
||||
{
|
||||
while (true) {
|
||||
if (wait_var_event_interruptible(&ub->nr_queue_ready,
|
||||
ublk_dev_ready(ub)))
|
||||
return -EINTR;
|
||||
|
||||
mutex_lock(&ub->mutex);
|
||||
if (ublk_dev_ready(ub))
|
||||
return 0;
|
||||
mutex_unlock(&ub->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int ublk_ctrl_start_dev(struct ublk_device *ub,
|
||||
const struct ublksrv_ctrl_cmd *header)
|
||||
{
|
||||
@@ -4499,15 +4517,10 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
|
||||
};
|
||||
}
|
||||
|
||||
if (wait_for_completion_interruptible(&ub->completion) != 0)
|
||||
if (ublk_wait_dev_ready_and_lock(ub))
|
||||
return -EINTR;
|
||||
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ub->mutex);
|
||||
/* device may become not ready in case of F_BATCH */
|
||||
if (!ublk_dev_ready(ub)) {
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
@@ -5071,7 +5084,6 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub)
|
||||
goto out_unlock;
|
||||
}
|
||||
pr_devel("%s: start recovery for dev id %d\n", __func__, ub->ub_number);
|
||||
init_completion(&ub->completion);
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&ub->mutex);
|
||||
@@ -5087,16 +5099,17 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
|
||||
pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__,
|
||||
header->dev_id);
|
||||
|
||||
if (wait_for_completion_interruptible(&ub->completion))
|
||||
if (ublk_wait_dev_ready_and_lock(ub))
|
||||
return -EINTR;
|
||||
|
||||
pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__,
|
||||
header->dev_id);
|
||||
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid))
|
||||
return -EINVAL;
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
mutex_lock(&ub->mutex);
|
||||
if (ublk_nosrv_should_stop_dev(ub))
|
||||
goto out_unlock;
|
||||
|
||||
|
||||
@@ -2782,7 +2782,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
|
||||
|
||||
static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
|
||||
if (skb->len >= HCI_EVENT_HDR_SIZE + 1 &&
|
||||
skb->data[0] == HCI_VENDOR_PKT &&
|
||||
skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
|
||||
struct rtk_dev_coredump_hdr hdr = {
|
||||
.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
|
||||
};
|
||||
|
||||
@@ -3187,6 +3187,7 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
|
||||
|
||||
/* set volume */
|
||||
cgc->buffer = buffer + offset - 8;
|
||||
cgc->buflen -= offset - 8;
|
||||
memset(cgc->buffer, 0, 8);
|
||||
return cdrom_mode_select(cdi, cgc);
|
||||
}
|
||||
|
||||
@@ -224,21 +224,22 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
|
||||
{
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct device *dev = ubuf->device->this_device;
|
||||
int ret = 0;
|
||||
|
||||
if (!ubuf->sg) {
|
||||
ubuf->sg = get_sg_table(dev, buf, direction);
|
||||
if (IS_ERR(ubuf->sg)) {
|
||||
int ret;
|
||||
|
||||
ret = PTR_ERR(ubuf->sg);
|
||||
ubuf->sg = NULL;
|
||||
return ret;
|
||||
} else {
|
||||
ubuf->sg_dir = direction;
|
||||
}
|
||||
} else {
|
||||
dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
|
||||
}
|
||||
|
||||
return ret;
|
||||
dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int end_cpu_udmabuf(struct dma_buf *buf,
|
||||
|
||||
@@ -372,19 +372,59 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/**
|
||||
* amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device
|
||||
* @adev: AMDGPU device
|
||||
* @vhdr: VFCT image header to check
|
||||
*
|
||||
* VFCT entries contain the PCI bus number as recorded during BIOS POST.
|
||||
* On systems where the kernel renumbers PCI buses (e.g. pci=realloc or
|
||||
* resource conflicts), the runtime bus number may differ from the POST
|
||||
* value. Match by device identity (vendor + device + function) and use
|
||||
* the bus number as a preference: exact bus match is preferred, but when
|
||||
* the bus numbers disagree we accept the entry if the device identity
|
||||
* matches.
|
||||
*
|
||||
* Returns: 0 on match, -ENODEV on no match
|
||||
*/
|
||||
static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev,
|
||||
VFCT_IMAGE_HEADER *vhdr)
|
||||
{
|
||||
/* Vendor and device IDs must always match */
|
||||
if (vhdr->VendorID != adev->pdev->vendor ||
|
||||
vhdr->DeviceID != adev->pdev->device)
|
||||
return -ENODEV;
|
||||
|
||||
if (vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
|
||||
vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn))
|
||||
return -ENODEV;
|
||||
|
||||
/* Exact bus number match - preferred */
|
||||
if (vhdr->PCIBus == adev->pdev->bus->number)
|
||||
return 0;
|
||||
|
||||
/* Bus mismatch but device identity matches (PCI renumbering case) */
|
||||
dev_notice(adev->dev,
|
||||
"VFCT bus number mismatch: table %u != runtime %u, matching by device identity (vendor 0x%04x device 0x%04x)\n",
|
||||
vhdr->PCIBus, adev->pdev->bus->number,
|
||||
adev->pdev->vendor, adev->pdev->device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
||||
{
|
||||
struct acpi_table_header *hdr;
|
||||
acpi_size tbl_size;
|
||||
UEFI_ACPI_VFCT *vfct;
|
||||
unsigned int offset;
|
||||
bool r = false;
|
||||
|
||||
if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
|
||||
return false;
|
||||
tbl_size = hdr->length;
|
||||
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
|
||||
dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n");
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vfct = (UEFI_ACPI_VFCT *)hdr;
|
||||
@@ -397,36 +437,36 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
||||
offset += sizeof(VFCT_IMAGE_HEADER);
|
||||
if (offset > tbl_size) {
|
||||
dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n");
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
offset += vhdr->ImageLength;
|
||||
if (offset > tbl_size) {
|
||||
dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vhdr->ImageLength &&
|
||||
vhdr->PCIBus == adev->pdev->bus->number &&
|
||||
vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
|
||||
vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
|
||||
vhdr->VendorID == adev->pdev->vendor &&
|
||||
vhdr->DeviceID == adev->pdev->device) {
|
||||
!amdgpu_acpi_vfct_match(adev, vhdr)) {
|
||||
adev->bios = kmemdup(&vbios->VbiosContent,
|
||||
vhdr->ImageLength,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!check_atom_bios(adev, vhdr->ImageLength)) {
|
||||
amdgpu_bios_release(adev);
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
adev->bios_size = vhdr->ImageLength;
|
||||
return true;
|
||||
r = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n");
|
||||
return false;
|
||||
|
||||
out:
|
||||
acpi_put_table(hdr);
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
||||
|
||||
@@ -234,6 +234,9 @@ amdgpu_devcoredump_print_ibs(struct drm_printer *p,
|
||||
drm_printf(p, "\nIB #%d 0x%llx %d dw\n", i,
|
||||
coredump->ibs[i].gpu_addr,
|
||||
coredump->ibs[i].ib_size_dw);
|
||||
|
||||
for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++)
|
||||
drm_printf(p, "0xffffffff\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -355,10 +358,14 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
drm_printf(&p, "kernel: %s\n", init_utsname()->release);
|
||||
drm_printf(&p, "module: " KBUILD_MODNAME "\n");
|
||||
drm_printf(&p, "time: %ptSp\n", &coredump->reset_time);
|
||||
drm_printf(&p, "pasid: %u\n", coredump->pasid);
|
||||
drm_printf(&p, "vmid: %u\n", coredump->vmid);
|
||||
|
||||
if (coredump->reset_task_info.task.pid)
|
||||
drm_printf(&p, "process_name: %s PID: %d\n",
|
||||
drm_printf(&p, "process_name: %s TGID: %d thread: %s PID: %d\n",
|
||||
coredump->reset_task_info.process_name,
|
||||
coredump->reset_task_info.tgid,
|
||||
coredump->reset_task_info.task.comm,
|
||||
coredump->reset_task_info.task.pid);
|
||||
|
||||
/* SOC Information */
|
||||
@@ -562,6 +569,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
amdgpu_vm_put_task_info(ti);
|
||||
}
|
||||
coredump->pasid = job->pasid;
|
||||
coredump->vmid = job->vmid;
|
||||
coredump->num_ibs = job->num_ibs;
|
||||
for (i = 0; i < job->num_ibs; ++i) {
|
||||
coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr;
|
||||
|
||||
@@ -63,6 +63,7 @@ struct amdgpu_coredump_info {
|
||||
char *formatted;
|
||||
|
||||
unsigned int pasid;
|
||||
unsigned int vmid;
|
||||
int num_ibs;
|
||||
struct amdgpu_coredump_ib_info ibs[] __counted_by(num_ibs);
|
||||
};
|
||||
|
||||
@@ -1323,6 +1323,15 @@ static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device
|
||||
|
||||
if (c->x86_vendor == X86_VENDOR_INTEL)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs don't
|
||||
* support PCIe dynamic speed switching.
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/work_items/5436
|
||||
*/
|
||||
if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 0x17 &&
|
||||
c->x86_model == 0x08)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3137,9 +3137,11 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
||||
case IP_VERSION(11, 5, 3):
|
||||
case IP_VERSION(11, 5, 4):
|
||||
case IP_VERSION(11, 5, 6):
|
||||
adev->family = AMDGPU_FAMILY_GC_11_5_0;
|
||||
break;
|
||||
case IP_VERSION(11, 7, 0):
|
||||
case IP_VERSION(11, 7, 1):
|
||||
adev->family = AMDGPU_FAMILY_GC_11_5_0;
|
||||
adev->family = AMDGPU_FAMILY_GC_11_5_4;
|
||||
break;
|
||||
case IP_VERSION(12, 0, 0):
|
||||
case IP_VERSION(12, 0, 1):
|
||||
|
||||
@@ -276,10 +276,12 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_pin(*bo_ptr, domain);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) kernel bo pin failed\n", r);
|
||||
goto error_unreserve;
|
||||
if (free) {
|
||||
r = amdgpu_bo_pin(*bo_ptr, domain);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "(%d) kernel bo pin failed\n", r);
|
||||
goto error_unreserve;
|
||||
}
|
||||
}
|
||||
|
||||
r = amdgpu_ttm_alloc_gart(&(*bo_ptr)->tbo);
|
||||
@@ -302,7 +304,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
|
||||
return 0;
|
||||
|
||||
error_unpin:
|
||||
amdgpu_bo_unpin(*bo_ptr);
|
||||
if (free)
|
||||
amdgpu_bo_unpin(*bo_ptr);
|
||||
error_unreserve:
|
||||
amdgpu_bo_unreserve(*bo_ptr);
|
||||
|
||||
|
||||
@@ -2684,12 +2684,22 @@ void amdgpu_sdma_set_buffer_funcs_scheds(struct amdgpu_device *adev,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Navi1x's workaround requires us to limit to a single SDMA sched
|
||||
* for ttm.
|
||||
*/
|
||||
hub = &adev->vmhub[AMDGPU_GFXHUB(0)];
|
||||
adev->mman.num_buffer_funcs_scheds = hub->sdma_invalidation_workaround ?
|
||||
1 : n;
|
||||
|
||||
/*
|
||||
* Allow using multiple SDMA schedulers only on GPUs where
|
||||
* we are allowed to do concurrent VM flushes.
|
||||
* This consideration is necessary because all GART windows
|
||||
* are mapped in VMID 0 (the kernel VMID) so each buffer
|
||||
* entity would flush VMID 0 concurrently.
|
||||
*
|
||||
* Also consider the SDMA invalidation workaround on
|
||||
* Navi 1x GPUs, which also prevents us from using
|
||||
* multiple SDMA engines on VMID 0 at the same time.
|
||||
*/
|
||||
adev->mman.num_buffer_funcs_scheds =
|
||||
(adev->vm_manager.concurrent_flush &&
|
||||
!hub->sdma_invalidation_workaround) ? n : 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
@@ -1376,16 +1376,19 @@ void amdgpu_userq_pre_reset(struct amdgpu_device *adev)
|
||||
|
||||
/* TODO: We probably need a new lock for the queue state */
|
||||
xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
|
||||
if (queue->state != AMDGPU_USERQ_STATE_MAPPED)
|
||||
continue;
|
||||
|
||||
userq_funcs = adev->userq_funcs[queue->queue_type];
|
||||
userq_funcs->unmap(queue);
|
||||
/* just mark all queues as hung at this point.
|
||||
* if unmap succeeds, we could map again
|
||||
* in amdgpu_userq_post_reset() if vram is not lost
|
||||
if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
|
||||
userq_funcs = adev->userq_funcs[queue->queue_type];
|
||||
userq_funcs->unmap(queue);
|
||||
/* just mark all queues as hung at this point.
|
||||
* if unmap succeeds, we could map again
|
||||
* in amdgpu_userq_post_reset() if vram is not lost
|
||||
*/
|
||||
queue->state = AMDGPU_USERQ_STATE_HUNG;
|
||||
}
|
||||
/* Force-complete any pending fence regardless of queue state so
|
||||
* that eviction/suspend and queue teardown waiters don't block
|
||||
* forever on a fence that will never signal after the reset.
|
||||
*/
|
||||
queue->state = AMDGPU_USERQ_STATE_HUNG;
|
||||
amdgpu_userq_fence_driver_force_completion(queue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,12 +855,10 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
|
||||
job->oa_size);
|
||||
}
|
||||
|
||||
if (vm_flush_needed || pasid_mapping_needed || cleaner_shader_needed) {
|
||||
amdgpu_fence_emit(ring, job->hw_vm_fence, 0);
|
||||
fence = &job->hw_vm_fence->base;
|
||||
/* get a ref for the job */
|
||||
dma_fence_get(fence);
|
||||
}
|
||||
amdgpu_fence_emit(ring, job->hw_vm_fence, 0);
|
||||
fence = &job->hw_vm_fence->base;
|
||||
/* get a ref for the job */
|
||||
dma_fence_get(fence);
|
||||
|
||||
if (vm_flush_needed) {
|
||||
mutex_lock(&id_mgr->lock);
|
||||
|
||||
@@ -3103,6 +3103,7 @@ static void deallocate_hiq_sdma_mqd(struct kfd_node *dev,
|
||||
struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
|
||||
{
|
||||
struct device_queue_manager *dqm;
|
||||
int i;
|
||||
|
||||
pr_debug("Loading device queue manager\n");
|
||||
|
||||
@@ -3231,6 +3232,9 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
|
||||
deallocate_hiq_sdma_mqd(dev, &dqm->hiq_sdma_mqd);
|
||||
|
||||
out_free:
|
||||
for (i = 0; i < KFD_MQD_TYPE_MAX; i++)
|
||||
kfree(dqm->mqd_mgrs[i]);
|
||||
|
||||
kfree(dqm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/overflow.h>
|
||||
#include "kfd_priv.h"
|
||||
#include "kfd_topology.h"
|
||||
#include "kfd_svm.h"
|
||||
@@ -235,7 +236,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
|
||||
struct kfd_topology_device *topo_dev;
|
||||
u64 expected_queue_size;
|
||||
struct amdgpu_vm *vm;
|
||||
u32 total_cwsr_size;
|
||||
u64 total_cwsr_size;
|
||||
int err;
|
||||
|
||||
topo_dev = kfd_topology_device_by_id(pdd->dev->id);
|
||||
@@ -308,8 +309,14 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
|
||||
goto out_err_unreserve;
|
||||
}
|
||||
|
||||
total_cwsr_size = (properties->ctx_save_restore_area_size +
|
||||
topo_dev->node_props.debug_memory_size) * NUM_XCC(pdd->dev->xcc_mask);
|
||||
total_cwsr_size = (u64)properties->ctx_save_restore_area_size +
|
||||
topo_dev->node_props.debug_memory_size;
|
||||
if (check_mul_overflow(total_cwsr_size,
|
||||
NUM_XCC(pdd->dev->xcc_mask),
|
||||
&total_cwsr_size)) {
|
||||
err = -EINVAL;
|
||||
goto out_err_unreserve;
|
||||
}
|
||||
total_cwsr_size = ALIGN(total_cwsr_size, PAGE_SIZE);
|
||||
|
||||
err = kfd_queue_buffer_get(vm, (void *)properties->ctx_save_restore_area_address,
|
||||
@@ -344,7 +351,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
|
||||
int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_properties *properties)
|
||||
{
|
||||
struct kfd_topology_device *topo_dev;
|
||||
u32 total_cwsr_size;
|
||||
u64 total_cwsr_size;
|
||||
|
||||
kfd_queue_buffer_put(&properties->wptr_bo);
|
||||
kfd_queue_buffer_put(&properties->rptr_bo);
|
||||
@@ -355,8 +362,12 @@ int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_prope
|
||||
topo_dev = kfd_topology_device_by_id(pdd->dev->id);
|
||||
if (!topo_dev)
|
||||
return -EINVAL;
|
||||
total_cwsr_size = (properties->ctx_save_restore_area_size +
|
||||
topo_dev->node_props.debug_memory_size) * NUM_XCC(pdd->dev->xcc_mask);
|
||||
total_cwsr_size = (u64)properties->ctx_save_restore_area_size +
|
||||
topo_dev->node_props.debug_memory_size;
|
||||
if (check_mul_overflow(total_cwsr_size,
|
||||
NUM_XCC(pdd->dev->xcc_mask),
|
||||
&total_cwsr_size))
|
||||
return -EINVAL;
|
||||
total_cwsr_size = ALIGN(total_cwsr_size, PAGE_SIZE);
|
||||
|
||||
kfd_queue_buffer_svm_put(pdd, properties->ctx_save_restore_area_address, total_cwsr_size);
|
||||
|
||||
@@ -580,89 +580,25 @@ static void schedule_dc_vmin_vmax(struct amdgpu_device *adev,
|
||||
queue_work(system_percpu_wq, &offload_work->work);
|
||||
}
|
||||
|
||||
static void dm_vupdate_high_irq(void *interrupt_params)
|
||||
{
|
||||
struct common_irq_params *irq_params = interrupt_params;
|
||||
struct amdgpu_device *adev = irq_params->adev;
|
||||
struct amdgpu_crtc *acrtc;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_vblank_crtc *vblank;
|
||||
ktime_t frame_duration_ns, previous_timestamp;
|
||||
unsigned long flags;
|
||||
int vrr_active;
|
||||
|
||||
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE);
|
||||
|
||||
if (acrtc) {
|
||||
vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
|
||||
drm_dev = acrtc->base.dev;
|
||||
vblank = drm_crtc_vblank_crtc(&acrtc->base);
|
||||
previous_timestamp = atomic64_read(&irq_params->previous_timestamp);
|
||||
frame_duration_ns = vblank->time - previous_timestamp;
|
||||
|
||||
if (frame_duration_ns > 0) {
|
||||
trace_amdgpu_refresh_rate_track(acrtc->base.index,
|
||||
frame_duration_ns,
|
||||
ktime_divns(NSEC_PER_SEC, frame_duration_ns));
|
||||
atomic64_set(&irq_params->previous_timestamp, vblank->time);
|
||||
}
|
||||
|
||||
drm_dbg_vbl(drm_dev,
|
||||
"crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id,
|
||||
vrr_active);
|
||||
|
||||
/* Core vblank handling is done here after end of front-porch in
|
||||
* vrr mode, as vblank timestamping will give valid results
|
||||
* while now done after front-porch. This will also deliver
|
||||
* page-flip completion events that have been queued to us
|
||||
* if a pageflip happened inside front-porch.
|
||||
*/
|
||||
if (vrr_active && acrtc->dm_irq_params.stream) {
|
||||
bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
|
||||
bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
|
||||
bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state
|
||||
== VRR_STATE_ACTIVE_VARIABLE;
|
||||
|
||||
amdgpu_dm_crtc_handle_vblank(acrtc);
|
||||
|
||||
/* BTR processing for pre-DCE12 ASICs */
|
||||
if (adev->family < AMDGPU_FAMILY_AI) {
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
mod_freesync_handle_v_update(
|
||||
adev->dm.freesync_module,
|
||||
acrtc->dm_irq_params.stream,
|
||||
&acrtc->dm_irq_params.vrr_params);
|
||||
|
||||
if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
|
||||
schedule_dc_vmin_vmax(adev,
|
||||
acrtc->dm_irq_params.stream,
|
||||
&acrtc->dm_irq_params.vrr_params.adjust);
|
||||
}
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_crtc_high_irq() - Handles CRTC interrupt
|
||||
* @interrupt_params: used for determining the CRTC instance
|
||||
* dm_crtc_high_irq_handler() - Common OTG vblank/flip event handling
|
||||
* @adev: amdgpu device
|
||||
* @acrtc: the CRTC to service
|
||||
*
|
||||
* Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK
|
||||
* event handler.
|
||||
* Performs writeback completion, vblank event handling, CRC processing, VRR BTR
|
||||
* updates and pageflip completion delivery.
|
||||
*
|
||||
* On DCN this is driven by VUPDATE_NO_LOCK (the register latch point) from
|
||||
* dm_vupdate_high_irq(); on DCE it is driven by VLINE0 at the start of vblank
|
||||
* from dm_crtc_high_irq().
|
||||
*/
|
||||
static void dm_crtc_high_irq(void *interrupt_params)
|
||||
static void dm_crtc_high_irq_handler(struct amdgpu_device *adev,
|
||||
struct amdgpu_crtc *acrtc)
|
||||
{
|
||||
struct common_irq_params *irq_params = interrupt_params;
|
||||
struct amdgpu_device *adev = irq_params->adev;
|
||||
struct drm_writeback_job *job;
|
||||
struct amdgpu_crtc *acrtc;
|
||||
unsigned long flags;
|
||||
int vrr_active;
|
||||
|
||||
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
|
||||
if (!acrtc)
|
||||
return;
|
||||
bool is_dcn = amdgpu_ip_version(adev, DCE_HWIP, 0) != 0;
|
||||
|
||||
if (acrtc->wb_conn) {
|
||||
spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
|
||||
@@ -699,12 +635,17 @@ static void dm_crtc_high_irq(void *interrupt_params)
|
||||
vrr_active, acrtc->dm_irq_params.active_planes);
|
||||
|
||||
/**
|
||||
* Core vblank handling at start of front-porch is only possible
|
||||
* in non-vrr mode, as only there vblank timestamping will give
|
||||
* valid results while done in front-porch. Otherwise defer it
|
||||
* to dm_vupdate_high_irq after end of front-porch.
|
||||
* Core vblank handling.
|
||||
*
|
||||
* On DCN this handler runs at VUPDATE_NO_LOCK, the register latch
|
||||
* point, which is the correct place to timestamp both VRR and non-VRR
|
||||
* vblanks.
|
||||
*
|
||||
* On DCE this handler runs at the start of front-porch, where only
|
||||
* non-VRR timestamping is valid; VRR vblank is deferred to
|
||||
* dm_vupdate_high_irq() after end of front-porch.
|
||||
*/
|
||||
if (!vrr_active)
|
||||
if (is_dcn || !vrr_active)
|
||||
amdgpu_dm_crtc_handle_vblank(acrtc);
|
||||
|
||||
/**
|
||||
@@ -737,18 +678,33 @@ static void dm_crtc_high_irq(void *interrupt_params)
|
||||
}
|
||||
|
||||
/*
|
||||
* If there aren't any active_planes then DCH HUBP may be clock-gated.
|
||||
* In that case, pageflip completion interrupts won't fire and pageflip
|
||||
* completion events won't get delivered. Prevent this by sending
|
||||
* pending pageflip events from here if a flip is still pending.
|
||||
* Deliver pageflip completion events (DCN only).
|
||||
*
|
||||
* If any planes are enabled, use dm_pflip_high_irq() instead, to
|
||||
* avoid race conditions between flip programming and completion,
|
||||
* which could cause too early flip completion events.
|
||||
* Since GRPH_PFLIP is not used, VUPDATE_NO_LOCK is the flip latch
|
||||
* point. Deliver any pending pageflip completion event from here,
|
||||
* once HW has consumed the new address (the OTG no longer reports a
|
||||
* pending flip).
|
||||
*
|
||||
* Also handle the case here where there aren't any active planes and
|
||||
* DCN HUBP may be clock-gated, so the flip-pending status may be
|
||||
* undefined.
|
||||
*/
|
||||
if (adev->family >= AMDGPU_FAMILY_RV &&
|
||||
acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
|
||||
acrtc->dm_irq_params.active_planes == 0) {
|
||||
if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
|
||||
acrtc->event) {
|
||||
|
||||
if (!dc_get_flip_pending_on_otg(adev->dm.dc, acrtc->otg_inst)) {
|
||||
drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
|
||||
acrtc->event = NULL;
|
||||
drm_crtc_vblank_put(&acrtc->base);
|
||||
acrtc->pflip_status = AMDGPU_FLIP_NONE;
|
||||
}
|
||||
/*
|
||||
* If the flip is still pending, leave it armed and
|
||||
* retry on the next vupdate.
|
||||
*/
|
||||
} else if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
|
||||
acrtc->dm_irq_params.active_planes == 0) {
|
||||
|
||||
if (acrtc->event) {
|
||||
drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
|
||||
acrtc->event = NULL;
|
||||
@@ -760,6 +716,104 @@ static void dm_crtc_high_irq(void *interrupt_params)
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
|
||||
static void dm_vupdate_high_irq(void *interrupt_params)
|
||||
{
|
||||
struct common_irq_params *irq_params = interrupt_params;
|
||||
struct amdgpu_device *adev = irq_params->adev;
|
||||
struct amdgpu_crtc *acrtc;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_vblank_crtc *vblank;
|
||||
ktime_t frame_duration_ns, previous_timestamp;
|
||||
unsigned long flags;
|
||||
int vrr_active;
|
||||
|
||||
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE);
|
||||
if (!acrtc)
|
||||
return;
|
||||
|
||||
vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
|
||||
drm_dev = acrtc->base.dev;
|
||||
vblank = drm_crtc_vblank_crtc(&acrtc->base);
|
||||
previous_timestamp = atomic64_read(&irq_params->previous_timestamp);
|
||||
frame_duration_ns = vblank->time - previous_timestamp;
|
||||
|
||||
if (frame_duration_ns > 0) {
|
||||
trace_amdgpu_refresh_rate_track(acrtc->base.index,
|
||||
frame_duration_ns,
|
||||
ktime_divns(NSEC_PER_SEC, frame_duration_ns));
|
||||
atomic64_set(&irq_params->previous_timestamp, vblank->time);
|
||||
}
|
||||
|
||||
drm_dbg_vbl(drm_dev,
|
||||
"crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id,
|
||||
vrr_active);
|
||||
|
||||
/*
|
||||
* On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver
|
||||
* vblank and pageflip completion events; VSTARTUP and GRPH_PFLIP are
|
||||
* not used. Run the full handler here.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
|
||||
dm_crtc_high_irq_handler(adev, acrtc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* DCE only below. */
|
||||
|
||||
/* Core vblank handling is done here after end of front-porch in
|
||||
* vrr mode, as vblank timestamping will give valid results
|
||||
* while now done after front-porch. This will also deliver
|
||||
* page-flip completion events that have been queued to us
|
||||
* if a pageflip happened inside front-porch.
|
||||
*/
|
||||
if (vrr_active && acrtc->dm_irq_params.stream) {
|
||||
bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
|
||||
bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
|
||||
bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state
|
||||
== VRR_STATE_ACTIVE_VARIABLE;
|
||||
|
||||
amdgpu_dm_crtc_handle_vblank(acrtc);
|
||||
|
||||
/* BTR processing for pre-DCE12 ASICs */
|
||||
if (adev->family < AMDGPU_FAMILY_AI) {
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
mod_freesync_handle_v_update(
|
||||
adev->dm.freesync_module,
|
||||
acrtc->dm_irq_params.stream,
|
||||
&acrtc->dm_irq_params.vrr_params);
|
||||
|
||||
if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
|
||||
schedule_dc_vmin_vmax(adev,
|
||||
acrtc->dm_irq_params.stream,
|
||||
&acrtc->dm_irq_params.vrr_params.adjust);
|
||||
}
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_crtc_high_irq() - Handles CRTC interrupt
|
||||
* @interrupt_params: used for determining the CRTC instance
|
||||
*
|
||||
* Handles the CRTC/VSYNC interrupt by notifying DRM's VBLANK event handler.
|
||||
*
|
||||
* Used on DCE (VLINE0, set to vblank start). On DCN the equivalent handling is
|
||||
* driven by VUPDATE_NO_LOCK in dm_vupdate_high_irq().
|
||||
*/
|
||||
static void dm_crtc_high_irq(void *interrupt_params)
|
||||
{
|
||||
struct common_irq_params *irq_params = interrupt_params;
|
||||
struct amdgpu_device *adev = irq_params->adev;
|
||||
struct amdgpu_crtc *acrtc;
|
||||
|
||||
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
|
||||
if (!acrtc)
|
||||
return;
|
||||
|
||||
dm_crtc_high_irq_handler(adev, acrtc);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
/**
|
||||
* dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
|
||||
@@ -3270,7 +3324,8 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
||||
acrtc = get_crtc_by_otg_inst(
|
||||
adev, state->stream_status[i].primary_otg_inst);
|
||||
|
||||
if (acrtc && state->stream_status[i].plane_count != 0) {
|
||||
if (acrtc && state->stream_status[i].plane_count != 0 &&
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
|
||||
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
if (rc)
|
||||
@@ -3298,6 +3353,13 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
||||
*/
|
||||
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
|
||||
drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
|
||||
|
||||
} else if (acrtc && state->stream_status[i].plane_count != 0) {
|
||||
/* DCN only needs to toggle VUPDATE_NO_LOCK */
|
||||
rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, enable);
|
||||
if (rc)
|
||||
drm_warn(adev_to_drm(adev), "Failed to %sable vupdate interrupt\n",
|
||||
enable ? "en" : "dis");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4069,6 +4131,8 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
|
||||
caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
|
||||
caps->aux_support = false;
|
||||
|
||||
panel_backlight_quirk = drm_get_panel_backlight_quirk(aconnector->drm_edid);
|
||||
|
||||
if (caps->ext_caps->bits.oled == 1
|
||||
/*
|
||||
* ||
|
||||
@@ -4081,6 +4145,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
|
||||
caps->aux_support = false;
|
||||
else if (amdgpu_backlight == 1)
|
||||
caps->aux_support = true;
|
||||
else if (!IS_ERR_OR_NULL(panel_backlight_quirk) &&
|
||||
panel_backlight_quirk->force_pwm)
|
||||
caps->aux_support = false;
|
||||
if (caps->aux_support)
|
||||
aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX;
|
||||
|
||||
@@ -4096,8 +4163,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
|
||||
else
|
||||
caps->aux_min_input_signal = 1;
|
||||
|
||||
panel_backlight_quirk =
|
||||
drm_get_panel_backlight_quirk(aconnector->drm_edid);
|
||||
if (!IS_ERR_OR_NULL(panel_backlight_quirk)) {
|
||||
if (panel_backlight_quirk->min_brightness) {
|
||||
caps->min_input_signal =
|
||||
@@ -4863,38 +4928,6 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
|
||||
* for acknowledging and handling.
|
||||
*/
|
||||
|
||||
/* Use VSTARTUP interrupt */
|
||||
for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP;
|
||||
i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1;
|
||||
i++) {
|
||||
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq);
|
||||
|
||||
if (r) {
|
||||
drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
|
||||
int_params.irq_source =
|
||||
dc_interrupt_to_irq_source(dc, i, 0);
|
||||
|
||||
if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
|
||||
int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 ||
|
||||
int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) {
|
||||
drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
|
||||
|
||||
c_irq_params->adev = adev;
|
||||
c_irq_params->irq_src = int_params.irq_source;
|
||||
|
||||
if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
|
||||
dm_crtc_high_irq, c_irq_params))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Use otg vertical line interrupt */
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
|
||||
@@ -4966,37 +4999,6 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Use GRPH_PFLIP interrupt */
|
||||
for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT;
|
||||
i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1;
|
||||
i++) {
|
||||
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq);
|
||||
if (r) {
|
||||
drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
|
||||
int_params.irq_source =
|
||||
dc_interrupt_to_irq_source(dc, i, 0);
|
||||
|
||||
if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
|
||||
int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST ||
|
||||
int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) {
|
||||
drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
|
||||
|
||||
c_irq_params->adev = adev;
|
||||
c_irq_params->irq_src = int_params.irq_source;
|
||||
|
||||
if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
|
||||
dm_pflip_high_irq, c_irq_params))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* HPD */
|
||||
r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
|
||||
&adev->hpd_irq);
|
||||
@@ -5563,11 +5565,11 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
|
||||
caps = &dm->backlight_caps[aconnector->bl_idx];
|
||||
if (get_brightness_range(caps, &min, &max)) {
|
||||
if (power_supply_is_system_supplied() > 0)
|
||||
props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->ac_level, 100);
|
||||
props.brightness = DIV_ROUND_CLOSEST(max * caps->ac_level, 100);
|
||||
else
|
||||
props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->dc_level, 100);
|
||||
props.brightness = DIV_ROUND_CLOSEST(max * caps->dc_level, 100);
|
||||
/* min is zero, so max needs to be adjusted */
|
||||
props.max_brightness = max - min;
|
||||
props.max_brightness = max;
|
||||
drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
|
||||
caps->ac_level, caps->dc_level);
|
||||
} else
|
||||
@@ -9674,21 +9676,9 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
|
||||
if (acrtc_state) {
|
||||
timing = &acrtc_state->stream->timing;
|
||||
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) >=
|
||||
IP_VERSION(3, 2, 0) &&
|
||||
!(adev->flags & AMD_IS_APU)) {
|
||||
/*
|
||||
* DGPUs NV3x and newer that support idle optimizations
|
||||
* experience intermittent flip-done timeouts on cursor
|
||||
* updates. Restore 5s offdelay behavior for now.
|
||||
*
|
||||
* Discussion on the issue:
|
||||
* https://lore.kernel.org/amd-gfx/20260217191632.1243826-1-sysdadmin@m1k.cloud/
|
||||
*/
|
||||
config.offdelay_ms = 5000;
|
||||
config.disable_immediate = false;
|
||||
} else if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
|
||||
IP_VERSION(3, 5, 0)) {
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
|
||||
IP_VERSION(3, 5, 0) ||
|
||||
!(adev->flags & AMD_IS_APU)) {
|
||||
/*
|
||||
* Older HW and DGPU have issues with instant off;
|
||||
* use a 2 frame offdelay.
|
||||
@@ -9707,14 +9697,22 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
|
||||
|
||||
drm_crtc_vblank_on_config(&acrtc->base,
|
||||
&config);
|
||||
/* Allow RX6xxx, RX7700, RX7800 GPUs to call amdgpu_irq_get.*/
|
||||
/*
|
||||
* Since pflip_high_irq is no longer registered for DCN, grab an
|
||||
* extra reference to vupdate irq instead to workaround this
|
||||
* issue:
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/work_items/3936
|
||||
*
|
||||
* The callbacks to drm_vblank_on/off should really take care of
|
||||
* this though.
|
||||
*/
|
||||
switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
|
||||
case IP_VERSION(3, 0, 0):
|
||||
case IP_VERSION(3, 0, 2):
|
||||
case IP_VERSION(3, 0, 3):
|
||||
case IP_VERSION(3, 2, 0):
|
||||
if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Cannot get pageflip irq!\n");
|
||||
if (amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Cannot get vupdate irq!\n");
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
if (amdgpu_irq_get(adev, &adev->vline0_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Cannot get vline0 irq!\n");
|
||||
@@ -9732,8 +9730,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
|
||||
if (amdgpu_irq_put(adev, &adev->vline0_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Cannot put vline0 irq!\n");
|
||||
#endif
|
||||
if (amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Cannot put pageflip irq!\n");
|
||||
if (amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Cannot put vupdate irq!\n");
|
||||
}
|
||||
|
||||
drm_crtc_vblank_off(&acrtc->base);
|
||||
@@ -9746,6 +9744,10 @@ static void dm_update_pflip_irq_state(struct amdgpu_device *adev,
|
||||
int irq_type =
|
||||
amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id);
|
||||
|
||||
/* GRPH_PFLIP is not used on DCN; nothing to reapply. */
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0)
|
||||
return;
|
||||
|
||||
/**
|
||||
* This reads the current state for the IRQ and force reapplies
|
||||
* the setting to hardware.
|
||||
@@ -10078,9 +10080,13 @@ static void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(new_state->base.crtc->dev);
|
||||
bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state);
|
||||
bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state);
|
||||
|
||||
/* Only DCE gates vupdate on VRR, keep it enabled for DCN */
|
||||
bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0;
|
||||
|
||||
if (!old_vrr_active && new_vrr_active) {
|
||||
/* Transition VRR inactive -> active:
|
||||
* While VRR is active, we must not disable vblank irq, as a
|
||||
@@ -10090,7 +10096,8 @@ static void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
|
||||
* We also need vupdate irq for the actual core vblank handling
|
||||
* at end of vblank.
|
||||
*/
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0);
|
||||
if (vrr_gates_vupdate)
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0);
|
||||
WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0);
|
||||
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n",
|
||||
__func__, new_state->base.crtc->base.id);
|
||||
@@ -10106,7 +10113,8 @@ static void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
|
||||
/* Transition VRR active -> inactive:
|
||||
* Allow vblank irq disable again for fixed refresh rate.
|
||||
*/
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0);
|
||||
if (vrr_gates_vupdate)
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0);
|
||||
drm_crtc_vblank_put(new_state->base.crtc);
|
||||
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n",
|
||||
__func__, new_state->base.crtc->base.id);
|
||||
@@ -10255,6 +10263,28 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
|
||||
}
|
||||
}
|
||||
|
||||
static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc,
|
||||
struct dm_crtc_state *acrtc_state,
|
||||
bool pflip_update,
|
||||
bool cursor_update)
|
||||
{
|
||||
assert_spin_locked(&acrtc->base.dev->event_lock);
|
||||
|
||||
if (!acrtc->base.state->event || acrtc_state->active_planes == 0)
|
||||
return;
|
||||
|
||||
if (pflip_update) {
|
||||
drm_crtc_vblank_get(&acrtc->base);
|
||||
WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
|
||||
/* Arm flip completion handling and event delivery after programming. */
|
||||
prepare_flip_isr(acrtc);
|
||||
} else if (cursor_update) {
|
||||
drm_crtc_vblank_get(&acrtc->base);
|
||||
acrtc->event = acrtc->base.state->event;
|
||||
acrtc->base.state->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
||||
struct drm_device *dev,
|
||||
struct amdgpu_display_manager *dm,
|
||||
@@ -10277,6 +10307,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
||||
bool vrr_active = amdgpu_dm_crtc_vrr_active(acrtc_state);
|
||||
bool cursor_update = false;
|
||||
bool pflip_present = false;
|
||||
bool immediate_flip = false;
|
||||
bool flip_latched_during_prog = false;
|
||||
bool dirty_rects_changed = false;
|
||||
bool updated_planes_and_streams = false;
|
||||
struct {
|
||||
@@ -10441,6 +10473,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
||||
acrtc_state->update_type == UPDATE_TYPE_FAST &&
|
||||
get_mem_type(old_plane_state->fb) == get_mem_type(fb);
|
||||
|
||||
immediate_flip |= bundle->flip_addrs[planes_count].flip_immediate;
|
||||
|
||||
timestamp_ns = ktime_get_ns();
|
||||
bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
|
||||
bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count];
|
||||
@@ -10509,39 +10543,24 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
||||
usleep_range(1000, 1100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the flip event for the pageflip interrupt to handle.
|
||||
*
|
||||
* This only works in the case where we've already turned on the
|
||||
* appropriate hardware blocks (eg. HUBP) so in the transition case
|
||||
* from 0 -> n planes we have to skip a hardware generated event
|
||||
* and rely on sending it from software.
|
||||
*/
|
||||
if (acrtc_attach->base.state->event &&
|
||||
acrtc_state->active_planes > 0) {
|
||||
drm_crtc_vblank_get(pcrtc);
|
||||
|
||||
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
|
||||
|
||||
WARN_ON(acrtc_attach->pflip_status != AMDGPU_FLIP_NONE);
|
||||
prepare_flip_isr(acrtc_attach);
|
||||
|
||||
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
|
||||
}
|
||||
|
||||
if (acrtc_state->stream) {
|
||||
if (acrtc_state->freesync_vrr_info_changed)
|
||||
bundle->stream_update.vrr_infopacket =
|
||||
&acrtc_state->stream->vrr_infopacket;
|
||||
}
|
||||
} else if (cursor_update && acrtc_state->active_planes > 0) {
|
||||
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
|
||||
if (acrtc_attach->base.state->event) {
|
||||
drm_crtc_vblank_get(pcrtc);
|
||||
acrtc_attach->event = acrtc_attach->base.state->event;
|
||||
acrtc_attach->base.state->event = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* DCE depends on a combination of GRPH_FLIP, VLINE0, and VUPDATE for
|
||||
* event delivery. Only GRPH_FLIP handler can send pflip events, and it
|
||||
* only fires if HW latched to the flip. Maintain legacy behavior by
|
||||
* arming event before programming.
|
||||
*/
|
||||
if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
|
||||
scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
|
||||
dm_arm_vblank_event(acrtc_attach, acrtc_state,
|
||||
pflip_present, cursor_update);
|
||||
}
|
||||
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
|
||||
}
|
||||
|
||||
/* Update the planes if changed or disable if we don't have any. */
|
||||
@@ -10633,6 +10652,115 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
||||
acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE)
|
||||
amdgpu_dm_commit_cursors(state);
|
||||
|
||||
/*
|
||||
* DCN specific vblank handling
|
||||
* ============================
|
||||
*
|
||||
* With the event_lock held, arm the vblank event, and determine whether
|
||||
* deliver it immediately, or in VUPDATE_NO_LOCK IRQ (i.e. HW latch
|
||||
* point) handler. Do this *after* programming so that the IRQ handler
|
||||
* will not deliver the event before HW laches onto the programmed
|
||||
* values:
|
||||
*
|
||||
* Commit thread IRQ handler HW
|
||||
* -----------------------------------------------------------------
|
||||
* arm_vblank_event()
|
||||
* vupdate()
|
||||
* vupdate_handler()
|
||||
* cook_timestamp()
|
||||
* # prev flip already latched,
|
||||
* # so flip_latched == true.
|
||||
* if event_armed && flip_latched:
|
||||
* send_vblank_event()
|
||||
* # sent before latch, **BAD!**
|
||||
* hw_program()
|
||||
* vupdate()
|
||||
* **latch**
|
||||
*
|
||||
* There's a consequence of arming after: it's possible for HW to latch
|
||||
* between start of HW programming and acrtc->event/pflip_status arming.
|
||||
* When this happens, the IRQ handler will send the event on the next
|
||||
* immediate latch point, even though HW has already latched. This is
|
||||
* handled by optimistically checking for HW latch after programming,
|
||||
* and if latched, send the event immediately:
|
||||
*
|
||||
* Commit thread IRQ handler HW
|
||||
* -----------------------------------------------------------------
|
||||
* hw_program()
|
||||
* vupdate()
|
||||
* **latch**
|
||||
* vupdate_handler()
|
||||
* cook_timestamp()
|
||||
* # event_armed == false
|
||||
* # **no event sent!**
|
||||
* arm_vblank_event()
|
||||
* if flip_latched:
|
||||
* **send_vblank_event()**
|
||||
* disarm_vblank_event()
|
||||
*
|
||||
* The IRQ handler is expected to cook the timestamp, but we need to
|
||||
* cook the timestamp before optimistic sending as well. That's because
|
||||
* the following sequence is possible:
|
||||
*
|
||||
* Commit thread IRQ handler HW
|
||||
* -----------------------------------------------------------------
|
||||
* hw_program()
|
||||
* arm_vblank_event()
|
||||
* vupdate()
|
||||
* **latch**
|
||||
* if flip_latched:
|
||||
* # Need cook before send!
|
||||
* **cook_timestamp()**
|
||||
* send_vblank_event()
|
||||
* disarm_vblank_event()
|
||||
* vupdate_handler()
|
||||
* cook_timestamp()
|
||||
* # event_armed == false
|
||||
* # no event sent!
|
||||
*
|
||||
* Cooking twice is OK, since DRM scanout accurate timestamps report A)
|
||||
* the previous vactive start if currently in vactive, or B) the next
|
||||
* vactive start if currently in vblank (see &get_vblank_counter). 'A)'
|
||||
* is what we want for the optimistic send, and for 'B)', we'll cook a
|
||||
* timestamp no later than the next IRQ handler run.
|
||||
*
|
||||
* The more correct fix is to wrap programming and arming with the
|
||||
* event_lock and thus serializing it with the IRQ handler. However,
|
||||
* there are various sleep-waits within
|
||||
* update_planes_and_stream_adapter() that makes spin locking illegal.
|
||||
* And on full updates, it can take 1-2 frame-times to return (see
|
||||
* commit_planes_for_stream).
|
||||
*
|
||||
* On DCE, GRPH_PFLIP IRQ is used and takes care of this.
|
||||
*/
|
||||
if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0) {
|
||||
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
|
||||
|
||||
if (updated_planes_and_streams) {
|
||||
flip_latched_during_prog =
|
||||
!dc_get_flip_pending_on_otg(dm->dc, acrtc_attach->otg_inst);
|
||||
}
|
||||
|
||||
dm_arm_vblank_event(acrtc_attach, acrtc_state,
|
||||
pflip_present, cursor_update);
|
||||
|
||||
/*
|
||||
* Deliver the event immediately on immediate flip, or on a
|
||||
* update that has already latched.
|
||||
*/
|
||||
if ((immediate_flip || flip_latched_during_prog) &&
|
||||
acrtc_attach->pflip_status == AMDGPU_FLIP_SUBMITTED &&
|
||||
acrtc_attach->event) {
|
||||
drm_crtc_accurate_vblank_count(&acrtc_attach->base);
|
||||
drm_crtc_send_vblank_event(&acrtc_attach->base,
|
||||
acrtc_attach->event);
|
||||
acrtc_attach->event = NULL;
|
||||
drm_crtc_vblank_put(&acrtc_attach->base);
|
||||
acrtc_attach->pflip_status = AMDGPU_FLIP_NONE;
|
||||
}
|
||||
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
kfree(bundle);
|
||||
}
|
||||
@@ -12098,6 +12226,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
||||
/* Release extra reference */
|
||||
if (new_stream)
|
||||
dc_stream_release(new_stream);
|
||||
new_stream = NULL;
|
||||
|
||||
/*
|
||||
* We want to do dc stream updates that do not require a
|
||||
@@ -12814,10 +12943,15 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
|
||||
/* Overlay cursor not supported on HW before DCN
|
||||
* DCN401/420 does not have the cursor-on-scaled-plane or cursor-on-yuv-plane restrictions
|
||||
* as previous DCN generations, so enable native mode on DCN401/420
|
||||
*
|
||||
* Always set native cursor mode when the CRTC is disabled,
|
||||
* to make sure it doesn't cause atomic commits to fail when
|
||||
* they are trying to disable the CRTC.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1) ||
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1)) {
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
|
||||
!dm_crtc_state->base.enable) {
|
||||
*cursor_mode = DM_CURSOR_NATIVE_MODE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -274,9 +274,25 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
|
||||
drm_crtc_vblank_restore(crtc);
|
||||
}
|
||||
|
||||
if (dc_supports_vrr(dm->dc->ctx->dce_version)) {
|
||||
/*
|
||||
* On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver
|
||||
* vblank and pageflip completion events, so enable it whenever vblank
|
||||
* is enabled. On DCE, vupdate is only needed in VRR mode.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
|
||||
if (enable) {
|
||||
/* vblank irq on -> Only need vupdate irq in vrr mode */
|
||||
rc = amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Get vupdate_irq ret=%d\n", rc);
|
||||
} else {
|
||||
rc = amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Put vupdate_irq ret=%d\n", rc);
|
||||
}
|
||||
} else if (dc_supports_vrr(dm->dc->ctx->dce_version)) {
|
||||
if (enable) {
|
||||
/* vblank irq on -> Only need vupdate irq in vrr mode
|
||||
* Not ref-counted since we need explicit enable/disable
|
||||
* for DCE VRR handling
|
||||
*/
|
||||
if (amdgpu_dm_crtc_vrr_active(acrtc_state))
|
||||
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true);
|
||||
} else {
|
||||
@@ -285,39 +301,46 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* crtc vblank or vstartup interrupt */
|
||||
if (enable) {
|
||||
rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc);
|
||||
} else {
|
||||
rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* hubp surface flip interrupt
|
||||
*
|
||||
* We have no guarantee that the frontend index maps to the same
|
||||
* backend index - some even map to more than one.
|
||||
*
|
||||
* TODO: Use a different interrupt or check DC itself for the mapping.
|
||||
* VLINE0 (crtc_irq) and GRPH_PFLIP (pageflip_irq) are only used on
|
||||
* DCE. On DCN, vblank and pageflip completion are delivered from
|
||||
* VUPDATE_NO_LOCK (enabled above), so don't touch them here.
|
||||
*/
|
||||
if (enable) {
|
||||
rc = amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Get pageflip_irq ret=%d\n", rc);
|
||||
} else {
|
||||
rc = amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Put pageflip_irq ret=%d\n", rc);
|
||||
}
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
|
||||
/* crtc vblank or vstartup interrupt */
|
||||
if (enable) {
|
||||
rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc);
|
||||
} else {
|
||||
rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* hubp surface flip interrupt
|
||||
*
|
||||
* We have no guarantee that the frontend index maps to the same
|
||||
* backend index - some even map to more than one.
|
||||
*
|
||||
* TODO: Use a different interrupt or check DC itself for the mapping.
|
||||
*/
|
||||
if (enable) {
|
||||
rc = amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Get pageflip_irq ret=%d\n", rc);
|
||||
} else {
|
||||
rc = amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Put pageflip_irq ret=%d\n", rc);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
/* crtc vline0 interrupt, only available on DCN+ */
|
||||
|
||||
@@ -1201,11 +1201,25 @@ enum dc_edid_status dm_helpers_read_local_edid(
|
||||
continue;
|
||||
|
||||
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
|
||||
if (!edid ||
|
||||
edid->extensions >= sizeof(sink->dc_edid.raw_edid) / EDID_LENGTH)
|
||||
/*
|
||||
* Use the length of the EDID property blob populated by
|
||||
* drm_edid_connector_update() above. It reflects the true number
|
||||
* of EDID blocks, including any HDMI Forum EDID Extension Override
|
||||
* Data Block (HF-EEODB) count, which the raw byte 0x7e extension
|
||||
* count can hide (e.g. HDMI 8K sinks).
|
||||
*/
|
||||
if (!edid || !connector->edid_blob_ptr ||
|
||||
connector->edid_blob_ptr->length > sizeof(sink->dc_edid.raw_edid))
|
||||
return EDID_BAD_INPUT;
|
||||
|
||||
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
|
||||
/*
|
||||
* FIXME: amdgpu_dm today does not consider the HF-EEODB, which
|
||||
* may contain additional mode info for sinks. This is a
|
||||
* workaround until dc_edid is refactored out from DC into
|
||||
* amdgpu_dm's ownership, allowing amdgpu_dm to use drm_edid
|
||||
* directly
|
||||
*/
|
||||
sink->dc_edid.length = connector->edid_blob_ptr->length;
|
||||
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
|
||||
|
||||
/* We don't need the original edid anymore */
|
||||
|
||||
@@ -6165,6 +6165,51 @@ void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src)
|
||||
dal_irq_service_ack(dc->res_pool->irqs, src);
|
||||
}
|
||||
|
||||
/*
|
||||
* dc_get_flip_pending_on_otg() - Check if a GRPH_FLIP is still pending on OTG
|
||||
*
|
||||
* @dc: display core context @otg_inst: OTG instance to query
|
||||
*
|
||||
* Reads the HUBP flip-pending status for the pipe(s) bound to @otg_inst,
|
||||
* returning true if any of them has not yet latched its programmed surface
|
||||
* address.
|
||||
*
|
||||
* Unlike dc_plane_get_status(), this does not take or mutate a dc_plane_state,
|
||||
* so it is safe to call from interrupt context without racing a concurrent
|
||||
* commit that may be updating plane state.
|
||||
*
|
||||
* Return: true if a flip is still pending on the OTG, false otherwise.
|
||||
*/
|
||||
bool dc_get_flip_pending_on_otg(struct dc *dc, int otg_inst)
|
||||
{
|
||||
bool flip_pending = false;
|
||||
int i;
|
||||
|
||||
if (!dc || !dc->current_state)
|
||||
return false;
|
||||
|
||||
dc_exit_ips_for_hw_access(dc);
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
|
||||
struct hubp *hubp = pipe_ctx->plane_res.hubp;
|
||||
|
||||
if (!pipe_ctx->plane_state || !pipe_ctx->stream_res.tg)
|
||||
continue;
|
||||
|
||||
if (pipe_ctx->stream_res.tg->inst != otg_inst)
|
||||
continue;
|
||||
|
||||
if (hubp && hubp->funcs->hubp_is_flip_pending &&
|
||||
hubp->funcs->hubp_is_flip_pending(hubp)) {
|
||||
flip_pending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flip_pending;
|
||||
}
|
||||
|
||||
void dc_power_down_on_boot(struct dc *dc)
|
||||
{
|
||||
if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW &&
|
||||
|
||||
@@ -1815,6 +1815,8 @@ struct dc_scratch_space {
|
||||
bool dp_skip_DID2;
|
||||
bool dp_skip_reset_segment;
|
||||
bool dp_skip_fs_144hz;
|
||||
/* Some DP bridges don't work with RBR and must use HBR. */
|
||||
bool dp_skip_rbr;
|
||||
bool dp_mot_reset_segment;
|
||||
/* Some USB4 docks do not handle turning off MST DSC once it has been enabled. */
|
||||
bool dpia_mst_dsc_always_on;
|
||||
@@ -2881,6 +2883,7 @@ enum dc_irq_source dc_interrupt_to_irq_source(
|
||||
uint32_t ext_id);
|
||||
bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable);
|
||||
void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src);
|
||||
bool dc_get_flip_pending_on_otg(struct dc *dc, int otg_inst);
|
||||
enum dc_irq_source dc_get_hpd_irq_source_at_index(
|
||||
struct dc *dc, uint32_t link_index);
|
||||
|
||||
|
||||
@@ -1229,9 +1229,9 @@ static bool get_dp_dto_frequency_100hz(
|
||||
*/
|
||||
modulo_hz = REG_READ(MODULO[inst]);
|
||||
if (modulo_hz) {
|
||||
temp = div_u64((uint64_t)clock_hz * dp_dto_ref_khz * 10, modulo_hz);
|
||||
ASSERT(temp / 100 <= 0xFFFFFFFFUL);
|
||||
*pixel_clk_100hz = (unsigned int)(temp / 100);
|
||||
temp = clock_hz * dp_dto_ref_khz * 10;
|
||||
ASSERT(temp <= UINT_MAX * modulo_hz * 100ULL);
|
||||
*pixel_clk_100hz = div_u64(temp, modulo_hz * 100);
|
||||
} else
|
||||
*pixel_clk_100hz = 0;
|
||||
} else {
|
||||
@@ -1285,13 +1285,12 @@ static bool dcn401_get_dp_dto_frequency_100hz(const struct clock_source *clock_s
|
||||
* - target pix_clk_hz = (DPDTO INTEGER * DPDTO MODULO + DPDTO PHASE)
|
||||
*/
|
||||
temp = (unsigned long long)dp_dto_integer * modulo_hz + phase_hz;
|
||||
|
||||
if (temp / 100 > 0xFFFFFFFFUL) {
|
||||
if (temp > (UINT_MAX * 100ULL)) {
|
||||
/* pixel rate 100hz should never be this high, if it is, throw an assert and return 0 */
|
||||
BREAK_TO_DEBUGGER();
|
||||
*pixel_clk_100hz = 0;
|
||||
} else {
|
||||
*pixel_clk_100hz = (unsigned int)(temp / 100);
|
||||
*pixel_clk_100hz = div_u64(temp, 100);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -623,7 +623,7 @@ static bool detect_dp(struct dc_link *link,
|
||||
link->dpcd_caps.sink_count.bits.SINK_COUNT = 1;
|
||||
/* NUTMEG requires that we use HBR, doesn't work with RBR. */
|
||||
if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_00001A)
|
||||
link->preferred_link_setting.link_rate = LINK_RATE_HIGH;
|
||||
link->wa_flags.dp_skip_rbr = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -750,8 +750,10 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting
|
||||
if (req_bw > dp_link_bandwidth_kbps(link, &link->verified_link_cap))
|
||||
return false;
|
||||
|
||||
if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
|
||||
initial_link_setting.link_rate = link->preferred_link_setting.link_rate;
|
||||
if (link->wa_flags.dp_skip_rbr) {
|
||||
initial_link_setting.link_rate = LINK_RATE_HIGH;
|
||||
current_link_setting.link_rate = LINK_RATE_HIGH;
|
||||
}
|
||||
|
||||
/* search for the minimum link setting that:
|
||||
* 1. is supported according to the link training result
|
||||
|
||||
@@ -992,6 +992,11 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link(
|
||||
for (i = 0; i < pool->stream_enc_count; i++) {
|
||||
if (!res_ctx->is_stream_enc_acquired[i] &&
|
||||
pool->stream_enc[i]) {
|
||||
/* DP/MST needs a digital encoder; skip analog/no-DP encoders */
|
||||
if (dc_is_dp_signal(stream->signal) &&
|
||||
(!pool->stream_enc[i]->funcs ||
|
||||
!pool->stream_enc[i]->funcs->dp_set_stream_attribute))
|
||||
continue;
|
||||
/* Store first available for MST second display
|
||||
* in daisy chain use case
|
||||
*/
|
||||
@@ -1014,7 +1019,7 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link(
|
||||
* required for non DP connectors.
|
||||
*/
|
||||
|
||||
if (j >= 0 && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT)
|
||||
if (j >= 0 && dc_is_dp_signal(stream->signal))
|
||||
return pool->stream_enc[j];
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -2142,6 +2142,7 @@ static bool dcn42_resource_construct(
|
||||
dc->config.use_pipe_ctx_sync_logic = true;
|
||||
dc->config.dc_mode_clk_limit_support = false;
|
||||
dc->config.enable_windowed_mpo_odm = true;
|
||||
dc->config.set_pipe_unlock_order = true; /* Need to ensure DET gets freed before allocating */
|
||||
/* Use psp mailbox to enable assr */
|
||||
dc->config.use_assr_psp_message = true;
|
||||
/* dcn42 and afterward always support external panel replay */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "dcn35/dcn35_resource.h"
|
||||
#include "dcn321/dcn321_resource.h"
|
||||
#include "dcn401/dcn401_resource.h"
|
||||
#include "dcn42/dcn42_resource.h"
|
||||
#include "dcn42/dcn42_resource_fpu.h"
|
||||
|
||||
#include "dcn10/dcn10_ipp.h"
|
||||
@@ -116,6 +117,23 @@
|
||||
#define regAPG9_APG_DBG_GEN_CONTROL 0x38ae
|
||||
#define regAPG9_APG_DBG_GEN_CONTROL_BASE_IDX 2
|
||||
|
||||
#define regHUBP0_HUBPREQ_DEBUG_DB 0x05f8
|
||||
#define regHUBP0_HUBPREQ_DEBUG_DB_BASE_IDX 2
|
||||
#define regHUBP0_HUBPREQ_DEBUG 0x05f9
|
||||
#define regHUBP0_HUBPREQ_DEBUG_BASE_IDX 2
|
||||
#define regHUBP1_HUBPREQ_DEBUG_DB 0x06d4
|
||||
#define regHUBP1_HUBPREQ_DEBUG_DB_BASE_IDX 2
|
||||
#define regHUBP1_HUBPREQ_DEBUG 0x06d5
|
||||
#define regHUBP1_HUBPREQ_DEBUG_BASE_IDX 2
|
||||
#define regHUBP2_HUBPREQ_DEBUG_DB 0x07b0
|
||||
#define regHUBP2_HUBPREQ_DEBUG_DB_BASE_IDX 2
|
||||
#define regHUBP2_HUBPREQ_DEBUG 0x07b1
|
||||
#define regHUBP2_HUBPREQ_DEBUG_BASE_IDX 2
|
||||
#define regHUBP3_HUBPREQ_DEBUG_DB 0x088c
|
||||
#define regHUBP3_HUBPREQ_DEBUG_DB_BASE_IDX 2
|
||||
#define regHUBP3_HUBPREQ_DEBUG 0x088d
|
||||
#define regHUBP3_HUBPREQ_DEBUG_BASE_IDX 2
|
||||
|
||||
enum dcn401_clk_src_array_id {
|
||||
DCN401_CLK_SRC_PLL0,
|
||||
DCN401_CLK_SRC_PLL1,
|
||||
@@ -461,7 +479,7 @@ static const struct dcn_optc_mask optc_mask = {
|
||||
OPTC_COMMON_MASK_SH_LIST_DCN42B(_MASK)};
|
||||
|
||||
#define hubp_regs_init(id) \
|
||||
HUBP_REG_LIST_DCN42B_RI(id)
|
||||
HUBP_REG_LIST_DCN42_RI(id)
|
||||
|
||||
static struct dcn_hubp2_registers hubp_regs[4];
|
||||
|
||||
@@ -1882,9 +1900,7 @@ static struct resource_funcs dcn42b_res_pool_funcs = {
|
||||
.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
|
||||
.add_phantom_pipes = dcn32_add_phantom_pipes,
|
||||
.calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes,
|
||||
#ifdef CONFIG_DRM_AMD_DC_DML21
|
||||
.prepare_mcache_programming = dcn42b_prepare_mcache_programming,
|
||||
#endif
|
||||
.build_pipe_pix_clk_params = dcn42b_build_pipe_pix_clk_params,
|
||||
.get_power_profile = dcn401_get_power_profile,
|
||||
.get_vstartup_for_pipe = dcn401_get_vstartup_for_pipe,
|
||||
@@ -2087,6 +2103,7 @@ static bool dcn42b_resource_construct(
|
||||
dc->config.use_pipe_ctx_sync_logic = true;
|
||||
dc->config.dc_mode_clk_limit_support = false;
|
||||
dc->config.enable_windowed_mpo_odm = true;
|
||||
dc->config.set_pipe_unlock_order = true; /* Need to ensure DET gets freed before allocating */
|
||||
/* Use psp mailbox to enable assr */
|
||||
dc->config.use_assr_psp_message = true;
|
||||
/* dcn42 and afterward always support external panel replay */
|
||||
|
||||
@@ -344,7 +344,6 @@
|
||||
* DCCG_SRII(PHASE, DP_DTO, 3),
|
||||
* DCCG_SRII(MODULO, DP_DTO, 3),
|
||||
* SR(DSCCLK3_DTO_PARAM),
|
||||
* SR(HDMISTREAMCLK_CNTL),
|
||||
* SR(SYMCLKD_CLOCK_ENABLE),
|
||||
* SR(SYMCLKE_CLOCK_ENABLE)
|
||||
*/
|
||||
@@ -360,6 +359,7 @@
|
||||
SR(PHYBSYMCLK_CLOCK_CNTL), \
|
||||
SR(PHYCSYMCLK_CLOCK_CNTL), \
|
||||
SR(DPSTREAMCLK_CNTL), \
|
||||
SR(HDMISTREAMCLK_CNTL), \
|
||||
SR(SYMCLK32_SE_CNTL), \
|
||||
SR(SYMCLK32_LE_CNTL), \
|
||||
DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0), \
|
||||
@@ -542,120 +542,6 @@
|
||||
SRI_ARR(DC_ABM1_ACE_OFFSET_SLOPE_DATA, ABM, id), \
|
||||
SRI_ARR(DC_ABM1_ACE_PWL_CNTL, ABM, id)
|
||||
|
||||
/* HUBP */
|
||||
/* Not in DCN42B: HUBPREQ_DEBUG_DB and HUBPREQ_DEBUG */
|
||||
#define HUBP_REG_LIST_DCN42B_RI(id) \
|
||||
SRI_ARR(DCN_DMDATA_VM_CNTL, HUBPREQ, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_3, HUBPREQ, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_4, HUBPREQ, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_5, HUBPREQ, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_6, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_5, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_6, HUBPREQ, id), \
|
||||
HUBP_REG_LIST_DCN_VM_RI(id), \
|
||||
SRI_ARR(PREFETCH_SETTINGS, HUBPREQ, id), \
|
||||
SRI_ARR(PREFETCH_SETTINGS_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_VM_SYSTEM_APERTURE_LOW_ADDR, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, HUBPREQ, id), \
|
||||
SRI_ARR(CURSOR_SETTINGS, HUBPREQ, id), \
|
||||
SRI_ARR(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR0_, id), \
|
||||
SRI_ARR(CURSOR_SURFACE_ADDRESS, CURSOR0_, id), \
|
||||
SRI_ARR(CURSOR_SIZE, CURSOR0_, id), \
|
||||
SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \
|
||||
SRI_ARR(CURSOR_POSITION, CURSOR0_, id), \
|
||||
SRI_ARR(CURSOR_HOT_SPOT, CURSOR0_, id), \
|
||||
SRI_ARR(CURSOR_DST_OFFSET, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_ADDRESS_HIGH, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_ADDRESS_LOW, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_CNTL, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_SW_CNTL, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_QOS_CNTL, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_SW_DATA, CURSOR0_, id), \
|
||||
SRI_ARR(DMDATA_STATUS, CURSOR0_, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_0, HUBPREQ, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_1, HUBPREQ, id), \
|
||||
SRI_ARR(FLIP_PARAMETERS_2, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_CUR1_TTU_CNTL0, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_CUR1_TTU_CNTL1, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_FLIP_CONTROL2, HUBPREQ, id), \
|
||||
SRI_ARR(VMID_SETTINGS_0, HUBPREQ, id), \
|
||||
SRI_ARR(DCHUBP_CNTL, HUBP, id), \
|
||||
SRI_ARR(DCSURF_ADDR_CONFIG, HUBP, id), \
|
||||
SRI_ARR(DCSURF_TILING_CONFIG, HUBP, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_PITCH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_PITCH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_CONFIG, HUBP, id), \
|
||||
SRI_ARR(DCSURF_FLIP_CONTROL, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRI_VIEWPORT_DIMENSION, HUBP, id), \
|
||||
SRI_ARR(DCSURF_PRI_VIEWPORT_START, HUBP, id), \
|
||||
SRI_ARR(DCSURF_SEC_VIEWPORT_DIMENSION, HUBP, id), \
|
||||
SRI_ARR(DCSURF_SEC_VIEWPORT_START, HUBP, id), \
|
||||
SRI_ARR(DCSURF_PRI_VIEWPORT_DIMENSION_C, HUBP, id), \
|
||||
SRI_ARR(DCSURF_PRI_VIEWPORT_START_C, HUBP, id), \
|
||||
SRI_ARR(DCSURF_SEC_VIEWPORT_DIMENSION_C, HUBP, id), \
|
||||
SRI_ARR(DCSURF_SEC_VIEWPORT_START_C, HUBP, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_INUSE, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_INUSE_HIGH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_INUSE_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_INUSE_HIGH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_CONTROL, HUBPREQ, id), \
|
||||
SRI_ARR(DCSURF_SURFACE_FLIP_INTERRUPT, HUBPREQ, id), \
|
||||
SRI_ARR(HUBPRET_CONTROL, HUBPRET, id), \
|
||||
SRI_ARR(HUBPRET_READ_LINE_STATUS, HUBPRET, id), \
|
||||
SRI_ARR(DCN_EXPANSION_MODE, HUBPREQ, id), \
|
||||
SRI_ARR(DCHUBP_REQ_SIZE_CONFIG, HUBP, id), \
|
||||
SRI_ARR(DCHUBP_REQ_SIZE_CONFIG_C, HUBP, id), \
|
||||
SRI_ARR(BLANK_OFFSET_0, HUBPREQ, id), \
|
||||
SRI_ARR(BLANK_OFFSET_1, HUBPREQ, id), \
|
||||
SRI_ARR(DST_DIMENSIONS, HUBPREQ, id), \
|
||||
SRI_ARR(DST_AFTER_SCALER, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_0, HUBPREQ, id), \
|
||||
SRI_ARR(REF_FREQ_TO_PIX_FREQ, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_1, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_3, HUBPREQ, id), \
|
||||
SRI_ARR(NOM_PARAMETERS_4, HUBPREQ, id), \
|
||||
SRI_ARR(NOM_PARAMETERS_5, HUBPREQ, id), \
|
||||
SRI_ARR(PER_LINE_DELIVERY_PRE, HUBPREQ, id), \
|
||||
SRI_ARR(PER_LINE_DELIVERY, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_2, HUBPREQ, id), \
|
||||
SRI_ARR(VBLANK_PARAMETERS_4, HUBPREQ, id), \
|
||||
SRI_ARR(NOM_PARAMETERS_6, HUBPREQ, id), \
|
||||
SRI_ARR(NOM_PARAMETERS_7, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_TTU_QOS_WM, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_GLOBAL_TTU_CNTL, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_SURF0_TTU_CNTL0, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_SURF0_TTU_CNTL1, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_SURF1_TTU_CNTL0, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_SURF1_TTU_CNTL1, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_CUR0_TTU_CNTL0, HUBPREQ, id), \
|
||||
SRI_ARR(DCN_CUR0_TTU_CNTL1, HUBPREQ, id), \
|
||||
SRI_ARR(HUBP_CLK_CNTL, HUBP, id), \
|
||||
SRI_ARR(HUBPRET_READ_LINE_VALUE, HUBPRET, id), \
|
||||
SRI_ARR(DCHUBP_MALL_CONFIG, HUBP, id), \
|
||||
SRI_ARR(DCHUBP_VMPG_CONFIG, HUBP, id), \
|
||||
SRI_ARR(UCLK_PSTATE_FORCE, HUBPREQ, id), \
|
||||
SRI_ARR(HUBP_3DLUT_DLG_PARAM, CURSOR0_, id), \
|
||||
HUBP_3DLUT_FL_REG_LIST_DCN401(id)
|
||||
struct dcn42b_resource_pool {
|
||||
struct resource_pool base;
|
||||
};
|
||||
|
||||
@@ -3892,13 +3892,16 @@ static void si_notify_hw_of_powersource(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
/* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
|
||||
if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
|
||||
return;
|
||||
|
||||
/* The SMU automatically notices DC, but needs to be notified when switching to AC. */
|
||||
if (adev->pm.ac_power)
|
||||
/*
|
||||
* Check if the platform already manages the AC/DC switch via dedicated GPIO.
|
||||
* Otherwise SMU automatically notices DC, but needs to be notified of AC.
|
||||
*/
|
||||
if (adev->pm.ac_power &&
|
||||
(adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC))
|
||||
amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC);
|
||||
|
||||
/* Recompute clocks with updated max_limits. */
|
||||
amdgpu_legacy_dpm_compute_clocks(adev);
|
||||
}
|
||||
|
||||
static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
@@ -7689,7 +7692,7 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev,
|
||||
break;
|
||||
}
|
||||
|
||||
if (queue_thermal)
|
||||
if (queue_thermal && amdgpu_dpm)
|
||||
schedule_work(&adev->pm.dpm.thermal.work);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -106,11 +106,8 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr)
|
||||
hwmgr->od_enabled = false;
|
||||
switch (hwmgr->chip_id) {
|
||||
case CHIP_BONAIRE:
|
||||
/* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM
|
||||
* R7 260X cards with old MC ucode: MCLK DPM is unstable
|
||||
*/
|
||||
if (adev->pdev->subsystem_vendor == 0x106B ||
|
||||
adev->pdev->device == 0x6658) {
|
||||
/* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM */
|
||||
if (adev->pdev->subsystem_vendor == 0x106B) {
|
||||
dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC");
|
||||
adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK;
|
||||
hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK;
|
||||
|
||||
@@ -5857,15 +5857,19 @@ static int smu7_power_off_asic(struct pp_hwmgr *hwmgr)
|
||||
static void smu7_notify_ac_dc(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
|
||||
/* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
/*
|
||||
* Check if the platform already manages the AC/DC switch via dedicated GPIO.
|
||||
* Otherwise SMU automatically notices DC, but needs to be notified of AC.
|
||||
*/
|
||||
if (adev->pm.ac_power &&
|
||||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_AutomaticDCTransition))
|
||||
return;
|
||||
|
||||
/* The SMU automatically notices DC, but needs to be notified when switching to AC. */
|
||||
if (adev->pm.ac_power)
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunningOnAC, NULL);
|
||||
|
||||
/* Recompute clocks with updated max_limits. */
|
||||
pp_funcs->pm_compute_clocks(adev->powerplay.pp_handle);
|
||||
}
|
||||
|
||||
static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
|
||||
|
||||
@@ -1367,6 +1367,14 @@ static void smu_feature_cap_init(struct smu_context *smu)
|
||||
bitmap_zero(fea_cap->cap_map, SMU_FEATURE_CAP_ID__COUNT);
|
||||
}
|
||||
|
||||
static int smu_set_power_dep(struct smu_context *smu, bool enable)
|
||||
{
|
||||
if (!smu->ppt_funcs->set_power_dep)
|
||||
return 0;
|
||||
|
||||
return smu->ppt_funcs->set_power_dep(smu, enable);
|
||||
}
|
||||
|
||||
static int smu_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
{
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
@@ -1428,6 +1436,8 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (!smu->ppt_funcs->get_fan_control_mode)
|
||||
smu->adev->pm.no_fan = true;
|
||||
|
||||
smu_set_power_dep(smu, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1450,6 +1460,8 @@ static int smu_sw_fini(struct amdgpu_ip_block *ip_block)
|
||||
|
||||
smu_fini_microcode(smu);
|
||||
|
||||
smu_set_power_dep(smu, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -749,6 +749,9 @@ struct smu_context {
|
||||
bool pm_enabled;
|
||||
bool is_apu;
|
||||
|
||||
/* Power dependency link from an integrated xHCI controller to the GPU */
|
||||
struct device_link *usb_power_link;
|
||||
|
||||
uint32_t smc_driver_if_version;
|
||||
uint32_t smc_fw_if_version;
|
||||
uint32_t smc_fw_version;
|
||||
@@ -1648,12 +1651,19 @@ struct pptable_funcs {
|
||||
int (*ras_send_msg)(struct smu_context *smu,
|
||||
enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
|
||||
|
||||
|
||||
/**
|
||||
* @get_ras_smu_drv: Get RAS smu driver interface
|
||||
* Return: ras_smu_drv *
|
||||
*/
|
||||
int (*get_ras_smu_drv)(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv);
|
||||
|
||||
/**
|
||||
* @set_power_dep: Create or destroy a power dependency link
|
||||
* from an integrated xHCI controller to the GPU so that the GPU is
|
||||
* resumed before the USB controller during PM resume. @enable is true
|
||||
* to create the link and false to tear it down.
|
||||
*/
|
||||
int (*set_power_dep)(struct smu_context *smu, bool enable);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -1701,6 +1701,50 @@ static int smu_v14_0_0_restore_user_od_settings(struct smu_context *smu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Link any xHCI controller sharing the GPU's PCIe root port as a consumer
|
||||
* of the GPU so the GPU resumes first, avoiding an xHCI resume race.
|
||||
*/
|
||||
static int smu_v14_0_0_set_power_dep(struct smu_context *smu, bool enable)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
struct pci_dev *gpu_pdev = adev->pdev;
|
||||
struct pci_dev *root_port, *usb_pdev = NULL;
|
||||
struct device_link *link;
|
||||
|
||||
if (!enable) {
|
||||
if (smu->usb_power_link) {
|
||||
device_link_del(smu->usb_power_link);
|
||||
smu->usb_power_link = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
root_port = pcie_find_root_port(gpu_pdev);
|
||||
while ((usb_pdev = pci_get_class(PCI_CLASS_SERIAL_USB_XHCI, usb_pdev))) {
|
||||
struct pci_dev *usb_root;
|
||||
|
||||
usb_root = pcie_find_root_port(usb_pdev);
|
||||
if (usb_root != root_port)
|
||||
continue;
|
||||
|
||||
/* Create device link: USB (consumer) depends on GPU (supplier) */
|
||||
link = device_link_add(&usb_pdev->dev, &gpu_pdev->dev,
|
||||
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
|
||||
if (link) {
|
||||
smu->usb_power_link = link;
|
||||
drm_info(adev_to_drm(adev), "USB controller %s D0 power state depends on %s\n",
|
||||
pci_name(usb_pdev), pci_name(gpu_pdev));
|
||||
/* Only create one link for the first USB controller found */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pci_dev_put(usb_pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
|
||||
.check_fw_status = smu_v14_0_check_fw_status,
|
||||
.check_fw_version = smu_cmn_check_fw_version,
|
||||
@@ -1734,6 +1778,7 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
|
||||
.dpm_set_umsch_mm_enable = smu_v14_0_0_set_umsch_mm_enable,
|
||||
.get_dpm_clock_table = smu_v14_0_common_get_dpm_table,
|
||||
.set_mall_enable = smu_v14_0_common_set_mall_enable,
|
||||
.set_power_dep = smu_v14_0_0_set_power_dep,
|
||||
};
|
||||
|
||||
static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu)
|
||||
|
||||
@@ -781,7 +781,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
|
||||
const struct dev_pagemap *other = NULL;
|
||||
int err, i;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
pfns = kvcalloc(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
if (!pfns)
|
||||
return DRM_GPUSVM_SCAN_UNPOPULATED;
|
||||
|
||||
@@ -1146,20 +1146,35 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
};
|
||||
bool use_iova = dma_use_iova(&svm_pages->state);
|
||||
|
||||
if (use_iova)
|
||||
dma_iova_destroy(dev, &svm_pages->state,
|
||||
svm_pages->state_offset,
|
||||
svm_pages->dma_addr[0].dir, 0);
|
||||
/*
|
||||
* IOVA is reserved for the whole range but only the linked
|
||||
* system pages (state_offset bytes) need unlinking; free the
|
||||
* entire reservation to avoid leaking the device-page part.
|
||||
* On the error path state_offset is 0, so just free it.
|
||||
*/
|
||||
if (use_iova) {
|
||||
if (svm_pages->state_offset)
|
||||
dma_iova_unlink(dev, &svm_pages->state, 0,
|
||||
svm_pages->state_offset,
|
||||
svm_pages->dma_addr[0].dir, 0);
|
||||
dma_iova_free(dev, &svm_pages->state);
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < npages; j++) {
|
||||
struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
|
||||
|
||||
if (!use_iova && addr->proto == DRM_INTERCONNECT_SYSTEM)
|
||||
dma_unmap_page(dev,
|
||||
addr->addr,
|
||||
PAGE_SIZE << addr->order,
|
||||
addr->dir);
|
||||
else if (dpagemap && dpagemap->ops->device_unmap)
|
||||
if (addr->proto == DRM_INTERCONNECT_SYSTEM) {
|
||||
/*
|
||||
* Linked IOVA pages were already torn down by
|
||||
* the dma_iova_unlink()/dma_iova_free() above;
|
||||
* only the non-IOVA mappings need unmap here.
|
||||
*/
|
||||
if (!use_iova)
|
||||
dma_unmap_page(dev,
|
||||
addr->addr,
|
||||
PAGE_SIZE << addr->order,
|
||||
addr->dir);
|
||||
} else if (dpagemap && dpagemap->ops->device_unmap)
|
||||
dpagemap->ops->device_unmap(dpagemap,
|
||||
dev, addr);
|
||||
i += 1 << addr->order;
|
||||
@@ -1486,7 +1501,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
||||
/* Unlock and restart mapping to allocate memory. */
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
svm_pages->dma_addr =
|
||||
kvmalloc_objs(*svm_pages->dma_addr, npages);
|
||||
kvzalloc_objs(*svm_pages->dma_addr, npages);
|
||||
if (!svm_pages->dma_addr) {
|
||||
err = -ENOMEM;
|
||||
goto err_free;
|
||||
@@ -1529,6 +1544,16 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
||||
err = -EAGAIN;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the dpagemap as soon as the first
|
||||
* device page is mapped so the err_unmap path
|
||||
* can device_unmap() the device mappings that
|
||||
* have already been created.
|
||||
*/
|
||||
drm_pagemap_get(dpagemap);
|
||||
drm_pagemap_put(svm_pages->dpagemap);
|
||||
svm_pages->dpagemap = dpagemap;
|
||||
}
|
||||
svm_pages->dma_addr[j] =
|
||||
dpagemap->ops->device_map(dpagemap,
|
||||
@@ -1596,12 +1621,8 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
if (pagemap) {
|
||||
if (pagemap)
|
||||
flags.has_devmem_pages = true;
|
||||
drm_pagemap_get(dpagemap);
|
||||
drm_pagemap_put(svm_pages->dpagemap);
|
||||
svm_pages->dpagemap = dpagemap;
|
||||
}
|
||||
|
||||
/* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
|
||||
WRITE_ONCE(svm_pages->flags.__flags, flags.__flags);
|
||||
@@ -1732,8 +1753,10 @@ int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm,
|
||||
return -EFAULT;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
if (!pfns)
|
||||
if (!pfns) {
|
||||
mmput(mm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hmm_range.hmm_pfns = pfns;
|
||||
while (!time_after(jiffies, timeout)) {
|
||||
|
||||
@@ -727,8 +727,10 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
|
||||
}
|
||||
|
||||
err = ops->populate_devmem_pfn(devmem_allocation, npages, migrate.dst);
|
||||
if (err)
|
||||
goto err_aborted_migration;
|
||||
if (err) {
|
||||
npages = 0;
|
||||
goto err_finalize;
|
||||
}
|
||||
|
||||
own_pages = 0;
|
||||
|
||||
@@ -807,8 +809,11 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
|
||||
msecs_to_jiffies(mdetails->timeslice_ms);
|
||||
|
||||
err_finalize:
|
||||
if (err)
|
||||
if (err) {
|
||||
drm_pagemap_migration_unlock_put_pages(npages, migrate.dst);
|
||||
for (i = npages; i < npages_in_range(start, end); ++i)
|
||||
migrate.dst[i] = 0;
|
||||
}
|
||||
err_aborted_migration:
|
||||
migrate_vma_pages(&migrate);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user