mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.2-rc8). No conflicts. Adjacent changes: drivers/net/ethernet/wangxun/ngbe/ngbe_main.c5f3a13e0bb("net: ngbe: fix NULL pointer dereference in non-MSI-X interrupt enabling")d661abdc30("net: ngbe: correct misleading interrupt comment") drivers/net/ipvlan/ipvlan_main.ce16e960d55("ipvlan: inherit needed_headroom and needed_tailroom from phy_dev")00a40d8092("ipvlan: Support per-netns netdev unregistration.") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -171,6 +171,7 @@ Boris Brezillon <bbrezillon@kernel.org> <b.brezillon@overkiz.com>
|
||||
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
|
||||
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
|
||||
Brendan Higgins <brendan.higgins@linux.dev> <brendanhiggins@google.com>
|
||||
Brendan Jackman <brendan.jackman@linux.dev> <jackmanb@google.com>
|
||||
Brian Avery <b.avery@hp.com>
|
||||
Brian Cain <bcain@kernel.org> <brian.cain@oss.qualcomm.com>
|
||||
Brian Cain <bcain@kernel.org> <bcain@quicinc.com>
|
||||
@@ -211,6 +212,10 @@ Christophe Ricard <christophe.ricard@gmail.com>
|
||||
Christopher Obbard <christopher.obbard@linaro.org> <chris.obbard@collabora.com>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Christoph Manszewski <c.manszewski@gmail.com> <christoph.manszewski@intel.com>
|
||||
Christoph Paasch <cpaasch@openai.com> <christoph.paasch@gmail.com>
|
||||
Christoph Paasch <cpaasch@openai.com> <christoph.paasch@student.uclouvain.be>
|
||||
Christoph Paasch <cpaasch@openai.com> <christoph.paasch@uclouvain.be>
|
||||
Christoph Paasch <cpaasch@openai.com> <cpaasch@apple.com>
|
||||
Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@netapp.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
|
||||
@@ -233,6 +238,8 @@ Daniel Lezcano <daniel.lezcano@kernel.org> <daniel.lezcano@linexp.org>
|
||||
Daniel Lezcano <daniel.lezcano@kernel.org> <dlezcano@fr.ibm.com>
|
||||
Daniel Thompson <danielt@kernel.org> <daniel.thompson@linaro.org>
|
||||
Daniele Alessandrelli <daniele.alessandrelli@gmail.com> <daniele.alessandrelli@intel.com>
|
||||
Danila Tikhonov <danila@mainlining.org> <danila@jiaxyga.com>
|
||||
Danila Tikhonov <danila@mainlining.org> <JIaxyga@protonmail.com>
|
||||
Danilo Krummrich <dakr@kernel.org> <dakr@redhat.com>
|
||||
David Brownell <david-b@pacbell.net>
|
||||
David Collins <quic_collinsd@quicinc.com> <collinsd@codeaurora.org>
|
||||
|
||||
@@ -8169,6 +8169,11 @@ Kernel parameters
|
||||
q = USB_QUIRK_FORCE_ONE_CONFIG (Device
|
||||
claims zero configurations,
|
||||
forcing to 1);
|
||||
r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device
|
||||
fails during initialization when asked for
|
||||
9-bytes configuration descriptor request.
|
||||
Ask for 255-bytes request instead to mirror
|
||||
Windows' behavior);
|
||||
Example: quirks=0781:5580:bk,0a5c:5834:gij
|
||||
|
||||
usbhid.mousepoll=
|
||||
|
||||
@@ -57,3 +57,40 @@ Basic development tools (git, gcc, make, editors) should not be listed.
|
||||
Example::
|
||||
|
||||
Assisted-by: Claude:claude-3-opus coccinelle sparse
|
||||
|
||||
Procedure for finding and fixing bugs
|
||||
=====================================
|
||||
|
||||
When an AI assistant is used to find and fix bugs, it **MUST** follow at least
|
||||
these steps:
|
||||
|
||||
1. Before starting, read the whole process documentation listed above, as well
|
||||
as any other document mentioned in the request. Do not rely on isolated
|
||||
parts found by keyword search.
|
||||
2. Note the commit ID and Locate a bug as instructed.
|
||||
3. For any bug found that is not trivial, verify that it looks real by
|
||||
attempting to create a reproducer to demonstrate it. Lacking it may cause
|
||||
the report to be ignored, as many unverified bug reports sent to maintainers
|
||||
happen to be invalid. Stop here if it finally looks wrong.
|
||||
4. Write a fix for the bug. This part is not optional: except in a few very
|
||||
rare cases, an AI assistant able to find a bug is able to fix it. Note that
|
||||
fixes written in the same session as used to find the bug will generally
|
||||
lead to better and more accurate fixes as the LLM's reasoning context
|
||||
remains present.
|
||||
5. Build and verify that the fix works either using the reproducer or by
|
||||
re-running a complete analysis; drop any fix that doesn't work and try
|
||||
another one. The fix must not add build warnings and must pass the
|
||||
checkpatch.pl checks (see submitting-patches.rst).
|
||||
6. Commit the working fix with a detailed message describing the problem, the
|
||||
solution and a Fixes tag. Do not add a Signed-off-by tag, and add an
|
||||
Assisted-by tag, as described above.
|
||||
7. Identify the maintainers and lists using scripts/get_maintainer.pl.
|
||||
Documentation/process/security-bugs.rst shows how to do that.
|
||||
8. Indicate what could not be done. If the fix could not be built or tested, or
|
||||
if no reproducer could be produced, say so explicitly: maintainers currently
|
||||
waste too much time analyzing unverified reports and untested fixes.
|
||||
9. Read Documentation/process/threat-model.rst to determine whether the bug is
|
||||
a vulnerability or a regular bug, and leave the result to the reporter for
|
||||
review (the assistant must never send anything itself). Regular bugs are
|
||||
submitted as described in Documentation/process/submitting-patches.rst,
|
||||
vulnerabilities as described in Documentation/process/security-bugs.rst.
|
||||
|
||||
@@ -18,6 +18,10 @@ information is helpful. The following information are absolutely necessary in
|
||||
**any** security bug report:
|
||||
|
||||
* **affected kernel version range**: with no version indication, your report
|
||||
will not be processed. Note that a time-dependent version such as "latest
|
||||
mainline" is not acceptable. A stable identifier such as a commit ID or an
|
||||
exact version is required. Versions designating kernels not coming from
|
||||
kernel.org (such as distro kernels) are meaningless to maintainers and
|
||||
will not be processed. A significant part of reports are for bugs that
|
||||
have already been fixed, so it is extremely important that vulnerabilities
|
||||
are verified on recent versions (development tree or latest stable
|
||||
@@ -225,6 +229,28 @@ there is no need to consume a maintainer's time with an unimportant report. If
|
||||
the issue is clearly trivial and publicly discoverable, you should report it
|
||||
directly to the public mailing lists.
|
||||
|
||||
At the very least, when using an AI assistant to find and report bugs, make the
|
||||
assistant read this file and threat-model.rst before proceeding, and have it
|
||||
follow the procedure described in coding-assistants.rst: work on an up-to-date
|
||||
mainline tree and note the commit ID, verify the bug is real, write a fix,
|
||||
build it warning-free and checkpatch-clean, commit it with a Fixes tag, and
|
||||
identify the maintainers with get_maintainer.pl.
|
||||
|
||||
On top of that procedure, the AI assistant **MUST**:
|
||||
|
||||
1. Prepare a plain-text report explaining the problem. It must contain the
|
||||
four items listed at the top of this file as absolutely necessary: the
|
||||
affected version or commit ID noted while following the procedure above,
|
||||
the description of the problem, the reproducer or its status, and the
|
||||
triggering conditions.
|
||||
2. Start the report with a temporary section listing the recipients' addresses
|
||||
(maintainers+list for the patch, maintainers only for the report and
|
||||
reproducer), and with instructions reminding the reporter to check that
|
||||
their email client is properly setup (see email-clients.rst), and leave it
|
||||
to the reporter to remove that temporary section.
|
||||
|
||||
A more detailed process is covered at https://github.com/masoncl/kres.git.
|
||||
|
||||
Sending the report
|
||||
------------------
|
||||
|
||||
|
||||
@@ -98,11 +98,11 @@ measures whose purpose is to avoid crossing a security boundary when certain
|
||||
classes of bugs are found, but a failure of these extra protections do not
|
||||
constitute a vulnerability alone.
|
||||
|
||||
What does not constitute a security bug
|
||||
---------------------------------------
|
||||
What classes of problems are not considered vulnerabilities
|
||||
-----------------------------------------------------------
|
||||
|
||||
In the Linux kernel's threat model, the following classes of problems are
|
||||
**NOT** considered as Linux Kernel security bugs. However, when it is believed
|
||||
**NOT** considered Linux Kernel vulnerabilities. However, when it is believed
|
||||
that the kernel could do better, they should be reported, so that they can be
|
||||
reviewed and fixed where reasonably possible, but they will be handled as any
|
||||
regular bug:
|
||||
@@ -111,8 +111,8 @@ regular bug:
|
||||
|
||||
* outdated kernels and particularly end-of-life branches are out of the scope
|
||||
of the kernel's threat model: administrators are responsible for keeping
|
||||
their system up to date. For a bug to qualify as a security bug, it must be
|
||||
demonstrated that it affects actively maintained versions.
|
||||
their system up to date. For a bug to qualify as a vulnerability, it must
|
||||
be demonstrated that it affects actively maintained versions.
|
||||
|
||||
* build-level: changes to the kernel configuration that are explicitly
|
||||
documented as lowering the security level (e.g. ``CONFIG_NOMMU``), or
|
||||
@@ -178,9 +178,6 @@ regular bug:
|
||||
involving tens of millions of threads, tens of thousands of CPUs,
|
||||
unrealistic CPU frequencies, RAM sizes or disk capacities, network speeds).
|
||||
|
||||
* issues whose reproduction requires hardware modification or emulation,
|
||||
including fake USB devices that pretend to be another one.
|
||||
|
||||
* as well as issues that can be triggered at a cost that is orders of
|
||||
magnitude higher than the expected benefits (e.g. fully functional keyboard
|
||||
emulator only to retrieve 7 uninitialized bytes in a structure, or
|
||||
@@ -208,19 +205,27 @@ regular bug:
|
||||
messages.
|
||||
|
||||
* Leaks of kernel memory addresses/pointers do not constitute an immediately
|
||||
exploitable vector and are not security bugs, though they must be reported
|
||||
and fixed.
|
||||
exploitable vector and are not vulnerabilities, though they must be
|
||||
reported and fixed.
|
||||
|
||||
* **Crafted file system images**:
|
||||
* **Non-conforming devices and media**:
|
||||
|
||||
Drivers are implemented against a specification. When a device or a storage
|
||||
medium violates the specification its driver was written against, the
|
||||
resulting misbehaviour is a regular bug to be fixed, not a vulnerability,
|
||||
unless the driver is specifically documented as being hardened against
|
||||
hostile inputs. The following are therefore not considered vulnerabilities:
|
||||
|
||||
* bugs triggered by mounting a corrupted or maliciously crafted file system
|
||||
image are generally not security bugs, as the kernel assumes the underlying
|
||||
storage media is under the administrator's control, unless the filesystem
|
||||
driver is specifically documented as being hardened against untrusted media.
|
||||
|
||||
* issues that are resolved, mitigated, or detected by running a filesystem
|
||||
image: mounting a block device is a privileged operation (see above), and
|
||||
the administrator is responsible for the media they mount. This includes
|
||||
issues that are resolved, mitigated, or detected by running a filesystem
|
||||
consistency check (fsck) on the image prior to mounting.
|
||||
|
||||
* bugs whose reproduction requires hardware modification or emulation,
|
||||
including fake USB devices that pretend to be another one, or devices
|
||||
reporting values outside their documented ranges.
|
||||
|
||||
* **Physical access**:
|
||||
|
||||
Issues that require physical access to the machine, hardware modification, or
|
||||
@@ -232,4 +237,4 @@ regular bug:
|
||||
* **Functional and performance regressions**:
|
||||
|
||||
Any issue that can be mitigated by setting proper permissions and limits
|
||||
doesn't qualify as a security bug.
|
||||
doesn't qualify as a vulnerability.
|
||||
|
||||
+12
-1
@@ -10136,6 +10136,11 @@ F: drivers/base/firmware_loader/
|
||||
F: rust/kernel/firmware.rs
|
||||
F: include/linux/firmware.h
|
||||
|
||||
FIXED-LAYOUT NVMEM LAYOUT DRIVER
|
||||
M: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
|
||||
S: Maintained
|
||||
F: drivers/nvmem/layouts/fixed-layout.c
|
||||
|
||||
FLEXTIMER FTM-QUADDEC DRIVER
|
||||
M: Patrick Havelange <patrick.havelange@essensium.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@@ -17163,7 +17168,7 @@ M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: Vlastimil Babka <vbabka@kernel.org>
|
||||
R: Suren Baghdasaryan <surenb@google.com>
|
||||
R: Michal Hocko <mhocko@suse.com>
|
||||
R: Brendan Jackman <jackmanb@google.com>
|
||||
R: Brendan Jackman <brendan.jackman@linux.dev>
|
||||
R: Johannes Weiner <hannes@cmpxchg.org>
|
||||
R: Zi Yan <ziy@nvidia.com>
|
||||
L: linux-mm@kvack.org
|
||||
@@ -25464,6 +25469,12 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
|
||||
F: drivers/i2c/busses/i2c-k1.c
|
||||
|
||||
SPACEMIT K1/K3 I2S DRIVER
|
||||
M: Troy Mitchell <troy.mitchell@linux.spacemit.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
|
||||
F: sound/soc/spacemit/k1_i2s.c
|
||||
|
||||
SPANISH DOCUMENTATION
|
||||
M: Carlos Bilbao <carlos.bilbao@kernel.org>
|
||||
R: Avadhut Naik <avadhut.naik@amd.com>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
VERSION = 7
|
||||
PATCHLEVEL = 2
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc6
|
||||
EXTRAVERSION = -rc7
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
#include <linux/ptdump.h>
|
||||
|
||||
DECLARE_STATIC_KEY_FALSE(arm64_ptdump_lock_key);
|
||||
|
||||
#ifdef CONFIG_PTDUMP
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
|
||||
+4
-39
@@ -49,8 +49,6 @@
|
||||
#define NO_CONT_MAPPINGS BIT(1)
|
||||
#define NO_EXEC_MAPPINGS BIT(2) /* assumes FEAT_HPDS is not used */
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(arm64_ptdump_lock_key);
|
||||
|
||||
u64 kimage_voffset __ro_after_init;
|
||||
EXPORT_SYMBOL(kimage_voffset);
|
||||
|
||||
@@ -1864,8 +1862,7 @@ int pmd_clear_huge(pmd_t *pmdp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __pmd_free_pte_page(pmd_t *pmdp, unsigned long addr,
|
||||
bool acquire_mmap_lock)
|
||||
int pmd_free_pte_page(pmd_t *pmdp, unsigned long addr)
|
||||
{
|
||||
pte_t *table;
|
||||
pmd_t pmd;
|
||||
@@ -1877,25 +1874,13 @@ static int __pmd_free_pte_page(pmd_t *pmdp, unsigned long addr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* See comment in pud_free_pmd_page for static key logic */
|
||||
table = pte_offset_kernel(pmdp, addr);
|
||||
pmd_clear(pmdp);
|
||||
__flush_tlb_kernel_pgtable(addr);
|
||||
if (static_branch_unlikely(&arm64_ptdump_lock_key) && acquire_mmap_lock) {
|
||||
mmap_read_lock(&init_mm);
|
||||
mmap_read_unlock(&init_mm);
|
||||
}
|
||||
|
||||
pte_free_kernel(NULL, table);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pmd_free_pte_page(pmd_t *pmdp, unsigned long addr)
|
||||
{
|
||||
/* If ptdump is walking the pagetables, acquire init_mm.mmap_lock */
|
||||
return __pmd_free_pte_page(pmdp, addr, /* acquire_mmap_lock = */ true);
|
||||
}
|
||||
|
||||
int pud_free_pmd_page(pud_t *pudp, unsigned long addr)
|
||||
{
|
||||
pmd_t *table;
|
||||
@@ -1911,36 +1896,16 @@ int pud_free_pmd_page(pud_t *pudp, unsigned long addr)
|
||||
}
|
||||
|
||||
table = pmd_offset(pudp, addr);
|
||||
|
||||
/*
|
||||
* Our objective is to prevent ptdump from reading a PMD table which has
|
||||
* been freed. In this race, if pud_free_pmd_page observes the key on
|
||||
* (which got flipped by ptdump) then the mmap lock sequence here will,
|
||||
* as a result of the mmap write lock/unlock sequence in ptdump, give
|
||||
* us the correct synchronization. If not, this means that ptdump has
|
||||
* yet not started walking the pagetables - the sequence of barriers
|
||||
* issued by __flush_tlb_kernel_pgtable() guarantees that ptdump will
|
||||
* observe an empty PUD.
|
||||
*/
|
||||
pud_clear(pudp);
|
||||
__flush_tlb_kernel_pgtable(addr);
|
||||
if (static_branch_unlikely(&arm64_ptdump_lock_key)) {
|
||||
mmap_read_lock(&init_mm);
|
||||
mmap_read_unlock(&init_mm);
|
||||
}
|
||||
|
||||
pmdp = table;
|
||||
next = addr;
|
||||
end = addr + PUD_SIZE;
|
||||
do {
|
||||
if (pmd_present(pmdp_get(pmdp)))
|
||||
/*
|
||||
* PMD has been isolated, so ptdump won't see it. No
|
||||
* need to acquire init_mm.mmap_lock.
|
||||
*/
|
||||
__pmd_free_pte_page(pmdp, next, /* acquire_mmap_lock = */ false);
|
||||
pmd_free_pte_page(pmdp, next);
|
||||
} while (pmdp++, next += PMD_SIZE, next != end);
|
||||
|
||||
pud_clear(pudp);
|
||||
__flush_tlb_kernel_pgtable(addr);
|
||||
pmd_free(NULL, table);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -283,13 +283,6 @@ void note_page_flush(struct ptdump_state *pt_st)
|
||||
note_page(pt_st, 0, -1, pte_val(pte_zero));
|
||||
}
|
||||
|
||||
static void arm64_ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm)
|
||||
{
|
||||
static_branch_inc(&arm64_ptdump_lock_key);
|
||||
ptdump_walk_pgd(st, mm, NULL);
|
||||
static_branch_dec(&arm64_ptdump_lock_key);
|
||||
}
|
||||
|
||||
void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
|
||||
{
|
||||
unsigned long end = ~0UL;
|
||||
@@ -318,7 +311,7 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
|
||||
}
|
||||
};
|
||||
|
||||
arm64_ptdump_walk_pgd(&st.ptdump, info->mm);
|
||||
ptdump_walk_pgd(&st.ptdump, info->mm, NULL);
|
||||
}
|
||||
|
||||
static void __init ptdump_initialize(void)
|
||||
@@ -360,7 +353,7 @@ bool ptdump_check_wx(void)
|
||||
}
|
||||
};
|
||||
|
||||
arm64_ptdump_walk_pgd(&st.ptdump, &init_mm);
|
||||
ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
|
||||
|
||||
if (st.wx_pages || st.uxn_pages) {
|
||||
pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
|
||||
|
||||
@@ -549,6 +549,10 @@ config CACHE_COPYBACK
|
||||
endchoice
|
||||
endif # HAVE_CACHE_CB
|
||||
|
||||
config NR_CPUS
|
||||
int
|
||||
default "1"
|
||||
|
||||
# Coldfire cores that do not have a data cache configured can do coherent DMA.
|
||||
config COLDFIRE_COHERENT_DMA
|
||||
bool
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <asm/processor.h>
|
||||
|
||||
.section .data
|
||||
/* The MMU requires a page aligned page directory. */
|
||||
.align 12
|
||||
.global swapper_pg_dir
|
||||
swapper_pg_dir:
|
||||
.space PAGE_SIZE
|
||||
|
||||
@@ -699,7 +699,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
|
||||
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
|
||||
return -EINVAL;
|
||||
|
||||
if (count > sizeof(kbuf))
|
||||
if (count == 0 || count > sizeof(kbuf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(kbuf, buf, count))
|
||||
|
||||
@@ -230,10 +230,17 @@ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(¶ms->cmd, ulc,
|
||||
sizeof(struct papr_phy_attest_io_block)))
|
||||
sizeof(struct papr_phy_attest_io_block))) {
|
||||
kfree(params);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
params->cmd_len = be32_to_cpu(params->cmd.length);
|
||||
if (params->cmd_len == 0 || params->cmd_len > sizeof(params->cmd)) {
|
||||
kfree(params);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
seq = (struct papr_rtas_sequence) {
|
||||
.begin = phy_attest_sequence_begin,
|
||||
.end = phy_attest_sequence_end,
|
||||
@@ -246,6 +253,9 @@ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user
|
||||
&papr_phy_attest_handle_ops,
|
||||
"[papr-physical-attestation]");
|
||||
|
||||
if (fd < 0)
|
||||
kfree(params);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ static int pseries_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
|
||||
|
||||
/* First integer stores max config */
|
||||
max_config_vfs = of_read_number(&max_vfs[0], 1);
|
||||
if (max_config_vfs < num_vfs && num_vfs > MAX_VFS_FOR_MAP_PE) {
|
||||
if (max_config_vfs < num_vfs || num_vfs > MAX_VFS_FOR_MAP_PE) {
|
||||
dev_err(&pdev->dev,
|
||||
"Num VFs %x > %x Configurable VFs\n",
|
||||
num_vfs, (num_vfs > MAX_VFS_FOR_MAP_PE) ?
|
||||
|
||||
@@ -440,6 +440,7 @@ struct kvm_vcpu_arch {
|
||||
bool skey_enabled;
|
||||
/* Indicator if the access registers have been loaded from guest */
|
||||
bool acrs_loaded;
|
||||
bool initialized;
|
||||
struct kvm_s390_pv_vcpu pv;
|
||||
union diag318_info diag318_info;
|
||||
struct kvm_s390_mmu_cache *mc;
|
||||
|
||||
+16
-7
@@ -755,13 +755,15 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn)
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
|
||||
{
|
||||
union pgste pgste, old;
|
||||
union crste *crstep;
|
||||
union pte *ptep;
|
||||
int rc;
|
||||
|
||||
skey->skey = 0;
|
||||
|
||||
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -771,21 +773,23 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn)
|
||||
|
||||
if (!crste.h.fc || !crste.s.fc1.pr)
|
||||
return 0;
|
||||
return page_reset_referenced(large_crste_to_phys(*crstep, gfn));
|
||||
skey->skey = page_reset_referenced(large_crste_to_phys(*crstep, gfn)) << 1;
|
||||
return 0;
|
||||
}
|
||||
old = pgste_get_lock(ptep);
|
||||
pgste = old;
|
||||
|
||||
if (!ptep->h.i) {
|
||||
rc = page_reset_referenced(pte_origin(*ptep));
|
||||
pgste.hr = rc >> 1;
|
||||
skey->skey = page_reset_referenced(pte_origin(*ptep)) << 1;
|
||||
pgste.hr = skey->r;
|
||||
}
|
||||
rc |= (pgste.gr << 1) | pgste.gc;
|
||||
skey->r |= pgste.gr;
|
||||
skey->c |= pgste.gc;
|
||||
pgste.gr = 0;
|
||||
|
||||
dat_update_ptep_sd(old, pgste, ptep);
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dat_reset_skeys_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
@@ -846,6 +850,7 @@ static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_wal
|
||||
struct slot_priv *p = walk->priv;
|
||||
union crste dummy = { .val = p->token };
|
||||
union pte new_pte, pte = READ_ONCE(*ptep);
|
||||
union pgste pgste;
|
||||
|
||||
new_pte = _PTE_TOK(dummy.tok.type, dummy.tok.par);
|
||||
|
||||
@@ -853,7 +858,11 @@ static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_wal
|
||||
if (pte.val == new_pte.val)
|
||||
return 0;
|
||||
|
||||
dat_ptep_xchg(ptep, new_pte, gfn, walk->asce, false);
|
||||
pgste = pgste_get_lock(ptep);
|
||||
pgste = __dat_ptep_xchg(ptep, pgste, new_pte, gfn, walk->asce, false);
|
||||
pgste.cmma_d = 0;
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -537,7 +537,7 @@ int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gf
|
||||
union skey skey, bool nq);
|
||||
int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
|
||||
union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn);
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey);
|
||||
long dat_reset_skeys(union asce asce, gfn_t start);
|
||||
|
||||
unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);
|
||||
|
||||
@@ -91,9 +91,9 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
|
||||
/* Access outside memory, addressing exception. */
|
||||
if (is_noslot_pfn(f->pfn))
|
||||
return PGM_ADDRESSING;
|
||||
/* Signal pending: try again. */
|
||||
if (f->pfn == KVM_PFN_ERR_SIGPENDING)
|
||||
return -EAGAIN;
|
||||
/* Fatal signal pending: bail out. */
|
||||
if (is_sigpending_pfn(f->pfn))
|
||||
return -EINTR;
|
||||
/* Check if it's read-only memory; don't try to actually handle that case. */
|
||||
if (f->pfn == KVM_PFN_ERR_RO_FAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -45,13 +45,16 @@ static struct kvm_s390_gib *gib;
|
||||
static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
|
||||
{
|
||||
struct esca_block *sca = vcpu->kvm->arch.sca;
|
||||
union esca_sigp_ctrl sigp_ctrl = sca->cpu[vcpu->vcpu_id].sigp_ctrl;
|
||||
union esca_sigp_ctrl sigp_ctrl;
|
||||
|
||||
if (!kvm_s390_test_cpuflags(vcpu, CPUSTAT_ECALL_PEND))
|
||||
return 0;
|
||||
if (kvm_is_ucontrol(vcpu->kvm))
|
||||
return 0;
|
||||
|
||||
BUG_ON(!kvm_s390_use_sca_entries());
|
||||
|
||||
sigp_ctrl = sca->cpu[vcpu->vcpu_id].sigp_ctrl;
|
||||
if (src_id)
|
||||
*src_id = sigp_ctrl.scn;
|
||||
|
||||
@@ -60,13 +63,16 @@ static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
|
||||
|
||||
static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
|
||||
{
|
||||
struct esca_block *sca = vcpu->kvm->arch.sca;
|
||||
union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
|
||||
union esca_sigp_ctrl old_val, new_val = {.scn = src_id, .c = 1};
|
||||
struct esca_block *sca = vcpu->kvm->arch.sca;
|
||||
union esca_sigp_ctrl *sigp_ctrl;
|
||||
int expect, rc;
|
||||
|
||||
BUG_ON(!kvm_s390_use_sca_entries());
|
||||
if (kvm_is_ucontrol(vcpu->kvm))
|
||||
return -EINVAL;
|
||||
|
||||
sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
|
||||
old_val = READ_ONCE(*sigp_ctrl);
|
||||
old_val.c = 0;
|
||||
|
||||
@@ -84,10 +90,13 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
|
||||
static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct esca_block *sca = vcpu->kvm->arch.sca;
|
||||
union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
|
||||
union esca_sigp_ctrl *sigp_ctrl;
|
||||
|
||||
if (!kvm_s390_use_sca_entries())
|
||||
if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized || kvm_is_ucontrol(vcpu->kvm))
|
||||
return;
|
||||
|
||||
/* Initialize after the above check, to prevent going out of bounds */
|
||||
sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
|
||||
kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
|
||||
|
||||
WRITE_ONCE(sigp_ctrl->value, 0);
|
||||
|
||||
+81
-44
@@ -571,7 +571,7 @@ static int kvm_s390_keyop(struct kvm_s390_mmu_cache *mc, struct kvm *kvm, int op
|
||||
switch (op) {
|
||||
case KVM_S390_KEYOP_SSKE:
|
||||
r = dat_cond_set_storage_key(mc, asce, gfn, skey, &skey, 0, 0, 0);
|
||||
if (r >= 0)
|
||||
if (r == 0 || r == 1)
|
||||
return skey.skey;
|
||||
break;
|
||||
case KVM_S390_KEYOP_ISKE:
|
||||
@@ -580,14 +580,14 @@ static int kvm_s390_keyop(struct kvm_s390_mmu_cache *mc, struct kvm *kvm, int op
|
||||
return skey.skey;
|
||||
break;
|
||||
case KVM_S390_KEYOP_RRBE:
|
||||
r = dat_reset_reference_bit(asce, gfn);
|
||||
if (r > 0)
|
||||
return r << 1;
|
||||
r = dat_reset_reference_bit(asce, gfn, &skey);
|
||||
if (!r)
|
||||
return skey.skey;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return r;
|
||||
return r > 0 ? -EFAULT : r;
|
||||
}
|
||||
|
||||
/* Section: device related */
|
||||
@@ -1219,8 +1219,8 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
|
||||
|
||||
/*
|
||||
* Must be called with kvm->srcu held to avoid races on memslots, and with
|
||||
* kvm->slots_lock to avoid races with ourselves, kvm_s390_vm_stop_migration(),
|
||||
* and kvm_s390_get_cmma_bits().
|
||||
* kvm->slots_arch_lock to avoid races with ourselves,
|
||||
* kvm_s390_vm_stop_migration(), and kvm_s390_get_cmma_bits().
|
||||
*/
|
||||
static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
||||
{
|
||||
@@ -1265,7 +1265,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with kvm->slots_lock to avoid races with ourselves,
|
||||
* Must be called with kvm->slots_arch_lock to avoid races with ourselves,
|
||||
* kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().
|
||||
*/
|
||||
static int kvm_s390_vm_stop_migration(struct kvm *kvm)
|
||||
@@ -1300,7 +1300,9 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
|
||||
{
|
||||
int res = -ENXIO;
|
||||
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
guard(srcu)(&kvm->srcu);
|
||||
guard(mutex)(&kvm->slots_arch_lock);
|
||||
|
||||
switch (attr->attr) {
|
||||
case KVM_S390_VM_MIGRATION_START:
|
||||
res = kvm_s390_vm_start_migration(kvm);
|
||||
@@ -1311,7 +1313,6 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -2214,7 +2215,7 @@ static int kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
||||
}
|
||||
|
||||
kvfree(keys);
|
||||
return r;
|
||||
return r <= 0 ? r : -EFAULT;
|
||||
}
|
||||
|
||||
static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
||||
@@ -2276,7 +2277,7 @@ static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
||||
kvm_s390_free_mmu_cache(mc);
|
||||
out:
|
||||
kvfree(keys);
|
||||
return r;
|
||||
return r <= 0 ? r : -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2386,7 +2387,7 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
||||
|
||||
set_bit(GMAP_FLAG_USES_CMM, &kvm->arch.gmap->flags);
|
||||
|
||||
return r;
|
||||
return r <= 0 ? r : -EFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2934,6 +2935,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||
case KVM_S390_INTERRUPT: {
|
||||
struct kvm_s390_interrupt s390int;
|
||||
|
||||
r = -EINVAL;
|
||||
if (kvm_is_ucontrol(kvm))
|
||||
break;
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&s390int, argp, sizeof(s390int)))
|
||||
break;
|
||||
@@ -2998,9 +3002,8 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&args, argp, sizeof(args)))
|
||||
break;
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
r = kvm_s390_get_cmma_bits(kvm, &args);
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
scoped_guard(mutex, &kvm->slots_arch_lock)
|
||||
r = kvm_s390_get_cmma_bits(kvm, &args);
|
||||
if (!r) {
|
||||
r = copy_to_user(argp, &args, sizeof(args));
|
||||
if (r)
|
||||
@@ -3014,9 +3017,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&args, argp, sizeof(args)))
|
||||
break;
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
mutex_lock(&kvm->slots_arch_lock);
|
||||
r = kvm_s390_set_cmma_bits(kvm, &args);
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
mutex_unlock(&kvm->slots_arch_lock);
|
||||
break;
|
||||
}
|
||||
case KVM_S390_PV_COMMAND: {
|
||||
@@ -3247,7 +3250,8 @@ static void kvm_s390_crypto_init(struct kvm *kvm)
|
||||
|
||||
static void sca_dispose(struct kvm *kvm)
|
||||
{
|
||||
free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
|
||||
if (kvm->arch.sca)
|
||||
free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
|
||||
kvm->arch.sca = NULL;
|
||||
}
|
||||
|
||||
@@ -3461,7 +3465,7 @@ static void sca_del_vcpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct esca_block *sca = vcpu->kvm->arch.sca;
|
||||
|
||||
if (!kvm_s390_use_sca_entries())
|
||||
if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized)
|
||||
return;
|
||||
|
||||
clear_bit_inv(vcpu->vcpu_id, (unsigned long *)sca->mcn);
|
||||
@@ -3481,8 +3485,8 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu)
|
||||
if (!kvm_s390_use_sca_entries())
|
||||
return;
|
||||
|
||||
WRITE_ONCE(sca->cpu[vcpu->vcpu_id].sda, virt_to_phys(vcpu->arch.sie_block));
|
||||
set_bit_inv(vcpu->vcpu_id, (unsigned long *)sca->mcn);
|
||||
sca->cpu[vcpu->vcpu_id].sda = virt_to_phys(vcpu->arch.sie_block);
|
||||
}
|
||||
|
||||
static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
|
||||
@@ -3613,6 +3617,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
||||
if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0 ||
|
||||
vcpu->kvm->arch.user_operexec)
|
||||
vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
|
||||
|
||||
/* Pairs with smp_load_acquire() in kvm_arch_vcpu_ioctl_run() and kvm_arch_vcpu_ioctl() */
|
||||
smp_store_release(&vcpu->arch.initialized, true);
|
||||
}
|
||||
|
||||
static bool kvm_has_pckmo_subfunc(struct kvm *kvm, unsigned long nr)
|
||||
@@ -3674,7 +3681,8 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
|
||||
|
||||
void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
free_page((unsigned long)phys_to_virt(vcpu->arch.sie_block->cbrlo));
|
||||
if (vcpu->arch.sie_block->cbrlo)
|
||||
free_page((unsigned long)phys_to_virt(vcpu->arch.sie_block->cbrlo));
|
||||
vcpu->arch.sie_block->cbrlo = 0;
|
||||
}
|
||||
|
||||
@@ -3792,21 +3800,21 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_FREE(sie_page, struct sie_page *, if (_T) free_page((unsigned long)(_T)))
|
||||
|
||||
int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct sie_page *sie_page;
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
struct sie_page *sie_page __free(sie_page) = NULL;
|
||||
int rc;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct sie_page) != 4096);
|
||||
vcpu->arch.mc = kvm_s390_new_mmu_cache();
|
||||
if (!vcpu->arch.mc)
|
||||
mc = kvm_s390_new_mmu_cache();
|
||||
if (!mc)
|
||||
return -ENOMEM;
|
||||
sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL_ACCOUNT);
|
||||
if (!sie_page) {
|
||||
kvm_s390_free_mmu_cache(vcpu->arch.mc);
|
||||
vcpu->arch.mc = NULL;
|
||||
if (!sie_page)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vcpu->arch.sie_block = &sie_page->sie_block;
|
||||
vcpu->arch.sie_block->itdba = virt_to_phys(&sie_page->itdb);
|
||||
@@ -3848,10 +3856,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS;
|
||||
|
||||
if (kvm_is_ucontrol(vcpu->kvm)) {
|
||||
rc = -ENOMEM;
|
||||
vcpu->arch.gmap = gmap_new_child(vcpu->kvm->arch.gmap, -1UL);
|
||||
if (!vcpu->arch.gmap)
|
||||
goto out_free_sie_block;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sie block at 0x%p",
|
||||
@@ -3859,20 +3866,19 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
|
||||
|
||||
rc = kvm_s390_vcpu_setup(vcpu);
|
||||
if (rc)
|
||||
goto out_ucontrol_uninit;
|
||||
if (rc) {
|
||||
if (kvm_is_ucontrol(vcpu->kvm)) {
|
||||
scoped_guard(spinlock, &vcpu->kvm->arch.gmap->children_lock)
|
||||
gmap_remove_child(vcpu->arch.gmap);
|
||||
vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
vcpu->arch.mc = no_free_ptr(mc);
|
||||
sie_page = NULL;
|
||||
kvm_s390_update_topology_change_report(vcpu->kvm, 1);
|
||||
return 0;
|
||||
|
||||
out_ucontrol_uninit:
|
||||
if (kvm_is_ucontrol(vcpu->kvm)) {
|
||||
gmap_remove_child(vcpu->arch.gmap);
|
||||
vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
|
||||
}
|
||||
out_free_sie_block:
|
||||
free_page((unsigned long)(vcpu->arch.sie_block));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
|
||||
@@ -5039,6 +5045,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
|
||||
kvm_run->kvm_dirty_regs & ~KVM_SYNC_S390_VALID_FIELDS)
|
||||
return -EINVAL;
|
||||
|
||||
/* Pairs with smp_store_release() in kvm_arch_vcpu_postcreate() */
|
||||
if (!smp_load_acquire(&vcpu->arch.initialized))
|
||||
return -EINVAL;
|
||||
|
||||
vcpu_load(vcpu);
|
||||
|
||||
if (guestdbg_exit_pending(vcpu)) {
|
||||
@@ -5447,6 +5457,8 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
|
||||
struct kvm_s390_interrupt s390int;
|
||||
struct kvm_s390_irq s390irq = {};
|
||||
|
||||
if (kvm_is_ucontrol(vcpu->kvm))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&s390int, argp, sizeof(s390int)))
|
||||
return -EFAULT;
|
||||
if (s390int_to_s390irq(&s390int, &s390irq))
|
||||
@@ -5523,6 +5535,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
long r;
|
||||
u16 rc, rrc;
|
||||
|
||||
/* Pairs with smp_store_release() in kvm_arch_vcpu_postcreate() */
|
||||
if (!smp_load_acquire(&vcpu->arch.initialized))
|
||||
return -EINVAL;
|
||||
|
||||
vcpu_load(vcpu);
|
||||
|
||||
switch (ioctl) {
|
||||
@@ -5794,14 +5810,30 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
{
|
||||
union pgste pgste;
|
||||
|
||||
pgste = pgste_get_lock(ptep);
|
||||
if (pgste.cmma_d) {
|
||||
pgste.cmma_d = 0;
|
||||
atomic64_dec(walk->priv);
|
||||
}
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_commit_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *old,
|
||||
const struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
struct kvm_s390_mmu_cache *mc = NULL;
|
||||
const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
int rc = 0;
|
||||
|
||||
guard(mutex)(&kvm->slots_arch_lock);
|
||||
|
||||
if (change == KVM_MR_FLAGS_ONLY)
|
||||
return;
|
||||
|
||||
@@ -5812,6 +5844,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
|
||||
}
|
||||
|
||||
scoped_guard(write_lock, &kvm->mmu_lock) {
|
||||
if (kvm->arch.migration_mode && kvm->arch.use_cmma && old) {
|
||||
_dat_walk_gfn_range(old->base_gfn, old->base_gfn + old->npages,
|
||||
kvm->arch.gmap->asce, &ops, DAT_WALK_IGN_HOLES,
|
||||
&kvm->arch.cmma_dirty_pages);
|
||||
}
|
||||
|
||||
switch (change) {
|
||||
case KVM_MR_DELETE:
|
||||
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
|
||||
@@ -5833,7 +5871,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
|
||||
out:
|
||||
if (rc)
|
||||
pr_warn("failed to commit memory region\n");
|
||||
kvm_s390_free_mmu_cache(mc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ static int handle_iske(struct kvm_vcpu *vcpu)
|
||||
static int handle_rrbe(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long gaddr;
|
||||
union skey skey;
|
||||
int reg1, reg2;
|
||||
int rc;
|
||||
|
||||
@@ -307,12 +308,12 @@ static int handle_rrbe(struct kvm_vcpu *vcpu)
|
||||
gaddr = kvm_s390_logical_to_effective(vcpu, gaddr);
|
||||
gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
|
||||
scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
|
||||
rc = dat_reset_reference_bit(vcpu->arch.gmap->asce, gpa_to_gfn(gaddr));
|
||||
rc = dat_reset_reference_bit(vcpu->arch.gmap->asce, gpa_to_gfn(gaddr), &skey);
|
||||
if (rc > 0)
|
||||
return kvm_s390_inject_program_int(vcpu, rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
kvm_s390_set_psw_cc(vcpu, rc);
|
||||
kvm_s390_set_psw_cc(vcpu, (skey.skey >> 1) & 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1260,8 +1261,9 @@ static int handle_essa(struct kvm_vcpu *vcpu)
|
||||
/* Retry the ESSA instruction */
|
||||
kvm_s390_retry_instr(vcpu);
|
||||
} else {
|
||||
scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
|
||||
i = __do_essa(vcpu, orc);
|
||||
scoped_guard(mutex, &vcpu->kvm->slots_arch_lock)
|
||||
scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
|
||||
i = __do_essa(vcpu, orc);
|
||||
if (i < 0)
|
||||
return i;
|
||||
/* Account for the possible extra cbrl entry */
|
||||
|
||||
+22
-21
@@ -244,6 +244,24 @@ static void kvm_s390_clear_pv_state(struct kvm *kvm)
|
||||
kvm->arch.pv.stor_var = NULL;
|
||||
}
|
||||
|
||||
static void kvm_s390_pv_dispose_cpu(struct kvm_vcpu *vcpu, bool free_stor_base)
|
||||
{
|
||||
if (free_stor_base)
|
||||
free_pages(vcpu->arch.pv.stor_base, get_order(uv_info.guest_cpu_stor_len));
|
||||
free_page((unsigned long)sida_addr(vcpu->arch.sie_block));
|
||||
vcpu->arch.sie_block->pv_handle_cpu = 0;
|
||||
vcpu->arch.sie_block->pv_handle_config = 0;
|
||||
memset(&vcpu->arch.pv, 0, sizeof(vcpu->arch.pv));
|
||||
vcpu->arch.sie_block->sdf = 0;
|
||||
/*
|
||||
* The sidad field (for sdf == 2) is now the gbea field (for sdf == 0).
|
||||
* Use the reset value of gbea to avoid leaking the kernel pointer of
|
||||
* the just freed sida.
|
||||
*/
|
||||
vcpu->arch.sie_block->gbea = 1;
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
|
||||
}
|
||||
|
||||
int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
|
||||
{
|
||||
int cc;
|
||||
@@ -258,24 +276,9 @@ int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
|
||||
WARN_ONCE(cc, "protvirt destroy cpu failed rc %x rrc %x", *rc, *rrc);
|
||||
|
||||
/* Intended memory leak for something that should never happen. */
|
||||
if (!cc)
|
||||
free_pages(vcpu->arch.pv.stor_base,
|
||||
get_order(uv_info.guest_cpu_stor_len));
|
||||
kvm_s390_pv_dispose_cpu(vcpu, !cc);
|
||||
|
||||
free_page((unsigned long)sida_addr(vcpu->arch.sie_block));
|
||||
vcpu->arch.sie_block->pv_handle_cpu = 0;
|
||||
vcpu->arch.sie_block->pv_handle_config = 0;
|
||||
memset(&vcpu->arch.pv, 0, sizeof(vcpu->arch.pv));
|
||||
vcpu->arch.sie_block->sdf = 0;
|
||||
/*
|
||||
* The sidad field (for sdf == 2) is now the gbea field (for sdf == 0).
|
||||
* Use the reset value of gbea to avoid leaking the kernel pointer of
|
||||
* the just freed sida.
|
||||
*/
|
||||
vcpu->arch.sie_block->gbea = 1;
|
||||
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
|
||||
|
||||
return cc ? EIO : 0;
|
||||
return cc ? -EIO : 0;
|
||||
}
|
||||
|
||||
int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
|
||||
@@ -319,9 +322,7 @@ int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
|
||||
uvcb.header.rrc);
|
||||
|
||||
if (cc) {
|
||||
u16 dummy;
|
||||
|
||||
kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
|
||||
kvm_s390_pv_dispose_cpu(vcpu, true);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -809,7 +810,7 @@ static int unpack_one(struct kvm *kvm, unsigned long addr, u64 tweak,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (ret && ret != -EAGAIN)
|
||||
if (ret && ret != -EAGAIN && ret != -EINTR)
|
||||
KVM_UV_EVENT(kvm, 3, "PROTVIRT VM UNPACK: failed addr %llx with rc %x rrc %x",
|
||||
uvcb.gaddr, *rc, *rrc);
|
||||
return ret;
|
||||
|
||||
@@ -1858,7 +1858,7 @@ struct kvm_x86_ops {
|
||||
* Can potentially get non-canonical addresses through INVLPGs, which
|
||||
* the implementation may choose to ignore if appropriate.
|
||||
*/
|
||||
void (*flush_tlb_gva)(struct kvm_vcpu *vcpu, gva_t addr);
|
||||
void (*flush_tlb_gva)(struct kvm_vcpu *vcpu, gva_t addr, bool *full);
|
||||
|
||||
/*
|
||||
* Flush any TLB entries created by the guest. Like tlb_flush_gva(),
|
||||
|
||||
@@ -2266,10 +2266,10 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c)
|
||||
|
||||
mca_cfg.initialized = 1;
|
||||
|
||||
__mcheck_cpu_setup_timer();
|
||||
__mcheck_cpu_init_generic();
|
||||
__mcheck_cpu_init_vendor(c);
|
||||
__mcheck_cpu_init_prepare_banks();
|
||||
__mcheck_cpu_setup_timer();
|
||||
cr4_set_bits(X86_CR4_MCE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1974,6 +1974,7 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
|
||||
u64 entries[KVM_HV_TLB_FLUSH_FIFO_SIZE];
|
||||
int i, j, count;
|
||||
gva_t gva;
|
||||
bool full = false;
|
||||
|
||||
if (!tdp_enabled || !hv_vcpu)
|
||||
return -EINVAL;
|
||||
@@ -1982,7 +1983,7 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
|
||||
|
||||
count = kfifo_out(&tlb_flush_fifo->entries, entries, KVM_HV_TLB_FLUSH_FIFO_SIZE);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < count && !full; i++) {
|
||||
if (entries[i] == KVM_HV_TLB_FLUSHALL_ENTRY)
|
||||
goto out_flush_all;
|
||||
|
||||
@@ -1991,11 +1992,11 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
|
||||
* pages to flush.
|
||||
*/
|
||||
gva = entries[i] & PAGE_MASK;
|
||||
for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1; j++) {
|
||||
for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1 && !full; j++) {
|
||||
if (is_noncanonical_invlpg_address(gva + j * PAGE_SIZE, vcpu))
|
||||
continue;
|
||||
|
||||
kvm_x86_call(flush_tlb_gva)(vcpu, gva + j * PAGE_SIZE);
|
||||
kvm_x86_call(flush_tlb_gva)(vcpu, gva + j * PAGE_SIZE, &full);
|
||||
}
|
||||
|
||||
++vcpu->stat.tlb_flush;
|
||||
|
||||
@@ -2442,6 +2442,9 @@ static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct,
|
||||
role.direct = direct;
|
||||
role.passthrough = 0;
|
||||
|
||||
WARN_ON_ONCE(role.invalid);
|
||||
role.invalid = 0;
|
||||
|
||||
/*
|
||||
* If the guest has 4-byte PTEs then that means it's using 32-bit,
|
||||
* 2-level, non-PAE paging. KVM shadows such guests with PAE paging
|
||||
@@ -6652,7 +6655,7 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
|
||||
if (is_noncanonical_invlpg_address(addr, vcpu))
|
||||
return;
|
||||
|
||||
kvm_x86_call(flush_tlb_gva)(vcpu, addr);
|
||||
kvm_x86_call(flush_tlb_gva)(vcpu, addr, NULL);
|
||||
}
|
||||
|
||||
if (!mmu->sync_spte)
|
||||
|
||||
+25
-9
@@ -97,6 +97,8 @@ static u64 sev_supported_vmsa_features __ro_after_init;
|
||||
static u8 sev_enc_bit;
|
||||
static DECLARE_RWSEM(sev_deactivate_lock);
|
||||
static DEFINE_MUTEX(sev_bitmap_lock);
|
||||
/* Protects kvm_sev_info's enc_context_owner, mirror_vms and mirror_entry. */
|
||||
static DEFINE_MUTEX(sev_mirror_lock);
|
||||
unsigned int max_sev_asid;
|
||||
static unsigned int min_sev_asid;
|
||||
static unsigned int max_sev_es_asid;
|
||||
@@ -2018,7 +2020,6 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
|
||||
dst->asid = src->asid;
|
||||
dst->handle = src->handle;
|
||||
dst->pages_locked = src->pages_locked;
|
||||
dst->enc_context_owner = src->enc_context_owner;
|
||||
dst->es_active = src->es_active;
|
||||
dst->vmsa_features = src->vmsa_features;
|
||||
|
||||
@@ -2026,11 +2027,12 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
|
||||
src->active = false;
|
||||
src->handle = 0;
|
||||
src->pages_locked = 0;
|
||||
src->enc_context_owner = NULL;
|
||||
src->es_active = false;
|
||||
|
||||
list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list);
|
||||
|
||||
mutex_lock(&sev_mirror_lock);
|
||||
|
||||
/*
|
||||
* If this VM has mirrors, "transfer" each mirror's refcount of the
|
||||
* source to the destination (this KVM). The caller holds a reference
|
||||
@@ -2047,12 +2049,15 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
|
||||
* If this VM is a mirror, remove the old mirror from the owners list
|
||||
* and add the new mirror to the list.
|
||||
*/
|
||||
if (is_mirroring_enc_context(dst_kvm)) {
|
||||
struct kvm_sev_info *owner_sev_info = to_kvm_sev_info(dst->enc_context_owner);
|
||||
if (is_mirroring_enc_context(src_kvm)) {
|
||||
struct kvm_sev_info *owner_sev_info = to_kvm_sev_info(src->enc_context_owner);
|
||||
|
||||
dst->enc_context_owner = src->enc_context_owner;
|
||||
src->enc_context_owner = NULL;
|
||||
list_del(&src->mirror_entry);
|
||||
list_add_tail(&dst->mirror_entry, &owner_sev_info->mirror_vms);
|
||||
}
|
||||
mutex_unlock(&sev_mirror_lock);
|
||||
|
||||
kvm_for_each_vcpu(i, dst_vcpu, dst_kvm) {
|
||||
dst_svm = to_svm(dst_vcpu);
|
||||
@@ -2871,11 +2876,14 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd)
|
||||
* disappear until we're done with it
|
||||
*/
|
||||
source_sev = to_kvm_sev_info(source_kvm);
|
||||
kvm_get_kvm(source_kvm);
|
||||
list_add_tail(&mirror_sev->mirror_entry, &source_sev->mirror_vms);
|
||||
|
||||
/* Set enc_context_owner and copy its encryption context over */
|
||||
mutex_lock(&sev_mirror_lock);
|
||||
kvm_get_kvm(source_kvm);
|
||||
list_add_tail(&mirror_sev->mirror_entry, &source_sev->mirror_vms);
|
||||
mirror_sev->enc_context_owner = source_kvm;
|
||||
mutex_unlock(&sev_mirror_lock);
|
||||
|
||||
mirror_sev->active = true;
|
||||
mirror_sev->asid = source_sev->asid;
|
||||
mirror_sev->fd = source_sev->fd;
|
||||
@@ -2963,11 +2971,19 @@ void sev_vm_destroy(struct kvm *kvm)
|
||||
* Note, mirror VMs don't support registering encrypted regions.
|
||||
*/
|
||||
if (is_mirroring_enc_context(kvm)) {
|
||||
struct kvm *owner_kvm = sev->enc_context_owner;
|
||||
struct kvm *owner_kvm;
|
||||
|
||||
mutex_lock(&owner_kvm->lock);
|
||||
mutex_lock(&sev_mirror_lock);
|
||||
owner_kvm = sev->enc_context_owner;
|
||||
list_del(&sev->mirror_entry);
|
||||
mutex_unlock(&owner_kvm->lock);
|
||||
sev->enc_context_owner = NULL;
|
||||
|
||||
/*
|
||||
* The reference to owner_kvm cannot move after sev_mirror_lock is
|
||||
* released. Release it before kvm_put_kvm() so that owner_kvm is
|
||||
* never destroyed inside sev_mirror_lock.
|
||||
*/
|
||||
mutex_unlock(&sev_mirror_lock);
|
||||
kvm_put_kvm(owner_kvm);
|
||||
return;
|
||||
}
|
||||
|
||||
+20
-7
@@ -4227,13 +4227,6 @@ static void svm_flush_tlb_all(struct kvm_vcpu *vcpu)
|
||||
svm_flush_tlb_asid(vcpu);
|
||||
}
|
||||
|
||||
static void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
invlpga(gva, svm->vmcb->control.asid);
|
||||
}
|
||||
|
||||
static void svm_flush_tlb_guest(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_register_mark_dirty(vcpu, VCPU_REG_ERAPS);
|
||||
@@ -4241,6 +4234,26 @@ static void svm_flush_tlb_guest(struct kvm_vcpu *vcpu)
|
||||
svm_flush_tlb_asid(vcpu);
|
||||
}
|
||||
|
||||
static void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva, bool *full)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
/*
|
||||
* INVLPGA has had errata on Genoa and Turin, and even on older
|
||||
* generations there were reports of Windows BSODs if INVLPGA
|
||||
* was used for Hyper-V tlbflush. Use it only for shadow paging
|
||||
* where it seems to be okay.
|
||||
*/
|
||||
if (!npt_enabled) {
|
||||
invlpga(gva, svm->vmcb->control.asid);
|
||||
return;
|
||||
}
|
||||
|
||||
svm_flush_tlb_guest(vcpu);
|
||||
if (full)
|
||||
*full = true;
|
||||
}
|
||||
|
||||
static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
@@ -109,6 +109,7 @@ struct kvm_sev_info {
|
||||
u64 ap_jump_table; /* SEV-ES AP Jump Table address */
|
||||
u64 vmsa_features;
|
||||
u16 ghcb_version; /* Highest guest GHCB protocol version allowed */
|
||||
/* The three fields below are protected by sev_mirror_lock */
|
||||
struct kvm *enc_context_owner; /* Owner of copied encryption context */
|
||||
struct list_head mirror_vms; /* List of VMs mirroring */
|
||||
struct list_head mirror_entry; /* Use as a list entry of mirrors */
|
||||
|
||||
@@ -535,12 +535,12 @@ static void vt_flush_tlb_current(struct kvm_vcpu *vcpu)
|
||||
vmx_flush_tlb_current(vcpu);
|
||||
}
|
||||
|
||||
static void vt_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr)
|
||||
static void vt_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr, bool *full)
|
||||
{
|
||||
if (is_td_vcpu(vcpu))
|
||||
return;
|
||||
|
||||
vmx_flush_tlb_gva(vcpu, addr);
|
||||
vmx_flush_tlb_gva(vcpu, addr, full);
|
||||
}
|
||||
|
||||
static void vt_flush_tlb_guest(struct kvm_vcpu *vcpu)
|
||||
|
||||
@@ -3361,7 +3361,7 @@ void vmx_flush_tlb_current(struct kvm_vcpu *vcpu)
|
||||
vpid_sync_context(vmx_get_current_vpid(vcpu));
|
||||
}
|
||||
|
||||
void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr)
|
||||
void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr, bool *full)
|
||||
{
|
||||
/*
|
||||
* vpid_sync_vcpu_addr() is a nop if vpid==0, see the comment in
|
||||
|
||||
@@ -82,7 +82,7 @@ void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
|
||||
bool vmx_get_if_flag(struct kvm_vcpu *vcpu);
|
||||
void vmx_flush_tlb_all(struct kvm_vcpu *vcpu);
|
||||
void vmx_flush_tlb_current(struct kvm_vcpu *vcpu);
|
||||
void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr);
|
||||
void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr, bool *full);
|
||||
void vmx_flush_tlb_guest(struct kvm_vcpu *vcpu);
|
||||
void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask);
|
||||
u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/string.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
@@ -309,7 +310,12 @@ static struct proto_ops algif_skcipher_ops_nokey = {
|
||||
|
||||
static void *skcipher_bind(const char *name)
|
||||
{
|
||||
return crypto_alloc_skcipher(name, 0, AF_ALG_CRYPTOAPI_MASK);
|
||||
u32 mask = AF_ALG_CRYPTOAPI_MASK;
|
||||
|
||||
if (strcmp(name, "cbc(paes)") == 0)
|
||||
mask = 0;
|
||||
|
||||
return crypto_alloc_skcipher(name, 0, mask);
|
||||
}
|
||||
|
||||
static void skcipher_release(void *private)
|
||||
|
||||
+1
-1
@@ -747,7 +747,7 @@ static int crypto_rfc4309_create(struct crypto_template *tmpl,
|
||||
|
||||
inst->alg.ivsize = 8;
|
||||
inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
|
||||
inst->alg.maxauthsize = 16;
|
||||
inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
|
||||
|
||||
inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
|
||||
|
||||
|
||||
@@ -436,6 +436,23 @@ static void amdxdna_gem_dev_obj_free(struct drm_gem_object *gobj)
|
||||
amdxdna_gem_destroy_obj(abo);
|
||||
}
|
||||
|
||||
static void amdxdna_mark_mapp_invalid(struct amdxdna_gem_obj *abo,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
|
||||
struct amdxdna_umap *mapp;
|
||||
|
||||
down_write(&xdna->notifier_lock);
|
||||
abo->mem.map_invalid = true;
|
||||
list_for_each_entry(mapp, &abo->mem.umap_list, node) {
|
||||
if (compare_range(mapp, vma->vm_mm, vma->vm_start, vma->vm_end)) {
|
||||
mapp->invalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_write(&xdna->notifier_lock);
|
||||
}
|
||||
|
||||
static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
@@ -450,26 +467,17 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
|
||||
XDNA_ERR(xdna, "Failed shmem mmap %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The buffer is based on memory pages. Fix the flag. */
|
||||
vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
|
||||
ret = vm_insert_pages(vma, vma->vm_start, abo->base.pages,
|
||||
&num_pages);
|
||||
} else {
|
||||
vma->vm_private_data = NULL;
|
||||
vma->vm_ops = NULL;
|
||||
ret = dma_buf_mmap(abo->dma_buf, vma, 0);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed insert pages %d", ret);
|
||||
vma->vm_ops->close(vma);
|
||||
XDNA_ERR(xdna, "Failed to mmap dma buf %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vma->vm_private_data = NULL;
|
||||
vma->vm_ops = NULL;
|
||||
ret = dma_buf_mmap(abo->dma_buf, vma, 0);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to mmap dma buf %d", ret);
|
||||
return ret;
|
||||
/* Drop the reference drm_gem_mmap_obj() acquired.*/
|
||||
drm_gem_object_put(to_gobj(abo));
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -478,17 +486,14 @@ static int amdxdna_insert_pages(struct amdxdna_gem_obj *abo,
|
||||
fault_ret = handle_mm_fault(vma, vma->vm_start + offset,
|
||||
FAULT_FLAG_WRITE, NULL);
|
||||
if (fault_ret & VM_FAULT_ERROR) {
|
||||
vma->vm_ops->close(vma);
|
||||
XDNA_ERR(xdna, "Fault in page failed");
|
||||
return -EFAULT;
|
||||
amdxdna_mark_mapp_invalid(abo, vma);
|
||||
break;
|
||||
}
|
||||
|
||||
offset += PAGE_SIZE;
|
||||
} while (--num_pages);
|
||||
|
||||
/* Drop the reference drm_gem_mmap_obj() acquired.*/
|
||||
drm_gem_object_put(to_gobj(abo));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1586,6 +1586,10 @@ impl Process {
|
||||
cmd: u32,
|
||||
reader: &mut UserSliceReader,
|
||||
) -> Result {
|
||||
if cmd == uapi::BINDER_FREEZE {
|
||||
return ioctl_freeze(reader);
|
||||
}
|
||||
|
||||
let thread = this.get_current_thread()?;
|
||||
match cmd {
|
||||
uapi::BINDER_SET_MAX_THREADS => this.set_max_threads(reader.read()?),
|
||||
@@ -1597,7 +1601,6 @@ impl Process {
|
||||
uapi::BINDER_ENABLE_ONEWAY_SPAM_DETECTION => {
|
||||
this.set_oneway_spam_detection_enabled(reader.read()?)
|
||||
}
|
||||
uapi::BINDER_FREEZE => ioctl_freeze(reader)?,
|
||||
_ => return Err(EINVAL),
|
||||
}
|
||||
Ok(())
|
||||
@@ -1612,15 +1615,16 @@ impl Process {
|
||||
cmd: u32,
|
||||
data: UserSlice,
|
||||
) -> Result {
|
||||
let thread = this.get_current_thread()?;
|
||||
let blocking = (file.flags() & file::flags::O_NONBLOCK) == 0;
|
||||
match cmd {
|
||||
uapi::BINDER_WRITE_READ => thread.write_read(data, blocking)?,
|
||||
uapi::BINDER_WRITE_READ => this.get_current_thread()?.write_read(data, blocking)?,
|
||||
uapi::BINDER_GET_NODE_DEBUG_INFO => this.get_node_debug_info(data)?,
|
||||
uapi::BINDER_GET_NODE_INFO_FOR_REF => this.get_node_info_from_ref(data)?,
|
||||
uapi::BINDER_VERSION => this.version(data)?,
|
||||
uapi::BINDER_GET_FROZEN_INFO => get_frozen_status(data)?,
|
||||
uapi::BINDER_GET_EXTENDED_ERROR => thread.get_extended_error(data)?,
|
||||
uapi::BINDER_GET_EXTENDED_ERROR => {
|
||||
this.get_current_thread()?.get_extended_error(data)?
|
||||
}
|
||||
_ => return Err(EINVAL),
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -4420,6 +4420,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
|
||||
*/
|
||||
{ "WDC WD100EFGX-68CPLN0", NULL, ATA_QUIRK_NOLPM },
|
||||
{ "WDC WD102KFBX-68M95N0", NULL, ATA_QUIRK_NOLPM },
|
||||
{ "WDC WD141KFGX-68FH9N0", NULL, ATA_QUIRK_NOLPM },
|
||||
{ "WD Green 2.5 480GB", NULL, ATA_QUIRK_NOLPM },
|
||||
|
||||
/*
|
||||
|
||||
@@ -264,6 +264,7 @@ static struct ata_port_operations sl82c105_port_ops = {
|
||||
static int sl82c105_bridge_revision(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *bridge;
|
||||
u8 revision;
|
||||
|
||||
/*
|
||||
* The bridge should be part of the same device, but function 0.
|
||||
@@ -285,8 +286,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
|
||||
/*
|
||||
* We need to find function 0's revision, not function 1
|
||||
*/
|
||||
revision = bridge->revision;
|
||||
pci_dev_put(bridge);
|
||||
return bridge->revision;
|
||||
return revision;
|
||||
}
|
||||
|
||||
static void sl82c105_fixup(struct pci_dev *pdev)
|
||||
|
||||
@@ -123,6 +123,8 @@ static void regcache_hw_exit(struct regmap *map)
|
||||
|
||||
int regcache_init(struct regmap *map, const struct regmap_config *config)
|
||||
{
|
||||
bool sort_defaults = false;
|
||||
unsigned int reg_prev = 0;
|
||||
int count = 0;
|
||||
int ret;
|
||||
int i;
|
||||
@@ -149,10 +151,16 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < config->num_reg_defaults; i++)
|
||||
for (i = 0; i < config->num_reg_defaults; i++) {
|
||||
if (config->reg_defaults[i].reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
if (reg_prev > config->reg_defaults[i].reg)
|
||||
sort_defaults = true;
|
||||
|
||||
reg_prev = config->reg_defaults[i].reg;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cache_types); i++)
|
||||
if (cache_types[i]->type == map->cache_type)
|
||||
break;
|
||||
@@ -186,6 +194,13 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
||||
sizeof(*map->reg_defaults), GFP_KERNEL);
|
||||
if (!tmp_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* regcache_lookup_reg() bsearch()es this array */
|
||||
if (sort_defaults) {
|
||||
dev_warn(map->dev,
|
||||
"Driver needs fixing: Unsorted reg_defaults, sorting the copy\n");
|
||||
regcache_sort_defaults(tmp_buf, map->num_reg_defaults);
|
||||
}
|
||||
map->reg_defaults = tmp_buf;
|
||||
} else if (map->num_reg_defaults_raw) {
|
||||
count = regcache_count_cacheable_registers(map);
|
||||
@@ -727,14 +742,6 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int regcache_default_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct reg_default *_a = a;
|
||||
const struct reg_default *_b = b;
|
||||
|
||||
return _a->reg - _b->reg;
|
||||
}
|
||||
|
||||
int regcache_lookup_reg(struct regmap *map, unsigned int reg)
|
||||
{
|
||||
struct reg_default key;
|
||||
@@ -744,7 +751,7 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
|
||||
key.def = 0;
|
||||
|
||||
r = bsearch(&key, map->reg_defaults, map->num_reg_defaults,
|
||||
sizeof(struct reg_default), regcache_default_cmp);
|
||||
sizeof(struct reg_default), regcache_defaults_cmp);
|
||||
|
||||
if (r)
|
||||
return r - map->reg_defaults;
|
||||
|
||||
@@ -483,7 +483,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
|
||||
char clk_name[7];
|
||||
struct regmap *regmap;
|
||||
struct clk *clk[3];
|
||||
int channel;
|
||||
u32 channel;
|
||||
int ret, i;
|
||||
|
||||
counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
|
||||
@@ -517,7 +517,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
|
||||
|
||||
priv->channel[i] = channel;
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
|
||||
snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
|
||||
|
||||
clk[i] = of_clk_get_by_name(np->parent, clk_name);
|
||||
if (IS_ERR(clk[i])) {
|
||||
|
||||
@@ -58,7 +58,7 @@ static int devm_qce_register_algs(struct qce_device *qce)
|
||||
ret = ops->register_algs(qce);
|
||||
if (ret) {
|
||||
for (j = i - 1; j >= 0; j--)
|
||||
ops->unregister_algs(qce);
|
||||
qce_ops[j]->unregister_algs(qce);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,7 +677,7 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq
|
||||
|
||||
if (cryp->total_in)
|
||||
sg_zero_buffer(rctx->in_sg, sg_nents(rctx->in_sg),
|
||||
sg_dma_len(rctx->in_sg) - cryp->total_in,
|
||||
rctx->in_sg->length - cryp->total_in,
|
||||
cryp->total_in);
|
||||
|
||||
ctx->rctx = rctx;
|
||||
|
||||
@@ -45,7 +45,6 @@ struct tegra_aes_reqctx {
|
||||
|
||||
struct tegra_aead_ctx {
|
||||
struct tegra_se *se;
|
||||
unsigned int authsize;
|
||||
u32 alg;
|
||||
u32 key_id;
|
||||
u32 keylen;
|
||||
@@ -1290,7 +1289,7 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
|
||||
if (rctx->encrypt)
|
||||
rctx->cryptlen = req->cryptlen;
|
||||
else
|
||||
rctx->cryptlen = req->cryptlen - ctx->authsize;
|
||||
rctx->cryptlen = req->cryptlen - rctx->authsize;
|
||||
|
||||
memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);
|
||||
rctx->iv[3] = (1 << 24);
|
||||
@@ -1394,8 +1393,6 @@ static int tegra_aead_cra_init(struct crypto_aead *tfm)
|
||||
|
||||
static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
|
||||
{
|
||||
struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
|
||||
switch (authsize) {
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -1404,28 +1401,15 @@ static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->authsize = authsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
|
||||
{
|
||||
struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
int ret;
|
||||
|
||||
ret = crypto_gcm_check_authsize(authsize);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->authsize = authsize;
|
||||
|
||||
return 0;
|
||||
return crypto_gcm_check_authsize(authsize);
|
||||
}
|
||||
|
||||
static void tegra_aead_cra_exit(struct crypto_aead *tfm)
|
||||
|
||||
@@ -335,7 +335,6 @@ static int dibs_lo_dev_probe(void)
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
kfree(dibs->dmb_clientid_arr);
|
||||
/* pairs with dibs_dev_alloc() */
|
||||
put_device(&dibs->dev);
|
||||
kfree(ldev);
|
||||
|
||||
@@ -128,6 +128,7 @@ static void dibs_dev_release(struct device *dev)
|
||||
|
||||
dibs = container_of(dev, struct dibs_dev, dev);
|
||||
|
||||
kfree(dibs->dmb_clientid_arr);
|
||||
kfree(dibs);
|
||||
}
|
||||
|
||||
@@ -194,12 +195,13 @@ int dibs_dev_add(struct dibs_dev *dibs)
|
||||
|
||||
ret = device_add(&dibs->dev);
|
||||
if (ret)
|
||||
goto free_client_arr;
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
|
||||
if (ret) {
|
||||
dev_err(&dibs->dev, "sysfs_create_group failed for dibs_dev\n");
|
||||
goto err_device_del;
|
||||
device_del(&dibs->dev);
|
||||
return ret;
|
||||
}
|
||||
mutex_lock(&dibs_dev_list.mutex);
|
||||
mutex_lock(&clients_lock);
|
||||
@@ -214,13 +216,6 @@ int dibs_dev_add(struct dibs_dev *dibs)
|
||||
mutex_unlock(&dibs_dev_list.mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_device_del:
|
||||
device_del(&dibs->dev);
|
||||
free_client_arr:
|
||||
kfree(dibs->dmb_clientid_arr);
|
||||
return ret;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dibs_dev_add);
|
||||
|
||||
@@ -247,7 +242,6 @@ void dibs_dev_del(struct dibs_dev *dibs)
|
||||
mutex_unlock(&dibs_dev_list.mutex);
|
||||
|
||||
device_del(&dibs->dev);
|
||||
kfree(dibs->dmb_clientid_arr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dibs_dev_del);
|
||||
|
||||
|
||||
@@ -540,11 +540,13 @@ static void ar_context_link_page(struct ar_context *ctx, unsigned int index)
|
||||
|
||||
static void ar_context_release(struct ar_context *ctx)
|
||||
{
|
||||
struct device *dev = ctx->ohci->card.device;
|
||||
struct device *dev;
|
||||
|
||||
if (!ctx->buffer)
|
||||
return;
|
||||
|
||||
dev = ctx->ohci->card.device;
|
||||
|
||||
for (int i = 0; i < AR_BUFFERS; ++i) {
|
||||
dma_addr_t dma_addr = ctx->dma_addrs[i];
|
||||
if (dma_addr)
|
||||
|
||||
+38
-33
@@ -73,7 +73,7 @@ struct ioh_gpio_reg_data {
|
||||
* @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM
|
||||
* @ch: Indicate GPIO channel
|
||||
* @irq_base: Save base of IRQ number for interrupt
|
||||
* @spinlock: Used for register access protection
|
||||
* @spinlock: Shared register access lock
|
||||
*/
|
||||
struct ioh_gpio {
|
||||
void __iomem *base;
|
||||
@@ -84,7 +84,12 @@ struct ioh_gpio {
|
||||
u32 gpio_use_sel;
|
||||
int ch;
|
||||
int irq_base;
|
||||
spinlock_t spinlock;
|
||||
raw_spinlock_t *spinlock;
|
||||
};
|
||||
|
||||
struct ioh_gpio_device {
|
||||
raw_spinlock_t spinlock;
|
||||
struct ioh_gpio chip[8];
|
||||
};
|
||||
|
||||
static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
|
||||
@@ -95,7 +100,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
|
||||
struct ioh_gpio *chip = gpiochip_get_data(gpio);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(chip->spinlock, flags);
|
||||
reg_val = ioread32(&chip->reg->regs[chip->ch].po);
|
||||
if (val)
|
||||
reg_val |= BIT(nr);
|
||||
@@ -103,7 +108,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
|
||||
reg_val &= ~BIT(nr);
|
||||
|
||||
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -123,7 +128,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||
u32 reg_val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->regs[chip->ch].pm);
|
||||
pm &= BIT(num_ports[chip->ch]) - 1;
|
||||
pm |= BIT(nr);
|
||||
@@ -136,7 +141,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||
reg_val &= ~BIT(nr);
|
||||
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
|
||||
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -147,12 +152,12 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
||||
u32 pm;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(chip->spinlock, flags);
|
||||
pm = ioread32(&chip->reg->regs[chip->ch].pm);
|
||||
pm &= BIT(num_ports[chip->ch]) - 1;
|
||||
pm &= ~BIT(nr);
|
||||
iowrite32(pm, &chip->reg->regs[chip->ch].pm);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -256,7 +261,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
|
||||
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
|
||||
__func__, irq, type, ch, im_pos, type);
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(chip->spinlock, flags);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
@@ -296,7 +301,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
|
||||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
|
||||
end:
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -326,11 +331,11 @@ static void ioh_irq_disable(struct irq_data *d)
|
||||
unsigned long flags;
|
||||
u32 ien;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(chip->spinlock, flags);
|
||||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
ien &= ~BIT(d->irq - chip->irq_base);
|
||||
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(chip->spinlock, flags);
|
||||
}
|
||||
|
||||
static void ioh_irq_enable(struct irq_data *d)
|
||||
@@ -340,11 +345,11 @@ static void ioh_irq_enable(struct irq_data *d)
|
||||
unsigned long flags;
|
||||
u32 ien;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(chip->spinlock, flags);
|
||||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
ien |= BIT(d->irq - chip->irq_base);
|
||||
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_unlock_irqrestore(chip->spinlock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
|
||||
@@ -407,8 +412,8 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
int ret;
|
||||
int i, j;
|
||||
struct ioh_gpio *chip;
|
||||
struct ioh_gpio_device *priv;
|
||||
void __iomem *base;
|
||||
void *chip_save;
|
||||
int irq_base;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
@@ -429,18 +434,18 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip_save = devm_kcalloc(dev, 8, sizeof(*chip), GFP_KERNEL);
|
||||
if (chip_save == NULL) {
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
raw_spin_lock_init(&priv->spinlock);
|
||||
chip = priv->chip;
|
||||
for (i = 0; i < 8; i++, chip++) {
|
||||
chip->dev = dev;
|
||||
chip->base = base;
|
||||
chip->reg = chip->base;
|
||||
chip->ch = i;
|
||||
spin_lock_init(&chip->spinlock);
|
||||
chip->spinlock = &priv->spinlock;
|
||||
ioh_gpio_setup(chip, num_ports[i]);
|
||||
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
|
||||
if (ret) {
|
||||
@@ -449,7 +454,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
chip = priv->chip;
|
||||
for (j = 0; j < 8; j++, chip++) {
|
||||
irq_base = devm_irq_alloc_descs(dev, -1, IOH_IRQ_BASE,
|
||||
num_ports[j], NUMA_NO_NODE);
|
||||
@@ -466,7 +471,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
chip = priv->chip;
|
||||
ret = devm_request_irq(dev, pdev->irq, ioh_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
if (ret != 0) {
|
||||
@@ -474,33 +479,33 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, chip);
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioh_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct ioh_gpio *chip = dev_get_drvdata(dev);
|
||||
struct ioh_gpio_device *priv = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
ioh_gpio_save_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&priv->spinlock, flags);
|
||||
ioh_gpio_save_reg_conf(priv->chip);
|
||||
raw_spin_unlock_irqrestore(&priv->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioh_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct ioh_gpio *chip = dev_get_drvdata(dev);
|
||||
struct ioh_gpio_device *priv = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
iowrite32(0x01, &chip->reg->srst);
|
||||
iowrite32(0x00, &chip->reg->srst);
|
||||
ioh_gpio_restore_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
raw_spin_lock_irqsave(&priv->spinlock, flags);
|
||||
iowrite32(0x01, &priv->chip->reg->srst);
|
||||
iowrite32(0x00, &priv->chip->reg->srst);
|
||||
ioh_gpio_restore_reg_conf(priv->chip);
|
||||
raw_spin_unlock_irqrestore(&priv->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
|
||||
debugfs_create_ulong("delay_ns_acquisition", 0400, priv->debug_dir, &priv->acq_delay);
|
||||
debugfs_create_file_unsafe("buf_size", 0600, priv->debug_dir, priv, &fops_buf_size);
|
||||
debugfs_create_file_unsafe("capture", 0200, priv->debug_dir, priv, &fops_capture);
|
||||
debugfs_create_file_unsafe("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
|
||||
debugfs_create_file("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5420,7 +5420,8 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *gc)
|
||||
flags = READ_ONCE(desc->flags);
|
||||
is_irq = test_bit(GPIOD_FLAG_USED_AS_IRQ, &flags);
|
||||
if (is_irq || test_bit(GPIOD_FLAG_REQUESTED, &flags)) {
|
||||
gpiod_get_direction(desc);
|
||||
if (gc->get_direction)
|
||||
gpiod_get_direction(desc);
|
||||
is_out = test_bit(GPIOD_FLAG_IS_OUT, &flags);
|
||||
value = gpio_chip_get_value(gc, desc);
|
||||
active_low = test_bit(GPIOD_FLAG_ACTIVE_LOW, &flags);
|
||||
|
||||
@@ -42,6 +42,26 @@
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_hmm.h"
|
||||
|
||||
/*
|
||||
* Maximum IB length (dwords) for rings whose emit_ib packet format
|
||||
* documents a 20-bit size field.
|
||||
*/
|
||||
#define AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW 0xFFFFF
|
||||
#define AMDGPU_MM_IB_PACKET_SIZE_MAX_DW 0x7FFFF0
|
||||
|
||||
static u32 amdgpu_cs_ib_packet_size_max_dw(enum amdgpu_ring_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case AMDGPU_RING_TYPE_GFX:
|
||||
case AMDGPU_RING_TYPE_COMPUTE:
|
||||
case AMDGPU_RING_TYPE_SDMA:
|
||||
case AMDGPU_RING_TYPE_VPE:
|
||||
return AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW;
|
||||
default:
|
||||
return AMDGPU_MM_IB_PACKET_SIZE_MAX_DW;
|
||||
}
|
||||
}
|
||||
|
||||
static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p,
|
||||
struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
@@ -345,7 +365,6 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,
|
||||
|
||||
job = p->jobs[r];
|
||||
ring = amdgpu_job_ring(job);
|
||||
ib = &job->ibs[job->num_ibs++];
|
||||
|
||||
/* submissions to kernel queues are disabled */
|
||||
if (ring->no_user_submission)
|
||||
@@ -374,6 +393,12 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (chunk_ib->ib_bytes / 4 >
|
||||
amdgpu_cs_ib_packet_size_max_dw(ring->funcs->type))
|
||||
return -EINVAL;
|
||||
|
||||
ib = &job->ibs[job->num_ibs++];
|
||||
|
||||
if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE)
|
||||
job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT;
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
struct amdgpu_ip_block *ip_block;
|
||||
struct amdgpu_ring *ring;
|
||||
int ver, i, j;
|
||||
u32 ring_idx, off;
|
||||
u32 ring_idx;
|
||||
bool sizing_pass;
|
||||
|
||||
sizing_pass = buffer == NULL;
|
||||
@@ -442,7 +442,6 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
for (i = 0; i < coredump->num_rings; i++) {
|
||||
ring_idx = coredump->rings[i].ring_index;
|
||||
ring = coredump->adev->rings[ring_idx];
|
||||
off = coredump->rings[i].offset;
|
||||
|
||||
drm_printf(&p, "ring name: %s\n", ring->name);
|
||||
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
|
||||
@@ -451,12 +450,18 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
ring->buf_mask);
|
||||
drm_printf(&p, "Ring size in dwords: %d\n",
|
||||
ring->ring_size / 4);
|
||||
|
||||
if (!coredump->rings[i].ring_dw) {
|
||||
drm_printf(&p, "Ring contents unavailable\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_printf(&p, "Ring contents\n");
|
||||
drm_printf(&p, "Offset \t Value\n");
|
||||
|
||||
for (j = 0; j < ring->ring_size; j += 4)
|
||||
drm_printf(&p, "0x%x \t 0x%x\n", j,
|
||||
coredump->rings_dw[off + j / 4]);
|
||||
coredump->rings[i].ring_dw[j / 4]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,10 +502,12 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
|
||||
static void amdgpu_devcoredump_free(void *data)
|
||||
{
|
||||
struct amdgpu_coredump_info *coredump = data;
|
||||
u32 i;
|
||||
|
||||
kvfree(coredump->formatted);
|
||||
for (i = 0; i < coredump->num_rings; i++)
|
||||
kvfree(coredump->rings[i].ring_dw);
|
||||
kvfree(coredump->rings);
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(data);
|
||||
}
|
||||
|
||||
@@ -542,9 +549,9 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
struct amdgpu_coredump_info *coredump;
|
||||
size_t size = sizeof(*coredump);
|
||||
struct drm_sched_job *s_job;
|
||||
u64 total_ring_size, ring_count;
|
||||
u64 ring_count;
|
||||
struct amdgpu_ring *ring;
|
||||
int i, off, idx;
|
||||
int i, idx;
|
||||
|
||||
/* No need to generate a new coredump if there's one in progress already. */
|
||||
if (work_busy(&adev->coredump_work))
|
||||
@@ -553,7 +560,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
if (job && job->pasid)
|
||||
size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
|
||||
|
||||
coredump = kzalloc(size, GFP_NOWAIT);
|
||||
coredump = kvzalloc(size, GFP_NOWAIT);
|
||||
if (!coredump)
|
||||
return;
|
||||
|
||||
@@ -584,7 +591,6 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
|
||||
/* Dump ring content if memory allocation succeeds. */
|
||||
ring_count = 0;
|
||||
total_ring_size = 0;
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
ring = adev->rings[i];
|
||||
|
||||
@@ -593,34 +599,34 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
total_ring_size += ring->ring_size;
|
||||
ring_count++;
|
||||
}
|
||||
coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT);
|
||||
coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT);
|
||||
if (coredump->rings && coredump->rings_dw) {
|
||||
for (i = 0, off = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
|
||||
if (ring_count)
|
||||
coredump->rings = kvcalloc(ring_count,
|
||||
sizeof(struct amdgpu_coredump_ring),
|
||||
GFP_NOWAIT);
|
||||
if (coredump->rings) {
|
||||
for (i = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
|
||||
struct amdgpu_coredump_ring *cdump_ring;
|
||||
|
||||
ring = adev->rings[i];
|
||||
|
||||
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
coredump->rings[idx].ring_index = ring->idx;
|
||||
coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring);
|
||||
coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring);
|
||||
coredump->rings[idx].offset = off;
|
||||
cdump_ring = &coredump->rings[idx];
|
||||
|
||||
memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
|
||||
off += ring->ring_size / 4;
|
||||
cdump_ring->ring_dw = kvzalloc(ring->ring_size, GFP_NOWAIT);
|
||||
if (cdump_ring->ring_dw)
|
||||
memcpy(cdump_ring->ring_dw, ring->ring, ring->ring_size);
|
||||
|
||||
cdump_ring->ring_index = ring->idx;
|
||||
cdump_ring->rptr = amdgpu_ring_get_rptr(ring);
|
||||
cdump_ring->wptr = amdgpu_ring_get_wptr(ring);
|
||||
idx++;
|
||||
}
|
||||
coredump->num_rings = idx;
|
||||
} else {
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(coredump->rings);
|
||||
coredump->rings_dw = NULL;
|
||||
coredump->rings = NULL;
|
||||
}
|
||||
|
||||
coredump->adev = adev;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
struct amdgpu_coredump_ring {
|
||||
u64 rptr;
|
||||
u64 wptr;
|
||||
u32 *ring_dw;
|
||||
u32 ring_index;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct amdgpu_coredump_ib_info {
|
||||
@@ -53,7 +53,6 @@ struct amdgpu_coredump_info {
|
||||
struct amdgpu_ring *ring;
|
||||
|
||||
struct amdgpu_coredump_ring *rings;
|
||||
u32 *rings_dw;
|
||||
u32 num_rings;
|
||||
|
||||
/* Readable form of coredevdump, generate once to speed up
|
||||
|
||||
@@ -4194,6 +4194,8 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev)
|
||||
|
||||
iounmap(adev->rmmio);
|
||||
adev->rmmio = NULL;
|
||||
if (adev->mman.aper_base_kaddr)
|
||||
iounmap(adev->mman.aper_base_kaddr);
|
||||
adev->mman.aper_base_kaddr = NULL;
|
||||
|
||||
/* Memory manager related */
|
||||
|
||||
@@ -135,6 +135,21 @@ int amdgpu_lockdep_init(void)
|
||||
lockdep_set_class(&locks->srbm_mutex, &amdgpu_srbm_lock_key);
|
||||
lockdep_set_class(&locks->grbm_idx_mutex, &amdgpu_grbm_lock_key);
|
||||
lockdep_set_class(&locks->mmio_idx_lock, &amdgpu_mmio_lock_key);
|
||||
|
||||
/*
|
||||
* Register fs_reclaim lock class FIRST, before taking any locks.
|
||||
*
|
||||
* This acquire/release pair does NOT create a static lockdep edge
|
||||
* (no locks are held between acquire and release). It only registers
|
||||
* the fs_reclaim lock class with lockdep.
|
||||
*
|
||||
* The actual fs_reclaim -> notifier_lock dependency is established at
|
||||
* RUNTIME when memory reclaim invokes MMU notifiers:
|
||||
* fs_reclaim (held by reclaim) -> notifier_lock (acquired in callback)
|
||||
*/
|
||||
fs_reclaim_acquire(GFP_KERNEL);
|
||||
fs_reclaim_release(GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Take locks in the correct order to train lockdep.
|
||||
* This establishes the dependency chain.
|
||||
@@ -154,11 +169,6 @@ int amdgpu_lockdep_init(void)
|
||||
|
||||
/* Level 6: Reset control lock */
|
||||
mutex_lock(&locks->reset_lock);
|
||||
/*
|
||||
* Mark potential memory reclaim boundary.
|
||||
* GPU operations might trigger memory allocation/reclaim.
|
||||
*/
|
||||
fs_reclaim_acquire(GFP_KERNEL);
|
||||
|
||||
/* Level 7: SRBM register access */
|
||||
mutex_lock(&locks->srbm_mutex);
|
||||
@@ -176,7 +186,6 @@ int amdgpu_lockdep_init(void)
|
||||
spin_unlock_irqrestore(&locks->mmio_idx_lock, flags);
|
||||
mutex_unlock(&locks->grbm_idx_mutex);
|
||||
mutex_unlock(&locks->srbm_mutex);
|
||||
fs_reclaim_release(GFP_KERNEL);
|
||||
|
||||
mutex_unlock(&locks->reset_lock);
|
||||
up_read(&reset_domain->sem);
|
||||
|
||||
@@ -2120,23 +2120,17 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
||||
/* Change the size here instead of the init above so only lpfn is affected */
|
||||
amdgpu_ttm_disable_buffer_funcs(adev);
|
||||
#ifdef CONFIG_64BIT
|
||||
if (adev->gmc.xgmi.connected_to_cpu) {
|
||||
void *kaddr = devm_memremap(adev->dev, adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size,
|
||||
MEMREMAP_WB);
|
||||
if (IS_ERR(kaddr))
|
||||
return PTR_ERR(kaddr);
|
||||
adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr;
|
||||
} else if (adev->gmc.is_app_apu) {
|
||||
#ifdef CONFIG_X86
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
else if (adev->gmc.is_app_apu)
|
||||
DRM_DEBUG_DRIVER(
|
||||
"No need to ioremap when real vram size is 0\n");
|
||||
} else {
|
||||
adev->mman.aper_base_kaddr = devm_ioremap_wc(adev->dev,
|
||||
adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
if (!adev->mman.aper_base_kaddr)
|
||||
return -ENOMEM;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
#endif
|
||||
|
||||
amdgpu_ttm_init_vram_resv_regions(adev);
|
||||
@@ -2287,7 +2281,10 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE);
|
||||
|
||||
adev->mman.aper_base_kaddr = NULL;
|
||||
if (adev->mman.aper_base_kaddr) {
|
||||
iounmap(adev->mman.aper_base_kaddr);
|
||||
adev->mman.aper_base_kaddr = NULL;
|
||||
}
|
||||
|
||||
if (!adev->gmc.is_app_apu)
|
||||
amdgpu_vram_mgr_fini(adev);
|
||||
|
||||
@@ -700,7 +700,12 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
||||
if (!adev->userq_halt_for_enforce_isolation ||
|
||||
((queue->queue_type != AMDGPU_HW_IP_GFX) &&
|
||||
(queue->queue_type != AMDGPU_HW_IP_COMPUTE))) {
|
||||
/* Serialize the map against an in-progress GPU reset (MES is
|
||||
* unresponsive during recovery), matching amdgpu_userq_cleanup().
|
||||
*/
|
||||
down_read(&adev->reset_domain->sem);
|
||||
r = amdgpu_userq_map_helper(queue);
|
||||
up_read(&adev->reset_domain->sem);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
@@ -1823,6 +1823,11 @@ static void gfx_v12_0_constants_init(struct amdgpu_device *adev)
|
||||
gfx_v12_0_get_tcc_info(adev);
|
||||
adev->gfx.config.pa_sc_tile_steering_override = 0;
|
||||
|
||||
/* Set whether texture coordinate truncation is conformant. */
|
||||
tmp = RREG32_SOC15(GC, 0, regTA_CNTL2);
|
||||
adev->gfx.config.ta_cntl2_truncate_coord_mode =
|
||||
REG_GET_FIELD(tmp, TA_CNTL2, TRUNCATE_COORD_MODE);
|
||||
|
||||
/* XXX SH_MEM regs */
|
||||
/* where to put LDS, scratch, GPUVM in FSA64 space */
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
|
||||
@@ -267,9 +267,24 @@ static bool gmc_v12_1_get_vmid_pasid_mapping_info(struct amdgpu_device *adev,
|
||||
* by the amdgpu vm/hsa code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* gmc_v12_1_use_invalidate_semaphore - judge whether to use semaphore
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @vmhub: vmhub type
|
||||
*
|
||||
*/
|
||||
static bool gmc_v12_1_use_invalidate_semaphore(struct amdgpu_device *adev,
|
||||
uint32_t vmhub)
|
||||
{
|
||||
return ((!AMDGPU_IS_GFXHUB(vmhub)) &&
|
||||
(!amdgpu_sriov_vf(adev)));
|
||||
}
|
||||
|
||||
static void gmc_v12_1_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
unsigned int vmhub, uint32_t flush_type)
|
||||
{
|
||||
bool use_semaphore = gmc_v12_1_use_invalidate_semaphore(adev, vmhub);
|
||||
struct amdgpu_vmhub *hub = &adev->vmhub[vmhub];
|
||||
u32 inv_req = hub->vmhub_funcs->get_invalidate_req(vmid, flush_type);
|
||||
u32 tmp;
|
||||
@@ -283,6 +298,19 @@ static void gmc_v12_1_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
|
||||
spin_lock(&adev->gmc.invalidate_lock);
|
||||
|
||||
if (use_semaphore) {
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
tmp = RREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem + hub->eng_distance * eng, hub_ip);
|
||||
if (tmp & 0x1)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i >= adev->usec_timeout)
|
||||
DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
|
||||
}
|
||||
|
||||
WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_req + hub->eng_distance * eng, inv_req, hub_ip);
|
||||
|
||||
/* Wait for ACK with a delay.*/
|
||||
@@ -296,6 +324,9 @@ static void gmc_v12_1_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (use_semaphore)
|
||||
WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem + hub->eng_distance * eng, 0, hub_ip);
|
||||
|
||||
/* Issue additional private vm invalidation to MMHUB */
|
||||
if (!AMDGPU_IS_GFXHUB(vmhub) &&
|
||||
(hub->vm_l2_bank_select_reserved_cid2) &&
|
||||
@@ -396,7 +427,7 @@ static void gmc_v12_1_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
|
||||
|
||||
if (all_hub) {
|
||||
/* invalidate mm_hub */
|
||||
if (test_bit(AMDGPU_MMHUB1(0), adev->vmhubs_mask)) {
|
||||
if (test_bit(AMDGPU_MMHUB0(0), adev->vmhubs_mask)) {
|
||||
input.hub_id = AMDGPU_MMHUB0(0);
|
||||
adev->mes.funcs->invalidate_tlbs_pasid(&adev->mes, &input);
|
||||
}
|
||||
@@ -431,10 +462,17 @@ static void gmc_v12_1_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
|
||||
static uint64_t gmc_v12_1_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
unsigned vmid, uint64_t pd_addr)
|
||||
{
|
||||
bool use_semaphore = gmc_v12_1_use_invalidate_semaphore(ring->adev, ring->vm_hub);
|
||||
struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub];
|
||||
uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0);
|
||||
unsigned eng = ring->vm_inv_eng;
|
||||
|
||||
if (use_semaphore)
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
amdgpu_ring_emit_reg_wait(ring,
|
||||
hub->vm_inv_eng0_sem +
|
||||
hub->eng_distance * eng, 0x1, 0x1);
|
||||
|
||||
amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 +
|
||||
(hub->ctx_addr_distance * vmid),
|
||||
lower_32_bits(pd_addr));
|
||||
@@ -449,6 +487,14 @@ static uint64_t gmc_v12_1_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
hub->eng_distance * eng,
|
||||
req, 1 << vmid);
|
||||
|
||||
if (use_semaphore)
|
||||
/*
|
||||
* add semaphore release after invalidation,
|
||||
* write with 0 means semaphore release
|
||||
*/
|
||||
amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem +
|
||||
hub->eng_distance * eng, 0);
|
||||
|
||||
return pd_addr;
|
||||
}
|
||||
|
||||
|
||||
@@ -772,15 +772,28 @@ static int jpeg_v4_0_5_ring_reset(struct amdgpu_ring *ring,
|
||||
unsigned int vmid,
|
||||
struct amdgpu_fence *timedout_fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 pg_flags = adev->pg_flags;
|
||||
int r;
|
||||
|
||||
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
|
||||
r = jpeg_v4_0_5_stop(ring->adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = jpeg_v4_0_5_start(ring->adev);
|
||||
|
||||
/*
|
||||
* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
|
||||
* hung JRBC, so the post-reset ring test times out and the driver falls
|
||||
* back to a full MODE1 reset. Temporarily force the static power-gating
|
||||
* path so the stop/start sequence actually power-cycles the JPEG block
|
||||
* (JMI soft reset + static power off/on), matching the working jpeg_v4_0
|
||||
* reset.
|
||||
*/
|
||||
adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
|
||||
r = jpeg_v4_0_5_stop(adev);
|
||||
if (!r)
|
||||
r = jpeg_v4_0_5_start(adev);
|
||||
adev->pg_flags = pg_flags;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||
}
|
||||
|
||||
|
||||
@@ -648,15 +648,28 @@ static int jpeg_v5_0_0_ring_reset(struct amdgpu_ring *ring,
|
||||
unsigned int vmid,
|
||||
struct amdgpu_fence *timedout_fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 pg_flags = adev->pg_flags;
|
||||
int r;
|
||||
|
||||
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
|
||||
r = jpeg_v5_0_0_stop(ring->adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = jpeg_v5_0_0_start(ring->adev);
|
||||
|
||||
/*
|
||||
* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
|
||||
* hung JRBC, so the post-reset ring test times out and the driver falls
|
||||
* back to a full MODE1 reset. Temporarily force the static power-gating
|
||||
* path so the stop/start sequence actually power-cycles the JPEG block
|
||||
* (JMI soft reset + ONO1 power off/on), matching the working jpeg_v4_0
|
||||
* reset.
|
||||
*/
|
||||
adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
|
||||
r = jpeg_v5_0_0_stop(adev);
|
||||
if (!r)
|
||||
r = jpeg_v5_0_0_start(adev);
|
||||
adev->pg_flags = pg_flags;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||
}
|
||||
|
||||
|
||||
@@ -655,15 +655,28 @@ static int jpeg_v5_3_0_ring_reset(struct amdgpu_ring *ring,
|
||||
unsigned int vmid,
|
||||
struct amdgpu_fence *timedout_fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 pg_flags = adev->pg_flags;
|
||||
int r;
|
||||
|
||||
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
|
||||
r = jpeg_v5_3_0_stop(ring->adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = jpeg_v5_3_0_start(ring->adev);
|
||||
|
||||
/*
|
||||
* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
|
||||
* hung JRBC, so the post-reset ring test times out and the driver falls
|
||||
* back to a full MODE1 reset. Temporarily force the static power-gating
|
||||
* path so the stop/start sequence actually power-cycles the JPEG block
|
||||
* (JMI soft reset + static power off/on), matching the working jpeg_v4_0
|
||||
* reset.
|
||||
*/
|
||||
adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
|
||||
r = jpeg_v5_3_0_stop(adev);
|
||||
if (!r)
|
||||
r = jpeg_v5_3_0_start(adev);
|
||||
adev->pg_flags = pg_flags;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||
}
|
||||
|
||||
|
||||
@@ -2189,6 +2189,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
|
||||
init_data.flags.unify_link_enc_assignment = true;
|
||||
init_data.flags.usb4_bw_alloc_support = true;
|
||||
}
|
||||
|
||||
/* DCN201 audio desyncs using DP SS */
|
||||
if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2)
|
||||
init_data.flags.ignore_dpref_ss = true;
|
||||
|
||||
retrieve_dmi_info(&adev->dm);
|
||||
if (adev->dm.edp0_on_dp1_quirk)
|
||||
init_data.flags.support_edp0_on_dp1 = true;
|
||||
|
||||
@@ -119,7 +119,11 @@ void amdgpu_dm_crtc_set_static_screen_optimze(
|
||||
struct dc_link *link = stream->link;
|
||||
bool set_vsync_event = !sso_enable;
|
||||
|
||||
if (!allow_sr_entry)
|
||||
/*
|
||||
* allow_sr_entry gates only entry. A disable request must still set
|
||||
* the vsync events to force Replay and PSR1 out and keep them blocked.
|
||||
*/
|
||||
if (sso_enable && !allow_sr_entry)
|
||||
return;
|
||||
|
||||
amdgpu_dm_replay_set_event(dm, stream,
|
||||
|
||||
@@ -1348,7 +1348,10 @@ void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
|
||||
* process the mute state, especially after link re-establishment
|
||||
* with HDMI 2.0 scrambling enabled.
|
||||
*/
|
||||
if (enable && pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
|
||||
if (enable && pipe_ctx->stream_res.tg &&
|
||||
pipe_ctx->stream_res.tg->funcs->is_tg_enabled &&
|
||||
pipe_ctx->stream_res.tg->funcs->wait_for_state &&
|
||||
pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
|
||||
int i;
|
||||
|
||||
pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
|
||||
|
||||
@@ -257,8 +257,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
|
||||
addr_len[PAGE0_SWAUX_LENGTH - base] = (len == 0) ? SWAUX_NO_PAYLOAD :
|
||||
((len - 1) & SWAUX_LENGTH_MASK);
|
||||
|
||||
regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
|
||||
ARRAY_SIZE(addr_len));
|
||||
ret = regmap_bulk_write(map, PAGE0_SWAUX_ADDR_7_0, addr_len,
|
||||
ARRAY_SIZE(addr_len));
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev,
|
||||
"failed to write AUX address %#x, len %zu: %d\n",
|
||||
msg->address, len, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (len && (request == DP_AUX_NATIVE_WRITE ||
|
||||
request == DP_AUX_I2C_WRITE)) {
|
||||
@@ -274,13 +280,22 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux,
|
||||
}
|
||||
}
|
||||
|
||||
regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
|
||||
ret = regmap_write(map, PAGE0_SWAUX_CTRL, SWAUX_SEND);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev, "failed to start AUX transfer: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Zero delay loop because i2c transactions are slow already */
|
||||
regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
|
||||
!(data & SWAUX_SEND), 0, 50 * 1000);
|
||||
ret = regmap_read_poll_timeout(map, PAGE0_SWAUX_CTRL, data,
|
||||
!(data & SWAUX_SEND), 0, 50 * 1000);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev, "failed to complete AUX transfer: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_read(map, PAGE0_SWAUX_STATUS, &data);
|
||||
ret = regmap_read(map, PAGE0_SWAUX_STATUS, &data);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev, "failed to read PAGE0_SWAUX_STATUS: %d\n",
|
||||
ret);
|
||||
|
||||
@@ -597,9 +597,13 @@ static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order,
|
||||
#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
|
||||
} else if (order == PMD_ORDER) {
|
||||
unsigned long paddr = pfn << PAGE_SHIFT;
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
unsigned long start = ALIGN_DOWN(vmf->address, PMD_SIZE);
|
||||
unsigned long end = start + PMD_SIZE;
|
||||
bool in_range = vma->vm_start <= start && end <= vma->vm_end;
|
||||
bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK);
|
||||
|
||||
if (aligned &&
|
||||
if (aligned && in_range &&
|
||||
folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) {
|
||||
vm_fault_t ret;
|
||||
|
||||
|
||||
@@ -603,6 +603,9 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!section_size)
|
||||
return 0;
|
||||
|
||||
name_len = iter->size - iter->offset;
|
||||
|
||||
section = drmm_kzalloc(&ptdev->base, sizeof(*section), GFP_KERNEL);
|
||||
|
||||
@@ -802,9 +802,13 @@ static vm_fault_t insert_page(struct vm_fault *vmf, unsigned int order, struct p
|
||||
} else if (order == PMD_ORDER) {
|
||||
unsigned long pfn = page_to_pfn(page);
|
||||
unsigned long paddr = pfn << PAGE_SHIFT;
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
unsigned long start = ALIGN_DOWN(vmf->address, PMD_SIZE);
|
||||
unsigned long end = start + PMD_SIZE;
|
||||
bool in_range = vma->vm_start <= start && end <= vma->vm_end;
|
||||
bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK);
|
||||
|
||||
if (aligned &&
|
||||
if (aligned && in_range &&
|
||||
folio_test_pmd_mappable(page_folio(page))) {
|
||||
pfn &= PMD_MASK >> PAGE_SHIFT;
|
||||
return vmf_insert_pfn_pmd(vmf, pfn, vmf->flags & FAULT_FLAG_WRITE);
|
||||
|
||||
@@ -360,6 +360,13 @@ static bool radeon_fence_is_signaled(struct dma_fence *f)
|
||||
if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq)
|
||||
return true;
|
||||
|
||||
if (down_read_trylock(&rdev->exclusive_lock)) {
|
||||
radeon_fence_activity(rdev, ring);
|
||||
up_read(&rdev->exclusive_lock);
|
||||
|
||||
if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,12 @@ struct v3d_dev {
|
||||
*/
|
||||
struct mutex reset_lock;
|
||||
|
||||
/* Ordered workqueue shared by every queue's scheduler timeout work.
|
||||
* V3D reset is global to all queues, so the timeout handlers must not
|
||||
* run concurrently.
|
||||
*/
|
||||
struct workqueue_struct *reset_wq;
|
||||
|
||||
/* Lock taken when creating and pushing the GPU scheduler
|
||||
* jobs, to keep the sched-fence seqnos in order.
|
||||
*/
|
||||
|
||||
@@ -837,6 +837,7 @@ v3d_queue_sched_init(struct v3d_dev *v3d, const struct drm_sched_backend_ops *op
|
||||
struct drm_sched_init_args args = {
|
||||
.credit_limit = 1,
|
||||
.timeout = msecs_to_jiffies(500),
|
||||
.timeout_wq = v3d->reset_wq,
|
||||
.dev = v3d->drm.dev,
|
||||
};
|
||||
|
||||
@@ -851,9 +852,13 @@ v3d_sched_init(struct v3d_dev *v3d)
|
||||
{
|
||||
int ret;
|
||||
|
||||
v3d->reset_wq = alloc_ordered_workqueue("v3d_reset", 0);
|
||||
if (!v3d->reset_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = v3d_queue_sched_init(v3d, &v3d_bin_sched_ops, V3D_BIN, "v3d_bin");
|
||||
if (ret)
|
||||
return ret;
|
||||
goto fail;
|
||||
|
||||
ret = v3d_queue_sched_init(v3d, &v3d_render_sched_ops, V3D_RENDER,
|
||||
"v3d_render");
|
||||
@@ -896,4 +901,6 @@ v3d_sched_fini(struct v3d_dev *v3d)
|
||||
if (v3d->queue[q].sched.ready)
|
||||
drm_sched_fini(&v3d->queue[q].sched);
|
||||
}
|
||||
|
||||
destroy_workqueue(v3d->reset_wq);
|
||||
}
|
||||
|
||||
@@ -805,6 +805,9 @@ static int exec_queue_set_hang_replay_state(struct xe_device *xe,
|
||||
u64 __user *address = u64_to_user_ptr(value);
|
||||
void *ptr;
|
||||
|
||||
if (q->replay_state)
|
||||
return -EINVAL;
|
||||
|
||||
ptr = vmemdup_user(address, size);
|
||||
if (XE_IOCTL_DBG(xe, IS_ERR(ptr)))
|
||||
return PTR_ERR(ptr);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "xe_guc_pc.h"
|
||||
#include "xe_guc_rc.h"
|
||||
#include "xe_guc_engine_activity.h"
|
||||
#include "xe_guc_submit.h"
|
||||
#include "xe_huc.h"
|
||||
#include "xe_sriov.h"
|
||||
#include "xe_wopcm.h"
|
||||
@@ -159,12 +160,14 @@ static int vf_uc_load_hw(struct xe_uc *uc)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uc->guc.submission_state.enabled = true;
|
||||
|
||||
err = xe_guc_opt_in_features_enable(&uc->guc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = xe_guc_submit_enable(&uc->guc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = xe_gt_record_default_lrcs(uc_to_gt(uc));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -106,12 +106,11 @@ static int ads7828_probe(struct i2c_client *client)
|
||||
struct ads7828_data *data;
|
||||
struct device *hwmon_dev;
|
||||
unsigned int vref_mv = ADS7828_INT_VREF_MV;
|
||||
unsigned int vref_uv;
|
||||
int vref_uv;
|
||||
bool diff_input = false;
|
||||
bool ext_vref = false;
|
||||
unsigned int regval;
|
||||
enum ads7828_chips chip;
|
||||
struct regulator *reg;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
@@ -125,9 +124,11 @@ static int ads7828_probe(struct i2c_client *client)
|
||||
} else if (dev->of_node) {
|
||||
diff_input = of_property_read_bool(dev->of_node,
|
||||
"ti,differential-input");
|
||||
reg = devm_regulator_get_optional(dev, "vref");
|
||||
if (!IS_ERR(reg)) {
|
||||
vref_uv = regulator_get_voltage(reg);
|
||||
vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
|
||||
if (vref_uv < 0) {
|
||||
if (vref_uv != -ENODEV)
|
||||
return vref_uv;
|
||||
} else {
|
||||
vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
|
||||
if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
|
||||
vref_mv > ADS7828_EXT_VREF_MV_MAX)
|
||||
|
||||
+20
-11
@@ -137,13 +137,18 @@ struct corsairpsu_data {
|
||||
};
|
||||
|
||||
/* some values are SMBus LINEAR11 data which need a conversion */
|
||||
static int corsairpsu_linear11_to_int(const u16 val, const int scale)
|
||||
static long corsairpsu_linear11_to_long(const u16 val, const int scale)
|
||||
{
|
||||
const int exp = ((s16)val) >> 11;
|
||||
const int mant = (((s16)(val & 0x7ff)) << 5) >> 5;
|
||||
const int result = mant * scale;
|
||||
const int mant = ((s16)((val & 0x7ff) << 5)) >> 5;
|
||||
s64 result = mant * scale;
|
||||
|
||||
return (exp >= 0) ? (result << exp) : (result >> -exp);
|
||||
if (exp >= 0)
|
||||
result *= (int)(1UL << exp);
|
||||
else
|
||||
result >>= -exp;
|
||||
|
||||
return clamp(result, LONG_MIN, LONG_MAX);
|
||||
}
|
||||
|
||||
/* the micro-controller uses percentage values to control pwm */
|
||||
@@ -263,13 +268,13 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
|
||||
case PSU_CMD_RAIL_AMPS:
|
||||
case PSU_CMD_TEMP0:
|
||||
case PSU_CMD_TEMP1:
|
||||
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000);
|
||||
*val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1000);
|
||||
break;
|
||||
case PSU_CMD_FAN:
|
||||
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
|
||||
*val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1);
|
||||
break;
|
||||
case PSU_CMD_FAN_PWM_ENABLE:
|
||||
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
|
||||
*val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1);
|
||||
/*
|
||||
* 0 = automatic mode, means the micro-controller controls the fan using a plan
|
||||
* which can be modified, but changing this plan is not supported by this
|
||||
@@ -283,12 +288,12 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
|
||||
*val = 2;
|
||||
break;
|
||||
case PSU_CMD_FAN_PWM:
|
||||
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
|
||||
*val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1);
|
||||
*val = corsairpsu_dutycycle_to_pwm(*val);
|
||||
break;
|
||||
case PSU_CMD_RAIL_WATTS:
|
||||
case PSU_CMD_TOTAL_WATTS:
|
||||
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000);
|
||||
*val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1000000);
|
||||
break;
|
||||
case PSU_CMD_TOTAL_UPTIME:
|
||||
case PSU_CMD_UPTIME:
|
||||
@@ -664,6 +669,8 @@ static void print_uptime(struct seq_file *seqf, u8 cmd)
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
guard(hwmon_lock)(priv->hwmon_dev);
|
||||
|
||||
ret = corsairpsu_get_value(priv, cmd, 0, &val);
|
||||
if (ret < 0) {
|
||||
seq_puts(seqf, "N/A\n");
|
||||
@@ -701,7 +708,7 @@ static int vendor_show(struct seq_file *seqf, void *unused)
|
||||
{
|
||||
struct corsairpsu_data *priv = seqf->private;
|
||||
|
||||
seq_printf(seqf, "%s\n", priv->vendor);
|
||||
seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -711,7 +718,7 @@ static int product_show(struct seq_file *seqf, void *unused)
|
||||
{
|
||||
struct corsairpsu_data *priv = seqf->private;
|
||||
|
||||
seq_printf(seqf, "%s\n", priv->product);
|
||||
seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -723,6 +730,8 @@ static int ocpmode_show(struct seq_file *seqf, void *unused)
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
guard(hwmon_lock)(priv->hwmon_dev);
|
||||
|
||||
/*
|
||||
* The rail mode is switchable on the fly. The RAW interface can be used for this. But it
|
||||
* will not be included here, because I consider it somewhat dangerous for the health of the
|
||||
|
||||
@@ -1083,7 +1083,6 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
|
||||
* @dev: the parent device
|
||||
* @name: hwmon name attribute
|
||||
* @drvdata: driver data to attach to created device
|
||||
* @extra_groups: pointer to list of additional non-standard attribute groups
|
||||
*
|
||||
* The use of this function is restricted. It is provided for legacy reasons
|
||||
* and must only be called from the thermal subsystem.
|
||||
@@ -1095,13 +1094,12 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_info);
|
||||
*/
|
||||
struct device *
|
||||
hwmon_device_register_for_thermal(struct device *dev, const char *name,
|
||||
void *drvdata,
|
||||
const struct attribute_group **extra_groups)
|
||||
void *drvdata)
|
||||
{
|
||||
if (!name || !dev)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return __hwmon_device_register(dev, name, drvdata, NULL, extra_groups);
|
||||
return __hwmon_device_register(dev, name, drvdata, NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(hwmon_device_register_for_thermal, "HWMON_THERMAL");
|
||||
|
||||
|
||||
+12
-8
@@ -14,6 +14,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -137,7 +138,7 @@ struct ltc4282_state {
|
||||
*/
|
||||
struct ltc4282_cache in0_1_cache[LTC4282_CHAN_VGPIO];
|
||||
u32 vsense_max;
|
||||
long power_max;
|
||||
s64 power_max;
|
||||
u32 rsense;
|
||||
u16 vdd;
|
||||
u16 vfs_out;
|
||||
@@ -613,13 +614,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
|
||||
static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
|
||||
long val)
|
||||
s64 val)
|
||||
{
|
||||
u32 power;
|
||||
u64 temp;
|
||||
|
||||
if (val > st->power_max)
|
||||
val = st->power_max;
|
||||
val = clamp(val, 0, st->power_max);
|
||||
|
||||
temp = val * int_pow(U8_MAX, 2) * st->rsense;
|
||||
power = DIV64_U64_ROUND_CLOSEST(temp,
|
||||
@@ -629,7 +629,7 @@ static int ltc4282_write_power_byte(const struct ltc4282_state *st, u32 reg,
|
||||
}
|
||||
|
||||
static int ltc4282_write_power_word(const struct ltc4282_state *st, u32 reg,
|
||||
long val)
|
||||
u64 val)
|
||||
{
|
||||
u64 temp = int_pow(U16_MAX, 2) * st->rsense, temp_2;
|
||||
__be16 __raw;
|
||||
@@ -930,8 +930,11 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
|
||||
static int ltc4282_write_curr(struct ltc4282_state *st, u32 attr,
|
||||
long val)
|
||||
{
|
||||
s32 ulimit = min_t(u64, INT_MAX,
|
||||
div_u64((u64)INT_MAX * DECA * MICRO, st->rsense));
|
||||
u64 val64 = clamp(val, 0, ulimit);
|
||||
/* need to pass it in millivolt */
|
||||
u32 in = DIV_ROUND_CLOSEST_ULL((u64)val * st->rsense, DECA * MICRO);
|
||||
u32 in = DIV_ROUND_CLOSEST_ULL(val64 * st->rsense, DECA * MICRO);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_curr_max:
|
||||
@@ -1222,7 +1225,8 @@ static int ltc4282_set_max_limits(struct ltc4282_state *st)
|
||||
return ret;
|
||||
|
||||
/* Power is given by ISENSE * Vout. */
|
||||
st->power_max = DIV_ROUND_CLOSEST(st->vsense_max * DECA * MILLI, st->rsense) * st->vfs_out;
|
||||
st->power_max = DIV_ROUND_CLOSEST_ULL((u64)st->vsense_max * DECA * MILLI,
|
||||
st->rsense) * st->vfs_out;
|
||||
ret = ltc4282_write_power_byte(st, LTC4282_POWER_MAX, st->power_max);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1390,7 +1394,7 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev)
|
||||
if (!ret) {
|
||||
int reg_val;
|
||||
|
||||
switch (val) {
|
||||
switch (st->vsense_max) {
|
||||
case 12500:
|
||||
reg_val = 0;
|
||||
break;
|
||||
|
||||
@@ -754,7 +754,11 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
|
||||
|
||||
hid_device_io_start(hdev);
|
||||
|
||||
init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
|
||||
ret = init_device(drvdata, UPDATE_INTERVAL_DEFAULT_MS);
|
||||
if (ret) {
|
||||
dev_err(&hdev->dev, "init_device failed: %d\n", ret);
|
||||
goto out_hw_close;
|
||||
}
|
||||
|
||||
drvdata->hwmon =
|
||||
hwmon_device_register_with_info(&hdev->dev, "nzxtsmart2", drvdata,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/of.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
@@ -542,8 +543,8 @@ static int lm25066_probe(struct i2c_client *client)
|
||||
if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
|
||||
shunt = 1000;
|
||||
|
||||
info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
|
||||
info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
|
||||
info->m[PSC_CURRENT_IN] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_CURRENT_IN] * shunt, 1000);
|
||||
info->m[PSC_POWER] = DIV_ROUND_CLOSEST_ULL((u64)info->m[PSC_POWER] * shunt, 1000);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SENSORS_LM25066_REGULATOR)
|
||||
/* LM25056 doesn't support OPERATION */
|
||||
|
||||
@@ -45,7 +45,7 @@ module_param(wp, int, 0444);
|
||||
struct pmbus_sensor {
|
||||
struct pmbus_sensor *next;
|
||||
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
|
||||
struct device_attribute attribute;
|
||||
struct sensor_device_attribute attribute;
|
||||
u8 page; /* page number */
|
||||
u8 phase; /* phase number, 0xff for all phases */
|
||||
u16 reg; /* register */
|
||||
@@ -68,7 +68,7 @@ struct pmbus_boolean {
|
||||
|
||||
struct pmbus_label {
|
||||
char name[PMBUS_NAME_SIZE]; /* sysfs label name */
|
||||
struct device_attribute attribute;
|
||||
struct sensor_device_attribute attribute;
|
||||
char label[PMBUS_NAME_SIZE]; /* label */
|
||||
};
|
||||
#define to_pmbus_label(_attr) \
|
||||
@@ -1241,7 +1241,8 @@ static ssize_t pmbus_show_sensor(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
s64 val;
|
||||
|
||||
@@ -1261,7 +1262,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
|
||||
s64 val;
|
||||
int ret;
|
||||
u16 regval;
|
||||
@@ -1283,7 +1285,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
|
||||
static ssize_t pmbus_show_label(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct pmbus_label *label = to_pmbus_label(da);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct pmbus_label *label = to_pmbus_label(attr);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", label->label);
|
||||
}
|
||||
@@ -1436,8 +1439,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
||||
bool update, bool readonly,
|
||||
bool writeonly, bool convert)
|
||||
{
|
||||
struct sensor_device_attribute *a;
|
||||
struct pmbus_sensor *sensor;
|
||||
struct device_attribute *a;
|
||||
|
||||
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
|
||||
if (!sensor)
|
||||
@@ -1461,12 +1464,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
|
||||
sensor->update = update;
|
||||
sensor->convert = convert;
|
||||
sensor->data = -ENODATA;
|
||||
pmbus_dev_attr_init(a, sensor->name,
|
||||
readonly ? 0444 : 0644,
|
||||
writeonly ? pmbus_show_zero : pmbus_show_sensor,
|
||||
pmbus_set_sensor);
|
||||
pmbus_attr_init(a, sensor->name, readonly ? 0444 : 0644,
|
||||
writeonly ? pmbus_show_zero : pmbus_show_sensor,
|
||||
pmbus_set_sensor, -1);
|
||||
|
||||
if (pmbus_add_attribute(data, &a->attr))
|
||||
if (pmbus_add_attribute(data, &a->dev_attr.attr))
|
||||
return NULL;
|
||||
|
||||
sensor->next = data->sensors;
|
||||
@@ -1483,8 +1485,8 @@ static int pmbus_add_label(struct pmbus_data *data,
|
||||
const char *name, int seq,
|
||||
const char *lstring, int index, int phase)
|
||||
{
|
||||
struct sensor_device_attribute *a;
|
||||
struct pmbus_label *label;
|
||||
struct device_attribute *a;
|
||||
|
||||
label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
|
||||
if (!label)
|
||||
@@ -1508,8 +1510,8 @@ static int pmbus_add_label(struct pmbus_data *data,
|
||||
lstring, index, phase);
|
||||
}
|
||||
|
||||
pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
|
||||
return pmbus_add_attribute(data, &a->attr);
|
||||
pmbus_attr_init(a, label->name, 0444, pmbus_show_label, NULL, -1);
|
||||
return pmbus_add_attribute(data, &a->dev_attr.attr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2397,7 +2399,7 @@ struct pmbus_samples_attr {
|
||||
struct pmbus_samples_reg {
|
||||
int page;
|
||||
struct pmbus_samples_attr *attr;
|
||||
struct device_attribute dev_attr;
|
||||
struct sensor_device_attribute attribute;
|
||||
};
|
||||
|
||||
static struct pmbus_samples_attr pmbus_samples_registers[] = {
|
||||
@@ -2419,14 +2421,15 @@ static struct pmbus_samples_attr pmbus_samples_registers[] = {
|
||||
}
|
||||
};
|
||||
|
||||
#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr)
|
||||
#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, attribute)
|
||||
|
||||
static ssize_t pmbus_show_samples(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int val;
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_samples_reg *reg = to_samples_reg(devattr);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pmbus_samples_reg *reg = to_samples_reg(attr);
|
||||
|
||||
scoped_guard(pmbus_lock, client) {
|
||||
val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
|
||||
@@ -2444,7 +2447,8 @@ static ssize_t pmbus_set_samples(struct device *dev,
|
||||
int ret;
|
||||
long val;
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_samples_reg *reg = to_samples_reg(devattr);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct pmbus_samples_reg *reg = to_samples_reg(attr);
|
||||
|
||||
if (kstrtol(buf, 0, &val) < 0)
|
||||
return -EINVAL;
|
||||
@@ -2459,6 +2463,7 @@ static ssize_t pmbus_set_samples(struct device *dev,
|
||||
static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
|
||||
struct pmbus_samples_attr *attr)
|
||||
{
|
||||
struct sensor_device_attribute *a;
|
||||
struct pmbus_samples_reg *reg;
|
||||
|
||||
reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL);
|
||||
@@ -2468,10 +2473,12 @@ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
|
||||
reg->attr = attr;
|
||||
reg->page = page;
|
||||
|
||||
pmbus_dev_attr_init(®->dev_attr, attr->name, 0644,
|
||||
pmbus_show_samples, pmbus_set_samples);
|
||||
a = ®->attribute;
|
||||
|
||||
return pmbus_add_attribute(data, ®->dev_attr.attr);
|
||||
pmbus_attr_init(a, attr->name, 0644,
|
||||
pmbus_show_samples, pmbus_set_samples, -1);
|
||||
|
||||
return pmbus_add_attribute(data, &a->dev_attr.attr);
|
||||
}
|
||||
|
||||
static int pmbus_add_samples_attributes(struct i2c_client *client,
|
||||
@@ -2979,9 +2986,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
|
||||
struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int index = attr->index;
|
||||
u16 smask = pb_index_to_mask(index);
|
||||
u8 spage = pb_index_to_page(index);
|
||||
u16 sreg = pb_index_to_reg(index);
|
||||
u16 smask, sreg;
|
||||
u8 spage;
|
||||
|
||||
if (index == -1)
|
||||
continue;
|
||||
|
||||
smask = pb_index_to_mask(index);
|
||||
spage = pb_index_to_page(index);
|
||||
sreg = pb_index_to_reg(index);
|
||||
|
||||
if (reg == sreg && page == spage && (smask & flags)) {
|
||||
dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
|
||||
@@ -3427,6 +3440,8 @@ static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg,
|
||||
{
|
||||
int ret;
|
||||
|
||||
guard(pmbus_lock)(client);
|
||||
|
||||
ret = _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8));
|
||||
|
||||
/*
|
||||
@@ -3662,6 +3677,8 @@ static void pmbus_init_debugfs(struct i2c_client *client,
|
||||
if (!entries)
|
||||
return;
|
||||
|
||||
guard(pmbus_lock)(client);
|
||||
|
||||
/*
|
||||
* Add device-specific entries.
|
||||
* Please note that the PMBUS standard allows all registers to be
|
||||
|
||||
+16
-11
@@ -21,6 +21,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cdev.h>
|
||||
#include "input-compat.h"
|
||||
@@ -67,8 +68,10 @@ static size_t evdev_get_mask_cnt(unsigned int type)
|
||||
[EV_SND] = SND_CNT,
|
||||
[EV_FF] = FF_CNT,
|
||||
};
|
||||
unsigned long mask = array_index_mask_nospec(type, EV_CNT);
|
||||
|
||||
return (type < EV_CNT) ? counts[type] : 0;
|
||||
/* Returns 0 for out-of-bounds types, including speculatively */
|
||||
return counts[type & mask] & mask;
|
||||
}
|
||||
|
||||
/* requires the buffer lock to be held */
|
||||
@@ -146,11 +149,11 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
|
||||
struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]);
|
||||
struct input_event ev;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.input_event_sec = ts.tv_sec;
|
||||
ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
|
||||
ev.type = EV_SYN;
|
||||
ev.code = SYN_DROPPED;
|
||||
ev.value = 0;
|
||||
|
||||
client->buffer[client->head++] = ev;
|
||||
client->head &= client->bufsize - 1;
|
||||
@@ -218,20 +221,20 @@ static void __pass_event(struct evdev_client *client,
|
||||
client->head &= client->bufsize - 1;
|
||||
|
||||
if (unlikely(client->head == client->tail)) {
|
||||
struct input_event ev;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.input_event_sec = event->input_event_sec;
|
||||
ev.input_event_usec = event->input_event_usec;
|
||||
ev.type = EV_SYN;
|
||||
ev.code = SYN_DROPPED;
|
||||
|
||||
/*
|
||||
* This effectively "drops" all unconsumed events, leaving
|
||||
* EV_SYN/SYN_DROPPED plus the newest event in the queue.
|
||||
*/
|
||||
client->tail = (client->head - 2) & (client->bufsize - 1);
|
||||
|
||||
client->buffer[client->tail] = (struct input_event) {
|
||||
.input_event_sec = event->input_event_sec,
|
||||
.input_event_usec = event->input_event_usec,
|
||||
.type = EV_SYN,
|
||||
.code = SYN_DROPPED,
|
||||
.value = 0,
|
||||
};
|
||||
|
||||
client->buffer[client->tail] = ev;
|
||||
client->packet_head = client->tail;
|
||||
}
|
||||
|
||||
@@ -253,6 +256,8 @@ static void evdev_pass_values(struct evdev_client *client,
|
||||
if (client->revoked)
|
||||
return;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
ts = ktime_to_timespec64(ev_time[client->clk_type]);
|
||||
event.input_event_sec = ts.tv_sec;
|
||||
event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
|
||||
|
||||
@@ -155,6 +155,9 @@ void iforce_process_packet(struct iforce *iforce,
|
||||
switch (packet_id) {
|
||||
|
||||
case 0x01: /* joystick position data */
|
||||
if (len < 7)
|
||||
break;
|
||||
|
||||
input_report_abs(dev, ABS_X,
|
||||
(__s16) get_unaligned_le16(data));
|
||||
input_report_abs(dev, ABS_Y,
|
||||
@@ -170,6 +173,9 @@ void iforce_process_packet(struct iforce *iforce,
|
||||
break;
|
||||
|
||||
case 0x03: /* wheel position data */
|
||||
if (len < 7)
|
||||
break;
|
||||
|
||||
input_report_abs(dev, ABS_WHEEL,
|
||||
(__s16) get_unaligned_le16(data));
|
||||
input_report_abs(dev, ABS_GAS, 255 - data[2]);
|
||||
@@ -181,6 +187,9 @@ void iforce_process_packet(struct iforce *iforce,
|
||||
break;
|
||||
|
||||
case 0x02: /* status report */
|
||||
if (len < 2)
|
||||
break;
|
||||
|
||||
input_report_key(dev, BTN_DEAD, data[0] & 0x02);
|
||||
input_sync(dev);
|
||||
|
||||
@@ -200,7 +209,7 @@ void iforce_process_packet(struct iforce *iforce,
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 3; j < len; j += 2)
|
||||
for (j = 3; j + sizeof(u16) <= len; j += sizeof(u16))
|
||||
mark_core_as_ready(iforce, get_unaligned_le16(data + j));
|
||||
|
||||
break;
|
||||
|
||||
@@ -158,6 +158,9 @@ static void iforce_usb_irq(struct urb *urb)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!urb->actual_length)
|
||||
goto exit;
|
||||
|
||||
iforce_process_packet(iforce, iforce_usb->data_in[0],
|
||||
iforce_usb->data_in + 1, urb->actual_length - 1);
|
||||
|
||||
|
||||
@@ -373,6 +373,7 @@ static int psxpad_spi_probe(struct spi_device *spi)
|
||||
return err;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, pad);
|
||||
pm_runtime_enable(&spi->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -394,6 +394,7 @@ static const struct xpad_device {
|
||||
{ 0x3285, 0x0646, "Nacon Pro Compact", 0, XTYPE_XBOXONE },
|
||||
{ 0x3285, 0x0662, "Nacon Revolution5 Pro", 0, XTYPE_XBOX360 },
|
||||
{ 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE },
|
||||
{ 0x3507, 0x000b, "ZENAIM LEVERLESS", 0, XTYPE_XBOX360 },
|
||||
{ 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 },
|
||||
{ 0x3537, 0x100f, "GameSir Nova 2 Lite", 0, XTYPE_XBOX360 },
|
||||
{ 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
|
||||
@@ -557,6 +558,7 @@ static const struct usb_device_id xpad_table[] = {
|
||||
XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */
|
||||
XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */
|
||||
XPAD_XBOXONE_VENDOR(0x3285), /* Nacon Evol-X */
|
||||
XPAD_XBOX360_VENDOR(0x3507), /* ZENAIM Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */
|
||||
|
||||
@@ -1916,6 +1916,13 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
|
||||
},
|
||||
.callback = atkbd_deactivate_fixup,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "BCC-N"),
|
||||
},
|
||||
.callback = atkbd_deactivate_fixup,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
|
||||
@@ -1923,6 +1930,14 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
|
||||
},
|
||||
.callback = atkbd_deactivate_fixup,
|
||||
},
|
||||
{
|
||||
/* HONOR MagicBook Pro 14 2026 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ZQC-P"),
|
||||
},
|
||||
.callback = atkbd_deactivate_fixup,
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga Air 14 (83QK) */
|
||||
.matches = {
|
||||
@@ -1932,9 +1947,10 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
|
||||
.callback = atkbd_deactivate_fixup,
|
||||
},
|
||||
{
|
||||
/* Xiaomi Book Pro 14 (TM2424) */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "BCC-N"),
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14"),
|
||||
},
|
||||
.callback = atkbd_deactivate_fixup,
|
||||
},
|
||||
|
||||
@@ -139,10 +139,10 @@ static struct cs40l50_effect *cs40l50_find_effect(int id, struct list_head *effe
|
||||
static int cs40l50_effect_bank_set(struct cs40l50_work *work_data,
|
||||
struct cs40l50_effect *effect)
|
||||
{
|
||||
s16 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
|
||||
u32 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
|
||||
|
||||
if (bank_type >= CS40L50_WVFRM_BANK_NUM) {
|
||||
dev_err(work_data->vib->dev, "Invalid bank (%d)\n", bank_type);
|
||||
dev_err(work_data->vib->dev, "Invalid bank (%u)\n", bank_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -326,6 +326,12 @@ static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (periodic->custom_len < CS40L50_OWT_CUSTOM_DATA_SIZE) {
|
||||
dev_err(vib->dev, "Invalid custom data length (%u)\n",
|
||||
periodic->custom_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
work_data.custom_data = memdup_array_user(effect->u.periodic.custom_data,
|
||||
effect->u.periodic.custom_len,
|
||||
sizeof(s16));
|
||||
|
||||
@@ -423,7 +423,7 @@ static void byd_disconnect(struct psmouse *psmouse)
|
||||
struct byd_data *priv = psmouse->private;
|
||||
|
||||
if (priv) {
|
||||
timer_delete(&priv->timer);
|
||||
timer_shutdown_sync(&priv->timer);
|
||||
kfree(psmouse->private);
|
||||
psmouse->private = NULL;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ static void focaltech_process_rel_packet(struct psmouse *psmouse,
|
||||
{
|
||||
struct focaltech_data *priv = psmouse->private;
|
||||
struct focaltech_hw_state *state = &priv->state;
|
||||
int finger1, finger2;
|
||||
unsigned int finger1, finger2;
|
||||
|
||||
state->pressed = packet[0] >> 7;
|
||||
finger1 = ((packet[0] >> 4) & 0x7) - 1;
|
||||
|
||||
@@ -104,7 +104,9 @@ struct f54_data {
|
||||
|
||||
enum rmi_f54_report_type report_type;
|
||||
u8 *report_data;
|
||||
size_t max_report_size;
|
||||
int report_size;
|
||||
int report_error;
|
||||
|
||||
bool is_busy;
|
||||
struct mutex status_mutex;
|
||||
@@ -339,6 +341,12 @@ static void rmi_f54_buffer_queue(struct vb2_buffer *vb)
|
||||
mutex_lock(&f54->data_mutex);
|
||||
}
|
||||
|
||||
if (f54->report_error) {
|
||||
dev_err(&f54->fn->dev, "Error acquiring report: %d\n", f54->report_error);
|
||||
state = VB2_BUF_STATE_ERROR;
|
||||
goto data_done;
|
||||
}
|
||||
|
||||
ptr = vb2_plane_vaddr(vb, 0);
|
||||
if (!ptr) {
|
||||
dev_err(&f54->fn->dev, "Error acquiring frame ptr\n");
|
||||
@@ -444,7 +452,12 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
|
||||
|
||||
static int rmi_f54_vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
||||
{
|
||||
return rmi_f54_set_input(video_drvdata(file), i);
|
||||
struct f54_data *f54 = video_drvdata(file);
|
||||
|
||||
if (vb2_is_busy(&f54->queue))
|
||||
return -EBUSY;
|
||||
|
||||
return rmi_f54_set_input(f54, i);
|
||||
}
|
||||
|
||||
static int rmi_f54_vidioc_g_input(struct file *file, void *priv,
|
||||
@@ -545,7 +558,14 @@ static void rmi_f54_work(struct work_struct *work)
|
||||
dev_err(&fn->dev, "Bad report size, report type=%d\n",
|
||||
f54->report_type);
|
||||
error = -EINVAL;
|
||||
goto error; /* retry won't help */
|
||||
goto out; /* retry won't help */
|
||||
}
|
||||
|
||||
if (report_size > f54->max_report_size) {
|
||||
dev_err(&fn->dev, "Report size %d exceeds buffer size %zu\n",
|
||||
report_size, f54->max_report_size);
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -556,7 +576,7 @@ static void rmi_f54_work(struct work_struct *work)
|
||||
&command);
|
||||
if (error) {
|
||||
dev_err(&fn->dev, "Failed to read back command\n");
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
if (command & F54_GET_REPORT) {
|
||||
if (time_after(jiffies, f54->timeout)) {
|
||||
@@ -564,7 +584,7 @@ static void rmi_f54_work(struct work_struct *work)
|
||||
error = -ETIMEDOUT;
|
||||
}
|
||||
report_size = 0;
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Get report command completed, reading data\n");
|
||||
@@ -579,7 +599,7 @@ static void rmi_f54_work(struct work_struct *work)
|
||||
fifo, sizeof(fifo));
|
||||
if (error) {
|
||||
dev_err(&fn->dev, "Failed to set fifo start offset\n");
|
||||
goto abort;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr +
|
||||
@@ -588,16 +608,17 @@ static void rmi_f54_work(struct work_struct *work)
|
||||
if (error) {
|
||||
dev_err(&fn->dev, "%s: read [%d bytes] returned %d\n",
|
||||
__func__, size, error);
|
||||
goto abort;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
abort:
|
||||
f54->report_size = error ? 0 : report_size;
|
||||
error:
|
||||
out:
|
||||
if (error)
|
||||
report_size = 0;
|
||||
|
||||
f54->report_size = report_size;
|
||||
f54->report_error = error;
|
||||
|
||||
if (report_size == 0 && !error) {
|
||||
queue_delayed_work(f54->workqueue, &f54->work,
|
||||
msecs_to_jiffies(1));
|
||||
@@ -678,8 +699,8 @@ static int rmi_f54_probe(struct rmi_function *fn)
|
||||
|
||||
rx = f54->num_rx_electrodes;
|
||||
tx = f54->num_tx_electrodes;
|
||||
f54->report_data = devm_kzalloc(&fn->dev,
|
||||
array3_size(tx, rx, sizeof(u16)),
|
||||
f54->max_report_size = array3_size(tx, rx, sizeof(u16));
|
||||
f54->report_data = devm_kzalloc(&fn->dev, f54->max_report_size,
|
||||
GFP_KERNEL);
|
||||
if (f54->report_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -54,10 +54,10 @@ static int rmi_f55_detect(struct rmi_function *fn)
|
||||
f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
|
||||
|
||||
f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
|
||||
f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
|
||||
f55->cfg_num_tx_electrodes = f55->num_tx_electrodes;
|
||||
|
||||
drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
|
||||
drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
|
||||
drv_data->num_tx_electrodes = f55->cfg_num_tx_electrodes;
|
||||
|
||||
if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
|
||||
int i, total;
|
||||
|
||||
@@ -331,6 +331,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
||||
swap(x, y);
|
||||
|
||||
id = (buf[2] >> 4) & 0x0f;
|
||||
if (id >= tsdata->max_support_points)
|
||||
continue;
|
||||
|
||||
input_mt_slot(tsdata->input, id);
|
||||
if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
|
||||
|
||||
@@ -312,6 +312,12 @@ static void cst3xx_touch_report(struct i2c_client *client)
|
||||
return;
|
||||
|
||||
touch_cnt = buf[5] & CST3XX_TOUCH_COUNT_MASK;
|
||||
if (touch_cnt > ts_data->chip->max_touch_num) {
|
||||
dev_err(&client->dev, "cst3xx invalid touch count (%d vs %d max)\n",
|
||||
touch_cnt, ts_data->chip->max_touch_num);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the check bit of the last touch slot. The check bit is
|
||||
* always present after touch point 1 for valid data, and then
|
||||
@@ -334,9 +340,10 @@ static void cst3xx_touch_report(struct i2c_client *client)
|
||||
finger_id = (buf[idx] >> 4) & 0x0f;
|
||||
|
||||
/* Sanity check we don't have more fingers than we expect */
|
||||
if (ts_data->chip->max_touch_num < finger_id) {
|
||||
dev_err(&client->dev, "cst3xx touch read failure\n");
|
||||
break;
|
||||
if (finger_id >= ts_data->chip->max_touch_num) {
|
||||
dev_err(&client->dev,
|
||||
"cst3xx invalid finger id %d\n", finger_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sw value of 0 means no touch, 0x03 means touch */
|
||||
|
||||
+18
-9
@@ -492,6 +492,7 @@ static void fastrpc_channel_ctx_free(struct kref *ref)
|
||||
|
||||
cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
|
||||
|
||||
idr_destroy(&cctx->ctx_idr);
|
||||
kfree(cctx);
|
||||
}
|
||||
|
||||
@@ -1305,10 +1306,12 @@ bail:
|
||||
}
|
||||
|
||||
if (err == -ERESTARTSYS) {
|
||||
spin_lock(&fl->lock);
|
||||
list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
|
||||
list_del(&buf->node);
|
||||
list_add_tail(&buf->node, &fl->cctx->invoke_interrupted_mmaps);
|
||||
}
|
||||
spin_unlock(&fl->lock);
|
||||
}
|
||||
|
||||
if (err)
|
||||
@@ -1370,7 +1373,9 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
|
||||
err = PTR_ERR(name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
inbuf.client_id = fl->client_id;
|
||||
inbuf.namelen = init.namelen;
|
||||
inbuf.pageslen = 0;
|
||||
if (!fl->cctx->remote_heap) {
|
||||
err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
|
||||
&fl->cctx->remote_heap);
|
||||
@@ -1393,12 +1398,10 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
|
||||
goto err_map;
|
||||
}
|
||||
scm_done = true;
|
||||
inbuf.pageslen = 1;
|
||||
}
|
||||
}
|
||||
|
||||
inbuf.client_id = fl->client_id;
|
||||
inbuf.namelen = init.namelen;
|
||||
inbuf.pageslen = 0;
|
||||
fl->pd = USER_PD;
|
||||
|
||||
args[0].ptr = (u64)(uintptr_t)&inbuf;
|
||||
@@ -1673,7 +1676,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
|
||||
dev_err(&cctx->rpdev->dev, "No session available\n");
|
||||
mutex_destroy(&fl->mutex);
|
||||
kfree(fl);
|
||||
|
||||
fastrpc_channel_ctx_put(cctx);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -1889,9 +1892,6 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *
|
||||
&args[0]);
|
||||
if (!err) {
|
||||
dev_dbg(dev, "unmmap\tpt 0x%09lx OK\n", buf->raddr);
|
||||
spin_lock(&fl->lock);
|
||||
list_del(&buf->node);
|
||||
spin_unlock(&fl->lock);
|
||||
fastrpc_buf_free(buf);
|
||||
} else {
|
||||
dev_err(dev, "unmmap\tpt 0x%09lx ERROR\n", buf->raddr);
|
||||
@@ -1905,6 +1905,7 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
|
||||
struct fastrpc_buf *buf = NULL, *iter, *b;
|
||||
struct fastrpc_req_munmap req;
|
||||
struct device *dev = fl->sctx->dev;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&req, argp, sizeof(req)))
|
||||
return -EFAULT;
|
||||
@@ -1912,6 +1913,7 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
|
||||
spin_lock(&fl->lock);
|
||||
list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
|
||||
if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
|
||||
list_del(&iter->node);
|
||||
buf = iter;
|
||||
break;
|
||||
}
|
||||
@@ -1924,7 +1926,14 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return fastrpc_req_munmap_impl(fl, buf);
|
||||
err = fastrpc_req_munmap_impl(fl, buf);
|
||||
if (err) {
|
||||
spin_lock(&fl->lock);
|
||||
list_add_tail(&buf->node, &fl->mmaps);
|
||||
spin_unlock(&fl->lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
|
||||
|
||||
+15
-10
@@ -425,18 +425,24 @@ static void mei_io_tx_list_free_cl(struct list_head *head,
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_io_list_free_fp - free cb from a list that matches file pointer
|
||||
* mei_io_rd_list_free_fp - free cb from a rd_completed list that matches file pointer
|
||||
*
|
||||
* @head: io list
|
||||
* @cl: host client
|
||||
* @fp: file pointer (matching cb file object), may be NULL
|
||||
*/
|
||||
static void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
|
||||
static void mei_io_rd_list_free_fp(struct mei_cl *cl, const struct file *fp)
|
||||
{
|
||||
struct mei_cl_cb *cb, *next;
|
||||
LIST_HEAD(cmpl_list);
|
||||
|
||||
list_for_each_entry_safe(cb, next, head, list)
|
||||
spin_lock(&cl->rd_completed_lock);
|
||||
list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
|
||||
if (!fp || fp == cb->fp)
|
||||
mei_io_cb_free(cb);
|
||||
list_move(&cb->list, &cmpl_list);
|
||||
spin_unlock(&cl->rd_completed_lock);
|
||||
|
||||
list_for_each_entry_safe(cb, next, &cmpl_list, list)
|
||||
mei_io_cb_free(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,9 +571,7 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
|
||||
mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl);
|
||||
mei_cl_free_pending(cl);
|
||||
}
|
||||
spin_lock(&cl->rd_completed_lock);
|
||||
mei_io_list_free_fp(&cl->rd_completed, fp);
|
||||
spin_unlock(&cl->rd_completed_lock);
|
||||
mei_io_rd_list_free_fp(cl, fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1401,7 +1405,7 @@ void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_cl_del_rd_completed - free read completed callback with lock
|
||||
* mei_cl_del_rd_completed - unlink read completed callback with lock and free it
|
||||
*
|
||||
* @cl: host client
|
||||
* @cb: callback block
|
||||
@@ -1410,8 +1414,9 @@ void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
|
||||
void mei_cl_del_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
|
||||
{
|
||||
spin_lock(&cl->rd_completed_lock);
|
||||
mei_io_cb_free(cb);
|
||||
list_del_init(&cb->list);
|
||||
spin_unlock(&cl->rd_completed_lock);
|
||||
mei_io_cb_free(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11789,10 +11789,21 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,
|
||||
{
|
||||
struct bnxt_irq *irq;
|
||||
u16 tag;
|
||||
int err;
|
||||
|
||||
irq = container_of(notify, struct bnxt_irq, affinity_notify);
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
if (irq->bp->dev->rx_cpu_rmap && irq->ring_nr < irq->bp->rx_nr_rings) {
|
||||
int err;
|
||||
|
||||
err = cpu_rmap_update(irq->bp->dev->rx_cpu_rmap, irq->ring_nr,
|
||||
mask);
|
||||
if (err)
|
||||
netdev_warn(irq->bp->dev,
|
||||
"aRFS rmap update failed: %d\n", err);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!irq->bp->tph_mode)
|
||||
return;
|
||||
|
||||
@@ -11802,20 +11813,11 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,
|
||||
return;
|
||||
|
||||
if (pcie_tph_get_cpu_st(irq->bp->pdev, TPH_MEM_TYPE_VM,
|
||||
cpumask_first(irq->cpu_mask), &tag))
|
||||
cpumask_first(mask), &tag))
|
||||
return;
|
||||
|
||||
if (pcie_tph_set_st_entry(irq->bp->pdev, irq->msix_nr, tag))
|
||||
return;
|
||||
|
||||
netdev_lock(irq->bp->dev);
|
||||
if (netif_running(irq->bp->dev)) {
|
||||
err = netdev_rx_queue_restart(irq->bp->dev, irq->ring_nr);
|
||||
if (err)
|
||||
netdev_err(irq->bp->dev,
|
||||
"RX queue restart failed: err=%d\n", err);
|
||||
}
|
||||
netdev_unlock(irq->bp->dev);
|
||||
WRITE_ONCE(irq->new_tag, tag);
|
||||
bnxt_queue_sp_work(irq->bp, BNXT_TPH_UPDATE_SP_EVENT);
|
||||
}
|
||||
|
||||
static void bnxt_irq_affinity_release(struct kref *ref)
|
||||
@@ -11866,10 +11868,6 @@ static void bnxt_free_irq(struct bnxt *bp)
|
||||
struct bnxt_irq *irq;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
|
||||
bp->dev->rx_cpu_rmap = NULL;
|
||||
#endif
|
||||
if (!bp->irq_tbl || !bp->bnapi)
|
||||
return;
|
||||
|
||||
@@ -11878,27 +11876,35 @@ static void bnxt_free_irq(struct bnxt *bp)
|
||||
|
||||
irq = &bp->irq_tbl[map_idx];
|
||||
if (irq->requested) {
|
||||
bnxt_release_irq_notifier(irq);
|
||||
|
||||
if (irq->have_cpumask) {
|
||||
irq_update_affinity_hint(irq->vector, NULL);
|
||||
free_cpumask_var(irq->cpu_mask);
|
||||
irq->have_cpumask = 0;
|
||||
}
|
||||
|
||||
bnxt_release_irq_notifier(irq);
|
||||
|
||||
free_irq(irq->vector, bp->bnapi[i]);
|
||||
}
|
||||
|
||||
irq->requested = 0;
|
||||
irq->tag = 0;
|
||||
irq->new_tag = 0;
|
||||
}
|
||||
|
||||
/* Disable TPH support */
|
||||
pcie_disable_tph(bp->pdev);
|
||||
bp->tph_mode = 0;
|
||||
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
|
||||
bp->dev->rx_cpu_rmap = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int bnxt_request_irq(struct bnxt *bp)
|
||||
{
|
||||
const int numa_node = dev_to_node(&bp->pdev->dev);
|
||||
struct cpu_rmap *rmap = NULL;
|
||||
int i, j, rc = 0;
|
||||
unsigned long flags = 0;
|
||||
@@ -11921,6 +11927,8 @@ static int bnxt_request_irq(struct bnxt *bp)
|
||||
for (i = 0, j = 0; i < bp->cp_nr_rings; i++) {
|
||||
int map_idx = bnxt_cp_num_to_irq_num(bp, i);
|
||||
struct bnxt_irq *irq = &bp->irq_tbl[map_idx];
|
||||
unsigned int cpu_num;
|
||||
u16 tag;
|
||||
|
||||
if (IS_ENABLED(CONFIG_RFS_ACCEL) &&
|
||||
rmap && bp->bnapi[i]->rx_ring) {
|
||||
@@ -11939,32 +11947,31 @@ static int bnxt_request_irq(struct bnxt *bp)
|
||||
netif_napi_set_irq_locked(&bp->bnapi[i]->napi, irq->vector);
|
||||
irq->requested = 1;
|
||||
|
||||
if (zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL)) {
|
||||
int numa_node = dev_to_node(&bp->pdev->dev);
|
||||
u16 tag;
|
||||
if (!zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL))
|
||||
continue;
|
||||
|
||||
irq->have_cpumask = 1;
|
||||
irq->msix_nr = map_idx;
|
||||
irq->ring_nr = i;
|
||||
cpumask_set_cpu(cpumask_local_spread(i, numa_node),
|
||||
irq->cpu_mask);
|
||||
rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
|
||||
if (rc) {
|
||||
netdev_warn(bp->dev,
|
||||
"Update affinity hint failed, IRQ = %d\n",
|
||||
irq->vector);
|
||||
break;
|
||||
}
|
||||
irq->have_cpumask = 1;
|
||||
irq->msix_nr = map_idx;
|
||||
irq->ring_nr = i;
|
||||
cpu_num = cpumask_local_spread(i, numa_node);
|
||||
cpumask_set_cpu(cpu_num, irq->cpu_mask);
|
||||
|
||||
bnxt_register_irq_notifier(bp, irq);
|
||||
/* Init ST table entry if we can get the mapping */
|
||||
if (!pcie_tph_get_cpu_st(bp->pdev, TPH_MEM_TYPE_VM,
|
||||
cpu_num, &tag)) {
|
||||
pcie_tph_set_st_entry(bp->pdev, irq->msix_nr, tag);
|
||||
irq->tag = tag;
|
||||
irq->new_tag = tag;
|
||||
}
|
||||
|
||||
/* Init ST table entry */
|
||||
if (pcie_tph_get_cpu_st(irq->bp->pdev, TPH_MEM_TYPE_VM,
|
||||
cpumask_first(irq->cpu_mask),
|
||||
&tag))
|
||||
continue;
|
||||
bnxt_register_irq_notifier(bp, irq);
|
||||
|
||||
pcie_tph_set_st_entry(irq->bp->pdev, irq->msix_nr, tag);
|
||||
rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
|
||||
if (rc) {
|
||||
netdev_warn(bp->dev,
|
||||
"Update affinity hint failed, IRQ = %d\n",
|
||||
irq->vector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -14468,6 +14475,43 @@ static void bnxt_rtnl_unlock_sp(struct bnxt *bp)
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void bnxt_tph_update(struct bnxt *bp)
|
||||
{
|
||||
struct net_device *dev = bp->dev;
|
||||
int i;
|
||||
|
||||
bnxt_lock_sp(bp);
|
||||
if (!test_bit(BNXT_STATE_OPEN, &bp->state))
|
||||
goto unlock;
|
||||
|
||||
for (i = 0; i < bp->rx_nr_rings; i++) {
|
||||
struct bnxt_irq *irq;
|
||||
int map_idx, err;
|
||||
u16 tag;
|
||||
|
||||
map_idx = bnxt_cp_num_to_irq_num(bp, i);
|
||||
irq = &bp->irq_tbl[map_idx];
|
||||
tag = READ_ONCE(irq->new_tag);
|
||||
if (irq->tag == tag)
|
||||
continue;
|
||||
|
||||
if (pcie_tph_set_st_entry(bp->pdev, irq->msix_nr, tag))
|
||||
continue;
|
||||
|
||||
err = netdev_rx_queue_restart(dev, irq->ring_nr);
|
||||
if (err) {
|
||||
netdev_err(dev, "RX queue restart failed: err=%d\n",
|
||||
err);
|
||||
continue;
|
||||
}
|
||||
|
||||
irq->tag = tag;
|
||||
}
|
||||
|
||||
unlock:
|
||||
bnxt_unlock_sp(bp);
|
||||
}
|
||||
|
||||
/* Only called from bnxt_sp_task() */
|
||||
static void bnxt_reset(struct bnxt *bp, bool silent)
|
||||
{
|
||||
@@ -14892,6 +14936,9 @@ static void bnxt_sp_task(struct work_struct *work)
|
||||
bnxt_devlink_health_fw_report(bp);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(BNXT_TPH_UPDATE_SP_EVENT, &bp->sp_event))
|
||||
bnxt_tph_update(bp);
|
||||
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
|
||||
}
|
||||
|
||||
@@ -1268,6 +1268,8 @@ struct bnxt_irq {
|
||||
struct bnxt *bp;
|
||||
int msix_nr;
|
||||
int ring_nr;
|
||||
u16 tag;
|
||||
u16 new_tag;
|
||||
struct irq_affinity_notify affinity_notify;
|
||||
};
|
||||
|
||||
@@ -2642,6 +2644,7 @@ struct bnxt {
|
||||
#define BNXT_RING_COAL_NOW_SP_EVENT 17
|
||||
#define BNXT_FW_RESET_NOTIFY_SP_EVENT 18
|
||||
#define BNXT_FW_EXCEPTION_SP_EVENT 19
|
||||
#define BNXT_TPH_UPDATE_SP_EVENT 20
|
||||
#define BNXT_LINK_CFG_CHANGE_SP_EVENT 21
|
||||
#define BNXT_THERMAL_THRESHOLD_SP_EVENT 22
|
||||
#define BNXT_FW_ECHO_REQUEST_SP_EVENT 23
|
||||
|
||||
@@ -26,6 +26,11 @@ int gve_clock_nic_ts_read(struct gve_priv *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gve_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int gve_ptp_gettimex64(struct ptp_clock_info *info,
|
||||
struct timespec64 *ts,
|
||||
struct ptp_system_timestamp *sts)
|
||||
@@ -60,6 +65,7 @@ out:
|
||||
static const struct ptp_clock_info gve_ptp_caps = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "gve clock",
|
||||
.adjfine = gve_ptp_adjfine,
|
||||
.gettimex64 = gve_ptp_gettimex64,
|
||||
.settime64 = gve_ptp_settime64,
|
||||
.do_aux_work = gve_ptp_do_aux_work,
|
||||
|
||||
@@ -883,6 +883,11 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
|
||||
rx->rx_hsplit_unsplit_pkt += unsplit;
|
||||
rx->rx_hsplit_bytes += hdr_len;
|
||||
u64_stats_update_end(&rx->statss);
|
||||
|
||||
if (!buf_len) {
|
||||
gve_free_buffer(rx, buf_state);
|
||||
return 0;
|
||||
}
|
||||
} else if (!rx->ctx.skb_head && rx->dqo.page_pool &&
|
||||
netmem_is_net_iov(buf_state->page_info.netmem)) {
|
||||
/* when header split is disabled, the header went to the packet
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user