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.c
  5f3a13e0bb ("net: ngbe: fix NULL pointer dereference in non-MSI-X interrupt enabling")
  d661abdc30 ("net: ngbe: correct misleading interrupt comment")

drivers/net/ipvlan/ipvlan_main.c
  e16e960d55 ("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:
Jakub Kicinski
2026-08-13 11:00:14 -07:00
306 changed files with 4317 additions and 1492 deletions
+7
View File
@@ -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.
+26
View File
@@ -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
------------------
+22 -17
View File
@@ -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
View File
@@ -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>
+1 -1
View File
@@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 2
SUBLEVEL = 0
EXTRAVERSION = -rc6
EXTRAVERSION = -rc7
NAME = Baby Opossum Posse
# *DOCUMENTATION*
-2
View File
@@ -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
View File
@@ -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;
}
+2 -9
View File
@@ -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",
+4
View File
@@ -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
+2
View File
@@ -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
+1 -1
View File
@@ -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(&params->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;
}
+1 -1
View File
@@ -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) ?
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+3 -3
View File
@@ -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;
+14 -5
View File
@@ -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
View File
@@ -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;
}
+6 -4
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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(),
+1 -1
View File
@@ -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);
}
+4 -3
View File
@@ -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;
+4 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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 */
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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);
+7 -1
View File
@@ -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
View File
@@ -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);
+26 -21
View File
@@ -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;
}
+8 -4
View File
@@ -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(())
+1
View File
@@ -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 },
/*
+3 -1
View File
@@ -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)
+17 -10
View File
@@ -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;
+2 -2
View File
@@ -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])) {
+1 -1
View File
@@ -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;
}
}
+1 -1
View File
@@ -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;
+3 -19
View File
@@ -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)
-1
View File
@@ -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);
+4 -10
View File
@@ -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);
+3 -1
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+2 -1
View File
@@ -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);
+26 -1
View File
@@ -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 */
+15 -6
View File
@@ -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);
+13 -16
View File
@@ -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);
+5
View File
@@ -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);
+47 -1
View File
@@ -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;
}
+17 -4
View File
@@ -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);
}
+17 -4
View File
@@ -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);
}
+17 -4
View File
@@ -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);
+21 -6
View File
@@ -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);
+5 -1
View File
@@ -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;
+3
View File
@@ -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);
+5 -1
View File
@@ -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);
+7
View File
@@ -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;
}
+6
View File
@@ -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.
*/
+8 -1
View File
@@ -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);
}
+3
View File
@@ -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);
+5 -2
View File
@@ -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;
+6 -5
View File
@@ -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
View File
@@ -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
+2 -4
View File
@@ -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
View File
@@ -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;
+5 -1
View File
@@ -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,
+3 -2
View File
@@ -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 */
+41 -24
View File
@@ -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(&reg->dev_attr, attr->name, 0644,
pmbus_show_samples, pmbus_set_samples);
a = &reg->attribute;
return pmbus_add_attribute(data, &reg->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
View File
@@ -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;
+10 -1
View File
@@ -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);
+1
View File
@@ -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;
+2
View File
@@ -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 */
+18 -2
View File
@@ -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,
},
+8 -2
View File
@@ -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));
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+32 -11
View File
@@ -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;
+2 -2
View File
@@ -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;
+2
View File
@@ -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,
+10 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
/**
+88 -41
View File
@@ -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