mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 03:35:32 -04:00
ASoC: Fix races on creation of SDCA jack detection
Charles Keepax <ckeepax@opensource.cirrus.com> says: Currently there exists a couple races that can result in the DAPM graph coming up in a state that doesn't match the hardware with respect to SDCA jack detection. This series fixes these up by adding a component level fixup_controls helper into the asoc core and shuffling around the IRQ requests from the SDCA side. The core creates DAPM widgets/routes quite a long time before it creates the associated ALSA control, and the jack detection IRQ is currently registered in component probe. At the time of component probe, the DAPM widgets exist, shortly after this the DAPM routes are added. At the time the DAPM routes are added the register value for the control is checked and the appropriate path is connected. The existing handling in the SDCA jack IRQ handles the case the control doesn't exist and updates the registers directly, which works until the DAPM routes are added. After the routes are added the DAPM graph has already set connected on a particular DAPM path, which will not be updated until an IRQ is received when the control is present. Thus those updates are usually not reflected in the resulting DAPM graph which can lead to the audio path being erroneously powered on/off. Link: https://patch.msgid.link/20260721143636.361814-1-ckeepax@opensource.cirrus.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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -24,7 +24,11 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: spacemit,k1-spi
|
||||
oneOf:
|
||||
- const: spacemit,k1-spi
|
||||
- items:
|
||||
- const: spacemit,k3-spi
|
||||
- const: spacemit,k1-spi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -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
|
||||
|
||||
17
MAINTAINERS
17
MAINTAINERS
@@ -6478,7 +6478,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/
|
||||
@@ -7125,7 +7125,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
|
||||
@@ -11108,6 +11108,7 @@ F: drivers/platform/x86/gpd-pocket-fan.c
|
||||
|
||||
GPIB DRIVERS
|
||||
M: Dave Penkler <dpenkler@gmail.com>
|
||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
S: Maintained
|
||||
F: drivers/gpib/
|
||||
F: include/uapi/linux/gpib.h
|
||||
@@ -14142,7 +14143,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/
|
||||
@@ -17257,6 +17258,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
|
||||
@@ -19108,6 +19110,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>
|
||||
@@ -19299,7 +19302,7 @@ F: fs/ntfs3/
|
||||
|
||||
NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER
|
||||
M: Elizabeth Figura <zfigura@codeweavers.com>
|
||||
L: wine-devel@winehq.org
|
||||
L: wine-devel@list.winehq.org
|
||||
S: Supported
|
||||
F: Documentation/userspace-api/ntsync.rst
|
||||
F: drivers/misc/ntsync.c
|
||||
@@ -25972,8 +25975,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/
|
||||
|
||||
@@ -27929,7 +27933,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
|
||||
@@ -29398,7 +29401,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*
|
||||
|
||||
7
Makefile
7
Makefile
@@ -2,7 +2,7 @@
|
||||
VERSION = 7
|
||||
PATCHLEVEL = 2
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
@@ -475,6 +475,10 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS)
|
||||
|
||||
# These flags apply to all Rust code in the tree, including the kernel and
|
||||
# host programs.
|
||||
#
|
||||
# `-Aclippy::unwrap_or_default`: the lint is buggy [1] and ignores our
|
||||
# MSRV. It can trigger depending on the optimization level.
|
||||
# [1] https://github.com/rust-lang/rust-clippy/issues/17379
|
||||
export rust_common_flags := --edition=2021 \
|
||||
-Zbinary_dep_depinfo=y \
|
||||
-Astable_features \
|
||||
@@ -503,6 +507,7 @@ export rust_common_flags := --edition=2021 \
|
||||
-Aclippy::uninlined_format_args \
|
||||
-Wclippy::unnecessary_safety_comment \
|
||||
-Wclippy::unnecessary_safety_doc \
|
||||
-Aclippy::unwrap_or_default \
|
||||
-Wrustdoc::missing_crate_level_docs \
|
||||
-Wrustdoc::unescaped_backticks
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#ifdef CONFIG_64BIT
|
||||
#define TASK_STRUCT_OFFSET 0
|
||||
#else
|
||||
#define TASK_STRUCT_OFFSET 2000
|
||||
#define TASK_STRUCT_OFFSET 2040
|
||||
#endif
|
||||
|
||||
.macro cpu_save_nonscratch thread
|
||||
|
||||
@@ -201,10 +201,12 @@ static void __init acpi_process_madt(void)
|
||||
}
|
||||
|
||||
int pptt_enabled;
|
||||
static int acpi_nr_packages;
|
||||
static int acpi_package_ids[MAX_PACKAGES];
|
||||
|
||||
int __init parse_acpi_topology(void)
|
||||
{
|
||||
int cpu, topology_id;
|
||||
int i, cpu, topology_id;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
topology_id = find_acpi_cpu_topology(cpu, 0);
|
||||
@@ -222,6 +224,29 @@ int __init parse_acpi_topology(void)
|
||||
|
||||
cpu_data[cpu].core = topology_id;
|
||||
}
|
||||
|
||||
topology_id = find_acpi_cpu_topology_package(cpu);
|
||||
if (topology_id < 0) {
|
||||
pr_warn("Invalid BIOS PPTT\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for (i = 0; i < acpi_nr_packages; i++)
|
||||
if (acpi_package_ids[i] == topology_id)
|
||||
break;
|
||||
|
||||
if (i == acpi_nr_packages)
|
||||
acpi_package_ids[acpi_nr_packages++] = topology_id;
|
||||
|
||||
cpu_data[cpu].package = topology_id;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
for (i = 0; i < acpi_nr_packages; i++)
|
||||
if (cpu_data[cpu].package == acpi_package_ids[i]) {
|
||||
cpu_data[cpu].package = i; /* Canonicalize */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pptt_enabled = 1;
|
||||
|
||||
@@ -252,7 +252,8 @@ static int kgdb_loongarch_notify(struct notifier_block *self, unsigned long cmd,
|
||||
if (atomic_read(&kgdb_active) != -1)
|
||||
kgdb_nmicallback(smp_processor_id(), regs);
|
||||
|
||||
if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs))
|
||||
if (kgdb_handle_exception(regs->csr_era == stepped_address ? 0 : args->trapnr,
|
||||
args->signr, cmd, regs))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (atomic_read(&kgdb_setting_breakpoint))
|
||||
|
||||
@@ -42,6 +42,7 @@ static unsigned long first_ind_entry;
|
||||
int machine_kexec_prepare(struct kimage *kimage)
|
||||
{
|
||||
int i;
|
||||
char head[8];
|
||||
char *bootloader = "kexec";
|
||||
void *cmdline_ptr = (void *)KEXEC_CMDLINE_ADDR;
|
||||
|
||||
@@ -59,7 +60,9 @@ int machine_kexec_prepare(struct kimage *kimage)
|
||||
} else {
|
||||
/* Find the command line */
|
||||
for (i = 0; i < kimage->nr_segments; i++) {
|
||||
if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
|
||||
if (copy_from_user(head, kimage->segment[i].buf, strlen(bootloader)))
|
||||
continue;
|
||||
if (!strncmp(bootloader, head, strlen(bootloader))) {
|
||||
if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
|
||||
kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
|
||||
break;
|
||||
|
||||
@@ -71,27 +71,27 @@
|
||||
cfi_ld s7, PT_R30
|
||||
cfi_ld s8, PT_R31
|
||||
LONG_L t0, sp, PT_CRMD
|
||||
li.d t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
|
||||
LONG_LI t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
|
||||
csrxchg t0, t1, LOONGARCH_CSR_CRMD
|
||||
.endm
|
||||
|
||||
SYM_CODE_START(arch_rethook_trampoline)
|
||||
UNWIND_HINT_UNDEFINED
|
||||
addi.d sp, sp, -PT_SIZE
|
||||
PTR_ADDI sp, sp, -PT_SIZE
|
||||
save_all_base_regs
|
||||
|
||||
addi.d t0, sp, PT_SIZE
|
||||
LONG_S t0, sp, PT_R3
|
||||
PTR_ADDI t0, sp, PT_SIZE
|
||||
LONG_S t0, sp, PT_R3
|
||||
|
||||
move a0, sp /* pt_regs */
|
||||
move a0, sp /* pt_regs */
|
||||
|
||||
bl arch_rethook_trampoline_callback
|
||||
bl arch_rethook_trampoline_callback
|
||||
|
||||
/* use the result as the return-address */
|
||||
move ra, a0
|
||||
move ra, a0
|
||||
|
||||
restore_all_base_regs
|
||||
addi.d sp, sp, PT_SIZE
|
||||
PTR_ADDI sp, sp, PT_SIZE
|
||||
|
||||
jr ra
|
||||
jr ra
|
||||
SYM_CODE_END(arch_rethook_trampoline)
|
||||
|
||||
@@ -603,6 +603,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
memblock_init();
|
||||
pagetable_init();
|
||||
bootcmdline_init(cmdline_p);
|
||||
jump_label_init(); /* Initialise the static keys for early params */
|
||||
parse_early_param();
|
||||
reserve_initrd_mem();
|
||||
|
||||
@@ -610,8 +611,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
arch_mem_init(cmdline_p);
|
||||
|
||||
resource_init();
|
||||
jump_label_init(); /* Initialise the static keys for paravirtualization */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
plat_smp_setup();
|
||||
prefill_possible_map();
|
||||
|
||||
@@ -426,10 +426,10 @@ void loongson_init_secondary(void)
|
||||
numa_add_cpu(cpu);
|
||||
#endif
|
||||
per_cpu(cpu_state, cpu) = CPU_ONLINE;
|
||||
cpu_data[cpu].package =
|
||||
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
|
||||
cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core :
|
||||
cpu_logical_map(cpu) % loongson_sysconf.cores_per_package;
|
||||
cpu_data[cpu].package = pptt_enabled ? cpu_data[cpu].package :
|
||||
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
|
||||
cpu_data[cpu].global_id = cpu_logical_map(cpu);
|
||||
}
|
||||
|
||||
|
||||
@@ -835,7 +835,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
||||
move_reg(ctx, t1, src);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -852,7 +852,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -870,7 +870,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
||||
move_reg(ctx, t1, src);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -887,7 +887,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2361,6 +2361,7 @@ void bpf_jit_free(struct bpf_prog *prog)
|
||||
*/
|
||||
if (jit_data) {
|
||||
bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header);
|
||||
kvfree(jit_data->ctx.offset);
|
||||
kfree(jit_data);
|
||||
}
|
||||
hdr = bpf_jit_binary_pack_hdr(prog);
|
||||
|
||||
@@ -110,7 +110,7 @@ void wildfiremod_halt(void)
|
||||
printk(KERN_INFO "WildFireMod hibernating...\n");
|
||||
|
||||
/* Set portE.5 to Digital IO */
|
||||
mcf_write16(read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
|
||||
mcf_write16(mcf_read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
|
||||
|
||||
/* Make portE.5 an output */
|
||||
mcf_write8(mcf_read8(MCFGPIO_PDDR_E) | (1 << 5), MCFGPIO_PDDR_E);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -27,6 +27,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
|
||||
KBUILD_CFLAGS := -m$(BITS) -O2 $(CLANG_FLAGS)
|
||||
KBUILD_CFLAGS += $(CC_FLAGS_DIALECT)
|
||||
KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
|
||||
KBUILD_CFLAGS += -fno-jump-tables
|
||||
KBUILD_CFLAGS += -Wundef
|
||||
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
|
||||
cflags-$(CONFIG_X86_32) := -march=i386
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1273,14 +1273,14 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
|
||||
inner.extended_error =
|
||||
ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
|
||||
}
|
||||
}
|
||||
|
||||
pr_warn!(
|
||||
"{}:{} transaction to {} failed: {err:?}",
|
||||
info.from_pid,
|
||||
info.from_tid,
|
||||
info.to_pid
|
||||
);
|
||||
pr_warn!(
|
||||
"{}:{} transaction to {} failed: {err:?}",
|
||||
info.from_pid,
|
||||
info.from_tid,
|
||||
info.to_pid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(int irq, void *d)
|
||||
unsigned int ctrl;
|
||||
unsigned short val = 0;
|
||||
|
||||
/*
|
||||
* Check device is fully attached. Device interrupts should have
|
||||
* been disabled, but do this in case of bad hardware.
|
||||
*/
|
||||
if (!dev->attached)
|
||||
return IRQ_NONE;
|
||||
|
||||
ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
|
||||
if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
|
||||
return IRQ_NONE;
|
||||
@@ -233,6 +240,9 @@ static int parport_attach(struct comedi_device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
outb(0, dev->iobase + PARPORT_DATA_REG);
|
||||
outb(0, dev->iobase + PARPORT_CTRL_REG);
|
||||
|
||||
if (it->options[1]) {
|
||||
ret = request_irq(it->options[1], parport_interrupt, 0,
|
||||
dev->board_name, dev);
|
||||
@@ -288,9 +298,6 @@ static int parport_attach(struct comedi_device *dev,
|
||||
s->cancel = parport_intr_cancel;
|
||||
}
|
||||
|
||||
outb(0, dev->iobase + PARPORT_DATA_REG);
|
||||
outb(0, dev->iobase + PARPORT_CTRL_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -297,31 +297,34 @@ static struct fwnet_fragment_info *fwnet_frag_new(
|
||||
if (fi->offset + fi->len == offset) {
|
||||
/* The new fragment can be tacked on to the end */
|
||||
/* Did the new fragment plug a hole? */
|
||||
fi2 = list_entry(fi->fi_link.next,
|
||||
struct fwnet_fragment_info, fi_link);
|
||||
if (fi->offset + fi->len == fi2->offset) {
|
||||
/* glue fragments together */
|
||||
fi->len += len + fi2->len;
|
||||
list_del(&fi2->fi_link);
|
||||
kfree(fi2);
|
||||
} else {
|
||||
fi->len += len;
|
||||
if (!list_is_last(&fi->fi_link, &pd->fi_list)) {
|
||||
fi2 = list_next_entry(fi, fi_link);
|
||||
if (offset + len == fi2->offset) {
|
||||
/* glue fragments together */
|
||||
fi->len += len + fi2->len;
|
||||
list_del(&fi2->fi_link);
|
||||
kfree(fi2);
|
||||
|
||||
return fi;
|
||||
}
|
||||
}
|
||||
fi->len += len;
|
||||
|
||||
return fi;
|
||||
}
|
||||
if (offset + len == fi->offset) {
|
||||
/* The new fragment can be tacked on to the beginning */
|
||||
/* Did the new fragment plug a hole? */
|
||||
fi2 = list_entry(fi->fi_link.prev,
|
||||
struct fwnet_fragment_info, fi_link);
|
||||
if (fi2->offset + fi2->len == fi->offset) {
|
||||
/* glue fragments together */
|
||||
fi2->len += fi->len + len;
|
||||
list_del(&fi->fi_link);
|
||||
kfree(fi);
|
||||
if (!list_is_first(&fi->fi_link, &pd->fi_list)) {
|
||||
fi2 = list_prev_entry(fi, fi_link);
|
||||
if (fi2->offset + fi2->len == offset) {
|
||||
/* glue fragments together */
|
||||
fi2->len += fi->len + len;
|
||||
list_del(&fi->fi_link);
|
||||
kfree(fi);
|
||||
|
||||
return fi2;
|
||||
return fi2;
|
||||
}
|
||||
}
|
||||
fi->offset = offset;
|
||||
fi->len += len;
|
||||
|
||||
@@ -1499,8 +1499,9 @@ int stratix10_svc_async_poll(struct stratix10_svc_chan *chan,
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
return 0;
|
||||
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY) {
|
||||
dev_dbg(ctrl->dev, "async message is still in progress\n");
|
||||
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY ||
|
||||
handle->res.a0 == INTEL_SIP_SMC_STATUS_NO_RESPONSE) {
|
||||
dev_dbg(ctrl->dev, "async message is not ready yet\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
@@ -1857,14 +1858,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
|
||||
struct gen_pool *genpool = chan->ctrl->genpool;
|
||||
size_t s = roundup(size, 1 << genpool->min_alloc_order);
|
||||
|
||||
pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
|
||||
pmem = kzalloc_obj(*pmem);
|
||||
if (!pmem)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
guard(mutex)(&svc_mem_lock);
|
||||
va = gen_pool_alloc(genpool, s);
|
||||
if (!va)
|
||||
if (!va) {
|
||||
kfree(pmem);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
memset((void *)va, 0, s);
|
||||
pa = gen_pool_virt_to_phys(genpool, va);
|
||||
@@ -1890,6 +1893,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
|
||||
void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
|
||||
{
|
||||
struct stratix10_svc_data_mem *pmem;
|
||||
|
||||
guard(mutex)(&svc_mem_lock);
|
||||
|
||||
list_for_each_entry(pmem, &svc_data_mem, node)
|
||||
@@ -1898,10 +1902,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
|
||||
(unsigned long)kaddr, pmem->size);
|
||||
pmem->vaddr = NULL;
|
||||
list_del(&pmem->node);
|
||||
kfree(pmem);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(&svc_data_mem);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
|
||||
|
||||
@@ -2046,12 +2049,12 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
|
||||
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
|
||||
struct stratix10_svc *svc = ctrl->svc;
|
||||
|
||||
platform_device_unregister(svc->stratix10_svc_rsu);
|
||||
|
||||
stratix10_svc_async_exit(ctrl);
|
||||
|
||||
of_platform_depopulate(ctrl->dev);
|
||||
|
||||
platform_device_unregister(svc->stratix10_svc_rsu);
|
||||
|
||||
for (i = 0; i < SVC_NUM_CHANNEL; i++) {
|
||||
if (ctrl->chans[i].task) {
|
||||
kthread_stop(ctrl->chans[i].task);
|
||||
|
||||
@@ -3324,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)
|
||||
|
||||
@@ -280,10 +280,19 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
|
||||
* is enabled. On DCE, vupdate is only needed in VRR mode.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
|
||||
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, enable);
|
||||
if (enable) {
|
||||
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 */
|
||||
/* 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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1753,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);
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
|
||||
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
|
||||
u32 temp;
|
||||
int ret;
|
||||
|
||||
i2c_dev->status = I2C_STAT_INIT;
|
||||
i2c_dev->msg = pmsg;
|
||||
@@ -109,9 +110,14 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
|
||||
HDMI_WRITE(HDMI_HI2CHCR, temp);
|
||||
HDMI_READ(HDMI_HI2CHCR);
|
||||
|
||||
while (i2c_dev->status != I2C_TRANSACTION_DONE)
|
||||
wait_for_completion_interruptible_timeout(&i2c_dev->complete,
|
||||
while (i2c_dev->status != I2C_TRANSACTION_DONE) {
|
||||
ret = wait_for_completion_interruptible_timeout(&i2c_dev->complete,
|
||||
10 * HZ);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -130,7 +136,7 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
||||
{
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
|
||||
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
mutex_lock(&i2c_dev->i2c_lock);
|
||||
|
||||
@@ -142,9 +148,11 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
||||
for (i = 0; i < num; i++) {
|
||||
if (pmsg->len && pmsg->buf) {
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
xfer_read(adap, pmsg);
|
||||
ret = xfer_read(adap, pmsg);
|
||||
else
|
||||
xfer_write(adap, pmsg);
|
||||
ret = xfer_write(adap, pmsg);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
pmsg++; /* next message */
|
||||
}
|
||||
@@ -154,6 +162,9 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
||||
|
||||
mutex_unlock(&i2c_dev->i2c_lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@@ -615,12 +615,7 @@ check_if_vesa_backlight_possible(struct intel_dp *intel_dp)
|
||||
int ret;
|
||||
u8 bit_min, bit_max;
|
||||
|
||||
/*
|
||||
* Since we only support Fully AUX Based VESA Backlight interface make sure
|
||||
* backlight enable is possible via AUX along with backlight adjustment
|
||||
*/
|
||||
if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP &&
|
||||
intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
|
||||
if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
|
||||
return false;
|
||||
|
||||
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min);
|
||||
|
||||
@@ -747,6 +747,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
|
||||
|
||||
pvr_gem_object_get(pvr_obj);
|
||||
|
||||
mutex_lock(&vm_ctx->lock);
|
||||
err = drm_gpuvm_exec_lock(&vm_exec);
|
||||
if (err)
|
||||
goto err_cleanup;
|
||||
@@ -756,6 +757,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
|
||||
drm_gpuvm_exec_unlock(&vm_exec);
|
||||
|
||||
err_cleanup:
|
||||
mutex_unlock(&vm_ctx->lock);
|
||||
pvr_vm_bind_op_fini(&bind_op);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -232,6 +232,7 @@ config DRM_PANEL_HIMAX_HX83121A
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
help
|
||||
@@ -332,6 +333,7 @@ config DRM_PANEL_ILITEK_ILI9882T
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
help
|
||||
Say Y if you want to enable support for panels based on the
|
||||
@@ -954,6 +956,7 @@ config DRM_PANEL_SAMSUNG_S6E3HA8
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
help
|
||||
Say Y or M here if you want to enable support for the
|
||||
|
||||
@@ -2562,9 +2562,12 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
|
||||
"Couldn't get our power regulator\n");
|
||||
|
||||
ctx->iovcc = devm_regulator_get_optional(&dsi->dev, "iovcc");
|
||||
if (IS_ERR(ctx->iovcc))
|
||||
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
|
||||
if (IS_ERR(ctx->iovcc)) {
|
||||
if (PTR_ERR(ctx->iovcc) != -ENODEV)
|
||||
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
|
||||
"Couldn't get our iovcc regulator\n");
|
||||
ctx->iovcc = NULL;
|
||||
}
|
||||
|
||||
ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset))
|
||||
|
||||
@@ -95,13 +95,9 @@ static void drm_gem_shmem_test_obj_create_private(struct kunit *test)
|
||||
sg_init_one(sgt->sgl, buf, TEST_SIZE);
|
||||
|
||||
/*
|
||||
* Set the DMA mask to 64-bits and map the sgtables
|
||||
* otherwise drm_gem_shmem_free will cause a warning
|
||||
* on debug kernels.
|
||||
* Map the sgtables otherwise drm_gem_shmem_free will cause a warning on
|
||||
* debug kernels.
|
||||
*/
|
||||
ret = dma_set_mask(drm_dev->dev, DMA_BIT_MASK(64));
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = dma_map_sgtable(drm_dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
@@ -352,11 +348,19 @@ static int drm_gem_shmem_test_init(struct kunit *test)
|
||||
{
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
int ret;
|
||||
|
||||
/* Allocate a parent device */
|
||||
dev = drm_kunit_helper_alloc_device(test);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
|
||||
|
||||
/*
|
||||
* Set the DMA mask to 64-bits to avoid intermittent failures calling
|
||||
* drm_gem_shmem_get_pages_sgt().
|
||||
*/
|
||||
ret = dma_set_mask(dev, DMA_BIT_MASK(64));
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
/*
|
||||
* The DRM core will automatically initialize the GEM core and create
|
||||
* a DRM Memory Manager object which provides an address space pool
|
||||
|
||||
@@ -315,33 +315,16 @@ static const u32 appletbdrm_primary_plane_formats[] = {
|
||||
DRM_FORMAT_XRGB8888, /* emulated */
|
||||
};
|
||||
|
||||
static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *state)
|
||||
static int appletbdrm_primary_plane_helper_begin_fb_access(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_plane_state)
|
||||
{
|
||||
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
|
||||
struct drm_crtc *new_crtc = new_plane_state->crtc;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
struct appletbdrm_plane_state *appletbdrm_state = to_appletbdrm_plane_state(new_plane_state);
|
||||
size_t frames_size = 0;
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_rect damage;
|
||||
size_t frames_size = 0;
|
||||
size_t request_size;
|
||||
int ret;
|
||||
|
||||
if (new_crtc)
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
|
||||
|
||||
ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (!new_plane_state->visible)
|
||||
return 0;
|
||||
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, new_plane_state);
|
||||
drm_atomic_helper_damage_iter_init(&iter, plane->state, new_plane_state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &damage) {
|
||||
frames_size += struct_size((struct appletbdrm_frame *)0, buf, rect_size(&damage));
|
||||
}
|
||||
@@ -366,6 +349,29 @@ static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
|
||||
appletbdrm_state->request_size = request_size;
|
||||
appletbdrm_state->frames_size = frames_size;
|
||||
|
||||
return drm_gem_begin_shadow_fb_access(plane, new_plane_state);
|
||||
}
|
||||
|
||||
static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_crtc *new_crtc = new_plane_state->crtc;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
int ret;
|
||||
|
||||
if (new_crtc)
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
|
||||
|
||||
ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (!new_plane_state->visible)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -468,7 +474,7 @@ static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
|
||||
}
|
||||
|
||||
static void appletbdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *old_state)
|
||||
struct drm_atomic_commit *old_state)
|
||||
{
|
||||
struct appletbdrm_device *adev = drm_to_adev(plane->dev);
|
||||
struct drm_device *drm = plane->dev;
|
||||
@@ -552,7 +558,8 @@ static void appletbdrm_primary_plane_destroy_state(struct drm_plane *plane,
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs appletbdrm_primary_plane_helper_funcs = {
|
||||
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
|
||||
.begin_fb_access = appletbdrm_primary_plane_helper_begin_fb_access,
|
||||
.end_fb_access = drm_gem_end_shadow_fb_access,
|
||||
.atomic_check = appletbdrm_primary_plane_helper_atomic_check,
|
||||
.atomic_update = appletbdrm_primary_plane_helper_atomic_update,
|
||||
.atomic_disable = appletbdrm_primary_plane_helper_atomic_disable,
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
#include <drm/ttm/ttm_backup.h>
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/page-flags.h>
|
||||
#include <linux/swap.h>
|
||||
|
||||
#include "ttm_pool_internal.h"
|
||||
|
||||
/*
|
||||
* Need to map shmem indices to handle since a handle value
|
||||
* of 0 means error, following the swp_entry_t convention.
|
||||
@@ -68,17 +69,23 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
|
||||
}
|
||||
|
||||
/**
|
||||
* ttm_backup_backup_page() - Backup a page
|
||||
* ttm_backup_backup_folio() - Backup a folio
|
||||
* @backup: The struct backup pointer to use.
|
||||
* @page: The page to back up.
|
||||
* @writeback: Whether to perform immediate writeback of the page.
|
||||
* @folio: The folio to back up.
|
||||
* @order: The allocation order of @folio. Since TTM allocates higher-order
|
||||
* pages without __GFP_COMP, folio_nr_pages(@folio) would always
|
||||
* return 1; the caller must pass the true order explicitly.
|
||||
* @writeback: Whether to perform immediate writeback of the folio's pages.
|
||||
* This may have performance implications.
|
||||
* @idx: A unique integer for each page and each struct backup.
|
||||
* @idx: A unique integer for the first page of the folio and each struct backup.
|
||||
* This allows the backup implementation to avoid managing
|
||||
* its address space separately.
|
||||
* @page_gfp: The gfp value used when the page was allocated.
|
||||
* This is used for accounting purposes.
|
||||
* @folio_gfp: The gfp value used when the folio was allocated.
|
||||
* Currently unused.
|
||||
* @alloc_gfp: The gfp to be used when allocating memory.
|
||||
* @nr_pages_backed: Output. On a successful return, set to the number of
|
||||
* pages actually backed up, which may be less than (1 << @order)
|
||||
* if an -ENOMEM was encountered mid-folio.
|
||||
*
|
||||
* Context: If called from reclaim context, the caller needs to
|
||||
* assert that the shrinker gfp has __GFP_FS set, to avoid
|
||||
@@ -87,53 +94,87 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
|
||||
* that the shrinker gfp has __GFP_IO set, since without it,
|
||||
* we're not allowed to start backup IO.
|
||||
*
|
||||
* Return: A handle on success. Negative error code on failure.
|
||||
*
|
||||
* Note: This function could be extended to back up a folio and
|
||||
* implementations would then split the folio internally if needed.
|
||||
* Drawback is that the caller would then have to keep track of
|
||||
* the folio size- and usage.
|
||||
* Return: A handle for the first backed-up page on success (handles for
|
||||
* subsequent pages follow sequentially). -ENOMEM if no pages could be backed
|
||||
* up. Any other negative error code if a non-ENOMEM failure occurred; in that
|
||||
* case any pages backed up so far are truncated before returning.
|
||||
*/
|
||||
s64
|
||||
ttm_backup_backup_page(struct file *backup, struct page *page,
|
||||
bool writeback, pgoff_t idx, gfp_t page_gfp,
|
||||
gfp_t alloc_gfp)
|
||||
ttm_backup_backup_folio(struct file *backup, struct folio *folio,
|
||||
unsigned int order, bool writeback, pgoff_t idx,
|
||||
gfp_t folio_gfp, gfp_t alloc_gfp,
|
||||
pgoff_t *nr_pages_backed)
|
||||
{
|
||||
struct address_space *mapping = backup->f_mapping;
|
||||
unsigned long handle = 0;
|
||||
int nr_pages = 1 << order;
|
||||
struct folio *to_folio;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
to_folio = shmem_read_folio_gfp(mapping, idx, alloc_gfp);
|
||||
if (IS_ERR(to_folio))
|
||||
return PTR_ERR(to_folio);
|
||||
*nr_pages_backed = 0;
|
||||
|
||||
folio_mark_accessed(to_folio);
|
||||
folio_lock(to_folio);
|
||||
folio_mark_dirty(to_folio);
|
||||
copy_highpage(folio_file_page(to_folio, idx), page);
|
||||
handle = ttm_backup_shmem_idx_to_handle(idx);
|
||||
for (i = 0; i < nr_pages; ) {
|
||||
int to_nr, j;
|
||||
|
||||
if (writeback && !folio_mapped(to_folio) &&
|
||||
folio_clear_dirty_for_io(to_folio)) {
|
||||
folio_set_reclaim(to_folio);
|
||||
ret = shmem_writeout(to_folio, NULL, NULL);
|
||||
if (!folio_test_writeback(to_folio))
|
||||
folio_clear_reclaim(to_folio);
|
||||
/*
|
||||
* If writeout succeeds, it unlocks the folio. errors
|
||||
* are otherwise dropped, since writeout is only best
|
||||
* effort here.
|
||||
* Only inject past the first subpage so *nr_pages_backed is
|
||||
* always > 0 here, matching a genuine mid-compound -ENOMEM
|
||||
* and driving the caller's reactive split fallback instead
|
||||
* of an early, no-progress failure.
|
||||
*/
|
||||
if (ret)
|
||||
if (IS_ENABLED(CONFIG_FAULT_INJECTION) && i &&
|
||||
ttm_backup_fault_inject_folio())
|
||||
to_folio = ERR_PTR(-ENOMEM);
|
||||
else
|
||||
to_folio = shmem_read_folio_gfp(mapping, idx + i, alloc_gfp);
|
||||
if (IS_ERR(to_folio)) {
|
||||
int err = PTR_ERR(to_folio);
|
||||
|
||||
if (err == -ENOMEM && *nr_pages_backed)
|
||||
return ttm_backup_shmem_idx_to_handle(idx);
|
||||
|
||||
if (*nr_pages_backed) {
|
||||
shmem_truncate_range(file_inode(backup),
|
||||
(loff_t)idx << PAGE_SHIFT,
|
||||
((loff_t)(idx + i) << PAGE_SHIFT) - 1);
|
||||
/*
|
||||
* The pages just truncated are no longer
|
||||
* backed up; don't let the caller mistake
|
||||
* them for valid handles.
|
||||
*/
|
||||
*nr_pages_backed = 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
to_nr = min_t(int, nr_pages - i,
|
||||
folio_next_index(to_folio) - (idx + i));
|
||||
|
||||
folio_mark_accessed(to_folio);
|
||||
folio_lock(to_folio);
|
||||
folio_mark_dirty(to_folio);
|
||||
|
||||
for (j = 0; j < to_nr; j++)
|
||||
copy_highpage(folio_file_page(to_folio, idx + i + j),
|
||||
folio_page(folio, i + j));
|
||||
|
||||
if (writeback && !folio_mapped(to_folio) &&
|
||||
folio_clear_dirty_for_io(to_folio)) {
|
||||
folio_set_reclaim(to_folio);
|
||||
ret = shmem_writeout(to_folio, NULL, NULL);
|
||||
if (!folio_test_writeback(to_folio))
|
||||
folio_clear_reclaim(to_folio);
|
||||
if (ret == AOP_WRITEPAGE_ACTIVATE)
|
||||
folio_unlock(to_folio);
|
||||
} else {
|
||||
folio_unlock(to_folio);
|
||||
} else {
|
||||
folio_unlock(to_folio);
|
||||
}
|
||||
|
||||
folio_put(to_folio);
|
||||
i += to_nr;
|
||||
*nr_pages_backed = i;
|
||||
}
|
||||
|
||||
folio_put(to_folio);
|
||||
|
||||
return handle;
|
||||
return ttm_backup_shmem_idx_to_handle(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,8 +53,23 @@
|
||||
#ifdef CONFIG_FAULT_INJECTION
|
||||
#include <linux/fault-inject.h>
|
||||
static DECLARE_FAULT_ATTR(backup_fault_inject);
|
||||
|
||||
/*
|
||||
* Exposed to ttm_backup.c so a mid-compound subpage can be made to fail
|
||||
* with -ENOMEM, exercising the reactive split-and-retry fallback in
|
||||
* ttm_pool_backup() for high-order backups.
|
||||
*/
|
||||
bool ttm_backup_fault_inject_folio(void)
|
||||
{
|
||||
return should_fail(&backup_fault_inject, 1);
|
||||
}
|
||||
#else
|
||||
#define should_fail(...) false
|
||||
|
||||
bool ttm_backup_fault_inject_folio(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -487,7 +502,7 @@ static void ttm_pool_split_for_swap(struct ttm_pool *pool, struct page *p)
|
||||
/**
|
||||
* DOC: Partial backup and restoration of a struct ttm_tt.
|
||||
*
|
||||
* Swapout using ttm_backup_backup_page() and swapin using
|
||||
* Swapout using ttm_backup_backup_folio() and swapin using
|
||||
* ttm_backup_copy_page() may fail.
|
||||
* The former most likely due to lack of swap-space or memory, the latter due
|
||||
* to lack of memory or because of signal interruption during waits.
|
||||
@@ -1036,12 +1051,12 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
||||
{
|
||||
struct file *backup = tt->backup;
|
||||
struct page *page;
|
||||
unsigned long handle;
|
||||
gfp_t alloc_gfp;
|
||||
gfp_t gfp;
|
||||
int ret = 0;
|
||||
pgoff_t shrunken = 0;
|
||||
pgoff_t i, num_pages;
|
||||
pgoff_t i, j, num_pages, npages;
|
||||
pgoff_t nr_backed;
|
||||
|
||||
if (WARN_ON(ttm_tt_is_backed_up(tt)))
|
||||
return -EINVAL;
|
||||
@@ -1119,9 +1134,11 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
||||
if (IS_ENABLED(CONFIG_FAULT_INJECTION) && should_fail(&backup_fault_inject, 1))
|
||||
num_pages = DIV_ROUND_UP(num_pages, 2);
|
||||
|
||||
for (i = 0; i < num_pages; ++i) {
|
||||
s64 shandle;
|
||||
for (i = 0; i < num_pages; i += npages) {
|
||||
unsigned int order;
|
||||
s64 handle;
|
||||
|
||||
npages = 1;
|
||||
page = tt->pages[i];
|
||||
if (unlikely(!page))
|
||||
continue;
|
||||
@@ -1130,19 +1147,61 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
||||
if (unlikely(ttm_backup_page_ptr_is_handle(page)))
|
||||
continue;
|
||||
|
||||
ttm_pool_split_for_swap(pool, page);
|
||||
order = ttm_pool_page_order(pool, page);
|
||||
npages = 1UL << order;
|
||||
|
||||
shandle = ttm_backup_backup_page(backup, page, flags->writeback, i,
|
||||
gfp, alloc_gfp);
|
||||
if (shandle < 0) {
|
||||
/* We allow partially shrunken tts */
|
||||
ret = shandle;
|
||||
/*
|
||||
* We don't allow dipping kernel reserves for high order backup
|
||||
*/
|
||||
if (order)
|
||||
alloc_gfp |= __GFP_NOMEMALLOC;
|
||||
else
|
||||
alloc_gfp &= ~__GFP_NOMEMALLOC;
|
||||
|
||||
/*
|
||||
* Back up the compound atomically at its native order. If
|
||||
* fault injection truncated num_pages mid-compound, skip
|
||||
* the partial tail rather than splitting.
|
||||
*/
|
||||
if (unlikely(i + npages > num_pages))
|
||||
break;
|
||||
|
||||
handle = ttm_backup_backup_folio(backup, page_folio(page),
|
||||
order, flags->writeback, i,
|
||||
gfp, alloc_gfp,
|
||||
&nr_backed);
|
||||
/*
|
||||
* Zero progress on this compound (whether order 0 or a
|
||||
* high-order compound that failed before backing up even
|
||||
* its first subpage) is unrecoverable: bail out rather than
|
||||
* looping forever with npages == nr_backed == 0 below.
|
||||
*/
|
||||
if (unlikely(handle < 0 && !nr_backed)) {
|
||||
ret = handle;
|
||||
break;
|
||||
}
|
||||
handle = shandle;
|
||||
tt->pages[i] = ttm_backup_handle_to_page_ptr(handle);
|
||||
__free_pages_gpu_account(page, 0, false);
|
||||
shrunken++;
|
||||
|
||||
for (j = 0; j < nr_backed; j++)
|
||||
tt->pages[i + j] = ttm_backup_handle_to_page_ptr(handle + j);
|
||||
|
||||
shrunken += nr_backed;
|
||||
|
||||
if (unlikely(nr_backed < npages)) {
|
||||
/*
|
||||
* Partial OOM backup: split the compound and free the
|
||||
* subpages whose content is now in shmem. Continue the
|
||||
* loop from the first un-backed order-0 page.
|
||||
*/
|
||||
ttm_pool_split_for_swap(pool, page);
|
||||
for (j = 0; j < nr_backed; j++)
|
||||
__free_pages_gpu_account(page + j, 0, false);
|
||||
npages = nr_backed;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fully backed up: free at native order. */
|
||||
page->private = 0;
|
||||
__free_pages_gpu_account(page, order, false);
|
||||
}
|
||||
|
||||
return shrunken ? shrunken : ret;
|
||||
|
||||
@@ -22,4 +22,12 @@ static inline unsigned int ttm_pool_beneficial_order(struct ttm_pool *pool)
|
||||
return pool->alloc_flags & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implemented in ttm_pool.c, used by ttm_backup.c. Returns true if a fault
|
||||
* should be injected mid-compound to test the reactive split-and-retry
|
||||
* fallback in ttm_pool_backup(). Always returns false when
|
||||
* CONFIG_FAULT_INJECTION is disabled.
|
||||
*/
|
||||
bool ttm_backup_fault_inject_folio(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -571,6 +571,8 @@ extern bool super_pages;
|
||||
void v3d_init_hw_state(struct v3d_dev *v3d);
|
||||
int v3d_gem_init(struct drm_device *dev);
|
||||
void v3d_gem_destroy(struct drm_device *dev);
|
||||
void v3d_idle_axi(struct v3d_dev *v3d, int core);
|
||||
void v3d_idle_gca(struct v3d_dev *v3d);
|
||||
void v3d_reset_sms(struct v3d_dev *v3d);
|
||||
void v3d_reset(struct v3d_dev *v3d);
|
||||
void v3d_invalidate_caches(struct v3d_dev *v3d);
|
||||
|
||||
@@ -36,9 +36,21 @@ v3d_init_core(struct v3d_dev *v3d, int core)
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2TFLEND, ~0);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
v3d_idle_axi(struct v3d_dev *v3d, int core)
|
||||
{
|
||||
if (v3d->ver >= V3D_GEN_71) {
|
||||
V3D_WRITE(V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ);
|
||||
|
||||
if (wait_for((V3D_READ(V3D_GMP_STATUS(v3d->ver)) &
|
||||
(V3D_GMP_STATUS_RD_COUNT_MASK |
|
||||
V3D_GMP_STATUS_WR_COUNT_MASK |
|
||||
V3D_GMP_STATUS_CFG_BUSY)) == 0, 100)) {
|
||||
drm_err(&v3d->drm, "Failed to wait for safe GMP shutdown\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
V3D_CORE_WRITE(core, V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ);
|
||||
|
||||
if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS(v3d->ver)) &
|
||||
@@ -49,7 +61,7 @@ v3d_idle_axi(struct v3d_dev *v3d, int core)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
v3d_idle_gca(struct v3d_dev *v3d)
|
||||
{
|
||||
if (v3d->ver >= V3D_GEN_41)
|
||||
|
||||
@@ -54,8 +54,15 @@ int v3d_power_suspend(struct device *dev)
|
||||
|
||||
v3d_clean_caches(v3d);
|
||||
|
||||
/* Wait until V3D has no active or pending AXI transactions. */
|
||||
v3d_idle_axi(v3d, 0);
|
||||
v3d_idle_gca(v3d);
|
||||
|
||||
ret = v3d_suspend_sms(v3d);
|
||||
if (ret) {
|
||||
/* Staying active: undo the GMP STOP_REQ from v3d_idle_axi(). */
|
||||
V3D_WRITE(V3D_GMP_CFG(v3d->ver),
|
||||
V3D_READ(V3D_GMP_CFG(v3d->ver)) & ~V3D_GMP_CFG_STOP_REQ);
|
||||
v3d_irq_enable(v3d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -732,9 +732,13 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
|
||||
{
|
||||
struct vc4_bo *bo = to_vc4_bo(obj);
|
||||
|
||||
if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
|
||||
DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
|
||||
return -EINVAL;
|
||||
if (bo->validated_shader) {
|
||||
if (vma->vm_flags & VM_WRITE) {
|
||||
DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vm_flags_clear(vma, VM_MAYWRITE);
|
||||
}
|
||||
|
||||
mutex_lock(&bo->madv_lock);
|
||||
@@ -1044,7 +1048,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
int i;
|
||||
|
||||
timer_delete(&vc4->bo_cache.time_timer);
|
||||
timer_shutdown_sync(&vc4->bo_cache.time_timer);
|
||||
cancel_work_sync(&vc4->bo_cache.time_work);
|
||||
|
||||
vc4_bo_cache_purge(dev);
|
||||
|
||||
@@ -1752,7 +1752,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
|
||||
static void vc4_hvs_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(master);
|
||||
struct drm_device *drm = data;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(drm);
|
||||
struct vc4_hvs *hvs = vc4->hvs;
|
||||
struct drm_mm_node *node, *next;
|
||||
|
||||
@@ -494,7 +494,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
|
||||
static void vc4_v3d_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(master);
|
||||
struct drm_device *drm = data;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(drm);
|
||||
|
||||
vc4_irq_uninstall(drm);
|
||||
|
||||
@@ -78,7 +78,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res,
|
||||
static int vmw_gb_surface_destroy(struct vmw_resource *res);
|
||||
static int
|
||||
vmw_gb_surface_define_internal(struct drm_device *dev,
|
||||
struct drm_vmw_gb_surface_create_ext_req *req,
|
||||
const struct drm_vmw_gb_surface_create_ext_req *req,
|
||||
struct drm_vmw_gb_surface_create_rep *rep,
|
||||
struct drm_file *file_priv);
|
||||
static int
|
||||
@@ -1503,7 +1503,7 @@ int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data,
|
||||
*/
|
||||
static int
|
||||
vmw_gb_surface_define_internal(struct drm_device *dev,
|
||||
struct drm_vmw_gb_surface_create_ext_req *req,
|
||||
const struct drm_vmw_gb_surface_create_ext_req *req,
|
||||
struct drm_vmw_gb_surface_create_rep *rep,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
@@ -1521,9 +1521,21 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
|
||||
req->base.svga3d_flags);
|
||||
|
||||
/* array_size must be null for non-GL3 host. */
|
||||
if (req->base.array_size > 0 && !has_sm4_context(dev_priv)) {
|
||||
VMW_DEBUG_USER("SM4 surface not supported.\n");
|
||||
return -EINVAL;
|
||||
if (req->base.array_size > 0) {
|
||||
if (has_sm5_context(dev_priv)) {
|
||||
if (req->base.array_size > SVGA3D_SM5_MAX_SURFACE_ARRAYSIZE) {
|
||||
VMW_DEBUG_USER("Invalid Surface Array Size.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (has_sm4_context(dev_priv)) {
|
||||
if (req->base.array_size > SVGA3D_SM4_MAX_SURFACE_ARRAYSIZE) {
|
||||
VMW_DEBUG_USER("Invalid Surface Array Size.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
VMW_DEBUG_USER("SM4+ surface not supported.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_sm4_1_context(dev_priv)) {
|
||||
|
||||
@@ -95,18 +95,21 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c)
|
||||
struct platform_device *pdev;
|
||||
struct fwnode_handle *fwnode;
|
||||
int ret;
|
||||
u32 id;
|
||||
|
||||
fwnode = fwnode_create_software_node(xe_i2c_adapter_properties, NULL);
|
||||
if (IS_ERR(fwnode))
|
||||
return PTR_ERR(fwnode);
|
||||
|
||||
id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci);
|
||||
|
||||
/*
|
||||
* Not using platform_device_register_full() here because we don't have
|
||||
* a handle to the platform_device before it returns. xe_i2c_notifier()
|
||||
* uses that handle, but it may be called before
|
||||
* platform_device_register_full() is done.
|
||||
*/
|
||||
pdev = platform_device_alloc(adapter_name, pci_dev_id(pci));
|
||||
pdev = platform_device_alloc(adapter_name, id);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto err_fwnode_remove;
|
||||
|
||||
@@ -1313,6 +1313,7 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,
|
||||
* content.
|
||||
* @src_bo: The buffer object @src is currently bound to.
|
||||
* @read_write : Creates BB commands for CCS read/write.
|
||||
* @bound: Device is bound
|
||||
*
|
||||
* Directly clearing the BB lacks atomicity and can lead to undefined
|
||||
* behavior if the vCPU is halted mid-operation during the clearing
|
||||
@@ -1325,7 +1326,8 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,
|
||||
* Returns: None.
|
||||
*/
|
||||
void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo,
|
||||
enum xe_sriov_vf_ccs_rw_ctxs read_write)
|
||||
enum xe_sriov_vf_ccs_rw_ctxs read_write,
|
||||
bool bound)
|
||||
{
|
||||
struct xe_mem_pool_node *bb = src_bo->bb_ccs[read_write];
|
||||
struct xe_device *xe = xe_bo_device(src_bo);
|
||||
@@ -1339,13 +1341,15 @@ void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo,
|
||||
bb_pool = ctx->mem.ccs_bb_pool;
|
||||
|
||||
scoped_guard(mutex, xe_mem_pool_bo_swap_guard(bb_pool)) {
|
||||
xe_mem_pool_swap_shadow_locked(bb_pool);
|
||||
if (bound) {
|
||||
xe_mem_pool_swap_shadow_locked(bb_pool);
|
||||
|
||||
cs = xe_mem_pool_node_cpu_addr(bb);
|
||||
memset(cs, MI_NOOP, bb->sa_node.size);
|
||||
xe_sriov_vf_ccs_rw_update_bb_addr(ctx);
|
||||
cs = xe_mem_pool_node_cpu_addr(bb);
|
||||
memset(cs, MI_NOOP, bb->sa_node.size);
|
||||
xe_sriov_vf_ccs_rw_update_bb_addr(ctx);
|
||||
|
||||
xe_mem_pool_sync_shadow_locked(bb);
|
||||
xe_mem_pool_sync_shadow_locked(bb);
|
||||
}
|
||||
xe_mem_pool_free_node(bb);
|
||||
src_bo->bb_ccs[read_write] = NULL;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,8 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,
|
||||
enum xe_sriov_vf_ccs_rw_ctxs read_write);
|
||||
|
||||
void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo,
|
||||
enum xe_sriov_vf_ccs_rw_ctxs read_write);
|
||||
enum xe_sriov_vf_ccs_rw_ctxs read_write,
|
||||
bool bound);
|
||||
|
||||
struct xe_lrc *xe_migrate_lrc(struct xe_migrate *migrate);
|
||||
struct xe_exec_queue *xe_migrate_exec_queue(struct xe_migrate *migrate);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Copyright © 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#include "instructions/xe_mi_commands.h"
|
||||
#include "instructions/xe_gpu_commands.h"
|
||||
#include "xe_bb.h"
|
||||
@@ -446,7 +448,7 @@ int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo, struct ttm_resource *new_mem)
|
||||
*/
|
||||
for_each_ccs_rw_ctx(ctx_id) {
|
||||
if (bo->bb_ccs[ctx_id])
|
||||
xe_migrate_ccs_rw_copy_clear(bo, ctx_id);
|
||||
xe_migrate_ccs_rw_copy_clear(bo, ctx_id, true);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -466,19 +468,27 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo)
|
||||
struct xe_device *xe = xe_bo_device(bo);
|
||||
enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
|
||||
struct xe_mem_pool_node *bb;
|
||||
bool bound;
|
||||
int idx;
|
||||
|
||||
xe_assert(xe, IS_VF_CCS_READY(xe));
|
||||
|
||||
if (!xe_bo_has_valid_ccs_bb(bo))
|
||||
return 0;
|
||||
|
||||
bound = drm_dev_enter(&xe->drm, &idx);
|
||||
|
||||
for_each_ccs_rw_ctx(ctx_id) {
|
||||
bb = bo->bb_ccs[ctx_id];
|
||||
if (!bb)
|
||||
continue;
|
||||
|
||||
xe_migrate_ccs_rw_copy_clear(bo, ctx_id);
|
||||
xe_migrate_ccs_rw_copy_clear(bo, ctx_id, bound);
|
||||
}
|
||||
|
||||
if (bound)
|
||||
drm_dev_exit(idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1809,10 +1809,10 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err_svm_fini:
|
||||
if (flags & XE_VM_FLAG_FAULT_MODE) {
|
||||
vm->size = 0; /* close the vm */
|
||||
xe_svm_fini(vm);
|
||||
}
|
||||
vm->size = 0; /* close the vm */
|
||||
if (flags & XE_VM_FLAG_FAULT_MODE)
|
||||
xe_svm_close(vm);
|
||||
xe_svm_fini(vm);
|
||||
err_no_resv:
|
||||
mutex_destroy(&vm->snap_mutex);
|
||||
for_each_tile(tile, xe, id)
|
||||
|
||||
@@ -332,6 +332,20 @@ static int xe_vm_invalidate_madvise_range(struct xe_vm *vm, u64 start, u64 end)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* madvise_range_needs_invalidation() - Check whether madvise needs invalidation
|
||||
* @args: madvise ioctl arguments
|
||||
*
|
||||
* Purgeable state updates only touch VMA/BO metadata. PTEs stay valid and are
|
||||
* zapped only if the BO is later purged.
|
||||
*
|
||||
* Return: true when the update needs PTE invalidation.
|
||||
*/
|
||||
static bool madvise_range_needs_invalidation(const struct drm_xe_madvise *args)
|
||||
{
|
||||
return args->type != DRM_XE_VMA_ATTR_PURGEABLE_STATE;
|
||||
}
|
||||
|
||||
static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madvise *args)
|
||||
{
|
||||
if (XE_IOCTL_DBG(xe, !args))
|
||||
@@ -708,8 +722,9 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
|
||||
madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args,
|
||||
&details);
|
||||
|
||||
err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr,
|
||||
madvise_range.addr + args->range);
|
||||
if (madvise_range_needs_invalidation(args))
|
||||
err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr,
|
||||
madvise_range.addr + args->range);
|
||||
|
||||
if (madvise_range.has_svm_userptr_vmas)
|
||||
xe_svm_notifier_unlock(vm);
|
||||
|
||||
@@ -1009,7 +1009,7 @@ struct ec_sensors_data {
|
||||
/* sorted list of unique register banks */
|
||||
u8 banks[ASUS_EC_MAX_BANK + 1];
|
||||
/* in jiffies */
|
||||
unsigned long last_updated;
|
||||
u64 next_update;
|
||||
struct lock_data lock_data;
|
||||
/* number of board EC sensors */
|
||||
u8 nr_sensors;
|
||||
@@ -1189,7 +1189,7 @@ static int asus_ec_block_read(const struct device *dev,
|
||||
}
|
||||
for (ireg = 0; ireg < ec->nr_registers; ireg++) {
|
||||
reg_bank = register_bank(ec->registers[ireg]);
|
||||
if (reg_bank < bank) {
|
||||
if (reg_bank != bank) {
|
||||
continue;
|
||||
}
|
||||
ec_read(register_index(ec->registers[ireg]),
|
||||
@@ -1278,13 +1278,12 @@ static int get_cached_value_or_update(const struct device *dev,
|
||||
int sensor_index,
|
||||
struct ec_sensors_data *state, s32 *value)
|
||||
{
|
||||
if (time_after(jiffies, state->last_updated + HZ)) {
|
||||
if (time_after64(get_jiffies_64(), state->next_update)) {
|
||||
if (update_ec_sensors(dev, state)) {
|
||||
dev_err(dev, "update_ec_sensors() failure\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
state->last_updated = jiffies;
|
||||
state->next_update = get_jiffies_64() + HZ;
|
||||
}
|
||||
|
||||
*value = state->sensors[sensor_index].cached_value;
|
||||
@@ -1402,6 +1401,7 @@ static int asus_ec_probe(struct platform_device *pdev)
|
||||
if (!ec_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ec_data->next_update = INITIAL_JIFFIES;
|
||||
dev_set_drvdata(dev, ec_data);
|
||||
ec_data->board_info = pboard_info;
|
||||
|
||||
@@ -1495,9 +1495,11 @@ static int asus_ec_probe(struct platform_device *pdev)
|
||||
if (!nr_count[type])
|
||||
continue;
|
||||
|
||||
asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
|
||||
nr_count[type], type,
|
||||
hwmon_attributes[type]);
|
||||
status = asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
|
||||
nr_count[type], type,
|
||||
hwmon_attributes[type]);
|
||||
if (status)
|
||||
return status;
|
||||
*ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;
|
||||
}
|
||||
|
||||
|
||||
@@ -645,6 +645,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
||||
out_hw_close:
|
||||
hid_hw_close(hdev);
|
||||
hid_device_io_stop(hdev);
|
||||
out_hw_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
|
||||
@@ -822,6 +822,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
|
||||
fail_and_close:
|
||||
hid_hw_close(hdev);
|
||||
hid_device_io_stop(hdev);
|
||||
fail_and_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
|
||||
@@ -371,13 +371,15 @@ static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
if (IS_ERR(priv->hwmon_dev)) {
|
||||
ret = PTR_ERR(priv->hwmon_dev);
|
||||
hid_err(hdev, "hwmon registration failed with %d\n", ret);
|
||||
goto fail_and_close;
|
||||
goto fail_and_io_stop;
|
||||
}
|
||||
|
||||
waterforce_debugfs_init(priv);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_and_io_stop:
|
||||
hid_device_io_stop(hdev);
|
||||
fail_and_close:
|
||||
hid_hw_close(hdev);
|
||||
fail_and_stop:
|
||||
|
||||
@@ -948,7 +948,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
|
||||
ret = kraken3_init_device(hdev);
|
||||
if (ret < 0) {
|
||||
hid_err(hdev, "device init failed with %d\n", ret);
|
||||
goto fail_and_close;
|
||||
goto fail_and_stop_io;
|
||||
}
|
||||
|
||||
ret = kraken3_get_fw_ver(hdev);
|
||||
@@ -960,13 +960,15 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
|
||||
if (IS_ERR(priv->hwmon_dev)) {
|
||||
ret = PTR_ERR(priv->hwmon_dev);
|
||||
hid_err(hdev, "hwmon registration failed with %d\n", ret);
|
||||
goto fail_and_close;
|
||||
goto fail_and_stop_io;
|
||||
}
|
||||
|
||||
kraken3_debugfs_init(priv, device_name);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_and_stop_io:
|
||||
hid_device_io_stop(hdev);
|
||||
fail_and_close:
|
||||
hid_hw_close(hdev);
|
||||
fail_and_stop:
|
||||
|
||||
@@ -768,7 +768,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
|
||||
|
||||
out_hw_close:
|
||||
hid_hw_close(hdev);
|
||||
|
||||
hid_device_io_stop(hdev);
|
||||
out_hw_stop:
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
|
||||
@@ -1052,32 +1052,49 @@ static int occ_setup_sensor_attrs(struct occ *occ)
|
||||
}
|
||||
|
||||
/* only need to do this once at startup, as OCC won't change sensors on us */
|
||||
static void occ_parse_poll_response(struct occ *occ)
|
||||
static int occ_parse_poll_response(struct occ *occ)
|
||||
{
|
||||
unsigned int i, old_offset, offset = 0, size = 0;
|
||||
u16 data_length;
|
||||
struct occ_sensor *sensor;
|
||||
struct occ_sensors *sensors = &occ->sensors;
|
||||
struct occ_sensors parsed = {};
|
||||
struct occ_sensors *sensors = &parsed;
|
||||
struct occ_response *resp = &occ->resp;
|
||||
struct occ_poll_response *poll =
|
||||
(struct occ_poll_response *)&resp->data[0];
|
||||
struct occ_poll_response_header *header = &poll->header;
|
||||
struct occ_sensor_data_block *block = &poll->block;
|
||||
|
||||
data_length = get_unaligned_be16(&resp->data_length);
|
||||
if (data_length < sizeof(*header) || data_length > OCC_RESP_DATA_BYTES) {
|
||||
dev_err(occ->bus_dev, "invalid OCC poll response length %u\n",
|
||||
data_length);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
dev_info(occ->bus_dev, "OCC found, code level: %.16s\n",
|
||||
header->occ_code_level);
|
||||
|
||||
for (i = 0; i < header->num_sensor_data_blocks; ++i) {
|
||||
block = (struct occ_sensor_data_block *)((u8 *)block + offset);
|
||||
if (size + sizeof(*header) + sizeof(block->header) >
|
||||
data_length) {
|
||||
dev_err(occ->bus_dev,
|
||||
"truncated OCC sensor block header\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
old_offset = offset;
|
||||
offset = (block->header.num_sensors *
|
||||
block->header.sensor_length) + sizeof(block->header);
|
||||
size += offset;
|
||||
|
||||
/* validate all the length/size fields */
|
||||
if ((size + sizeof(*header)) >= OCC_RESP_DATA_BYTES) {
|
||||
dev_warn(occ->bus_dev, "exceeded response buffer\n");
|
||||
return;
|
||||
if (size + sizeof(*header) + offset > data_length) {
|
||||
dev_err(occ->bus_dev,
|
||||
"exceeded OCC poll response length\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
size += offset;
|
||||
|
||||
dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n",
|
||||
old_offset, offset - 1, block->header.eye_catcher,
|
||||
@@ -1107,6 +1124,9 @@ static void occ_parse_poll_response(struct occ *occ)
|
||||
|
||||
dev_dbg(occ->bus_dev, "Max resp size: %u+%zd=%zd\n", size,
|
||||
sizeof(*header), size + sizeof(*header));
|
||||
occ->sensors = parsed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int occ_active(struct occ *occ, bool active)
|
||||
@@ -1138,10 +1158,12 @@ int occ_active(struct occ *occ, bool active)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
occ->active = true;
|
||||
occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
|
||||
occ_parse_poll_response(occ);
|
||||
rc = occ_parse_poll_response(occ);
|
||||
if (rc)
|
||||
goto unlock;
|
||||
|
||||
occ->active = true;
|
||||
rc = occ_setup_sensor_attrs(occ);
|
||||
if (rc) {
|
||||
dev_err(occ->bus_dev,
|
||||
|
||||
@@ -88,6 +88,33 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
data->iout_oc_warn_limit);
|
||||
break;
|
||||
case PMBUS_VIN_OV_FAULT_LIMIT:
|
||||
case PMBUS_VIN_OV_WARN_LIMIT:
|
||||
case PMBUS_VIN_UV_WARN_LIMIT:
|
||||
case PMBUS_VIN_UV_FAULT_LIMIT:
|
||||
case PMBUS_MFR_VIN_MIN:
|
||||
case PMBUS_MFR_VIN_MAX:
|
||||
case PMBUS_IIN_OC_WARN_LIMIT:
|
||||
case PMBUS_IIN_OC_FAULT_LIMIT:
|
||||
case PMBUS_MFR_IIN_MAX:
|
||||
case PMBUS_MFR_VOUT_MIN:
|
||||
case PMBUS_MFR_VOUT_MAX:
|
||||
case PMBUS_IOUT_UC_FAULT_LIMIT:
|
||||
case PMBUS_MFR_IOUT_MAX:
|
||||
case PMBUS_UT_WARN_LIMIT:
|
||||
case PMBUS_UT_FAULT_LIMIT:
|
||||
case PMBUS_MFR_MAX_TEMP_1:
|
||||
/*
|
||||
* MAX34451/ADPM family do not support VIN/IIN limit registers,
|
||||
* manufacturer-specific min/max registers, or undercurrent/
|
||||
* undertemperature fault limits. Accessing these triggers CML
|
||||
* error and asserts ALERT.
|
||||
*/
|
||||
if (data->id == max34451 || data->id == adpm12160 ||
|
||||
data->id == adpm12200 || data->id == adpm12250)
|
||||
return -ENXIO;
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
case PMBUS_VIRT_READ_VOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page, phase,
|
||||
MAX34440_MFR_VOUT_MIN);
|
||||
@@ -244,6 +271,51 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max34451_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct max34440_data *data = to_max34440_data(info);
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_BYTE:
|
||||
case PMBUS_STATUS_OTHER:
|
||||
/*
|
||||
* MAX34451/ADPM family do not support STATUS_BYTE or
|
||||
* STATUS_OTHER registers. Accessing them triggers CML
|
||||
* error and asserts ALERT.
|
||||
*/
|
||||
if (data->id == max34451 || data->id == adpm12160 ||
|
||||
data->id == adpm12200 || data->id == adpm12250)
|
||||
return -ENXIO;
|
||||
return -ENODATA;
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int max34451_write_byte_data(struct i2c_client *client, int page,
|
||||
int reg, u8 byte)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
const struct max34440_data *data = to_max34440_data(info);
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_STATUS_BYTE:
|
||||
case PMBUS_STATUS_OTHER:
|
||||
/*
|
||||
* MAX34451/ADPM family do not support STATUS_BYTE or
|
||||
* STATUS_OTHER registers. Writing to them triggers CML
|
||||
* error and asserts ALERT.
|
||||
*/
|
||||
if (data->id == max34451 || data->id == adpm12160 ||
|
||||
data->id == adpm12200 || data->id == adpm12250)
|
||||
return -ENXIO;
|
||||
return -ENODATA;
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int max34451_set_supported_funcs(struct i2c_client *client,
|
||||
struct max34440_data *data)
|
||||
{
|
||||
@@ -363,7 +435,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[9] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[adpm12200] = {
|
||||
@@ -399,7 +473,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[14] = PMBUS_HAVE_IOUT,
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[adpm12250] = {
|
||||
@@ -433,7 +509,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
|
||||
.func[14] = PMBUS_HAVE_IOUT,
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
},
|
||||
[max34440] = {
|
||||
@@ -581,7 +659,9 @@ static struct pmbus_driver_info max34440_info[] = {
|
||||
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = max34451_read_byte_data,
|
||||
.read_word_data = max34440_read_word_data,
|
||||
.write_byte_data = max34451_write_byte_data,
|
||||
.write_word_data = max34440_write_word_data,
|
||||
.page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
|
||||
},
|
||||
|
||||
@@ -843,18 +843,8 @@ static int intel_th_output_open(struct inode *inode, struct file *file)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int intel_th_output_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct intel_th_device *thdev = file->private_data;
|
||||
|
||||
put_device(&thdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations intel_th_output_fops = {
|
||||
.open = intel_th_output_open,
|
||||
.release = intel_th_output_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
|
||||
@@ -1490,8 +1490,10 @@ static int intel_th_msc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct msc_iter *iter = file->private_data;
|
||||
struct msc *msc = iter->msc;
|
||||
struct intel_th_device *thdev = msc->thdev;
|
||||
|
||||
msc_iter_remove(iter, msc);
|
||||
put_device(&thdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ static void bng_re_fill_fw_msg(struct bnge_fw_msg *fw_msg, void *msg,
|
||||
}
|
||||
|
||||
static int bng_re_net_ring_free(struct bng_re_dev *rdev,
|
||||
u16 fw_ring_id, int type)
|
||||
u32 fw_ring_id, int type)
|
||||
{
|
||||
struct bnge_auxr_dev *aux_dev = rdev->aux_dev;
|
||||
struct hwrm_ring_free_input req = {};
|
||||
@@ -123,7 +123,7 @@ static int bng_re_net_ring_free(struct bng_re_dev *rdev,
|
||||
|
||||
bng_re_init_hwrm_hdr((void *)&req, HWRM_RING_FREE);
|
||||
req.ring_type = type;
|
||||
req.ring_id = cpu_to_le16(fw_ring_id);
|
||||
req.ring_id = cpu_to_le32(fw_ring_id);
|
||||
bng_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
|
||||
sizeof(resp), BNGE_DFLT_HWRM_CMD_TIMEOUT);
|
||||
rc = bnge_send_msg(aux_dev, &fw_msg);
|
||||
@@ -161,7 +161,7 @@ static int bng_re_net_ring_alloc(struct bng_re_dev *rdev,
|
||||
sizeof(resp), BNGE_DFLT_HWRM_CMD_TIMEOUT);
|
||||
rc = bnge_send_msg(aux_dev, &fw_msg);
|
||||
if (!rc)
|
||||
*fw_ring_id = le16_to_cpu(resp.ring_id);
|
||||
*fw_ring_id = (u16)le32_to_cpu(resp.ring_id);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3864,6 +3864,12 @@ static int __init parse_ivrs_acpihid(char *str)
|
||||
return 1;
|
||||
|
||||
found:
|
||||
if (early_acpihid_map_size == EARLY_MAP_SIZE) {
|
||||
pr_err("Early ACPI HID map overflow - ignoring ivrs_acpihid%s\n",
|
||||
str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = acpiid;
|
||||
hid = strsep(&p, ":");
|
||||
uid = p;
|
||||
|
||||
@@ -1450,11 +1450,23 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
|
||||
int ret;
|
||||
u64 data;
|
||||
|
||||
if (!iommu->need_sync)
|
||||
return 0;
|
||||
|
||||
raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||
|
||||
if (!iommu->need_sync) {
|
||||
/*
|
||||
* No command has been queued since the last completion-wait.
|
||||
* A concurrent CPU may have already queued that CWAIT and
|
||||
* cleared need_sync; need_sync == false only means a covering
|
||||
* CWAIT is queued, not that all prior commands have completed.
|
||||
* Wait for the last allocated sequence number so that any
|
||||
* command queued before this call (possibly on another CPU)
|
||||
* is guaranteed to have completed before returning.
|
||||
*/
|
||||
data = iommu->cmd_sem_val;
|
||||
raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
return wait_on_sem(iommu, data);
|
||||
}
|
||||
|
||||
data = get_cmdsem_val(iommu);
|
||||
build_completion_wait(&cmd, iommu, data);
|
||||
|
||||
@@ -1464,9 +1476,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wait_on_sem(iommu, data);
|
||||
|
||||
return ret;
|
||||
return wait_on_sem(iommu, data);
|
||||
}
|
||||
|
||||
static void domain_flush_complete(struct protection_domain *domain)
|
||||
|
||||
@@ -59,7 +59,9 @@ static int validate_gdte_nested(struct iommu_hwpt_amd_guest *gdte)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *gdom_info_load_or_alloc_locked(struct xarray *xa, unsigned long index)
|
||||
static void *gdom_info_load_or_alloc_locked(struct xarray *xa,
|
||||
unsigned long index,
|
||||
unsigned long *flags)
|
||||
{
|
||||
struct guest_domain_mapping_info *elm, *res;
|
||||
|
||||
@@ -67,13 +69,13 @@ static void *gdom_info_load_or_alloc_locked(struct xarray *xa, unsigned long ind
|
||||
if (elm)
|
||||
return elm;
|
||||
|
||||
xa_unlock(xa);
|
||||
xa_unlock_irqrestore(xa, *flags);
|
||||
elm = kzalloc_obj(struct guest_domain_mapping_info);
|
||||
xa_lock(xa);
|
||||
xa_lock_irqsave(xa, *flags);
|
||||
if (!elm)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
res = __xa_cmpxchg(xa, index, NULL, elm, GFP_KERNEL);
|
||||
res = __xa_cmpxchg(xa, index, NULL, elm, GFP_ATOMIC);
|
||||
if (xa_is_err(res))
|
||||
res = ERR_PTR(xa_err(res));
|
||||
|
||||
@@ -95,6 +97,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
|
||||
const struct iommu_user_data *user_data)
|
||||
{
|
||||
int ret;
|
||||
unsigned long irqflags;
|
||||
struct nested_domain *ndom;
|
||||
struct guest_domain_mapping_info *gdom_info;
|
||||
struct amd_iommu_viommu *aviommu = container_of(viommu, struct amd_iommu_viommu, core);
|
||||
@@ -136,11 +139,12 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
|
||||
* keep track of the gDomID mapping. When the S2 is changed, the INVALIDATE_IOMMU_PAGES
|
||||
* command must be issued for each hDomID in the xarray.
|
||||
*/
|
||||
xa_lock(&aviommu->gdomid_array);
|
||||
xa_lock_irqsave(&aviommu->gdomid_array, irqflags);
|
||||
|
||||
gdom_info = gdom_info_load_or_alloc_locked(&aviommu->gdomid_array, ndom->gdom_id);
|
||||
gdom_info = gdom_info_load_or_alloc_locked(&aviommu->gdomid_array,
|
||||
ndom->gdom_id, &irqflags);
|
||||
if (IS_ERR(gdom_info)) {
|
||||
xa_unlock(&aviommu->gdomid_array);
|
||||
xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
|
||||
ret = PTR_ERR(gdom_info);
|
||||
goto out_err;
|
||||
}
|
||||
@@ -148,7 +152,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
|
||||
/* Check if gDomID exist */
|
||||
if (refcount_inc_not_zero(&gdom_info->users)) {
|
||||
ndom->gdom_info = gdom_info;
|
||||
xa_unlock(&aviommu->gdomid_array);
|
||||
xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
|
||||
|
||||
pr_debug("%s: Found gdom_id=%#x, hdom_id=%#x\n",
|
||||
__func__, ndom->gdom_id, gdom_info->hdom_id);
|
||||
@@ -161,7 +165,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
|
||||
if (gdom_info->hdom_id <= 0) {
|
||||
__xa_cmpxchg(&aviommu->gdomid_array,
|
||||
ndom->gdom_id, gdom_info, NULL, GFP_ATOMIC);
|
||||
xa_unlock(&aviommu->gdomid_array);
|
||||
xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
|
||||
ret = -ENOSPC;
|
||||
goto out_err_gdom_info;
|
||||
}
|
||||
@@ -169,7 +173,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
|
||||
ndom->gdom_info = gdom_info;
|
||||
refcount_set(&gdom_info->users, 1);
|
||||
|
||||
xa_unlock(&aviommu->gdomid_array);
|
||||
xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
|
||||
|
||||
pr_debug("%s: Allocate gdom_id=%#x, hdom_id=%#x\n",
|
||||
__func__, ndom->gdom_id, gdom_info->hdom_id);
|
||||
@@ -257,14 +261,15 @@ static int nested_attach_device(struct iommu_domain *dom, struct device *dev,
|
||||
|
||||
static void nested_domain_free(struct iommu_domain *dom)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
struct guest_domain_mapping_info *curr;
|
||||
struct nested_domain *ndom = to_ndomain(dom);
|
||||
struct nested_domain *ndom __free(kfree) = to_ndomain(dom);
|
||||
struct amd_iommu_viommu *aviommu = ndom->viommu;
|
||||
|
||||
xa_lock(&aviommu->gdomid_array);
|
||||
xa_lock_irqsave(&aviommu->gdomid_array, irqflags);
|
||||
|
||||
if (!refcount_dec_and_test(&ndom->gdom_info->users)) {
|
||||
xa_unlock(&aviommu->gdomid_array);
|
||||
xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,7 +280,7 @@ static void nested_domain_free(struct iommu_domain *dom)
|
||||
curr = __xa_cmpxchg(&aviommu->gdomid_array, ndom->gdom_id,
|
||||
ndom->gdom_info, NULL, GFP_ATOMIC);
|
||||
|
||||
xa_unlock(&aviommu->gdomid_array);
|
||||
xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags);
|
||||
if (WARN_ON(!curr || xa_err(curr)))
|
||||
return;
|
||||
|
||||
@@ -285,7 +290,6 @@ static void nested_domain_free(struct iommu_domain *dom)
|
||||
|
||||
amd_iommu_pdom_id_free(ndom->gdom_info->hdom_id);
|
||||
kfree(curr);
|
||||
kfree(ndom);
|
||||
}
|
||||
|
||||
static const struct iommu_domain_ops nested_domain_ops = {
|
||||
|
||||
@@ -63,7 +63,7 @@ void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&latency_lock, flags);
|
||||
memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
|
||||
memset(&lstat[type], 0, sizeof(*lstat));
|
||||
spin_unlock_irqrestore(&latency_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
void intel_svm_check(struct intel_iommu *iommu)
|
||||
{
|
||||
if (!pasid_supported(iommu))
|
||||
if (!pasid_supported(iommu) || !ecap_smpwc(iommu->ecap))
|
||||
return;
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_GBPAGES) &&
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -1330,15 +1331,16 @@ static void mei_dev_bus_put(struct mei_device *bus)
|
||||
static void mei_cl_bus_dev_release(struct device *dev)
|
||||
{
|
||||
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
||||
struct mei_device *mdev = cldev->cl->dev;
|
||||
struct mei_device *bus = cldev->bus;
|
||||
struct mei_cl *cl;
|
||||
|
||||
mei_cl_flush_queues(cldev->cl, NULL);
|
||||
mei_me_cl_put(cldev->me_cl);
|
||||
mei_dev_bus_put(cldev->bus);
|
||||
|
||||
list_for_each_entry(cl, &mdev->file_list, link)
|
||||
WARN_ON(cl == cldev->cl);
|
||||
scoped_guard(mutex, &bus->device_lock) {
|
||||
mei_cl_flush_queues(cldev->cl, NULL);
|
||||
mei_me_cl_put(cldev->me_cl);
|
||||
list_for_each_entry(cl, &bus->file_list, link)
|
||||
WARN_ON(cl == cldev->cl);
|
||||
}
|
||||
mei_dev_bus_put(bus);
|
||||
|
||||
kfree(cldev->cl);
|
||||
kfree(cldev);
|
||||
|
||||
@@ -367,7 +367,7 @@ static long nsm_dev_ioctl(struct file *file, unsigned int cmd,
|
||||
/* Copy user argument struct to kernel argument struct */
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&raw, argp, _IOC_SIZE(cmd)))
|
||||
goto out;
|
||||
return r;
|
||||
|
||||
mutex_lock(&nsm->lock);
|
||||
|
||||
@@ -413,6 +413,7 @@ static int nsm_device_init_vq(struct virtio_device *vdev)
|
||||
}
|
||||
|
||||
static const struct file_operations nsm_dev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = nsm_dev_ioctl,
|
||||
.compat_ioctl = compat_ptr_ioctl,
|
||||
};
|
||||
|
||||
@@ -1211,7 +1211,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
data = true;
|
||||
}
|
||||
v6 = false;
|
||||
group.ip4 = iph->daddr;
|
||||
group.ip4 = ip_hdr(skb)->daddr;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else if (iph->version == 6) {
|
||||
ip6h = ipv6_hdr(skb);
|
||||
@@ -1235,7 +1235,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
data = true;
|
||||
}
|
||||
v6 = true;
|
||||
group.ip6 = ip6h->daddr;
|
||||
group.ip6 = ipv6_hdr(skb)->daddr;
|
||||
#endif
|
||||
} else {
|
||||
dev->stats.tx_errors++;
|
||||
@@ -1278,12 +1278,12 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
hlist_for_each_entry_rcu(gnode, &tunnel->groups[hash],
|
||||
node) {
|
||||
if (!v6) {
|
||||
if (gnode->group_addr.ip4 == iph->daddr)
|
||||
if (gnode->group_addr.ip4 == group.ip4)
|
||||
goto found;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else {
|
||||
if (ipv6_addr_equal(&gnode->group_addr.ip6,
|
||||
&ip6h->daddr))
|
||||
&group.ip6))
|
||||
goto found;
|
||||
#endif
|
||||
}
|
||||
@@ -2000,14 +2000,18 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
|
||||
struct igmpv3_report *ihrv3 = igmpv3_report_hdr(skb);
|
||||
int len = skb_transport_offset(skb) + sizeof(*ihrv3);
|
||||
void *zero_grec = (void *)&igmpv3_zero_grec;
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
struct amt_group_node *gnode;
|
||||
union amt_addr group, host;
|
||||
struct igmpv3_grec *grec;
|
||||
__be32 saddr;
|
||||
u16 nsrcs;
|
||||
u16 ngrec;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ntohs(ihrv3->ngrec); i++) {
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
ngrec = ntohs(ihrv3->ngrec);
|
||||
|
||||
for (i = 0; i < ngrec; i++) {
|
||||
len += sizeof(*grec);
|
||||
if (!ip_mc_may_pull(skb, len))
|
||||
break;
|
||||
@@ -2019,10 +2023,13 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
|
||||
if (!ip_mc_may_pull(skb, len))
|
||||
break;
|
||||
|
||||
grec = (void *)(skb->data + len - sizeof(*grec) -
|
||||
nsrcs * sizeof(__be32));
|
||||
|
||||
memset(&group, 0, sizeof(union amt_addr));
|
||||
group.ip4 = grec->grec_mca;
|
||||
memset(&host, 0, sizeof(union amt_addr));
|
||||
host.ip4 = iph->saddr;
|
||||
host.ip4 = saddr;
|
||||
gnode = amt_lookup_group(tunnel, &group, &host, false);
|
||||
if (!gnode) {
|
||||
gnode = amt_add_group(amt, tunnel, &group, &host,
|
||||
@@ -2162,14 +2169,18 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
|
||||
struct mld2_report *mld2r = (struct mld2_report *)icmp6_hdr(skb);
|
||||
int len = skb_transport_offset(skb) + sizeof(*mld2r);
|
||||
void *zero_grec = (void *)&mldv2_zero_grec;
|
||||
struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
struct amt_group_node *gnode;
|
||||
union amt_addr group, host;
|
||||
struct mld2_grec *grec;
|
||||
struct in6_addr saddr;
|
||||
u16 nsrcs;
|
||||
u16 ngrec;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ntohs(mld2r->mld2r_ngrec); i++) {
|
||||
saddr = ipv6_hdr(skb)->saddr;
|
||||
ngrec = ntohs(mld2r->mld2r_ngrec);
|
||||
|
||||
for (i = 0; i < ngrec; i++) {
|
||||
len += sizeof(*grec);
|
||||
if (!ipv6_mc_may_pull(skb, len))
|
||||
break;
|
||||
@@ -2181,10 +2192,13 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
|
||||
if (!ipv6_mc_may_pull(skb, len))
|
||||
break;
|
||||
|
||||
grec = (void *)(skb->data + len - sizeof(*grec) -
|
||||
nsrcs * sizeof(struct in6_addr));
|
||||
|
||||
memset(&group, 0, sizeof(union amt_addr));
|
||||
group.ip6 = grec->grec_mca;
|
||||
memset(&host, 0, sizeof(union amt_addr));
|
||||
host.ip6 = ip6h->saddr;
|
||||
host.ip6 = saddr;
|
||||
gnode = amt_lookup_group(tunnel, &group, &host, true);
|
||||
if (!gnode) {
|
||||
gnode = amt_add_group(amt, tunnel, &group, &host,
|
||||
@@ -2305,7 +2319,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
skb_push(skb, sizeof(*eth));
|
||||
skb_reset_mac_header(skb);
|
||||
skb_pull(skb, sizeof(*eth));
|
||||
eth = eth_hdr(skb);
|
||||
|
||||
if (skb_cow_head(skb, 0))
|
||||
return true;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*iph)))
|
||||
return true;
|
||||
@@ -2315,6 +2331,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
if (!ipv4_is_multicast(iph->daddr))
|
||||
return true;
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
eth = eth_hdr(skb);
|
||||
eth->h_proto = htons(ETH_P_IP);
|
||||
ip_eth_mc_map(iph->daddr, eth->h_dest);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
@@ -2328,6 +2345,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
if (!ipv6_addr_is_multicast(&ip6h->daddr))
|
||||
return true;
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
eth = eth_hdr(skb);
|
||||
eth->h_proto = htons(ETH_P_IPV6);
|
||||
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
|
||||
#endif
|
||||
@@ -2351,10 +2369,12 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct amt_header_membership_query *amtmq;
|
||||
struct igmpv3_query *ihv3;
|
||||
struct ethhdr *eth, *oeth;
|
||||
struct igmpv3_query *ihv3;
|
||||
u8 h_source[ETH_ALEN];
|
||||
struct iphdr *iph;
|
||||
int hdr_size, len;
|
||||
u64 response_mac;
|
||||
|
||||
hdr_size = sizeof(*amtmq) + sizeof(struct udphdr);
|
||||
if (!pskb_may_pull(skb, hdr_size))
|
||||
@@ -2367,6 +2387,8 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
if (amtmq->nonce != amt->nonce)
|
||||
return true;
|
||||
|
||||
response_mac = amtmq->response_mac;
|
||||
|
||||
hdr_size -= sizeof(*eth);
|
||||
if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
|
||||
return true;
|
||||
@@ -2376,6 +2398,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
skb_pull(skb, sizeof(*eth));
|
||||
skb_reset_network_header(skb);
|
||||
eth = eth_hdr(skb);
|
||||
ether_addr_copy(h_source, oeth->h_source);
|
||||
if (skb_cow_head(skb, 0))
|
||||
return true;
|
||||
if (!pskb_may_pull(skb, sizeof(*iph)))
|
||||
return true;
|
||||
|
||||
@@ -2388,6 +2413,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
sizeof(*ihv3)))
|
||||
return true;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
if (!ipv4_is_multicast(iph->daddr))
|
||||
return true;
|
||||
|
||||
@@ -2395,10 +2421,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
skb_reset_transport_header(skb);
|
||||
skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
|
||||
WRITE_ONCE(amt->ready4, true);
|
||||
amt->mac = amtmq->response_mac;
|
||||
amt->mac = response_mac;
|
||||
amt->req_cnt = 0;
|
||||
amt->qi = ihv3->qqic;
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
eth = eth_hdr(skb);
|
||||
eth->h_proto = htons(ETH_P_IP);
|
||||
ip_eth_mc_map(iph->daddr, eth->h_dest);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
@@ -2421,10 +2448,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
skb_reset_transport_header(skb);
|
||||
skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
|
||||
WRITE_ONCE(amt->ready6, true);
|
||||
amt->mac = amtmq->response_mac;
|
||||
amt->mac = response_mac;
|
||||
amt->req_cnt = 0;
|
||||
amt->qi = mld2q->mld2q_qqic;
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
eth = eth_hdr(skb);
|
||||
eth->h_proto = htons(ETH_P_IPV6);
|
||||
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
|
||||
#endif
|
||||
@@ -2432,7 +2460,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
|
||||
return true;
|
||||
}
|
||||
|
||||
ether_addr_copy(eth->h_source, oeth->h_source);
|
||||
ether_addr_copy(eth->h_source, h_source);
|
||||
skb->pkt_type = PACKET_MULTICAST;
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
len = skb->len;
|
||||
@@ -2455,8 +2483,11 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
struct ethhdr *eth;
|
||||
struct iphdr *iph;
|
||||
int len, hdr_size;
|
||||
u64 response_mac;
|
||||
__be32 saddr;
|
||||
__be32 nonce;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
|
||||
hdr_size = sizeof(*amtmu) + sizeof(struct udphdr);
|
||||
if (!pskb_may_pull(skb, hdr_size))
|
||||
@@ -2466,15 +2497,18 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
if (amtmu->reserved || amtmu->version)
|
||||
return true;
|
||||
|
||||
nonce = amtmu->nonce;
|
||||
response_mac = amtmu->response_mac;
|
||||
|
||||
if (iptunnel_pull_header(skb, hdr_size, skb->protocol, false))
|
||||
return true;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) {
|
||||
if (tunnel->ip4 == iph->saddr) {
|
||||
if ((amtmu->nonce == tunnel->nonce &&
|
||||
amtmu->response_mac == tunnel->mac)) {
|
||||
if (tunnel->ip4 == saddr) {
|
||||
if ((nonce == tunnel->nonce &&
|
||||
response_mac == tunnel->mac)) {
|
||||
mod_delayed_work(amt_wq, &tunnel->gc_wq,
|
||||
msecs_to_jiffies(amt_gmi(amt))
|
||||
* 3);
|
||||
@@ -2492,6 +2526,9 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
if (!pskb_may_pull(skb, sizeof(*iph)))
|
||||
return true;
|
||||
|
||||
if (skb_cow_head(skb, 0))
|
||||
return true;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
if (iph->version == 4) {
|
||||
if (ip_mc_check_igmp(skb)) {
|
||||
@@ -2508,6 +2545,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
eth = eth_hdr(skb);
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
eth->h_proto = htons(ETH_P_IP);
|
||||
iph = ip_hdr(skb);
|
||||
ip_eth_mc_map(iph->daddr, eth->h_dest);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else if (iph->version == 6) {
|
||||
@@ -2527,6 +2565,7 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
|
||||
eth = eth_hdr(skb);
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
eth->h_proto = htons(ETH_P_IPV6);
|
||||
ip6h = ipv6_hdr(skb);
|
||||
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
|
||||
#endif
|
||||
} else {
|
||||
@@ -2772,7 +2811,7 @@ static void amt_gw_rcv(struct amt_dev *amt, struct sk_buff *skb)
|
||||
static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct amt_dev *amt;
|
||||
struct iphdr *iph;
|
||||
__be32 saddr;
|
||||
int type;
|
||||
bool err;
|
||||
|
||||
@@ -2785,7 +2824,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
skb->dev = amt->dev;
|
||||
iph = ip_hdr(skb);
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
type = amt_parse_type(skb);
|
||||
if (type == -1) {
|
||||
err = true;
|
||||
@@ -2795,7 +2834,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
if (amt->mode == AMT_MODE_GATEWAY) {
|
||||
switch (type) {
|
||||
case AMT_MSG_ADVERTISEMENT:
|
||||
if (iph->saddr != amt->discovery_ip) {
|
||||
if (saddr != amt->discovery_ip) {
|
||||
netdev_dbg(amt->dev, "Invalid Relay IP\n");
|
||||
err = true;
|
||||
goto drop;
|
||||
@@ -2807,7 +2846,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
}
|
||||
goto out;
|
||||
case AMT_MSG_MULTICAST_DATA:
|
||||
if (iph->saddr != amt->remote_ip) {
|
||||
if (saddr != amt->remote_ip) {
|
||||
netdev_dbg(amt->dev, "Invalid Relay IP\n");
|
||||
err = true;
|
||||
goto drop;
|
||||
@@ -2818,7 +2857,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
else
|
||||
goto out;
|
||||
case AMT_MSG_MEMBERSHIP_QUERY:
|
||||
if (iph->saddr != amt->remote_ip) {
|
||||
if (saddr != amt->remote_ip) {
|
||||
netdev_dbg(amt->dev, "Invalid Relay IP\n");
|
||||
err = true;
|
||||
goto drop;
|
||||
@@ -2995,9 +3034,15 @@ static int amt_dev_open(struct net_device *dev)
|
||||
amt->event_idx = 0;
|
||||
amt->nr_events = 0;
|
||||
|
||||
enable_delayed_work(&amt->discovery_wq);
|
||||
enable_delayed_work(&amt->req_wq);
|
||||
|
||||
err = amt_socket_create(amt);
|
||||
if (err)
|
||||
if (err) {
|
||||
disable_delayed_work(&amt->req_wq);
|
||||
disable_delayed_work(&amt->discovery_wq);
|
||||
return err;
|
||||
}
|
||||
|
||||
amt->req_cnt = 0;
|
||||
amt->remote_ip = 0;
|
||||
@@ -3023,8 +3068,8 @@ static int amt_dev_stop(struct net_device *dev)
|
||||
struct sock *sk;
|
||||
int i;
|
||||
|
||||
cancel_delayed_work_sync(&amt->req_wq);
|
||||
cancel_delayed_work_sync(&amt->discovery_wq);
|
||||
disable_delayed_work_sync(&amt->req_wq);
|
||||
disable_delayed_work_sync(&amt->discovery_wq);
|
||||
cancel_delayed_work_sync(&amt->secret_wq);
|
||||
|
||||
/* shutdown */
|
||||
@@ -3278,6 +3323,8 @@ static int amt_newlink(struct net_device *dev,
|
||||
INIT_DELAYED_WORK(&amt->req_wq, amt_req_work);
|
||||
INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work);
|
||||
INIT_WORK(&amt->event_wq, amt_event_work);
|
||||
disable_delayed_work(&amt->req_wq);
|
||||
disable_delayed_work(&amt->discovery_wq);
|
||||
INIT_LIST_HEAD(&amt->tunnel_list);
|
||||
return 0;
|
||||
err:
|
||||
|
||||
@@ -3455,7 +3455,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave)
|
||||
{
|
||||
bond_arp_send_all(bond, slave);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
bond_ns_send_all(bond, slave);
|
||||
if (likely(ipv6_mod_enabled()))
|
||||
bond_ns_send_all(bond, slave);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1686,11 +1686,14 @@ static void airoha_qdma_stop_napi(struct airoha_qdma *qdma)
|
||||
}
|
||||
}
|
||||
|
||||
static void airoha_dev_get_hw_stats(struct airoha_gdm_dev *dev)
|
||||
static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = dev->port;
|
||||
struct airoha_eth *eth = dev->eth;
|
||||
u32 val, i = 0;
|
||||
u64 data;
|
||||
|
||||
spin_lock(&port->stats_lock);
|
||||
|
||||
/* Read relevant MIB for GDM with multiple port attached */
|
||||
if (port->id == AIROHA_GDM3_IDX || port->id == AIROHA_GDM4_IDX)
|
||||
@@ -1701,152 +1704,188 @@ static void airoha_dev_get_hw_stats(struct airoha_gdm_dev *dev)
|
||||
|
||||
u64_stats_update_begin(&dev->stats.syncp);
|
||||
|
||||
/* TX */
|
||||
/* TX - 64-bit H+L registers: hw accumulates the total, read directly.
|
||||
* Use local variable to prevent readers from seeing intermediate values.
|
||||
* Clamp to prevent regression from torn reads between H and L.
|
||||
*/
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_PKT_CNT_H(port->id));
|
||||
dev->stats.tx_ok_pkts += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_PKT_CNT_L(port->id));
|
||||
dev->stats.tx_ok_pkts += val;
|
||||
data += val;
|
||||
dev->stats.tx_ok_pkts = max(data, dev->stats.tx_ok_pkts);
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_BYTE_CNT_H(port->id));
|
||||
dev->stats.tx_ok_bytes += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_OK_BYTE_CNT_L(port->id));
|
||||
dev->stats.tx_ok_bytes += val;
|
||||
data += val;
|
||||
dev->stats.tx_ok_bytes = max(data, dev->stats.tx_ok_bytes);
|
||||
|
||||
/* TX - 32-bit registers: accumulate delta to handle wrap-around. */
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_DROP_CNT(port->id));
|
||||
dev->stats.tx_drops += val;
|
||||
dev->stats.tx_drops += (u32)(val - dev->stats.mib_prev.tx_drops);
|
||||
dev->stats.mib_prev.tx_drops = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_BC_CNT(port->id));
|
||||
dev->stats.tx_broadcast += val;
|
||||
dev->stats.tx_broadcast += (u32)(val - dev->stats.mib_prev.tx_broadcast);
|
||||
dev->stats.mib_prev.tx_broadcast = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_MC_CNT(port->id));
|
||||
dev->stats.tx_multicast += val;
|
||||
dev->stats.tx_multicast += (u32)(val - dev->stats.mib_prev.tx_multicast);
|
||||
dev->stats.mib_prev.tx_multicast = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_RUNT_CNT(port->id));
|
||||
dev->stats.tx_len[i] += val;
|
||||
dev->stats.mib_prev.tx_runt64 +=
|
||||
(u32)(val - dev->stats.mib_prev.tx_runt);
|
||||
dev->stats.mib_prev.tx_runt = val;
|
||||
|
||||
/* tx_len[0]: RUNT (32-bit, delta) + E64 (64-bit, absolute). */
|
||||
data = dev->stats.mib_prev.tx_runt64;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_E64_CNT_H(port->id));
|
||||
dev->stats.tx_len[i] += ((u64)val << 32);
|
||||
data += (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_E64_CNT_L(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L64_CNT_H(port->id));
|
||||
dev->stats.tx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L64_CNT_L(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L127_CNT_H(port->id));
|
||||
dev->stats.tx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L127_CNT_L(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L255_CNT_H(port->id));
|
||||
dev->stats.tx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L255_CNT_L(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L511_CNT_H(port->id));
|
||||
dev->stats.tx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L511_CNT_L(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L1023_CNT_H(port->id));
|
||||
dev->stats.tx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_L1023_CNT_L(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.tx_len[i] = max(data, dev->stats.tx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_TX_ETH_LONG_CNT(port->id));
|
||||
dev->stats.tx_len[i++] += val;
|
||||
dev->stats.tx_len[i++] += (u32)(val - dev->stats.mib_prev.tx_long);
|
||||
dev->stats.mib_prev.tx_long = val;
|
||||
|
||||
/* RX */
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_PKT_CNT_H(port->id));
|
||||
dev->stats.rx_ok_pkts += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_PKT_CNT_L(port->id));
|
||||
dev->stats.rx_ok_pkts += val;
|
||||
data += val;
|
||||
dev->stats.rx_ok_pkts = max(data, dev->stats.rx_ok_pkts);
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_BYTE_CNT_H(port->id));
|
||||
dev->stats.rx_ok_bytes += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OK_BYTE_CNT_L(port->id));
|
||||
dev->stats.rx_ok_bytes += val;
|
||||
data += val;
|
||||
dev->stats.rx_ok_bytes = max(data, dev->stats.rx_ok_bytes);
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_DROP_CNT(port->id));
|
||||
dev->stats.rx_drops += val;
|
||||
dev->stats.rx_drops += (u32)(val - dev->stats.mib_prev.rx_drops);
|
||||
dev->stats.mib_prev.rx_drops = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_BC_CNT(port->id));
|
||||
dev->stats.rx_broadcast += val;
|
||||
dev->stats.rx_broadcast += (u32)(val - dev->stats.mib_prev.rx_broadcast);
|
||||
dev->stats.mib_prev.rx_broadcast = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_MC_CNT(port->id));
|
||||
dev->stats.rx_multicast += val;
|
||||
dev->stats.rx_multicast += (u32)(val - dev->stats.mib_prev.rx_multicast);
|
||||
dev->stats.mib_prev.rx_multicast = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ERROR_DROP_CNT(port->id));
|
||||
dev->stats.rx_errors += val;
|
||||
dev->stats.rx_errors += (u32)(val - dev->stats.mib_prev.rx_errors);
|
||||
dev->stats.mib_prev.rx_errors = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_CRC_ERR_CNT(port->id));
|
||||
dev->stats.rx_crc_error += val;
|
||||
dev->stats.rx_crc_error += (u32)(val - dev->stats.mib_prev.rx_crc_error);
|
||||
dev->stats.mib_prev.rx_crc_error = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_OVERFLOW_DROP_CNT(port->id));
|
||||
dev->stats.rx_over_errors += val;
|
||||
dev->stats.rx_over_errors += (u32)(val - dev->stats.mib_prev.rx_over_errors);
|
||||
dev->stats.mib_prev.rx_over_errors = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_FRAG_CNT(port->id));
|
||||
dev->stats.rx_fragment += val;
|
||||
dev->stats.rx_fragment += (u32)(val - dev->stats.mib_prev.rx_fragment);
|
||||
dev->stats.mib_prev.rx_fragment = val;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_JABBER_CNT(port->id));
|
||||
dev->stats.rx_jabber += val;
|
||||
dev->stats.rx_jabber += (u32)(val - dev->stats.mib_prev.rx_jabber);
|
||||
dev->stats.mib_prev.rx_jabber = val;
|
||||
|
||||
i = 0;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_RUNT_CNT(port->id));
|
||||
dev->stats.rx_len[i] += val;
|
||||
dev->stats.mib_prev.rx_runt64 +=
|
||||
(u32)(val - dev->stats.mib_prev.rx_runt);
|
||||
dev->stats.mib_prev.rx_runt = val;
|
||||
|
||||
/* rx_len[0]: RUNT (32-bit, delta) + E64 (64-bit, absolute). */
|
||||
data = dev->stats.mib_prev.rx_runt64;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_E64_CNT_H(port->id));
|
||||
dev->stats.rx_len[i] += ((u64)val << 32);
|
||||
data += (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_E64_CNT_L(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L64_CNT_H(port->id));
|
||||
dev->stats.rx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L64_CNT_L(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L127_CNT_H(port->id));
|
||||
dev->stats.rx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L127_CNT_L(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L255_CNT_H(port->id));
|
||||
dev->stats.rx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L255_CNT_L(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L511_CNT_H(port->id));
|
||||
dev->stats.rx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L511_CNT_L(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L1023_CNT_H(port->id));
|
||||
dev->stats.rx_len[i] += ((u64)val << 32);
|
||||
data = (u64)val << 32;
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_L1023_CNT_L(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
data += val;
|
||||
dev->stats.rx_len[i] = max(data, dev->stats.rx_len[i]);
|
||||
i++;
|
||||
|
||||
val = airoha_fe_rr(eth, REG_FE_GDM_RX_ETH_LONG_CNT(port->id));
|
||||
dev->stats.rx_len[i++] += val;
|
||||
dev->stats.rx_len[i] += (u32)(val - dev->stats.mib_prev.rx_long);
|
||||
dev->stats.mib_prev.rx_long = val;
|
||||
|
||||
u64_stats_update_end(&dev->stats.syncp);
|
||||
}
|
||||
|
||||
static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = dev->port;
|
||||
int i;
|
||||
|
||||
spin_lock(&port->stats_lock);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
|
||||
if (port->devs[i])
|
||||
airoha_dev_get_hw_stats(port->devs[i]);
|
||||
}
|
||||
|
||||
/* Reset MIB counters */
|
||||
airoha_fe_set(dev->eth, REG_FE_GDM_MIB_CLEAR(port->id),
|
||||
FE_GDM_MIB_RX_CLEAR_MASK | FE_GDM_MIB_TX_CLEAR_MASK);
|
||||
|
||||
spin_unlock(&port->stats_lock);
|
||||
}
|
||||
@@ -2504,8 +2543,7 @@ static int airoha_tc_setup_qdisc_ets(struct net_device *dev,
|
||||
if (opt->parent == TC_H_ROOT)
|
||||
return -EINVAL;
|
||||
|
||||
channel = TC_H_MAJ(opt->handle) >> 16;
|
||||
channel = channel % AIROHA_NUM_QOS_CHANNELS;
|
||||
channel = TC_H_MIN(opt->parent) % AIROHA_NUM_QOS_CHANNELS;
|
||||
|
||||
switch (opt->command) {
|
||||
case TC_ETS_REPLACE:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user